1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
3*6a54128fSAndroid Build Coastguard Worker *
4*6a54128fSAndroid Build Coastguard Worker * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 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 Public
8*6a54128fSAndroid Build Coastguard Worker * License.
9*6a54128fSAndroid Build Coastguard Worker * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker *
11*6a54128fSAndroid Build Coastguard Worker * Pass #3 assures that all directories are connected to the
12*6a54128fSAndroid Build Coastguard Worker * filesystem tree, using the following algorithm:
13*6a54128fSAndroid Build Coastguard Worker *
14*6a54128fSAndroid Build Coastguard Worker * First, the root directory is checked to make sure it exists; if
15*6a54128fSAndroid Build Coastguard Worker * not, e2fsck will offer to create a new one. It is then marked as
16*6a54128fSAndroid Build Coastguard Worker * "done".
17*6a54128fSAndroid Build Coastguard Worker *
18*6a54128fSAndroid Build Coastguard Worker * Then, pass3 iterates over all directory inodes; for each directory
19*6a54128fSAndroid Build Coastguard Worker * it attempts to trace up the filesystem tree, using dirinfo.parent
20*6a54128fSAndroid Build Coastguard Worker * until it reaches a directory which has been marked "done". If it
21*6a54128fSAndroid Build Coastguard Worker * can not do so, then the directory must be disconnected, and e2fsck
22*6a54128fSAndroid Build Coastguard Worker * will offer to reconnect it to /lost+found. While it is chasing
23*6a54128fSAndroid Build Coastguard Worker * parent pointers up the filesystem tree, if pass3 sees a directory
24*6a54128fSAndroid Build Coastguard Worker * twice, then it has detected a filesystem loop, and it will again
25*6a54128fSAndroid Build Coastguard Worker * offer to reconnect the directory to /lost+found in order to break the
26*6a54128fSAndroid Build Coastguard Worker * filesystem loop.
27*6a54128fSAndroid Build Coastguard Worker *
28*6a54128fSAndroid Build Coastguard Worker * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
29*6a54128fSAndroid Build Coastguard Worker * reconnect inodes to /lost+found; this subroutine is also used by
30*6a54128fSAndroid Build Coastguard Worker * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
31*6a54128fSAndroid Build Coastguard Worker * is responsible for creating /lost+found if it does not exist.
32*6a54128fSAndroid Build Coastguard Worker *
33*6a54128fSAndroid Build Coastguard Worker * Pass 3 frees the following data structures:
34*6a54128fSAndroid Build Coastguard Worker * - The dirinfo directory information cache.
35*6a54128fSAndroid Build Coastguard Worker */
36*6a54128fSAndroid Build Coastguard Worker
37*6a54128fSAndroid Build Coastguard Worker #include "config.h"
38*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_ERRNO_H
39*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
40*6a54128fSAndroid Build Coastguard Worker #endif
41*6a54128fSAndroid Build Coastguard Worker
42*6a54128fSAndroid Build Coastguard Worker #include "e2fsck.h"
43*6a54128fSAndroid Build Coastguard Worker #include "problem.h"
44*6a54128fSAndroid Build Coastguard Worker
45*6a54128fSAndroid Build Coastguard Worker static void check_root(e2fsck_t ctx);
46*6a54128fSAndroid Build Coastguard Worker static int check_directory(e2fsck_t ctx, ext2_ino_t ino,
47*6a54128fSAndroid Build Coastguard Worker struct problem_context *pctx);
48*6a54128fSAndroid Build Coastguard Worker static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
49*6a54128fSAndroid Build Coastguard Worker
50*6a54128fSAndroid Build Coastguard Worker static ext2fs_inode_bitmap inode_loop_detect = 0;
51*6a54128fSAndroid Build Coastguard Worker static ext2fs_inode_bitmap inode_done_map = 0;
52*6a54128fSAndroid Build Coastguard Worker
e2fsck_pass3(e2fsck_t ctx)53*6a54128fSAndroid Build Coastguard Worker void e2fsck_pass3(e2fsck_t ctx)
54*6a54128fSAndroid Build Coastguard Worker {
55*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
56*6a54128fSAndroid Build Coastguard Worker struct dir_info_iter *iter = NULL;
57*6a54128fSAndroid Build Coastguard Worker #ifdef RESOURCE_TRACK
58*6a54128fSAndroid Build Coastguard Worker struct resource_track rtrack;
59*6a54128fSAndroid Build Coastguard Worker #endif
60*6a54128fSAndroid Build Coastguard Worker struct problem_context pctx;
61*6a54128fSAndroid Build Coastguard Worker struct dir_info *dir;
62*6a54128fSAndroid Build Coastguard Worker unsigned long maxdirs, count;
63*6a54128fSAndroid Build Coastguard Worker
64*6a54128fSAndroid Build Coastguard Worker init_resource_track(&rtrack, ctx->fs->io);
65*6a54128fSAndroid Build Coastguard Worker clear_problem_context(&pctx);
66*6a54128fSAndroid Build Coastguard Worker
67*6a54128fSAndroid Build Coastguard Worker #ifdef MTRACE
68*6a54128fSAndroid Build Coastguard Worker mtrace_print("Pass 3");
69*6a54128fSAndroid Build Coastguard Worker #endif
70*6a54128fSAndroid Build Coastguard Worker
71*6a54128fSAndroid Build Coastguard Worker if (!(ctx->options & E2F_OPT_PREEN))
72*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
73*6a54128fSAndroid Build Coastguard Worker
74*6a54128fSAndroid Build Coastguard Worker /*
75*6a54128fSAndroid Build Coastguard Worker * Allocate some bitmaps to do loop detection.
76*6a54128fSAndroid Build Coastguard Worker */
77*6a54128fSAndroid Build Coastguard Worker pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("inode done bitmap"),
78*6a54128fSAndroid Build Coastguard Worker EXT2FS_BMAP64_AUTODIR,
79*6a54128fSAndroid Build Coastguard Worker "inode_done_map", &inode_done_map);
80*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
81*6a54128fSAndroid Build Coastguard Worker pctx.num = 2;
82*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
83*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
84*6a54128fSAndroid Build Coastguard Worker goto abort_exit;
85*6a54128fSAndroid Build Coastguard Worker }
86*6a54128fSAndroid Build Coastguard Worker print_resource_track(ctx, _("Peak memory"), &ctx->global_rtrack, NULL);
87*6a54128fSAndroid Build Coastguard Worker
88*6a54128fSAndroid Build Coastguard Worker check_root(ctx);
89*6a54128fSAndroid Build Coastguard Worker if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
90*6a54128fSAndroid Build Coastguard Worker goto abort_exit;
91*6a54128fSAndroid Build Coastguard Worker
92*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(inode_done_map, EXT2_ROOT_INO);
93*6a54128fSAndroid Build Coastguard Worker
94*6a54128fSAndroid Build Coastguard Worker maxdirs = e2fsck_get_num_dirinfo(ctx);
95*6a54128fSAndroid Build Coastguard Worker count = 1;
96*6a54128fSAndroid Build Coastguard Worker
97*6a54128fSAndroid Build Coastguard Worker if (ctx->progress)
98*6a54128fSAndroid Build Coastguard Worker if ((ctx->progress)(ctx, 3, 0, maxdirs))
99*6a54128fSAndroid Build Coastguard Worker goto abort_exit;
100*6a54128fSAndroid Build Coastguard Worker
101*6a54128fSAndroid Build Coastguard Worker iter = e2fsck_dir_info_iter_begin(ctx);
102*6a54128fSAndroid Build Coastguard Worker while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) {
103*6a54128fSAndroid Build Coastguard Worker if (ctx->flags & E2F_FLAG_SIGNAL_MASK ||
104*6a54128fSAndroid Build Coastguard Worker ctx->flags & E2F_FLAG_RESTART)
105*6a54128fSAndroid Build Coastguard Worker goto abort_exit;
106*6a54128fSAndroid Build Coastguard Worker if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
107*6a54128fSAndroid Build Coastguard Worker goto abort_exit;
108*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dir->ino))
109*6a54128fSAndroid Build Coastguard Worker if (check_directory(ctx, dir->ino, &pctx))
110*6a54128fSAndroid Build Coastguard Worker goto abort_exit;
111*6a54128fSAndroid Build Coastguard Worker }
112*6a54128fSAndroid Build Coastguard Worker
113*6a54128fSAndroid Build Coastguard Worker /*
114*6a54128fSAndroid Build Coastguard Worker * Force the creation of /lost+found if not present
115*6a54128fSAndroid Build Coastguard Worker */
116*6a54128fSAndroid Build Coastguard Worker if ((ctx->options & E2F_OPT_READONLY) == 0)
117*6a54128fSAndroid Build Coastguard Worker e2fsck_get_lost_and_found(ctx, 1);
118*6a54128fSAndroid Build Coastguard Worker
119*6a54128fSAndroid Build Coastguard Worker /*
120*6a54128fSAndroid Build Coastguard Worker * If there are any directories that need to be indexed or
121*6a54128fSAndroid Build Coastguard Worker * optimized, do it here.
122*6a54128fSAndroid Build Coastguard Worker */
123*6a54128fSAndroid Build Coastguard Worker e2fsck_rehash_directories(ctx);
124*6a54128fSAndroid Build Coastguard Worker
125*6a54128fSAndroid Build Coastguard Worker abort_exit:
126*6a54128fSAndroid Build Coastguard Worker if (iter)
127*6a54128fSAndroid Build Coastguard Worker e2fsck_dir_info_iter_end(ctx, iter);
128*6a54128fSAndroid Build Coastguard Worker e2fsck_free_dir_info(ctx);
129*6a54128fSAndroid Build Coastguard Worker if (inode_loop_detect) {
130*6a54128fSAndroid Build Coastguard Worker ext2fs_free_inode_bitmap(inode_loop_detect);
131*6a54128fSAndroid Build Coastguard Worker inode_loop_detect = 0;
132*6a54128fSAndroid Build Coastguard Worker }
133*6a54128fSAndroid Build Coastguard Worker if (inode_done_map) {
134*6a54128fSAndroid Build Coastguard Worker ext2fs_free_inode_bitmap(inode_done_map);
135*6a54128fSAndroid Build Coastguard Worker inode_done_map = 0;
136*6a54128fSAndroid Build Coastguard Worker }
137*6a54128fSAndroid Build Coastguard Worker
138*6a54128fSAndroid Build Coastguard Worker if (ctx->lnf_repair_block) {
139*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(ctx->block_found_map,
140*6a54128fSAndroid Build Coastguard Worker ctx->lnf_repair_block);
141*6a54128fSAndroid Build Coastguard Worker ctx->lnf_repair_block = 0;
142*6a54128fSAndroid Build Coastguard Worker }
143*6a54128fSAndroid Build Coastguard Worker if (ctx->root_repair_block) {
144*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(ctx->block_found_map,
145*6a54128fSAndroid Build Coastguard Worker ctx->root_repair_block);
146*6a54128fSAndroid Build Coastguard Worker ctx->root_repair_block = 0;
147*6a54128fSAndroid Build Coastguard Worker }
148*6a54128fSAndroid Build Coastguard Worker
149*6a54128fSAndroid Build Coastguard Worker print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io);
150*6a54128fSAndroid Build Coastguard Worker }
151*6a54128fSAndroid Build Coastguard Worker
152*6a54128fSAndroid Build Coastguard Worker /*
153*6a54128fSAndroid Build Coastguard Worker * This makes sure the root inode is present; if not, we ask if the
154*6a54128fSAndroid Build Coastguard Worker * user wants us to create it. Not creating it is a fatal error.
155*6a54128fSAndroid Build Coastguard Worker */
check_root(e2fsck_t ctx)156*6a54128fSAndroid Build Coastguard Worker static void check_root(e2fsck_t ctx)
157*6a54128fSAndroid Build Coastguard Worker {
158*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
159*6a54128fSAndroid Build Coastguard Worker blk64_t blk;
160*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large inode;
161*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *iptr = (struct ext2_inode *) &inode;
162*6a54128fSAndroid Build Coastguard Worker char * block;
163*6a54128fSAndroid Build Coastguard Worker struct problem_context pctx;
164*6a54128fSAndroid Build Coastguard Worker
165*6a54128fSAndroid Build Coastguard Worker clear_problem_context(&pctx);
166*6a54128fSAndroid Build Coastguard Worker
167*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) {
168*6a54128fSAndroid Build Coastguard Worker /*
169*6a54128fSAndroid Build Coastguard Worker * If the root inode is not a directory, die here. The
170*6a54128fSAndroid Build Coastguard Worker * user must have answered 'no' in pass1 when we
171*6a54128fSAndroid Build Coastguard Worker * offered to clear it.
172*6a54128fSAndroid Build Coastguard Worker */
173*6a54128fSAndroid Build Coastguard Worker if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
174*6a54128fSAndroid Build Coastguard Worker EXT2_ROOT_INO))) {
175*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
176*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
177*6a54128fSAndroid Build Coastguard Worker }
178*6a54128fSAndroid Build Coastguard Worker return;
179*6a54128fSAndroid Build Coastguard Worker }
180*6a54128fSAndroid Build Coastguard Worker
181*6a54128fSAndroid Build Coastguard Worker if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
182*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
183*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
184*6a54128fSAndroid Build Coastguard Worker return;
185*6a54128fSAndroid Build Coastguard Worker }
186*6a54128fSAndroid Build Coastguard Worker
187*6a54128fSAndroid Build Coastguard Worker e2fsck_read_bitmaps(ctx);
188*6a54128fSAndroid Build Coastguard Worker
189*6a54128fSAndroid Build Coastguard Worker /*
190*6a54128fSAndroid Build Coastguard Worker * First, find a free block
191*6a54128fSAndroid Build Coastguard Worker */
192*6a54128fSAndroid Build Coastguard Worker if (ctx->root_repair_block) {
193*6a54128fSAndroid Build Coastguard Worker blk = ctx->root_repair_block;
194*6a54128fSAndroid Build Coastguard Worker ctx->root_repair_block = 0;
195*6a54128fSAndroid Build Coastguard Worker goto skip_new_block;
196*6a54128fSAndroid Build Coastguard Worker }
197*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
198*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
199*6a54128fSAndroid Build Coastguard Worker pctx.str = "ext2fs_new_block";
200*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
201*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
202*6a54128fSAndroid Build Coastguard Worker return;
203*6a54128fSAndroid Build Coastguard Worker }
204*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
205*6a54128fSAndroid Build Coastguard Worker skip_new_block:
206*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(fs->block_map, blk);
207*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_bb_dirty(fs);
208*6a54128fSAndroid Build Coastguard Worker
209*6a54128fSAndroid Build Coastguard Worker /*
210*6a54128fSAndroid Build Coastguard Worker * Set up the inode structure
211*6a54128fSAndroid Build Coastguard Worker */
212*6a54128fSAndroid Build Coastguard Worker memset(&inode, 0, sizeof(inode));
213*6a54128fSAndroid Build Coastguard Worker inode.i_mode = 040755;
214*6a54128fSAndroid Build Coastguard Worker inode.i_size = fs->blocksize;
215*6a54128fSAndroid Build Coastguard Worker inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
216*6a54128fSAndroid Build Coastguard Worker inode.i_links_count = 2;
217*6a54128fSAndroid Build Coastguard Worker ext2fs_iblk_set(fs, iptr, 1);
218*6a54128fSAndroid Build Coastguard Worker inode.i_block[0] = blk;
219*6a54128fSAndroid Build Coastguard Worker inode.i_extra_isize = sizeof(struct ext2_inode_large) -
220*6a54128fSAndroid Build Coastguard Worker EXT2_GOOD_OLD_INODE_SIZE;
221*6a54128fSAndroid Build Coastguard Worker
222*6a54128fSAndroid Build Coastguard Worker /*
223*6a54128fSAndroid Build Coastguard Worker * Write out the inode.
224*6a54128fSAndroid Build Coastguard Worker */
225*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, iptr);
226*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
227*6a54128fSAndroid Build Coastguard Worker pctx.str = "ext2fs_write_inode";
228*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
229*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
230*6a54128fSAndroid Build Coastguard Worker return;
231*6a54128fSAndroid Build Coastguard Worker }
232*6a54128fSAndroid Build Coastguard Worker
233*6a54128fSAndroid Build Coastguard Worker /*
234*6a54128fSAndroid Build Coastguard Worker * Now let's create the actual data block for the inode.
235*6a54128fSAndroid Build Coastguard Worker * Due to metadata_csum, we must write the dir blocks AFTER
236*6a54128fSAndroid Build Coastguard Worker * the inode has been written to disk!
237*6a54128fSAndroid Build Coastguard Worker */
238*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
239*6a54128fSAndroid Build Coastguard Worker &block);
240*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
241*6a54128fSAndroid Build Coastguard Worker pctx.str = "ext2fs_new_dir_block";
242*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
243*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
244*6a54128fSAndroid Build Coastguard Worker return;
245*6a54128fSAndroid Build Coastguard Worker }
246*6a54128fSAndroid Build Coastguard Worker
247*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0,
248*6a54128fSAndroid Build Coastguard Worker EXT2_ROOT_INO);
249*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&block);
250*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
251*6a54128fSAndroid Build Coastguard Worker pctx.str = "ext2fs_write_dir_block4";
252*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
253*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
254*6a54128fSAndroid Build Coastguard Worker return;
255*6a54128fSAndroid Build Coastguard Worker }
256*6a54128fSAndroid Build Coastguard Worker
257*6a54128fSAndroid Build Coastguard Worker /*
258*6a54128fSAndroid Build Coastguard Worker * Miscellaneous bookkeeping...
259*6a54128fSAndroid Build Coastguard Worker */
260*6a54128fSAndroid Build Coastguard Worker e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
261*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
262*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
263*6a54128fSAndroid Build Coastguard Worker
264*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO);
265*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO);
266*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO);
267*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_ib_dirty(fs);
268*6a54128fSAndroid Build Coastguard Worker quota_data_add(ctx->qctx, &inode, EXT2_ROOT_INO,
269*6a54128fSAndroid Build Coastguard Worker EXT2_CLUSTER_SIZE(fs->super));
270*6a54128fSAndroid Build Coastguard Worker quota_data_inodes(ctx->qctx, &inode, EXT2_ROOT_INO, +1);
271*6a54128fSAndroid Build Coastguard Worker }
272*6a54128fSAndroid Build Coastguard Worker
273*6a54128fSAndroid Build Coastguard Worker /*
274*6a54128fSAndroid Build Coastguard Worker * This subroutine is responsible for making sure that a particular
275*6a54128fSAndroid Build Coastguard Worker * directory is connected to the root; if it isn't we trace it up as
276*6a54128fSAndroid Build Coastguard Worker * far as we can go, and then offer to connect the resulting parent to
277*6a54128fSAndroid Build Coastguard Worker * the lost+found. We have to do loop detection; if we ever discover
278*6a54128fSAndroid Build Coastguard Worker * a loop, we treat that as a disconnected directory and offer to
279*6a54128fSAndroid Build Coastguard Worker * reparent it to lost+found.
280*6a54128fSAndroid Build Coastguard Worker *
281*6a54128fSAndroid Build Coastguard Worker * However, loop detection is expensive, because for very large
282*6a54128fSAndroid Build Coastguard Worker * filesystems, the inode_loop_detect bitmap is huge, and clearing it
283*6a54128fSAndroid Build Coastguard Worker * is non-trivial. Loops in filesystems are also a rare error case,
284*6a54128fSAndroid Build Coastguard Worker * and we shouldn't optimize for error cases. So we try two passes of
285*6a54128fSAndroid Build Coastguard Worker * the algorithm. The first time, we ignore loop detection and merely
286*6a54128fSAndroid Build Coastguard Worker * increment a counter; if the counter exceeds some extreme threshold,
287*6a54128fSAndroid Build Coastguard Worker * then we try again with the loop detection bitmap enabled.
288*6a54128fSAndroid Build Coastguard Worker */
check_directory(e2fsck_t ctx,ext2_ino_t dir,struct problem_context * pctx)289*6a54128fSAndroid Build Coastguard Worker static int check_directory(e2fsck_t ctx, ext2_ino_t dir,
290*6a54128fSAndroid Build Coastguard Worker struct problem_context *pctx)
291*6a54128fSAndroid Build Coastguard Worker {
292*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
293*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino = dir, parent;
294*6a54128fSAndroid Build Coastguard Worker int loop_pass = 0, parent_count = 0;
295*6a54128fSAndroid Build Coastguard Worker
296*6a54128fSAndroid Build Coastguard Worker while (1) {
297*6a54128fSAndroid Build Coastguard Worker /*
298*6a54128fSAndroid Build Coastguard Worker * Mark this inode as being "done"; by the time we
299*6a54128fSAndroid Build Coastguard Worker * return from this function, the inode we either be
300*6a54128fSAndroid Build Coastguard Worker * verified as being connected to the directory tree,
301*6a54128fSAndroid Build Coastguard Worker * or we will have offered to reconnect this to
302*6a54128fSAndroid Build Coastguard Worker * lost+found.
303*6a54128fSAndroid Build Coastguard Worker *
304*6a54128fSAndroid Build Coastguard Worker * If it was marked done already, then we've reached a
305*6a54128fSAndroid Build Coastguard Worker * parent we've already checked.
306*6a54128fSAndroid Build Coastguard Worker */
307*6a54128fSAndroid Build Coastguard Worker if (ext2fs_mark_inode_bitmap2(inode_done_map, ino))
308*6a54128fSAndroid Build Coastguard Worker break;
309*6a54128fSAndroid Build Coastguard Worker
310*6a54128fSAndroid Build Coastguard Worker if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) {
311*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
312*6a54128fSAndroid Build Coastguard Worker return 0;
313*6a54128fSAndroid Build Coastguard Worker }
314*6a54128fSAndroid Build Coastguard Worker
315*6a54128fSAndroid Build Coastguard Worker /*
316*6a54128fSAndroid Build Coastguard Worker * If this directory doesn't have a parent, or we've
317*6a54128fSAndroid Build Coastguard Worker * seen the parent once already, then offer to
318*6a54128fSAndroid Build Coastguard Worker * reparent it to lost+found
319*6a54128fSAndroid Build Coastguard Worker */
320*6a54128fSAndroid Build Coastguard Worker if (!parent ||
321*6a54128fSAndroid Build Coastguard Worker (loop_pass &&
322*6a54128fSAndroid Build Coastguard Worker ext2fs_test_inode_bitmap2(inode_loop_detect, parent))) {
323*6a54128fSAndroid Build Coastguard Worker pctx->ino = ino;
324*6a54128fSAndroid Build Coastguard Worker if (parent)
325*6a54128fSAndroid Build Coastguard Worker pctx->dir = parent;
326*6a54128fSAndroid Build Coastguard Worker else
327*6a54128fSAndroid Build Coastguard Worker (void) ext2fs_lookup(fs, ino, "..", 2, NULL,
328*6a54128fSAndroid Build Coastguard Worker &pctx->dir);
329*6a54128fSAndroid Build Coastguard Worker if (fix_problem(ctx, !parent ? PR_3_UNCONNECTED_DIR :
330*6a54128fSAndroid Build Coastguard Worker PR_3_LOOPED_DIR, pctx)) {
331*6a54128fSAndroid Build Coastguard Worker if (e2fsck_reconnect_file(ctx, pctx->ino)) {
332*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_valid(fs);
333*6a54128fSAndroid Build Coastguard Worker } else {
334*6a54128fSAndroid Build Coastguard Worker fix_dotdot(ctx, pctx->ino,
335*6a54128fSAndroid Build Coastguard Worker ctx->lost_and_found);
336*6a54128fSAndroid Build Coastguard Worker parent = ctx->lost_and_found;
337*6a54128fSAndroid Build Coastguard Worker }
338*6a54128fSAndroid Build Coastguard Worker }
339*6a54128fSAndroid Build Coastguard Worker break;
340*6a54128fSAndroid Build Coastguard Worker }
341*6a54128fSAndroid Build Coastguard Worker ino = parent;
342*6a54128fSAndroid Build Coastguard Worker if (loop_pass) {
343*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(inode_loop_detect, ino);
344*6a54128fSAndroid Build Coastguard Worker } else if (parent_count++ > 2048) {
345*6a54128fSAndroid Build Coastguard Worker /*
346*6a54128fSAndroid Build Coastguard Worker * If we've run into a path depth that's
347*6a54128fSAndroid Build Coastguard Worker * greater than 2048, try again with the inode
348*6a54128fSAndroid Build Coastguard Worker * loop bitmap turned on and start from the
349*6a54128fSAndroid Build Coastguard Worker * top.
350*6a54128fSAndroid Build Coastguard Worker */
351*6a54128fSAndroid Build Coastguard Worker loop_pass = 1;
352*6a54128fSAndroid Build Coastguard Worker if (inode_loop_detect)
353*6a54128fSAndroid Build Coastguard Worker ext2fs_clear_inode_bitmap(inode_loop_detect);
354*6a54128fSAndroid Build Coastguard Worker else {
355*6a54128fSAndroid Build Coastguard Worker pctx->errcode = e2fsck_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), EXT2FS_BMAP64_AUTODIR, "inode_loop_detect", &inode_loop_detect);
356*6a54128fSAndroid Build Coastguard Worker if (pctx->errcode) {
357*6a54128fSAndroid Build Coastguard Worker pctx->num = 1;
358*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx,
359*6a54128fSAndroid Build Coastguard Worker PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
360*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_ABORT;
361*6a54128fSAndroid Build Coastguard Worker return -1;
362*6a54128fSAndroid Build Coastguard Worker }
363*6a54128fSAndroid Build Coastguard Worker }
364*6a54128fSAndroid Build Coastguard Worker ino = dir;
365*6a54128fSAndroid Build Coastguard Worker }
366*6a54128fSAndroid Build Coastguard Worker }
367*6a54128fSAndroid Build Coastguard Worker
368*6a54128fSAndroid Build Coastguard Worker /*
369*6a54128fSAndroid Build Coastguard Worker * Make sure that .. and the parent directory are the same;
370*6a54128fSAndroid Build Coastguard Worker * offer to fix it if not.
371*6a54128fSAndroid Build Coastguard Worker */
372*6a54128fSAndroid Build Coastguard Worker pctx->ino = dir;
373*6a54128fSAndroid Build Coastguard Worker if (e2fsck_dir_info_get_dotdot(ctx, dir, &pctx->ino2) ||
374*6a54128fSAndroid Build Coastguard Worker e2fsck_dir_info_get_parent(ctx, dir, &pctx->dir)) {
375*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
376*6a54128fSAndroid Build Coastguard Worker return 0;
377*6a54128fSAndroid Build Coastguard Worker }
378*6a54128fSAndroid Build Coastguard Worker if (pctx->ino2 != pctx->dir) {
379*6a54128fSAndroid Build Coastguard Worker if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
380*6a54128fSAndroid Build Coastguard Worker fix_dotdot(ctx, dir, pctx->dir);
381*6a54128fSAndroid Build Coastguard Worker }
382*6a54128fSAndroid Build Coastguard Worker return 0;
383*6a54128fSAndroid Build Coastguard Worker }
384*6a54128fSAndroid Build Coastguard Worker
385*6a54128fSAndroid Build Coastguard Worker /*
386*6a54128fSAndroid Build Coastguard Worker * This routine gets the lost_and_found inode, making it a directory
387*6a54128fSAndroid Build Coastguard Worker * if necessary
388*6a54128fSAndroid Build Coastguard Worker */
e2fsck_get_lost_and_found(e2fsck_t ctx,int fix)389*6a54128fSAndroid Build Coastguard Worker ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
390*6a54128fSAndroid Build Coastguard Worker {
391*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
392*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino;
393*6a54128fSAndroid Build Coastguard Worker blk64_t blk;
394*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
395*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large inode;
396*6a54128fSAndroid Build Coastguard Worker char * block;
397*6a54128fSAndroid Build Coastguard Worker static const char name[] = "lost+found";
398*6a54128fSAndroid Build Coastguard Worker struct problem_context pctx;
399*6a54128fSAndroid Build Coastguard Worker int will_rehash, flags;
400*6a54128fSAndroid Build Coastguard Worker
401*6a54128fSAndroid Build Coastguard Worker if (ctx->lost_and_found)
402*6a54128fSAndroid Build Coastguard Worker return ctx->lost_and_found;
403*6a54128fSAndroid Build Coastguard Worker
404*6a54128fSAndroid Build Coastguard Worker clear_problem_context(&pctx);
405*6a54128fSAndroid Build Coastguard Worker
406*6a54128fSAndroid Build Coastguard Worker will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO);
407*6a54128fSAndroid Build Coastguard Worker if (will_rehash) {
408*6a54128fSAndroid Build Coastguard Worker flags = ctx->fs->flags;
409*6a54128fSAndroid Build Coastguard Worker ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
410*6a54128fSAndroid Build Coastguard Worker }
411*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
412*6a54128fSAndroid Build Coastguard Worker sizeof(name)-1, 0, &ino);
413*6a54128fSAndroid Build Coastguard Worker if (will_rehash)
414*6a54128fSAndroid Build Coastguard Worker ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
415*6a54128fSAndroid Build Coastguard Worker (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
416*6a54128fSAndroid Build Coastguard Worker if (retval && !fix)
417*6a54128fSAndroid Build Coastguard Worker return 0;
418*6a54128fSAndroid Build Coastguard Worker if (!retval) {
419*6a54128fSAndroid Build Coastguard Worker /* Lost+found shouldn't have inline data */
420*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_inode_full(fs, ino, EXT2_INODE(&inode),
421*6a54128fSAndroid Build Coastguard Worker sizeof(inode));
422*6a54128fSAndroid Build Coastguard Worker if (fix && retval)
423*6a54128fSAndroid Build Coastguard Worker return 0;
424*6a54128fSAndroid Build Coastguard Worker
425*6a54128fSAndroid Build Coastguard Worker if (fix && (inode.i_flags & EXT4_INLINE_DATA_FL)) {
426*6a54128fSAndroid Build Coastguard Worker if (!fix_problem(ctx, PR_3_LPF_INLINE_DATA, &pctx))
427*6a54128fSAndroid Build Coastguard Worker return 0;
428*6a54128fSAndroid Build Coastguard Worker goto unlink;
429*6a54128fSAndroid Build Coastguard Worker }
430*6a54128fSAndroid Build Coastguard Worker
431*6a54128fSAndroid Build Coastguard Worker if (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) {
432*6a54128fSAndroid Build Coastguard Worker if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx))
433*6a54128fSAndroid Build Coastguard Worker return 0;
434*6a54128fSAndroid Build Coastguard Worker goto unlink;
435*6a54128fSAndroid Build Coastguard Worker }
436*6a54128fSAndroid Build Coastguard Worker
437*6a54128fSAndroid Build Coastguard Worker if (ext2fs_check_directory(fs, ino) == 0) {
438*6a54128fSAndroid Build Coastguard Worker ctx->lost_and_found = ino;
439*6a54128fSAndroid Build Coastguard Worker return ino;
440*6a54128fSAndroid Build Coastguard Worker }
441*6a54128fSAndroid Build Coastguard Worker
442*6a54128fSAndroid Build Coastguard Worker /* Lost+found isn't a directory! */
443*6a54128fSAndroid Build Coastguard Worker if (!fix)
444*6a54128fSAndroid Build Coastguard Worker return 0;
445*6a54128fSAndroid Build Coastguard Worker pctx.ino = ino;
446*6a54128fSAndroid Build Coastguard Worker if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
447*6a54128fSAndroid Build Coastguard Worker return 0;
448*6a54128fSAndroid Build Coastguard Worker
449*6a54128fSAndroid Build Coastguard Worker unlink:
450*6a54128fSAndroid Build Coastguard Worker /* OK, unlink the old /lost+found file. */
451*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
452*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
453*6a54128fSAndroid Build Coastguard Worker pctx.str = "ext2fs_unlink";
454*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
455*6a54128fSAndroid Build Coastguard Worker return 0;
456*6a54128fSAndroid Build Coastguard Worker }
457*6a54128fSAndroid Build Coastguard Worker (void) e2fsck_dir_info_set_parent(ctx, ino, 0);
458*6a54128fSAndroid Build Coastguard Worker e2fsck_adjust_inode_count(ctx, ino, -1);
459*6a54128fSAndroid Build Coastguard Worker /*
460*6a54128fSAndroid Build Coastguard Worker * If the old lost+found was a directory, we've just
461*6a54128fSAndroid Build Coastguard Worker * disconnected it from the directory tree, which
462*6a54128fSAndroid Build Coastguard Worker * means we need to restart the directory tree scan.
463*6a54128fSAndroid Build Coastguard Worker * The simplest way to do this is restart the whole
464*6a54128fSAndroid Build Coastguard Worker * e2fsck operation.
465*6a54128fSAndroid Build Coastguard Worker */
466*6a54128fSAndroid Build Coastguard Worker if (LINUX_S_ISDIR(inode.i_mode))
467*6a54128fSAndroid Build Coastguard Worker ctx->flags |= E2F_FLAG_RESTART;
468*6a54128fSAndroid Build Coastguard Worker } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
469*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
470*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
471*6a54128fSAndroid Build Coastguard Worker }
472*6a54128fSAndroid Build Coastguard Worker if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
473*6a54128fSAndroid Build Coastguard Worker return 0;
474*6a54128fSAndroid Build Coastguard Worker
475*6a54128fSAndroid Build Coastguard Worker /*
476*6a54128fSAndroid Build Coastguard Worker * Read the inode and block bitmaps in; we'll be messing with
477*6a54128fSAndroid Build Coastguard Worker * them.
478*6a54128fSAndroid Build Coastguard Worker */
479*6a54128fSAndroid Build Coastguard Worker e2fsck_read_bitmaps(ctx);
480*6a54128fSAndroid Build Coastguard Worker
481*6a54128fSAndroid Build Coastguard Worker /*
482*6a54128fSAndroid Build Coastguard Worker * First, find a free block
483*6a54128fSAndroid Build Coastguard Worker */
484*6a54128fSAndroid Build Coastguard Worker if (ctx->lnf_repair_block) {
485*6a54128fSAndroid Build Coastguard Worker blk = ctx->lnf_repair_block;
486*6a54128fSAndroid Build Coastguard Worker ctx->lnf_repair_block = 0;
487*6a54128fSAndroid Build Coastguard Worker goto skip_new_block;
488*6a54128fSAndroid Build Coastguard Worker }
489*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
490*6a54128fSAndroid Build Coastguard Worker if (retval == EXT2_ET_BLOCK_ALLOC_FAIL &&
491*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) {
492*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx);
493*6a54128fSAndroid Build Coastguard Worker ctx->lost_and_found = EXT2_ROOT_INO;
494*6a54128fSAndroid Build Coastguard Worker return 0;
495*6a54128fSAndroid Build Coastguard Worker }
496*6a54128fSAndroid Build Coastguard Worker if (retval) {
497*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
498*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
499*6a54128fSAndroid Build Coastguard Worker return 0;
500*6a54128fSAndroid Build Coastguard Worker }
501*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
502*6a54128fSAndroid Build Coastguard Worker skip_new_block:
503*6a54128fSAndroid Build Coastguard Worker ext2fs_block_alloc_stats2(fs, blk, +1);
504*6a54128fSAndroid Build Coastguard Worker
505*6a54128fSAndroid Build Coastguard Worker /*
506*6a54128fSAndroid Build Coastguard Worker * Next find a free inode.
507*6a54128fSAndroid Build Coastguard Worker */
508*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
509*6a54128fSAndroid Build Coastguard Worker ctx->inode_used_map, &ino);
510*6a54128fSAndroid Build Coastguard Worker if (retval == EXT2_ET_INODE_ALLOC_FAIL &&
511*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) {
512*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx);
513*6a54128fSAndroid Build Coastguard Worker ctx->lost_and_found = EXT2_ROOT_INO;
514*6a54128fSAndroid Build Coastguard Worker return 0;
515*6a54128fSAndroid Build Coastguard Worker }
516*6a54128fSAndroid Build Coastguard Worker if (retval) {
517*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
518*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
519*6a54128fSAndroid Build Coastguard Worker return 0;
520*6a54128fSAndroid Build Coastguard Worker }
521*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
522*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino);
523*6a54128fSAndroid Build Coastguard Worker ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
524*6a54128fSAndroid Build Coastguard Worker
525*6a54128fSAndroid Build Coastguard Worker /*
526*6a54128fSAndroid Build Coastguard Worker * Set up the inode structure
527*6a54128fSAndroid Build Coastguard Worker */
528*6a54128fSAndroid Build Coastguard Worker memset(&inode, 0, sizeof(inode));
529*6a54128fSAndroid Build Coastguard Worker inode.i_mode = 040700;
530*6a54128fSAndroid Build Coastguard Worker inode.i_size = fs->blocksize;
531*6a54128fSAndroid Build Coastguard Worker inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
532*6a54128fSAndroid Build Coastguard Worker inode.i_links_count = 2;
533*6a54128fSAndroid Build Coastguard Worker ext2fs_iblk_set(fs, EXT2_INODE(&inode), 1);
534*6a54128fSAndroid Build Coastguard Worker inode.i_block[0] = blk;
535*6a54128fSAndroid Build Coastguard Worker
536*6a54128fSAndroid Build Coastguard Worker /*
537*6a54128fSAndroid Build Coastguard Worker * Next, write out the inode.
538*6a54128fSAndroid Build Coastguard Worker */
539*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_write_new_inode(fs, ino, EXT2_INODE(&inode));
540*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
541*6a54128fSAndroid Build Coastguard Worker pctx.str = "ext2fs_write_inode";
542*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
543*6a54128fSAndroid Build Coastguard Worker return 0;
544*6a54128fSAndroid Build Coastguard Worker }
545*6a54128fSAndroid Build Coastguard Worker
546*6a54128fSAndroid Build Coastguard Worker /*
547*6a54128fSAndroid Build Coastguard Worker * Now let's create the actual data block for the inode.
548*6a54128fSAndroid Build Coastguard Worker * Due to metadata_csum, the directory block MUST be written
549*6a54128fSAndroid Build Coastguard Worker * after the inode is written to disk!
550*6a54128fSAndroid Build Coastguard Worker */
551*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
552*6a54128fSAndroid Build Coastguard Worker if (retval) {
553*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
554*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
555*6a54128fSAndroid Build Coastguard Worker return 0;
556*6a54128fSAndroid Build Coastguard Worker }
557*6a54128fSAndroid Build Coastguard Worker
558*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
559*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&block);
560*6a54128fSAndroid Build Coastguard Worker if (retval) {
561*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
562*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
563*6a54128fSAndroid Build Coastguard Worker return 0;
564*6a54128fSAndroid Build Coastguard Worker }
565*6a54128fSAndroid Build Coastguard Worker
566*6a54128fSAndroid Build Coastguard Worker /*
567*6a54128fSAndroid Build Coastguard Worker * Finally, create the directory link
568*6a54128fSAndroid Build Coastguard Worker */
569*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
570*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) {
571*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO);
572*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode)
573*6a54128fSAndroid Build Coastguard Worker goto link_error;
574*6a54128fSAndroid Build Coastguard Worker pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino,
575*6a54128fSAndroid Build Coastguard Worker EXT2_FT_DIR);
576*6a54128fSAndroid Build Coastguard Worker }
577*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
578*6a54128fSAndroid Build Coastguard Worker link_error:
579*6a54128fSAndroid Build Coastguard Worker pctx.str = "ext2fs_link";
580*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
581*6a54128fSAndroid Build Coastguard Worker return 0;
582*6a54128fSAndroid Build Coastguard Worker }
583*6a54128fSAndroid Build Coastguard Worker
584*6a54128fSAndroid Build Coastguard Worker /*
585*6a54128fSAndroid Build Coastguard Worker * Miscellaneous bookkeeping that needs to be kept straight.
586*6a54128fSAndroid Build Coastguard Worker */
587*6a54128fSAndroid Build Coastguard Worker e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
588*6a54128fSAndroid Build Coastguard Worker e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
589*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_store(ctx->inode_count, ino, 2);
590*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_store(ctx->inode_link_info, ino, 2);
591*6a54128fSAndroid Build Coastguard Worker ctx->lost_and_found = ino;
592*6a54128fSAndroid Build Coastguard Worker quota_data_add(ctx->qctx, &inode, ino, EXT2_CLUSTER_SIZE(fs->super));
593*6a54128fSAndroid Build Coastguard Worker quota_data_inodes(ctx->qctx, &inode, ino, +1);
594*6a54128fSAndroid Build Coastguard Worker #if 0
595*6a54128fSAndroid Build Coastguard Worker printf("/lost+found created; inode #%lu\n", ino);
596*6a54128fSAndroid Build Coastguard Worker #endif
597*6a54128fSAndroid Build Coastguard Worker return ino;
598*6a54128fSAndroid Build Coastguard Worker }
599*6a54128fSAndroid Build Coastguard Worker
600*6a54128fSAndroid Build Coastguard Worker /*
601*6a54128fSAndroid Build Coastguard Worker * This routine will connect a file to lost+found
602*6a54128fSAndroid Build Coastguard Worker */
e2fsck_reconnect_file(e2fsck_t ctx,ext2_ino_t ino)603*6a54128fSAndroid Build Coastguard Worker int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
604*6a54128fSAndroid Build Coastguard Worker {
605*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
606*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
607*6a54128fSAndroid Build Coastguard Worker char name[80];
608*6a54128fSAndroid Build Coastguard Worker struct problem_context pctx;
609*6a54128fSAndroid Build Coastguard Worker struct ext2_inode inode;
610*6a54128fSAndroid Build Coastguard Worker int file_type = 0;
611*6a54128fSAndroid Build Coastguard Worker
612*6a54128fSAndroid Build Coastguard Worker clear_problem_context(&pctx);
613*6a54128fSAndroid Build Coastguard Worker pctx.ino = ino;
614*6a54128fSAndroid Build Coastguard Worker
615*6a54128fSAndroid Build Coastguard Worker if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
616*6a54128fSAndroid Build Coastguard Worker if (e2fsck_get_lost_and_found(ctx, 1) == 0)
617*6a54128fSAndroid Build Coastguard Worker ctx->bad_lost_and_found++;
618*6a54128fSAndroid Build Coastguard Worker }
619*6a54128fSAndroid Build Coastguard Worker if (ctx->bad_lost_and_found) {
620*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_NO_LPF, &pctx);
621*6a54128fSAndroid Build Coastguard Worker return 1;
622*6a54128fSAndroid Build Coastguard Worker }
623*6a54128fSAndroid Build Coastguard Worker
624*6a54128fSAndroid Build Coastguard Worker sprintf(name, "#%u", ino);
625*6a54128fSAndroid Build Coastguard Worker if (ext2fs_read_inode(fs, ino, &inode) == 0)
626*6a54128fSAndroid Build Coastguard Worker file_type = ext2_file_type(inode.i_mode);
627*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
628*6a54128fSAndroid Build Coastguard Worker if (retval == EXT2_ET_DIR_NO_SPACE) {
629*6a54128fSAndroid Build Coastguard Worker if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
630*6a54128fSAndroid Build Coastguard Worker return 1;
631*6a54128fSAndroid Build Coastguard Worker retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
632*6a54128fSAndroid Build Coastguard Worker 1, 0);
633*6a54128fSAndroid Build Coastguard Worker if (retval) {
634*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
635*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
636*6a54128fSAndroid Build Coastguard Worker return 1;
637*6a54128fSAndroid Build Coastguard Worker }
638*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_link(fs, ctx->lost_and_found, name,
639*6a54128fSAndroid Build Coastguard Worker ino, file_type);
640*6a54128fSAndroid Build Coastguard Worker }
641*6a54128fSAndroid Build Coastguard Worker if (retval) {
642*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
643*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
644*6a54128fSAndroid Build Coastguard Worker return 1;
645*6a54128fSAndroid Build Coastguard Worker }
646*6a54128fSAndroid Build Coastguard Worker e2fsck_adjust_inode_count(ctx, ino, 1);
647*6a54128fSAndroid Build Coastguard Worker
648*6a54128fSAndroid Build Coastguard Worker return 0;
649*6a54128fSAndroid Build Coastguard Worker }
650*6a54128fSAndroid Build Coastguard Worker
651*6a54128fSAndroid Build Coastguard Worker /*
652*6a54128fSAndroid Build Coastguard Worker * Utility routine to adjust the inode counts on an inode.
653*6a54128fSAndroid Build Coastguard Worker */
e2fsck_adjust_inode_count(e2fsck_t ctx,ext2_ino_t ino,int adj)654*6a54128fSAndroid Build Coastguard Worker errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
655*6a54128fSAndroid Build Coastguard Worker {
656*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
657*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
658*6a54128fSAndroid Build Coastguard Worker struct ext2_inode inode;
659*6a54128fSAndroid Build Coastguard Worker
660*6a54128fSAndroid Build Coastguard Worker if (!ino)
661*6a54128fSAndroid Build Coastguard Worker return 0;
662*6a54128fSAndroid Build Coastguard Worker
663*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_inode(fs, ino, &inode);
664*6a54128fSAndroid Build Coastguard Worker if (retval)
665*6a54128fSAndroid Build Coastguard Worker return retval;
666*6a54128fSAndroid Build Coastguard Worker
667*6a54128fSAndroid Build Coastguard Worker #if 0
668*6a54128fSAndroid Build Coastguard Worker printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
669*6a54128fSAndroid Build Coastguard Worker inode.i_links_count);
670*6a54128fSAndroid Build Coastguard Worker #endif
671*6a54128fSAndroid Build Coastguard Worker
672*6a54128fSAndroid Build Coastguard Worker if (adj == 1) {
673*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_increment(ctx->inode_count, ino, 0);
674*6a54128fSAndroid Build Coastguard Worker if (inode.i_links_count == (__u16) ~0)
675*6a54128fSAndroid Build Coastguard Worker return 0;
676*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
677*6a54128fSAndroid Build Coastguard Worker inode.i_links_count++;
678*6a54128fSAndroid Build Coastguard Worker } else if (adj == -1) {
679*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_decrement(ctx->inode_count, ino, 0);
680*6a54128fSAndroid Build Coastguard Worker if (inode.i_links_count == 0)
681*6a54128fSAndroid Build Coastguard Worker return 0;
682*6a54128fSAndroid Build Coastguard Worker ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
683*6a54128fSAndroid Build Coastguard Worker inode.i_links_count--;
684*6a54128fSAndroid Build Coastguard Worker }
685*6a54128fSAndroid Build Coastguard Worker
686*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_inode(fs, ino, &inode);
687*6a54128fSAndroid Build Coastguard Worker if (retval)
688*6a54128fSAndroid Build Coastguard Worker return retval;
689*6a54128fSAndroid Build Coastguard Worker
690*6a54128fSAndroid Build Coastguard Worker return 0;
691*6a54128fSAndroid Build Coastguard Worker }
692*6a54128fSAndroid Build Coastguard Worker
693*6a54128fSAndroid Build Coastguard Worker /*
694*6a54128fSAndroid Build Coastguard Worker * Fix parent --- this routine fixes up the parent of a directory.
695*6a54128fSAndroid Build Coastguard Worker */
696*6a54128fSAndroid Build Coastguard Worker struct fix_dotdot_struct {
697*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs;
698*6a54128fSAndroid Build Coastguard Worker ext2_ino_t parent;
699*6a54128fSAndroid Build Coastguard Worker int done;
700*6a54128fSAndroid Build Coastguard Worker e2fsck_t ctx;
701*6a54128fSAndroid Build Coastguard Worker };
702*6a54128fSAndroid Build Coastguard Worker
fix_dotdot_proc(struct ext2_dir_entry * dirent,int offset EXT2FS_ATTR ((unused)),int blocksize EXT2FS_ATTR ((unused)),char * buf EXT2FS_ATTR ((unused)),void * priv_data)703*6a54128fSAndroid Build Coastguard Worker static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
704*6a54128fSAndroid Build Coastguard Worker int offset EXT2FS_ATTR((unused)),
705*6a54128fSAndroid Build Coastguard Worker int blocksize EXT2FS_ATTR((unused)),
706*6a54128fSAndroid Build Coastguard Worker char *buf EXT2FS_ATTR((unused)),
707*6a54128fSAndroid Build Coastguard Worker void *priv_data)
708*6a54128fSAndroid Build Coastguard Worker {
709*6a54128fSAndroid Build Coastguard Worker struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
710*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
711*6a54128fSAndroid Build Coastguard Worker struct problem_context pctx;
712*6a54128fSAndroid Build Coastguard Worker
713*6a54128fSAndroid Build Coastguard Worker if (ext2fs_dirent_name_len(dirent) != 2)
714*6a54128fSAndroid Build Coastguard Worker return 0;
715*6a54128fSAndroid Build Coastguard Worker if (strncmp(dirent->name, "..", 2))
716*6a54128fSAndroid Build Coastguard Worker return 0;
717*6a54128fSAndroid Build Coastguard Worker
718*6a54128fSAndroid Build Coastguard Worker clear_problem_context(&pctx);
719*6a54128fSAndroid Build Coastguard Worker
720*6a54128fSAndroid Build Coastguard Worker retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
721*6a54128fSAndroid Build Coastguard Worker if (retval) {
722*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
723*6a54128fSAndroid Build Coastguard Worker fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
724*6a54128fSAndroid Build Coastguard Worker }
725*6a54128fSAndroid Build Coastguard Worker retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
726*6a54128fSAndroid Build Coastguard Worker if (retval) {
727*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
728*6a54128fSAndroid Build Coastguard Worker fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
729*6a54128fSAndroid Build Coastguard Worker }
730*6a54128fSAndroid Build Coastguard Worker dirent->inode = fp->parent;
731*6a54128fSAndroid Build Coastguard Worker if (ext2fs_has_feature_filetype(fp->ctx->fs->super))
732*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
733*6a54128fSAndroid Build Coastguard Worker else
734*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
735*6a54128fSAndroid Build Coastguard Worker
736*6a54128fSAndroid Build Coastguard Worker fp->done++;
737*6a54128fSAndroid Build Coastguard Worker return DIRENT_ABORT | DIRENT_CHANGED;
738*6a54128fSAndroid Build Coastguard Worker }
739*6a54128fSAndroid Build Coastguard Worker
fix_dotdot(e2fsck_t ctx,ext2_ino_t ino,ext2_ino_t parent)740*6a54128fSAndroid Build Coastguard Worker static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
741*6a54128fSAndroid Build Coastguard Worker {
742*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
743*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
744*6a54128fSAndroid Build Coastguard Worker struct fix_dotdot_struct fp;
745*6a54128fSAndroid Build Coastguard Worker struct problem_context pctx;
746*6a54128fSAndroid Build Coastguard Worker int flags, will_rehash;
747*6a54128fSAndroid Build Coastguard Worker
748*6a54128fSAndroid Build Coastguard Worker fp.fs = fs;
749*6a54128fSAndroid Build Coastguard Worker fp.parent = parent;
750*6a54128fSAndroid Build Coastguard Worker fp.done = 0;
751*6a54128fSAndroid Build Coastguard Worker fp.ctx = ctx;
752*6a54128fSAndroid Build Coastguard Worker
753*6a54128fSAndroid Build Coastguard Worker #if 0
754*6a54128fSAndroid Build Coastguard Worker printf("Fixing '..' of inode %lu to be %lu...\n", ino, parent);
755*6a54128fSAndroid Build Coastguard Worker #endif
756*6a54128fSAndroid Build Coastguard Worker
757*6a54128fSAndroid Build Coastguard Worker clear_problem_context(&pctx);
758*6a54128fSAndroid Build Coastguard Worker pctx.ino = ino;
759*6a54128fSAndroid Build Coastguard Worker will_rehash = e2fsck_dir_will_be_rehashed(ctx, ino);
760*6a54128fSAndroid Build Coastguard Worker if (will_rehash) {
761*6a54128fSAndroid Build Coastguard Worker flags = ctx->fs->flags;
762*6a54128fSAndroid Build Coastguard Worker ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
763*6a54128fSAndroid Build Coastguard Worker }
764*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
765*6a54128fSAndroid Build Coastguard Worker 0, fix_dotdot_proc, &fp);
766*6a54128fSAndroid Build Coastguard Worker if (will_rehash)
767*6a54128fSAndroid Build Coastguard Worker ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
768*6a54128fSAndroid Build Coastguard Worker (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
769*6a54128fSAndroid Build Coastguard Worker if (retval || !fp.done) {
770*6a54128fSAndroid Build Coastguard Worker pctx.errcode = retval;
771*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
772*6a54128fSAndroid Build Coastguard Worker PR_3_FIX_PARENT_NOFIND, &pctx);
773*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_valid(fs);
774*6a54128fSAndroid Build Coastguard Worker }
775*6a54128fSAndroid Build Coastguard Worker (void) e2fsck_dir_info_set_dotdot(ctx, ino, parent);
776*6a54128fSAndroid Build Coastguard Worker if (e2fsck_dir_info_set_parent(ctx, ino, ctx->lost_and_found))
777*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_3_NO_DIRINFO, &pctx);
778*6a54128fSAndroid Build Coastguard Worker
779*6a54128fSAndroid Build Coastguard Worker return;
780*6a54128fSAndroid Build Coastguard Worker }
781*6a54128fSAndroid Build Coastguard Worker
782*6a54128fSAndroid Build Coastguard Worker /*
783*6a54128fSAndroid Build Coastguard Worker * These routines are responsible for expanding a /lost+found if it is
784*6a54128fSAndroid Build Coastguard Worker * too small.
785*6a54128fSAndroid Build Coastguard Worker */
786*6a54128fSAndroid Build Coastguard Worker
787*6a54128fSAndroid Build Coastguard Worker struct expand_dir_struct {
788*6a54128fSAndroid Build Coastguard Worker blk64_t num;
789*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t guaranteed_size;
790*6a54128fSAndroid Build Coastguard Worker blk64_t newblocks;
791*6a54128fSAndroid Build Coastguard Worker blk64_t last_block;
792*6a54128fSAndroid Build Coastguard Worker errcode_t err;
793*6a54128fSAndroid Build Coastguard Worker e2fsck_t ctx;
794*6a54128fSAndroid Build Coastguard Worker ext2_ino_t dir;
795*6a54128fSAndroid Build Coastguard Worker };
796*6a54128fSAndroid Build Coastguard Worker
expand_dir_proc(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)797*6a54128fSAndroid Build Coastguard Worker static int expand_dir_proc(ext2_filsys fs,
798*6a54128fSAndroid Build Coastguard Worker blk64_t *blocknr,
799*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t blockcnt,
800*6a54128fSAndroid Build Coastguard Worker blk64_t ref_block EXT2FS_ATTR((unused)),
801*6a54128fSAndroid Build Coastguard Worker int ref_offset EXT2FS_ATTR((unused)),
802*6a54128fSAndroid Build Coastguard Worker void *priv_data)
803*6a54128fSAndroid Build Coastguard Worker {
804*6a54128fSAndroid Build Coastguard Worker struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
805*6a54128fSAndroid Build Coastguard Worker blk64_t new_blk;
806*6a54128fSAndroid Build Coastguard Worker static blk64_t last_blk = 0;
807*6a54128fSAndroid Build Coastguard Worker char *block;
808*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
809*6a54128fSAndroid Build Coastguard Worker e2fsck_t ctx;
810*6a54128fSAndroid Build Coastguard Worker
811*6a54128fSAndroid Build Coastguard Worker ctx = es->ctx;
812*6a54128fSAndroid Build Coastguard Worker
813*6a54128fSAndroid Build Coastguard Worker if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
814*6a54128fSAndroid Build Coastguard Worker return BLOCK_ABORT;
815*6a54128fSAndroid Build Coastguard Worker
816*6a54128fSAndroid Build Coastguard Worker if (blockcnt > 0)
817*6a54128fSAndroid Build Coastguard Worker es->last_block = blockcnt;
818*6a54128fSAndroid Build Coastguard Worker if (*blocknr) {
819*6a54128fSAndroid Build Coastguard Worker last_blk = *blocknr;
820*6a54128fSAndroid Build Coastguard Worker return 0;
821*6a54128fSAndroid Build Coastguard Worker }
822*6a54128fSAndroid Build Coastguard Worker
823*6a54128fSAndroid Build Coastguard Worker if (blockcnt &&
824*6a54128fSAndroid Build Coastguard Worker (EXT2FS_B2C(fs, last_blk) == EXT2FS_B2C(fs, last_blk + 1)))
825*6a54128fSAndroid Build Coastguard Worker new_blk = last_blk + 1;
826*6a54128fSAndroid Build Coastguard Worker else {
827*6a54128fSAndroid Build Coastguard Worker last_blk &= ~EXT2FS_CLUSTER_MASK(fs);
828*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_new_block2(fs, last_blk, ctx->block_found_map,
829*6a54128fSAndroid Build Coastguard Worker &new_blk);
830*6a54128fSAndroid Build Coastguard Worker if (retval) {
831*6a54128fSAndroid Build Coastguard Worker es->err = retval;
832*6a54128fSAndroid Build Coastguard Worker return BLOCK_ABORT;
833*6a54128fSAndroid Build Coastguard Worker }
834*6a54128fSAndroid Build Coastguard Worker es->newblocks++;
835*6a54128fSAndroid Build Coastguard Worker ext2fs_block_alloc_stats2(fs, new_blk, +1);
836*6a54128fSAndroid Build Coastguard Worker }
837*6a54128fSAndroid Build Coastguard Worker last_blk = new_blk;
838*6a54128fSAndroid Build Coastguard Worker
839*6a54128fSAndroid Build Coastguard Worker if (blockcnt > 0) {
840*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_new_dir_block(fs, 0, 0, &block);
841*6a54128fSAndroid Build Coastguard Worker if (retval) {
842*6a54128fSAndroid Build Coastguard Worker es->err = retval;
843*6a54128fSAndroid Build Coastguard Worker return BLOCK_ABORT;
844*6a54128fSAndroid Build Coastguard Worker }
845*6a54128fSAndroid Build Coastguard Worker es->num--;
846*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
847*6a54128fSAndroid Build Coastguard Worker es->dir);
848*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&block);
849*6a54128fSAndroid Build Coastguard Worker } else
850*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL);
851*6a54128fSAndroid Build Coastguard Worker if (retval) {
852*6a54128fSAndroid Build Coastguard Worker es->err = retval;
853*6a54128fSAndroid Build Coastguard Worker return BLOCK_ABORT;
854*6a54128fSAndroid Build Coastguard Worker }
855*6a54128fSAndroid Build Coastguard Worker *blocknr = new_blk;
856*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk);
857*6a54128fSAndroid Build Coastguard Worker
858*6a54128fSAndroid Build Coastguard Worker if (es->num == 0)
859*6a54128fSAndroid Build Coastguard Worker return (BLOCK_CHANGED | BLOCK_ABORT);
860*6a54128fSAndroid Build Coastguard Worker else
861*6a54128fSAndroid Build Coastguard Worker return BLOCK_CHANGED;
862*6a54128fSAndroid Build Coastguard Worker }
863*6a54128fSAndroid Build Coastguard Worker
e2fsck_expand_directory(e2fsck_t ctx,ext2_ino_t dir,int num,int guaranteed_size)864*6a54128fSAndroid Build Coastguard Worker errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
865*6a54128fSAndroid Build Coastguard Worker int num, int guaranteed_size)
866*6a54128fSAndroid Build Coastguard Worker {
867*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
868*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
869*6a54128fSAndroid Build Coastguard Worker struct expand_dir_struct es;
870*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large inode;
871*6a54128fSAndroid Build Coastguard Worker blk64_t sz;
872*6a54128fSAndroid Build Coastguard Worker
873*6a54128fSAndroid Build Coastguard Worker if (!(fs->flags & EXT2_FLAG_RW))
874*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_RO_FILSYS;
875*6a54128fSAndroid Build Coastguard Worker
876*6a54128fSAndroid Build Coastguard Worker /*
877*6a54128fSAndroid Build Coastguard Worker * Read the inode and block bitmaps in; we'll be messing with
878*6a54128fSAndroid Build Coastguard Worker * them.
879*6a54128fSAndroid Build Coastguard Worker */
880*6a54128fSAndroid Build Coastguard Worker e2fsck_read_bitmaps(ctx);
881*6a54128fSAndroid Build Coastguard Worker
882*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_check_directory(fs, dir);
883*6a54128fSAndroid Build Coastguard Worker if (retval)
884*6a54128fSAndroid Build Coastguard Worker return retval;
885*6a54128fSAndroid Build Coastguard Worker
886*6a54128fSAndroid Build Coastguard Worker es.num = num;
887*6a54128fSAndroid Build Coastguard Worker es.guaranteed_size = guaranteed_size;
888*6a54128fSAndroid Build Coastguard Worker es.last_block = 0;
889*6a54128fSAndroid Build Coastguard Worker es.err = 0;
890*6a54128fSAndroid Build Coastguard Worker es.newblocks = 0;
891*6a54128fSAndroid Build Coastguard Worker es.ctx = ctx;
892*6a54128fSAndroid Build Coastguard Worker es.dir = dir;
893*6a54128fSAndroid Build Coastguard Worker
894*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
895*6a54128fSAndroid Build Coastguard Worker 0, expand_dir_proc, &es);
896*6a54128fSAndroid Build Coastguard Worker
897*6a54128fSAndroid Build Coastguard Worker if (es.err)
898*6a54128fSAndroid Build Coastguard Worker return es.err;
899*6a54128fSAndroid Build Coastguard Worker
900*6a54128fSAndroid Build Coastguard Worker /*
901*6a54128fSAndroid Build Coastguard Worker * Update the size and block count fields in the inode.
902*6a54128fSAndroid Build Coastguard Worker */
903*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_inode_full(fs, dir,
904*6a54128fSAndroid Build Coastguard Worker EXT2_INODE(&inode), sizeof(inode));
905*6a54128fSAndroid Build Coastguard Worker if (retval)
906*6a54128fSAndroid Build Coastguard Worker return retval;
907*6a54128fSAndroid Build Coastguard Worker
908*6a54128fSAndroid Build Coastguard Worker sz = (es.last_block + 1) * fs->blocksize;
909*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_inode_size_set(fs, EXT2_INODE(&inode), sz);
910*6a54128fSAndroid Build Coastguard Worker if (retval)
911*6a54128fSAndroid Build Coastguard Worker return retval;
912*6a54128fSAndroid Build Coastguard Worker ext2fs_iblk_add_blocks(fs, EXT2_INODE(&inode), es.newblocks);
913*6a54128fSAndroid Build Coastguard Worker quota_data_add(ctx->qctx, &inode, dir,
914*6a54128fSAndroid Build Coastguard Worker es.newblocks * EXT2_CLUSTER_SIZE(fs->super));
915*6a54128fSAndroid Build Coastguard Worker
916*6a54128fSAndroid Build Coastguard Worker e2fsck_write_inode_full(ctx, dir, EXT2_INODE(&inode),
917*6a54128fSAndroid Build Coastguard Worker sizeof(inode), "expand_directory");
918*6a54128fSAndroid Build Coastguard Worker
919*6a54128fSAndroid Build Coastguard Worker return 0;
920*6a54128fSAndroid Build Coastguard Worker }
921*6a54128fSAndroid Build Coastguard Worker
922