xref: /aosp_15_r20/external/e2fsprogs/lib/ext2fs/dir_iterate.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * dir_iterate.c --- ext2fs directory iteration operations
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Library
8*6a54128fSAndroid Build Coastguard Worker  * General Public License, version 2.
9*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker  */
11*6a54128fSAndroid Build Coastguard Worker 
12*6a54128fSAndroid Build Coastguard Worker #include "config.h"
13*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
14*6a54128fSAndroid Build Coastguard Worker #include <string.h>
15*6a54128fSAndroid Build Coastguard Worker #if HAVE_UNISTD_H
16*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
17*6a54128fSAndroid Build Coastguard Worker #endif
18*6a54128fSAndroid Build Coastguard Worker #if HAVE_ERRNO_H
19*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
20*6a54128fSAndroid Build Coastguard Worker #endif
21*6a54128fSAndroid Build Coastguard Worker 
22*6a54128fSAndroid Build Coastguard Worker #include "ext2_fs.h"
23*6a54128fSAndroid Build Coastguard Worker #include "ext2fsP.h"
24*6a54128fSAndroid Build Coastguard Worker 
25*6a54128fSAndroid Build Coastguard Worker #define EXT4_MAX_REC_LEN		((1<<16)-1)
26*6a54128fSAndroid Build Coastguard Worker 
ext2fs_get_rec_len(ext2_filsys fs,struct ext2_dir_entry * dirent,unsigned int * rec_len)27*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_get_rec_len(ext2_filsys fs,
28*6a54128fSAndroid Build Coastguard Worker 			     struct ext2_dir_entry *dirent,
29*6a54128fSAndroid Build Coastguard Worker 			     unsigned int *rec_len)
30*6a54128fSAndroid Build Coastguard Worker {
31*6a54128fSAndroid Build Coastguard Worker 	unsigned int len = dirent->rec_len;
32*6a54128fSAndroid Build Coastguard Worker 
33*6a54128fSAndroid Build Coastguard Worker 	if (fs->blocksize < 65536)
34*6a54128fSAndroid Build Coastguard Worker 		*rec_len = len;
35*6a54128fSAndroid Build Coastguard Worker 	else if (len == EXT4_MAX_REC_LEN || len == 0)
36*6a54128fSAndroid Build Coastguard Worker 		*rec_len = fs->blocksize;
37*6a54128fSAndroid Build Coastguard Worker 	else
38*6a54128fSAndroid Build Coastguard Worker 		*rec_len = (len & 65532) | ((len & 3) << 16);
39*6a54128fSAndroid Build Coastguard Worker 	return 0;
40*6a54128fSAndroid Build Coastguard Worker }
41*6a54128fSAndroid Build Coastguard Worker 
ext2fs_set_rec_len(ext2_filsys fs,unsigned int len,struct ext2_dir_entry * dirent)42*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_set_rec_len(ext2_filsys fs,
43*6a54128fSAndroid Build Coastguard Worker 			     unsigned int len,
44*6a54128fSAndroid Build Coastguard Worker 			     struct ext2_dir_entry *dirent)
45*6a54128fSAndroid Build Coastguard Worker {
46*6a54128fSAndroid Build Coastguard Worker 	if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3))
47*6a54128fSAndroid Build Coastguard Worker 		return EINVAL;
48*6a54128fSAndroid Build Coastguard Worker 	if (len < 65536) {
49*6a54128fSAndroid Build Coastguard Worker 		dirent->rec_len = len;
50*6a54128fSAndroid Build Coastguard Worker 		return 0;
51*6a54128fSAndroid Build Coastguard Worker 	}
52*6a54128fSAndroid Build Coastguard Worker 	if (len == fs->blocksize) {
53*6a54128fSAndroid Build Coastguard Worker 		if (fs->blocksize == 65536)
54*6a54128fSAndroid Build Coastguard Worker 			dirent->rec_len = EXT4_MAX_REC_LEN;
55*6a54128fSAndroid Build Coastguard Worker 		else
56*6a54128fSAndroid Build Coastguard Worker 			dirent->rec_len = 0;
57*6a54128fSAndroid Build Coastguard Worker 	} else
58*6a54128fSAndroid Build Coastguard Worker 		dirent->rec_len = (len & 65532) | ((len >> 16) & 3);
59*6a54128fSAndroid Build Coastguard Worker 	return 0;
60*6a54128fSAndroid Build Coastguard Worker }
61*6a54128fSAndroid Build Coastguard Worker 
62*6a54128fSAndroid Build Coastguard Worker /*
63*6a54128fSAndroid Build Coastguard Worker  * This function checks to see whether or not a potential deleted
64*6a54128fSAndroid Build Coastguard Worker  * directory entry looks valid.  What we do is check the deleted entry
65*6a54128fSAndroid Build Coastguard Worker  * and each successive entry to make sure that they all look valid and
66*6a54128fSAndroid Build Coastguard Worker  * that the last deleted entry ends at the beginning of the next
67*6a54128fSAndroid Build Coastguard Worker  * undeleted entry.  Returns 1 if the deleted entry looks valid, zero
68*6a54128fSAndroid Build Coastguard Worker  * if not valid.
69*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_validate_entry(ext2_filsys fs,char * buf,unsigned int offset,unsigned int final_offset)70*6a54128fSAndroid Build Coastguard Worker static int ext2fs_validate_entry(ext2_filsys fs, char *buf,
71*6a54128fSAndroid Build Coastguard Worker 				 unsigned int offset,
72*6a54128fSAndroid Build Coastguard Worker 				 unsigned int final_offset)
73*6a54128fSAndroid Build Coastguard Worker {
74*6a54128fSAndroid Build Coastguard Worker 	struct ext2_dir_entry *dirent;
75*6a54128fSAndroid Build Coastguard Worker 	unsigned int rec_len;
76*6a54128fSAndroid Build Coastguard Worker #define DIRENT_MIN_LENGTH 12
77*6a54128fSAndroid Build Coastguard Worker 
78*6a54128fSAndroid Build Coastguard Worker 	while ((offset < final_offset) &&
79*6a54128fSAndroid Build Coastguard Worker 	       (offset <= fs->blocksize - DIRENT_MIN_LENGTH)) {
80*6a54128fSAndroid Build Coastguard Worker 		dirent = (struct ext2_dir_entry *)(buf + offset);
81*6a54128fSAndroid Build Coastguard Worker 		if (ext2fs_get_rec_len(fs, dirent, &rec_len))
82*6a54128fSAndroid Build Coastguard Worker 			return 0;
83*6a54128fSAndroid Build Coastguard Worker 		offset += rec_len;
84*6a54128fSAndroid Build Coastguard Worker 		if ((rec_len < 8) ||
85*6a54128fSAndroid Build Coastguard Worker 		    ((rec_len % 4) != 0) ||
86*6a54128fSAndroid Build Coastguard Worker 		    ((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len))
87*6a54128fSAndroid Build Coastguard Worker 			return 0;
88*6a54128fSAndroid Build Coastguard Worker 	}
89*6a54128fSAndroid Build Coastguard Worker 	return (offset == final_offset);
90*6a54128fSAndroid Build Coastguard Worker }
91*6a54128fSAndroid Build Coastguard Worker 
ext2fs_dir_iterate2(ext2_filsys fs,ext2_ino_t dir,int flags,char * block_buf,int (* func)(ext2_ino_t dir,int entry,struct ext2_dir_entry * dirent,int offset,int blocksize,char * buf,void * priv_data),void * priv_data)92*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
93*6a54128fSAndroid Build Coastguard Worker 			      ext2_ino_t dir,
94*6a54128fSAndroid Build Coastguard Worker 			      int flags,
95*6a54128fSAndroid Build Coastguard Worker 			      char *block_buf,
96*6a54128fSAndroid Build Coastguard Worker 			      int (*func)(ext2_ino_t	dir,
97*6a54128fSAndroid Build Coastguard Worker 					  int		entry,
98*6a54128fSAndroid Build Coastguard Worker 					  struct ext2_dir_entry *dirent,
99*6a54128fSAndroid Build Coastguard Worker 					  int	offset,
100*6a54128fSAndroid Build Coastguard Worker 					  int	blocksize,
101*6a54128fSAndroid Build Coastguard Worker 					  char	*buf,
102*6a54128fSAndroid Build Coastguard Worker 					  void	*priv_data),
103*6a54128fSAndroid Build Coastguard Worker 			      void *priv_data)
104*6a54128fSAndroid Build Coastguard Worker {
105*6a54128fSAndroid Build Coastguard Worker 	struct		dir_context	ctx;
106*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
107*6a54128fSAndroid Build Coastguard Worker 
108*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
109*6a54128fSAndroid Build Coastguard Worker 
110*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_check_directory(fs, dir);
111*6a54128fSAndroid Build Coastguard Worker 	if (retval)
112*6a54128fSAndroid Build Coastguard Worker 		return retval;
113*6a54128fSAndroid Build Coastguard Worker 
114*6a54128fSAndroid Build Coastguard Worker 	ctx.dir = dir;
115*6a54128fSAndroid Build Coastguard Worker 	ctx.flags = flags;
116*6a54128fSAndroid Build Coastguard Worker 	if (block_buf)
117*6a54128fSAndroid Build Coastguard Worker 		ctx.buf = block_buf;
118*6a54128fSAndroid Build Coastguard Worker 	else {
119*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
120*6a54128fSAndroid Build Coastguard Worker 		if (retval)
121*6a54128fSAndroid Build Coastguard Worker 			return retval;
122*6a54128fSAndroid Build Coastguard Worker 	}
123*6a54128fSAndroid Build Coastguard Worker 	ctx.func = func;
124*6a54128fSAndroid Build Coastguard Worker 	ctx.priv_data = priv_data;
125*6a54128fSAndroid Build Coastguard Worker 	ctx.errcode = 0;
126*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
127*6a54128fSAndroid Build Coastguard Worker 				       ext2fs_process_dir_block, &ctx);
128*6a54128fSAndroid Build Coastguard Worker 	if (!block_buf)
129*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&ctx.buf);
130*6a54128fSAndroid Build Coastguard Worker 	if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) {
131*6a54128fSAndroid Build Coastguard Worker 		(void) ext2fs_inline_data_dir_iterate(fs, dir, &ctx);
132*6a54128fSAndroid Build Coastguard Worker 		retval = 0;
133*6a54128fSAndroid Build Coastguard Worker 	}
134*6a54128fSAndroid Build Coastguard Worker 	if (retval)
135*6a54128fSAndroid Build Coastguard Worker 		return retval;
136*6a54128fSAndroid Build Coastguard Worker 	return ctx.errcode;
137*6a54128fSAndroid Build Coastguard Worker }
138*6a54128fSAndroid Build Coastguard Worker 
139*6a54128fSAndroid Build Coastguard Worker struct xlate {
140*6a54128fSAndroid Build Coastguard Worker 	int (*func)(struct ext2_dir_entry *dirent,
141*6a54128fSAndroid Build Coastguard Worker 		    int		offset,
142*6a54128fSAndroid Build Coastguard Worker 		    int		blocksize,
143*6a54128fSAndroid Build Coastguard Worker 		    char	*buf,
144*6a54128fSAndroid Build Coastguard Worker 		    void	*priv_data);
145*6a54128fSAndroid Build Coastguard Worker 	void *real_private;
146*6a54128fSAndroid Build Coastguard Worker };
147*6a54128fSAndroid Build Coastguard Worker 
xlate_func(ext2_ino_t dir EXT2FS_ATTR ((unused)),int entry EXT2FS_ATTR ((unused)),struct ext2_dir_entry * dirent,int offset,int blocksize,char * buf,void * priv_data)148*6a54128fSAndroid Build Coastguard Worker static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
149*6a54128fSAndroid Build Coastguard Worker 		      int entry EXT2FS_ATTR((unused)),
150*6a54128fSAndroid Build Coastguard Worker 		      struct ext2_dir_entry *dirent, int offset,
151*6a54128fSAndroid Build Coastguard Worker 		      int blocksize, char *buf, void *priv_data)
152*6a54128fSAndroid Build Coastguard Worker {
153*6a54128fSAndroid Build Coastguard Worker 	struct xlate *xl = (struct xlate *) priv_data;
154*6a54128fSAndroid Build Coastguard Worker 
155*6a54128fSAndroid Build Coastguard Worker 	return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
156*6a54128fSAndroid Build Coastguard Worker }
157*6a54128fSAndroid Build Coastguard Worker 
ext2fs_dir_iterate(ext2_filsys fs,ext2_ino_t dir,int flags,char * block_buf,int (* func)(struct ext2_dir_entry * dirent,int offset,int blocksize,char * buf,void * priv_data),void * priv_data)158*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_dir_iterate(ext2_filsys fs,
159*6a54128fSAndroid Build Coastguard Worker 			     ext2_ino_t dir,
160*6a54128fSAndroid Build Coastguard Worker 			     int flags,
161*6a54128fSAndroid Build Coastguard Worker 			     char *block_buf,
162*6a54128fSAndroid Build Coastguard Worker 			     int (*func)(struct ext2_dir_entry *dirent,
163*6a54128fSAndroid Build Coastguard Worker 					 int	offset,
164*6a54128fSAndroid Build Coastguard Worker 					 int	blocksize,
165*6a54128fSAndroid Build Coastguard Worker 					 char	*buf,
166*6a54128fSAndroid Build Coastguard Worker 					 void	*priv_data),
167*6a54128fSAndroid Build Coastguard Worker 			     void *priv_data)
168*6a54128fSAndroid Build Coastguard Worker {
169*6a54128fSAndroid Build Coastguard Worker 	struct xlate xl;
170*6a54128fSAndroid Build Coastguard Worker 
171*6a54128fSAndroid Build Coastguard Worker 	xl.real_private = priv_data;
172*6a54128fSAndroid Build Coastguard Worker 	xl.func = func;
173*6a54128fSAndroid Build Coastguard Worker 
174*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
175*6a54128fSAndroid Build Coastguard Worker 				   xlate_func, &xl);
176*6a54128fSAndroid Build Coastguard Worker }
177*6a54128fSAndroid Build Coastguard Worker 
178*6a54128fSAndroid Build Coastguard Worker 
179*6a54128fSAndroid Build Coastguard Worker /*
180*6a54128fSAndroid Build Coastguard Worker  * Helper function which is private to this module.  Used by
181*6a54128fSAndroid Build Coastguard Worker  * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
182*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_process_dir_block(ext2_filsys fs,blk64_t * blocknr,e2_blkcnt_t blockcnt,blk64_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data)183*6a54128fSAndroid Build Coastguard Worker int ext2fs_process_dir_block(ext2_filsys fs,
184*6a54128fSAndroid Build Coastguard Worker 			     blk64_t	*blocknr,
185*6a54128fSAndroid Build Coastguard Worker 			     e2_blkcnt_t blockcnt,
186*6a54128fSAndroid Build Coastguard Worker 			     blk64_t	ref_block EXT2FS_ATTR((unused)),
187*6a54128fSAndroid Build Coastguard Worker 			     int	ref_offset EXT2FS_ATTR((unused)),
188*6a54128fSAndroid Build Coastguard Worker 			     void	*priv_data)
189*6a54128fSAndroid Build Coastguard Worker {
190*6a54128fSAndroid Build Coastguard Worker 	struct dir_context *ctx = (struct dir_context *) priv_data;
191*6a54128fSAndroid Build Coastguard Worker 	unsigned int	offset = 0;
192*6a54128fSAndroid Build Coastguard Worker 	unsigned int	next_real_entry = 0;
193*6a54128fSAndroid Build Coastguard Worker 	int		ret = 0;
194*6a54128fSAndroid Build Coastguard Worker 	int		changed = 0;
195*6a54128fSAndroid Build Coastguard Worker 	int		do_abort = 0;
196*6a54128fSAndroid Build Coastguard Worker 	unsigned int	rec_len, size, buflen;
197*6a54128fSAndroid Build Coastguard Worker 	int		entry;
198*6a54128fSAndroid Build Coastguard Worker 	struct ext2_dir_entry *dirent;
199*6a54128fSAndroid Build Coastguard Worker 	int		csum_size = 0;
200*6a54128fSAndroid Build Coastguard Worker 	int		inline_data;
201*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval = 0;
202*6a54128fSAndroid Build Coastguard Worker 
203*6a54128fSAndroid Build Coastguard Worker 	if (blockcnt < 0)
204*6a54128fSAndroid Build Coastguard Worker 		return 0;
205*6a54128fSAndroid Build Coastguard Worker 
206*6a54128fSAndroid Build Coastguard Worker 	entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
207*6a54128fSAndroid Build Coastguard Worker 
208*6a54128fSAndroid Build Coastguard Worker 	/* If a dir has inline data, we don't need to read block */
209*6a54128fSAndroid Build Coastguard Worker 	inline_data = !!(ctx->flags & DIRENT_FLAG_INCLUDE_INLINE_DATA);
210*6a54128fSAndroid Build Coastguard Worker 	if (!inline_data) {
211*6a54128fSAndroid Build Coastguard Worker 		ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
212*6a54128fSAndroid Build Coastguard Worker 						      ctx->dir);
213*6a54128fSAndroid Build Coastguard Worker 		if (ctx->errcode)
214*6a54128fSAndroid Build Coastguard Worker 			return BLOCK_ABORT;
215*6a54128fSAndroid Build Coastguard Worker 		/* If we handle a normal dir, we traverse the entire block */
216*6a54128fSAndroid Build Coastguard Worker 		buflen = fs->blocksize;
217*6a54128fSAndroid Build Coastguard Worker 	} else {
218*6a54128fSAndroid Build Coastguard Worker 		buflen = ctx->buflen;
219*6a54128fSAndroid Build Coastguard Worker 	}
220*6a54128fSAndroid Build Coastguard Worker 
221*6a54128fSAndroid Build Coastguard Worker 	if (ext2fs_has_feature_metadata_csum(fs->super))
222*6a54128fSAndroid Build Coastguard Worker 		csum_size = sizeof(struct ext2_dir_entry_tail);
223*6a54128fSAndroid Build Coastguard Worker 
224*6a54128fSAndroid Build Coastguard Worker 	if (buflen < 8) {
225*6a54128fSAndroid Build Coastguard Worker 		ctx->errcode = EXT2_ET_DIR_CORRUPTED;
226*6a54128fSAndroid Build Coastguard Worker 		return BLOCK_ABORT;
227*6a54128fSAndroid Build Coastguard Worker 	}
228*6a54128fSAndroid Build Coastguard Worker 	while (offset < buflen - 8) {
229*6a54128fSAndroid Build Coastguard Worker 		dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
230*6a54128fSAndroid Build Coastguard Worker 		if (ext2fs_get_rec_len(fs, dirent, &rec_len))
231*6a54128fSAndroid Build Coastguard Worker 			return BLOCK_ABORT;
232*6a54128fSAndroid Build Coastguard Worker 		if (((offset + rec_len) > buflen) ||
233*6a54128fSAndroid Build Coastguard Worker 		    (rec_len < 8) ||
234*6a54128fSAndroid Build Coastguard Worker 		    ((rec_len % 4) != 0) ||
235*6a54128fSAndroid Build Coastguard Worker 		    ((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len)) {
236*6a54128fSAndroid Build Coastguard Worker 			ctx->errcode = EXT2_ET_DIR_CORRUPTED;
237*6a54128fSAndroid Build Coastguard Worker 			return BLOCK_ABORT;
238*6a54128fSAndroid Build Coastguard Worker 		}
239*6a54128fSAndroid Build Coastguard Worker 		if (!dirent->inode) {
240*6a54128fSAndroid Build Coastguard Worker 			/*
241*6a54128fSAndroid Build Coastguard Worker 			 * We just need to check metadata_csum when this
242*6a54128fSAndroid Build Coastguard Worker 			 * dir hasn't inline data.  That means that 'buflen'
243*6a54128fSAndroid Build Coastguard Worker 			 * should be blocksize.
244*6a54128fSAndroid Build Coastguard Worker 			 */
245*6a54128fSAndroid Build Coastguard Worker 			if (!inline_data &&
246*6a54128fSAndroid Build Coastguard Worker 			    (offset == buflen - csum_size) &&
247*6a54128fSAndroid Build Coastguard Worker 			    (dirent->rec_len == csum_size) &&
248*6a54128fSAndroid Build Coastguard Worker 			    (dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) {
249*6a54128fSAndroid Build Coastguard Worker 				if (!(ctx->flags & DIRENT_FLAG_INCLUDE_CSUM))
250*6a54128fSAndroid Build Coastguard Worker 					goto next;
251*6a54128fSAndroid Build Coastguard Worker 				entry = DIRENT_CHECKSUM;
252*6a54128fSAndroid Build Coastguard Worker 			} else if (!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
253*6a54128fSAndroid Build Coastguard Worker 				goto next;
254*6a54128fSAndroid Build Coastguard Worker 		}
255*6a54128fSAndroid Build Coastguard Worker 
256*6a54128fSAndroid Build Coastguard Worker 		ret = (ctx->func)(ctx->dir,
257*6a54128fSAndroid Build Coastguard Worker 				  (next_real_entry > offset) ?
258*6a54128fSAndroid Build Coastguard Worker 				  DIRENT_DELETED_FILE : entry,
259*6a54128fSAndroid Build Coastguard Worker 				  dirent, offset,
260*6a54128fSAndroid Build Coastguard Worker 				  buflen, ctx->buf,
261*6a54128fSAndroid Build Coastguard Worker 				  ctx->priv_data);
262*6a54128fSAndroid Build Coastguard Worker 		if (entry < DIRENT_OTHER_FILE)
263*6a54128fSAndroid Build Coastguard Worker 			entry++;
264*6a54128fSAndroid Build Coastguard Worker 
265*6a54128fSAndroid Build Coastguard Worker 		if (ret & DIRENT_CHANGED) {
266*6a54128fSAndroid Build Coastguard Worker 			if (ext2fs_get_rec_len(fs, dirent, &rec_len))
267*6a54128fSAndroid Build Coastguard Worker 				return BLOCK_ABORT;
268*6a54128fSAndroid Build Coastguard Worker 			changed++;
269*6a54128fSAndroid Build Coastguard Worker 		}
270*6a54128fSAndroid Build Coastguard Worker 		if (ret & DIRENT_ABORT) {
271*6a54128fSAndroid Build Coastguard Worker 			do_abort++;
272*6a54128fSAndroid Build Coastguard Worker 			break;
273*6a54128fSAndroid Build Coastguard Worker 		}
274*6a54128fSAndroid Build Coastguard Worker next:
275*6a54128fSAndroid Build Coastguard Worker  		if (next_real_entry == offset)
276*6a54128fSAndroid Build Coastguard Worker 			next_real_entry += rec_len;
277*6a54128fSAndroid Build Coastguard Worker 
278*6a54128fSAndroid Build Coastguard Worker  		if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
279*6a54128fSAndroid Build Coastguard Worker 			size = (ext2fs_dirent_name_len(dirent) + 11) & ~3;
280*6a54128fSAndroid Build Coastguard Worker 
281*6a54128fSAndroid Build Coastguard Worker 			if (rec_len != size)  {
282*6a54128fSAndroid Build Coastguard Worker 				unsigned int final_offset;
283*6a54128fSAndroid Build Coastguard Worker 
284*6a54128fSAndroid Build Coastguard Worker 				final_offset = offset + rec_len;
285*6a54128fSAndroid Build Coastguard Worker 				offset += size;
286*6a54128fSAndroid Build Coastguard Worker 				while (offset < final_offset &&
287*6a54128fSAndroid Build Coastguard Worker 				       !ext2fs_validate_entry(fs, ctx->buf,
288*6a54128fSAndroid Build Coastguard Worker 							      offset,
289*6a54128fSAndroid Build Coastguard Worker 							      final_offset))
290*6a54128fSAndroid Build Coastguard Worker 					offset += 4;
291*6a54128fSAndroid Build Coastguard Worker 				continue;
292*6a54128fSAndroid Build Coastguard Worker 			}
293*6a54128fSAndroid Build Coastguard Worker 		}
294*6a54128fSAndroid Build Coastguard Worker 		offset += rec_len;
295*6a54128fSAndroid Build Coastguard Worker 	}
296*6a54128fSAndroid Build Coastguard Worker 
297*6a54128fSAndroid Build Coastguard Worker 	if (changed) {
298*6a54128fSAndroid Build Coastguard Worker 		if (!inline_data) {
299*6a54128fSAndroid Build Coastguard Worker 			ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr,
300*6a54128fSAndroid Build Coastguard Worker 							       ctx->buf,
301*6a54128fSAndroid Build Coastguard Worker 							       0, ctx->dir);
302*6a54128fSAndroid Build Coastguard Worker 			if (ctx->errcode)
303*6a54128fSAndroid Build Coastguard Worker 				return BLOCK_ABORT;
304*6a54128fSAndroid Build Coastguard Worker 		} else {
305*6a54128fSAndroid Build Coastguard Worker 			/*
306*6a54128fSAndroid Build Coastguard Worker 			 * return BLOCK_INLINE_DATA_CHANGED to notify caller
307*6a54128fSAndroid Build Coastguard Worker 			 * that inline data has been changed.
308*6a54128fSAndroid Build Coastguard Worker 			 */
309*6a54128fSAndroid Build Coastguard Worker 			retval = BLOCK_INLINE_DATA_CHANGED;
310*6a54128fSAndroid Build Coastguard Worker 		}
311*6a54128fSAndroid Build Coastguard Worker 	}
312*6a54128fSAndroid Build Coastguard Worker 	if (do_abort)
313*6a54128fSAndroid Build Coastguard Worker 		return retval | BLOCK_ABORT;
314*6a54128fSAndroid Build Coastguard Worker 	return retval;
315*6a54128fSAndroid Build Coastguard Worker }
316