]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * pass1b.c --- Pass #1b of e2fsck | |
3 | * | |
4 | * This file contains pass1B, pass1C, and pass1D of e2fsck. They are | |
5 | * only invoked if pass 1 discovered blocks which are in use by more | |
6 | * than one inode. | |
7 | * | |
8 | * Pass1B scans the data blocks of all the inodes again, generating a | |
9 | * complete list of duplicate blocks and which inodes have claimed | |
10 | * them. | |
11 | * | |
12 | * Pass1C does a tree-traversal of the filesystem, to determine the | |
13 | * parent directories of these inodes. This step is necessary so that | |
14 | * e2fsck can print out the pathnames of affected inodes. | |
15 | * | |
16 | * Pass1D is a reconciliation pass. For each inode with duplicate | |
17 | * blocks, the user is prompted if s/he would like to clone the file | |
18 | * (so that the file gets a fresh copy of the duplicated blocks) or | |
19 | * simply to delete the file. | |
20 | * | |
21 | * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be | |
22 | * redistributed under the terms of the GNU Public License. | |
23 | * | |
24 | */ | |
25 | ||
26 | #include <time.h> | |
50e1e10f TT |
27 | #ifdef HAVE_ERRNO_H |
28 | #include <errno.h> | |
29 | #endif | |
3839e657 TT |
30 | |
31 | #include <et/com_err.h> | |
32 | #include "e2fsck.h" | |
33 | ||
34 | /* | |
35 | * This is structure is allocated for each time that a block is | |
36 | * claimed by more than one file. So if a particular block is claimed | |
37 | * by 3 files, then three copies of this structure will be allocated, | |
38 | * one for each conflict. | |
39 | * | |
40 | * The linked list structure is as follows: | |
41 | * | |
42 | * dup_blk --> block #34 --> block #35 --> block #47 | |
43 | * inode #12 inode #14 inode #17 | |
44 | * num_bad = 3 num_bad = 2 num_bad = 2 | |
45 | * | | | | |
46 | * V V V | |
47 | * block #34 block #35 block #47 | |
48 | * inode #14 inode #15 inode #23 | |
49 | * | | |
50 | * V | |
51 | * block #34 | |
52 | * inode #15 | |
53 | * | |
54 | * The num_bad field indicates how many inodes are sharing a | |
55 | * particular block, and is only stored in the first element of the | |
56 | * linked list for a particular block. As the block conflicts are | |
57 | * resolved, num_bad is decremented; when it reaches 1, then we no | |
58 | * longer need to worry about that block. | |
59 | */ | |
60 | struct dup_block { | |
61 | blk_t block; /* Block number */ | |
62 | ino_t ino; /* Inode number */ | |
63 | int num_bad; | |
64 | /* Pointer to next dup record with different block */ | |
65 | struct dup_block *next_block; | |
66 | /* Pointer to next dup record with different inode */ | |
67 | struct dup_block *next_inode; | |
68 | }; | |
69 | ||
70 | /* | |
71 | * This structure stores information about a particular inode which | |
72 | * is sharing blocks with other inodes. This information is collected | |
73 | * to display to the user, so that the user knows what files he or she | |
74 | * is dealing with, when trying to decide how to resolve the conflict | |
75 | * of multiply-claimed blocks. | |
76 | */ | |
77 | struct dup_inode { | |
78 | ino_t ino; | |
79 | time_t mtime; | |
80 | char *pathname; | |
81 | int num_dupblocks; | |
82 | int flags; | |
83 | struct dup_inode *next; | |
84 | }; | |
85 | ||
86 | #define DUP_INODE_DONT_FREE_PATHNAME 0x1 | |
87 | ||
88 | static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr, | |
89 | int blockcnt, void *private); | |
90 | static void delete_file(ext2_filsys fs, struct dup_inode *dp, | |
91 | char *block_buf); | |
92 | static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf); | |
93 | static void pass1b(ext2_filsys fs, char *block_buf); | |
94 | static void pass1c(ext2_filsys fs, char *block_buf); | |
95 | static void pass1d(ext2_filsys fs, char *block_buf); | |
96 | ||
97 | static struct dup_block *dup_blk = 0; | |
98 | static struct dup_inode *dup_ino = 0; | |
99 | static int dup_inode_count = 0; | |
100 | ||
f3db3566 | 101 | static ext2fs_inode_bitmap inode_dup_map; |
3839e657 TT |
102 | |
103 | /* | |
104 | * Main procedure for handling duplicate blocks | |
105 | */ | |
106 | void pass1_dupblocks(ext2_filsys fs, char *block_buf) | |
107 | { | |
108 | errcode_t retval; | |
109 | struct dup_block *p, *q, *next_p, *next_q; | |
110 | struct dup_inode *r, *next_r; | |
111 | ||
f3db3566 TT |
112 | retval = ext2fs_allocate_inode_bitmap(fs, |
113 | "multiply claimed inode map", &inode_dup_map); | |
3839e657 TT |
114 | if (retval) { |
115 | com_err("ext2fs_allocate_inode_bitmap", retval, | |
116 | "while allocating inode_dup_map"); | |
117 | fatal_error(0); | |
118 | } | |
119 | ||
120 | pass1b(fs, block_buf); | |
121 | pass1c(fs, block_buf); | |
122 | pass1d(fs, block_buf); | |
123 | ||
124 | /* | |
125 | * Time to free all of the accumulated data structures that we | |
126 | * don't need anymore. | |
127 | */ | |
f3db3566 TT |
128 | ext2fs_free_inode_bitmap(inode_dup_map); inode_dup_map = 0; |
129 | ext2fs_free_block_bitmap(block_dup_map); block_dup_map = 0; | |
3839e657 TT |
130 | for (p = dup_blk; p; p = next_p) { |
131 | next_p = p->next_block; | |
132 | for (q = p; q; q = next_q) { | |
133 | next_q = q->next_inode; | |
134 | free(q); | |
135 | } | |
136 | } | |
137 | for (r = dup_ino; r; r = next_r) { | |
138 | next_r = r->next; | |
139 | if (r->pathname && !(r->flags & DUP_INODE_DONT_FREE_PATHNAME)) | |
140 | free(r->pathname); | |
141 | free(r); | |
142 | } | |
143 | } | |
144 | ||
145 | /* | |
146 | * Scan the inodes looking for inodes that contain duplicate blocks. | |
147 | */ | |
148 | struct process_block_struct { | |
149 | ino_t ino; | |
150 | int dup_blocks; | |
151 | }; | |
152 | ||
153 | void pass1b(ext2_filsys fs, char *block_buf) | |
154 | { | |
155 | ino_t ino; | |
156 | struct ext2_inode inode; | |
157 | ext2_inode_scan scan; | |
158 | errcode_t retval; | |
159 | struct process_block_struct pb; | |
160 | struct dup_inode *dp; | |
161 | ||
162 | printf("Duplicate blocks found... invoking duplicate block passes.\n"); | |
163 | printf("Pass 1B: Rescan for duplicate/bad blocks\n"); | |
164 | retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan); | |
165 | if (retval) { | |
166 | com_err(program_name, retval, "while opening inode scan"); | |
167 | fatal_error(0); | |
168 | } | |
169 | retval = ext2fs_get_next_inode(scan, &ino, &inode); | |
170 | if (retval) { | |
171 | com_err(program_name, retval, "while starting inode scan"); | |
172 | fatal_error(0); | |
173 | } | |
174 | stashed_inode = &inode; | |
175 | while (ino) { | |
176 | stashed_ino = ino; | |
177 | if ((ino != EXT2_BAD_INO) && | |
f3db3566 | 178 | (!ext2fs_test_inode_bitmap(inode_used_map, ino) || |
3839e657 TT |
179 | !inode_has_valid_blocks(&inode))) |
180 | goto next; | |
181 | ||
182 | pb.ino = ino; | |
183 | pb.dup_blocks = 0; | |
184 | retval = ext2fs_block_iterate(fs, ino, 0, block_buf, | |
185 | process_pass1b_block, &pb); | |
186 | if (pb.dup_blocks) { | |
187 | if (ino != EXT2_BAD_INO) | |
188 | printf("\n"); | |
189 | dp = allocate_memory(sizeof(struct dup_inode), | |
190 | "duplicate inode record"); | |
191 | dp->ino = ino; | |
192 | dp->mtime = inode.i_mtime; | |
193 | dp->num_dupblocks = pb.dup_blocks; | |
194 | dp->pathname = 0; | |
195 | dp->flags = 0; | |
196 | dp->next = dup_ino; | |
197 | dup_ino = dp; | |
198 | if (ino != EXT2_BAD_INO) | |
199 | dup_inode_count++; | |
200 | } | |
201 | if (retval) | |
202 | com_err(program_name, retval, | |
203 | "while calling ext2fs_block_iterate in pass1b"); | |
204 | ||
205 | next: | |
206 | retval = ext2fs_get_next_inode(scan, &ino, &inode); | |
207 | if (retval) { | |
208 | com_err(program_name, retval, | |
209 | "while doing inode scan"); | |
210 | fatal_error(0); | |
211 | } | |
212 | } | |
213 | ext2fs_close_inode_scan(scan); | |
214 | fs->get_blocks = 0; | |
215 | fs->check_directory = 0; | |
216 | } | |
217 | ||
218 | int process_pass1b_block(ext2_filsys fs, | |
219 | blk_t *block_nr, | |
220 | int blockcnt, | |
221 | void *private) | |
222 | { | |
223 | struct process_block_struct *p; | |
224 | struct dup_block *dp, *q, *r; | |
225 | int i; | |
226 | ||
227 | if (!*block_nr) | |
228 | return 0; | |
229 | p = (struct process_block_struct *) private; | |
230 | ||
f3db3566 | 231 | if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) { |
3839e657 TT |
232 | /* OK, this is a duplicate block */ |
233 | if (p->ino != EXT2_BAD_INO) { | |
234 | if (!p->dup_blocks) | |
f3db3566 | 235 | printf("Duplicate/bad block(s) in inode %lu:", |
3839e657 | 236 | p->ino); |
50e1e10f | 237 | printf(" %u", *block_nr); |
3839e657 TT |
238 | } |
239 | p->dup_blocks++; | |
f3db3566 TT |
240 | ext2fs_mark_block_bitmap(block_dup_map, *block_nr); |
241 | ext2fs_mark_inode_bitmap(inode_dup_map, p->ino); | |
3839e657 TT |
242 | dp = allocate_memory(sizeof(struct dup_block), |
243 | "duplicate block record"); | |
244 | dp->block = *block_nr; | |
245 | dp->ino = p->ino; | |
246 | dp->num_bad = 0; | |
247 | q = dup_blk; | |
248 | while (q) { | |
249 | if (q->block == *block_nr) | |
250 | break; | |
251 | q = q->next_block; | |
252 | } | |
253 | if (q) { | |
254 | dp->next_inode = q->next_inode; | |
255 | q->next_inode = dp; | |
256 | } else { | |
257 | dp->next_block = dup_blk; | |
258 | dup_blk = dp; | |
259 | } | |
260 | } | |
261 | /* | |
262 | * Set the num_bad field | |
263 | */ | |
264 | for (q = dup_blk; q; q = q->next_block) { | |
265 | i = 0; | |
266 | for (r = q; r; r = r->next_inode) | |
267 | i++; | |
268 | q->num_bad = i; | |
269 | } | |
270 | return 0; | |
271 | } | |
272 | ||
273 | /* | |
274 | * Used by pass1c to name the "special" inodes. They are declared as | |
275 | * writeable strings to prevent const problems. | |
276 | */ | |
277 | #define num_special_inodes 7 | |
278 | char special_inode_name[num_special_inodes][40] = | |
279 | { | |
280 | "<The NULL inode>", /* 0 */ | |
281 | "<The bad blocks inode>", /* 1 */ | |
282 | "/", /* 2 */ | |
283 | "<The ACL index inode>", /* 3 */ | |
284 | "<The ACL data inode>", /* 4 */ | |
285 | "<The boot loader inode>", /* 5 */ | |
286 | "<The undelete directory inode>" /* 6 */ | |
287 | }; | |
288 | ||
289 | /* | |
290 | * Pass 1c: Scan directories for inodes with duplicate blocks. This | |
291 | * is used so that we can print pathnames when prompting the user for | |
292 | * what to do. | |
293 | */ | |
294 | struct process_dir_struct { | |
295 | ext2_filsys fs; | |
296 | ino_t dir_ino; | |
297 | int count; | |
298 | }; | |
299 | ||
300 | void pass1c(ext2_filsys fs, char *block_buf) | |
301 | { | |
302 | int i; | |
303 | struct dup_inode *p; | |
304 | errcode_t retval; | |
305 | char buf[80]; | |
306 | int inodes_left = dup_inode_count; | |
307 | int offset, entry; | |
308 | struct ext2_dir_entry *dirent; | |
309 | ||
310 | printf("Pass 1C: Scan directories for inodes with dup blocks.\n"); | |
311 | ||
312 | /* | |
313 | * First check to see if any of the inodes with dup blocks is | |
314 | * the bad block inode or the root inode; handle them as | |
315 | * special cases. | |
316 | */ | |
317 | for (p = dup_ino; p; p = p->next) { | |
318 | if (p->ino < num_special_inodes) { | |
319 | p->pathname = special_inode_name[p->ino]; | |
320 | p->flags |= DUP_INODE_DONT_FREE_PATHNAME; | |
321 | inodes_left--; | |
322 | } | |
323 | } | |
324 | ||
325 | /* | |
326 | * Search through all directories to translate inodes to names | |
327 | * (by searching for the containing directory for that inode.) | |
328 | */ | |
329 | for (i=0; inodes_left && i < dir_block_count; i++) { | |
50e1e10f TT |
330 | retval = ext2fs_read_dir_block(fs, dir_blocks[i].blk, |
331 | block_buf); | |
3839e657 TT |
332 | entry = offset = 0; |
333 | while (offset < fs->blocksize) { | |
334 | entry++; | |
335 | dirent = (struct ext2_dir_entry *) | |
336 | (block_buf + offset); | |
337 | if (!dirent->inode || | |
338 | ((dir_blocks[i].blockcnt == 0) && (entry <= 2))) | |
339 | goto next; | |
340 | ||
f3db3566 | 341 | if (!ext2fs_test_inode_bitmap(inode_dup_map, |
3839e657 TT |
342 | dirent->inode)) |
343 | goto next; | |
344 | ||
345 | for (p = dup_ino; p; p = p->next) { | |
346 | if (p->ino == dirent->inode) | |
347 | break; | |
348 | } | |
349 | ||
350 | if (!p || p->pathname) | |
351 | goto next; | |
352 | ||
353 | (void) ext2fs_get_pathname(fs, dir_blocks[i].ino, | |
354 | p->ino, &p->pathname); | |
355 | inodes_left--; | |
356 | ||
357 | next: | |
358 | if (dirent->rec_len < 8) | |
359 | break; | |
360 | offset += dirent->rec_len; | |
361 | } | |
362 | } | |
363 | ||
364 | ||
365 | /* | |
366 | * If we can't get a name, then put in a generic one. | |
367 | */ | |
368 | for (p = dup_ino; p; p = p->next) { | |
369 | if (!p->pathname) { | |
f3db3566 | 370 | sprintf(buf, "<Unknown inode #%lu>", p->ino); |
3839e657 TT |
371 | p->pathname = malloc(strlen(buf)+1); |
372 | if (!p->pathname) { | |
373 | fprintf(stderr, "pass1c: couldn't malloc " | |
374 | "generic pathname\n"); | |
375 | fatal_error(0); | |
376 | } | |
377 | strcpy(p->pathname, buf); | |
378 | } | |
379 | } | |
380 | } | |
381 | ||
382 | static void pass1d(ext2_filsys fs, char *block_buf) | |
383 | { | |
384 | struct dup_inode *p, *s; | |
385 | struct dup_block *q, *r; | |
386 | ino_t *shared; | |
387 | int shared_len; | |
388 | int i; | |
389 | errcode_t retval; | |
390 | char *time_str; | |
391 | int file_ok; | |
392 | ||
393 | printf("Pass 1D: Reconciling duplicate blocks\n"); | |
394 | read_bitmaps(fs); | |
395 | ||
396 | printf("(There are %d inodes containing duplicate/bad blocks.)\n\n", | |
397 | dup_inode_count); | |
398 | shared = allocate_memory(sizeof(ino_t) * dup_inode_count, | |
399 | "Shared inode list"); | |
400 | for (p = dup_ino; p; p = p->next) { | |
401 | shared_len = 0; | |
402 | file_ok = 1; | |
403 | if (p->ino == EXT2_BAD_INO) | |
404 | continue; | |
405 | ||
406 | /* | |
407 | * Search through the duplicate records to see which | |
408 | * inodes share blocks with this one | |
409 | */ | |
410 | for (q = dup_blk; q; q = q->next_block) { | |
411 | /* | |
412 | * See if this block is used by this inode. | |
413 | * If it isn't, continue. | |
414 | */ | |
415 | for (r = q; r; r = r->next_inode) | |
416 | if (r->ino == p->ino) | |
417 | break; | |
418 | if (!r) | |
419 | continue; | |
420 | if (q->num_bad > 1) | |
421 | file_ok = 0; | |
422 | /* | |
423 | * Add all inodes used by this block to the | |
424 | * shared[] --- which is a unique list, so | |
425 | * if an inode is already in shared[], don't | |
426 | * add it again. | |
427 | */ | |
428 | for (r = q; r; r = r->next_inode) { | |
429 | if (r->ino == p->ino) | |
430 | continue; | |
431 | for (i = 0; i < shared_len; i++) | |
432 | if (shared[i] == r->ino) | |
433 | break; | |
434 | if (i == shared_len) { | |
435 | shared[shared_len++] = r->ino; | |
436 | } | |
437 | } | |
438 | } | |
439 | time_str = ctime(&p->mtime); | |
440 | time_str[24] = 0; | |
f3db3566 | 441 | printf("File %s (inode #%lu, mod time %s) \n", |
3839e657 TT |
442 | p->pathname, p->ino, time_str); |
443 | printf(" has %d duplicate blocks, shared with %d file%s:\n", | |
444 | p->num_dupblocks, shared_len, | |
445 | (shared_len>1) ? "s" : ""); | |
446 | for (i = 0; i < shared_len; i++) { | |
447 | for (s = dup_ino; s; s = s->next) | |
448 | if (s->ino == shared[i]) | |
449 | break; | |
450 | if (!s) | |
451 | continue; | |
452 | time_str = ctime(&s->mtime); | |
453 | time_str[24] = 0; | |
f3db3566 | 454 | printf("\t%s (inode #%lu, mod time %s)\n", |
3839e657 TT |
455 | s->pathname, s->ino, time_str); |
456 | } | |
457 | if (file_ok) { | |
458 | printf("Duplicated blocks already reassigned or cloned.\n\n"); | |
459 | continue; | |
460 | } | |
461 | ||
462 | if (ask("Clone duplicate/bad blocks", 1)) { | |
463 | retval = clone_file(fs, p, block_buf); | |
464 | if (retval) | |
465 | printf("Couldn't clone file: %s\n", | |
466 | error_message(retval)); | |
467 | else { | |
468 | printf("\n"); | |
469 | continue; | |
470 | } | |
471 | } | |
472 | if (ask("Delete file", 1)) | |
473 | delete_file(fs, p, block_buf); | |
474 | else | |
475 | ext2fs_unmark_valid(fs); | |
476 | printf("\n"); | |
477 | } | |
50e1e10f | 478 | free(shared); |
3839e657 TT |
479 | } |
480 | ||
481 | static int delete_file_block(ext2_filsys fs, | |
482 | blk_t *block_nr, | |
483 | int blockcnt, | |
484 | void *private) | |
485 | { | |
486 | struct dup_block *p; | |
487 | ||
488 | if (!*block_nr) | |
489 | return 0; | |
490 | ||
f3db3566 | 491 | if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) { |
3839e657 TT |
492 | for (p = dup_blk; p; p = p->next_block) |
493 | if (p->block == *block_nr) | |
494 | break; | |
495 | if (p) { | |
496 | p->num_bad--; | |
497 | if (p->num_bad == 1) | |
f3db3566 | 498 | ext2fs_unmark_block_bitmap(block_dup_map, |
3839e657 TT |
499 | *block_nr); |
500 | } else | |
501 | com_err("delete_file_block", 0, | |
502 | "internal error; can't find dup_blk for %d\n", | |
503 | *block_nr); | |
504 | } else { | |
f3db3566 TT |
505 | ext2fs_unmark_block_bitmap(block_found_map, *block_nr); |
506 | ext2fs_unmark_block_bitmap(fs->block_map, *block_nr); | |
3839e657 TT |
507 | } |
508 | ||
509 | return 0; | |
510 | } | |
511 | ||
512 | static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf) | |
513 | { | |
514 | errcode_t retval; | |
515 | struct process_block_struct pb; | |
516 | struct ext2_inode inode; | |
517 | ||
518 | pb.ino = dp->ino; | |
519 | pb.dup_blocks = dp->num_dupblocks; | |
520 | ||
521 | retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf, | |
522 | delete_file_block, &pb); | |
523 | if (retval) | |
524 | com_err("delete_file", retval, | |
525 | "while calling ext2fs_block_iterate for inode %d", | |
526 | dp->ino); | |
f3db3566 TT |
527 | ext2fs_unmark_inode_bitmap(inode_used_map, dp->ino); |
528 | ext2fs_unmark_inode_bitmap(inode_dir_map, dp->ino); | |
3839e657 | 529 | if (inode_bad_map) |
f3db3566 TT |
530 | ext2fs_unmark_inode_bitmap(inode_bad_map, dp->ino); |
531 | ext2fs_unmark_inode_bitmap(fs->inode_map, dp->ino); | |
3839e657 TT |
532 | ext2fs_mark_ib_dirty(fs); |
533 | ext2fs_mark_bb_dirty(fs); | |
f3db3566 | 534 | e2fsck_read_inode(fs, dp->ino, &inode, "delete_file"); |
3839e657 TT |
535 | inode.i_links_count = 0; |
536 | inode.i_dtime = time(0); | |
f3db3566 | 537 | e2fsck_write_inode(fs, dp->ino, &inode, "delete_file"); |
3839e657 TT |
538 | } |
539 | ||
540 | struct clone_struct { | |
541 | errcode_t errcode; | |
542 | char *buf; | |
543 | }; | |
544 | ||
545 | static int clone_file_block(ext2_filsys fs, | |
546 | blk_t *block_nr, | |
547 | int blockcnt, | |
548 | void *private) | |
549 | { | |
550 | struct dup_block *p; | |
551 | blk_t new_block; | |
552 | errcode_t retval; | |
553 | struct clone_struct *cs = (struct clone_struct *) private; | |
554 | ||
555 | if (!*block_nr) | |
556 | return 0; | |
557 | ||
f3db3566 | 558 | if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) { |
3839e657 TT |
559 | for (p = dup_blk; p; p = p->next_block) |
560 | if (p->block == *block_nr) | |
561 | break; | |
562 | if (p) { | |
563 | retval = ext2fs_new_block(fs, 0, block_found_map, | |
564 | &new_block); | |
565 | if (retval) { | |
566 | cs->errcode = retval; | |
567 | return BLOCK_ABORT; | |
568 | } | |
569 | retval = io_channel_read_blk(fs->io, *block_nr, 1, | |
570 | cs->buf); | |
571 | if (retval) { | |
572 | cs->errcode = retval; | |
573 | return BLOCK_ABORT; | |
574 | } | |
575 | retval = io_channel_write_blk(fs->io, new_block, 1, | |
576 | cs->buf); | |
577 | if (retval) { | |
578 | cs->errcode = retval; | |
579 | return BLOCK_ABORT; | |
580 | } | |
581 | p->num_bad--; | |
582 | if (p->num_bad == 1) | |
f3db3566 | 583 | ext2fs_unmark_block_bitmap(block_dup_map, |
3839e657 TT |
584 | *block_nr); |
585 | *block_nr = new_block; | |
f3db3566 | 586 | ext2fs_mark_block_bitmap(block_found_map, |
3839e657 | 587 | new_block); |
f3db3566 | 588 | ext2fs_mark_block_bitmap(fs->block_map, new_block); |
3839e657 TT |
589 | return BLOCK_CHANGED; |
590 | } else | |
591 | com_err("clone_file_block", 0, | |
592 | "internal error; can't find dup_blk for %d\n", | |
593 | *block_nr); | |
594 | } | |
595 | return 0; | |
596 | } | |
597 | ||
598 | static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf) | |
599 | { | |
600 | errcode_t retval; | |
601 | struct clone_struct cs; | |
602 | ||
603 | cs.errcode = 0; | |
604 | cs.buf = malloc(fs->blocksize); | |
605 | if (!cs.buf) | |
606 | return ENOMEM; | |
607 | ||
608 | retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf, | |
609 | clone_file_block, &cs); | |
610 | ext2fs_mark_bb_dirty(fs); | |
611 | free(cs.buf); | |
612 | if (retval) { | |
613 | com_err("clone_file", retval, | |
614 | "while calling ext2fs_block_iterate for inode %d", | |
615 | dp->ino); | |
616 | return retval; | |
617 | } | |
618 | if (cs.errcode) { | |
619 | com_err("clone_file", retval, | |
620 | "returned from clone_file_block"); | |
621 | return retval; | |
622 | } | |
623 | return 0; | |
624 | } | |
625 | ||
626 | ||
627 | ||
628 | ||
629 |