• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/src/router/busybox-1.x/e2fsprogs/old_e2fsprogs/ext2fs/
1/* vi: set sw=4 ts=4: */
2/*
3 * block.c --- iterate over all blocks in an inode
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22struct block_context {
23	ext2_filsys	fs;
24	int (*func)(ext2_filsys	fs,
25		    blk_t	*blocknr,
26		    e2_blkcnt_t	bcount,
27		    blk_t	ref_blk,
28		    int		ref_offset,
29		    void	*priv_data);
30	e2_blkcnt_t	bcount;
31	int		bsize;
32	int		flags;
33	errcode_t	errcode;
34	char	*ind_buf;
35	char	*dind_buf;
36	char	*tind_buf;
37	void	*priv_data;
38};
39
40static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
41			     int ref_offset, struct block_context *ctx)
42{
43	int	ret = 0, changed = 0;
44	int	i, flags, limit, offset;
45	blk_t	*block_nr;
46
47	limit = ctx->fs->blocksize >> 2;
48	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
49	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
50		ret = (*ctx->func)(ctx->fs, ind_block,
51				   BLOCK_COUNT_IND, ref_block,
52				   ref_offset, ctx->priv_data);
53	if (!*ind_block || (ret & BLOCK_ABORT)) {
54		ctx->bcount += limit;
55		return ret;
56	}
57	if (*ind_block >= ctx->fs->super->s_blocks_count ||
58	    *ind_block < ctx->fs->super->s_first_data_block) {
59		ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
60		ret |= BLOCK_ERROR;
61		return ret;
62	}
63	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
64					     ctx->ind_buf);
65	if (ctx->errcode) {
66		ret |= BLOCK_ERROR;
67		return ret;
68	}
69
70	block_nr = (blk_t *) ctx->ind_buf;
71	offset = 0;
72	if (ctx->flags & BLOCK_FLAG_APPEND) {
73		for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
74			flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
75					     *ind_block, offset,
76					     ctx->priv_data);
77			changed	|= flags;
78			if (flags & BLOCK_ABORT) {
79				ret |= BLOCK_ABORT;
80				break;
81			}
82			offset += sizeof(blk_t);
83		}
84	} else {
85		for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
86			if (*block_nr == 0)
87				continue;
88			flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
89					     *ind_block, offset,
90					     ctx->priv_data);
91			changed	|= flags;
92			if (flags & BLOCK_ABORT) {
93				ret |= BLOCK_ABORT;
94				break;
95			}
96			offset += sizeof(blk_t);
97		}
98	}
99	if (changed & BLOCK_CHANGED) {
100		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
101						      ctx->ind_buf);
102		if (ctx->errcode)
103			ret |= BLOCK_ERROR | BLOCK_ABORT;
104	}
105	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
106	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
107	    !(ret & BLOCK_ABORT))
108		ret |= (*ctx->func)(ctx->fs, ind_block,
109				    BLOCK_COUNT_IND, ref_block,
110				    ref_offset, ctx->priv_data);
111	return ret;
112}
113
114static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
115			      int ref_offset, struct block_context *ctx)
116{
117	int	ret = 0, changed = 0;
118	int	i, flags, limit, offset;
119	blk_t	*block_nr;
120
121	limit = ctx->fs->blocksize >> 2;
122	if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
123			    BLOCK_FLAG_DATA_ONLY)))
124		ret = (*ctx->func)(ctx->fs, dind_block,
125				   BLOCK_COUNT_DIND, ref_block,
126				   ref_offset, ctx->priv_data);
127	if (!*dind_block || (ret & BLOCK_ABORT)) {
128		ctx->bcount += limit*limit;
129		return ret;
130	}
131	if (*dind_block >= ctx->fs->super->s_blocks_count ||
132	    *dind_block < ctx->fs->super->s_first_data_block) {
133		ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
134		ret |= BLOCK_ERROR;
135		return ret;
136	}
137	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
138					     ctx->dind_buf);
139	if (ctx->errcode) {
140		ret |= BLOCK_ERROR;
141		return ret;
142	}
143
144	block_nr = (blk_t *) ctx->dind_buf;
145	offset = 0;
146	if (ctx->flags & BLOCK_FLAG_APPEND) {
147		for (i = 0; i < limit; i++, block_nr++) {
148			flags = block_iterate_ind(block_nr,
149						  *dind_block, offset,
150						  ctx);
151			changed |= flags;
152			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
153				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
154				break;
155			}
156			offset += sizeof(blk_t);
157		}
158	} else {
159		for (i = 0; i < limit; i++, block_nr++) {
160			if (*block_nr == 0) {
161				ctx->bcount += limit;
162				continue;
163			}
164			flags = block_iterate_ind(block_nr,
165						  *dind_block, offset,
166						  ctx);
167			changed |= flags;
168			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
169				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
170				break;
171			}
172			offset += sizeof(blk_t);
173		}
174	}
175	if (changed & BLOCK_CHANGED) {
176		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
177						      ctx->dind_buf);
178		if (ctx->errcode)
179			ret |= BLOCK_ERROR | BLOCK_ABORT;
180	}
181	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
182	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
183	    !(ret & BLOCK_ABORT))
184		ret |= (*ctx->func)(ctx->fs, dind_block,
185				    BLOCK_COUNT_DIND, ref_block,
186				    ref_offset, ctx->priv_data);
187	return ret;
188}
189
190static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
191			      int ref_offset, struct block_context *ctx)
192{
193	int	ret = 0, changed = 0;
194	int	i, flags, limit, offset;
195	blk_t	*block_nr;
196
197	limit = ctx->fs->blocksize >> 2;
198	if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
199			    BLOCK_FLAG_DATA_ONLY)))
200		ret = (*ctx->func)(ctx->fs, tind_block,
201				   BLOCK_COUNT_TIND, ref_block,
202				   ref_offset, ctx->priv_data);
203	if (!*tind_block || (ret & BLOCK_ABORT)) {
204		ctx->bcount += limit*limit*limit;
205		return ret;
206	}
207	if (*tind_block >= ctx->fs->super->s_blocks_count ||
208	    *tind_block < ctx->fs->super->s_first_data_block) {
209		ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
210		ret |= BLOCK_ERROR;
211		return ret;
212	}
213	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
214					     ctx->tind_buf);
215	if (ctx->errcode) {
216		ret |= BLOCK_ERROR;
217		return ret;
218	}
219
220	block_nr = (blk_t *) ctx->tind_buf;
221	offset = 0;
222	if (ctx->flags & BLOCK_FLAG_APPEND) {
223		for (i = 0; i < limit; i++, block_nr++) {
224			flags = block_iterate_dind(block_nr,
225						   *tind_block,
226						   offset, ctx);
227			changed |= flags;
228			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
229				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
230				break;
231			}
232			offset += sizeof(blk_t);
233		}
234	} else {
235		for (i = 0; i < limit; i++, block_nr++) {
236			if (*block_nr == 0) {
237				ctx->bcount += limit*limit;
238				continue;
239			}
240			flags = block_iterate_dind(block_nr,
241						   *tind_block,
242						   offset, ctx);
243			changed |= flags;
244			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
245				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
246				break;
247			}
248			offset += sizeof(blk_t);
249		}
250	}
251	if (changed & BLOCK_CHANGED) {
252		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
253						      ctx->tind_buf);
254		if (ctx->errcode)
255			ret |= BLOCK_ERROR | BLOCK_ABORT;
256	}
257	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
258	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
259	    !(ret & BLOCK_ABORT))
260		ret |= (*ctx->func)(ctx->fs, tind_block,
261				    BLOCK_COUNT_TIND, ref_block,
262				    ref_offset, ctx->priv_data);
263
264	return ret;
265}
266
267errcode_t ext2fs_block_iterate2(ext2_filsys fs,
268				ext2_ino_t ino,
269				int	flags,
270				char *block_buf,
271				int (*func)(ext2_filsys fs,
272					    blk_t	*blocknr,
273					    e2_blkcnt_t	blockcnt,
274					    blk_t	ref_blk,
275					    int		ref_offset,
276					    void	*priv_data),
277				void *priv_data)
278{
279	int	i;
280	int	got_inode = 0;
281	int	ret = 0;
282	blk_t	blocks[EXT2_N_BLOCKS];	/* directory data blocks */
283	struct ext2_inode inode;
284	errcode_t	retval;
285	struct block_context ctx;
286	int	limit;
287
288	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
289
290	/*
291	 * Check to see if we need to limit large files
292	 */
293	if (flags & BLOCK_FLAG_NO_LARGE) {
294		ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
295		if (ctx.errcode)
296			return ctx.errcode;
297		got_inode = 1;
298		if (!LINUX_S_ISDIR(inode.i_mode) &&
299		    (inode.i_size_high != 0))
300			return EXT2_ET_FILE_TOO_BIG;
301	}
302
303	retval = ext2fs_get_blocks(fs, ino, blocks);
304	if (retval)
305		return retval;
306
307	limit = fs->blocksize >> 2;
308
309	ctx.fs = fs;
310	ctx.func = func;
311	ctx.priv_data = priv_data;
312	ctx.flags = flags;
313	ctx.bcount = 0;
314	if (block_buf) {
315		ctx.ind_buf = block_buf;
316	} else {
317		retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
318		if (retval)
319			return retval;
320	}
321	ctx.dind_buf = ctx.ind_buf + fs->blocksize;
322	ctx.tind_buf = ctx.dind_buf + fs->blocksize;
323
324	/*
325	 * Iterate over the HURD translator block (if present)
326	 */
327	if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
328	    !(flags & BLOCK_FLAG_DATA_ONLY)) {
329		ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
330		if (ctx.errcode)
331			goto abort_exit;
332		got_inode = 1;
333		if (inode.osd1.hurd1.h_i_translator) {
334			ret |= (*ctx.func)(fs,
335					   &inode.osd1.hurd1.h_i_translator,
336					   BLOCK_COUNT_TRANSLATOR,
337					   0, 0, priv_data);
338			if (ret & BLOCK_ABORT)
339				goto abort_exit;
340		}
341	}
342
343	/*
344	 * Iterate over normal data blocks
345	 */
346	for (i = 0; i < EXT2_NDIR_BLOCKS; i++, ctx.bcount++) {
347		if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
348			ret |= (*ctx.func)(fs, &blocks[i],
349					    ctx.bcount, 0, i, priv_data);
350			if (ret & BLOCK_ABORT)
351				goto abort_exit;
352		}
353	}
354	if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
355		ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
356					 0, EXT2_IND_BLOCK, &ctx);
357		if (ret & BLOCK_ABORT)
358			goto abort_exit;
359	} else
360		ctx.bcount += limit;
361	if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
362		ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
363					  0, EXT2_DIND_BLOCK, &ctx);
364		if (ret & BLOCK_ABORT)
365			goto abort_exit;
366	} else
367		ctx.bcount += limit * limit;
368	if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
369		ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
370					  0, EXT2_TIND_BLOCK, &ctx);
371		if (ret & BLOCK_ABORT)
372			goto abort_exit;
373	}
374
375abort_exit:
376	if (ret & BLOCK_CHANGED) {
377		if (!got_inode) {
378			retval = ext2fs_read_inode(fs, ino, &inode);
379			if (retval)
380				return retval;
381		}
382		for (i=0; i < EXT2_N_BLOCKS; i++)
383			inode.i_block[i] = blocks[i];
384		retval = ext2fs_write_inode(fs, ino, &inode);
385		if (retval)
386			return retval;
387	}
388
389	if (!block_buf)
390		ext2fs_free_mem(&ctx.ind_buf);
391
392	return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
393}
394
395/*
396 * Emulate the old ext2fs_block_iterate function!
397 */
398
399struct xlate {
400	int (*func)(ext2_filsys	fs,
401		    blk_t	*blocknr,
402		    int		bcount,
403		    void	*priv_data);
404	void *real_private;
405};
406
407#ifdef __TURBOC__
408# pragma argsused
409#endif
410static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
411		      blk_t ref_block EXT2FS_ATTR((unused)),
412		      int ref_offset EXT2FS_ATTR((unused)),
413		      void *priv_data)
414{
415	struct xlate *xl = (struct xlate *) priv_data;
416
417	return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
418}
419
420errcode_t ext2fs_block_iterate(ext2_filsys fs,
421			       ext2_ino_t ino,
422			       int	flags,
423			       char *block_buf,
424			       int (*func)(ext2_filsys fs,
425					   blk_t	*blocknr,
426					   int	blockcnt,
427					   void	*priv_data),
428			       void *priv_data)
429{
430	struct xlate xl;
431
432	xl.real_private = priv_data;
433	xl.func = func;
434
435	return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
436				     block_buf, xlate_func, &xl);
437}
438