File: | src/sbin/fsck_ext2fs/dir.c |
Warning: | line 427, column 3 Value stored to 'dp' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: dir.c,v 1.20 2015/01/16 06:39:57 deraadt Exp $ */ |
2 | /* $NetBSD: dir.c,v 1.5 2000/01/28 16:01:46 bouyer Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 1997 Manuel Bouyer. |
6 | * Copyright (c) 1980, 1986, 1993 |
7 | * The Regents of the University of California. All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. Neither the name of the University nor the names of its contributors |
18 | * may be used to endorse or promote products derived from this software |
19 | * without specific prior written permission. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | * SUCH DAMAGE. |
32 | */ |
33 | |
34 | #include <sys/param.h> /* DEV_BSIZE roundup */ |
35 | #include <sys/time.h> |
36 | #include <ufs/ufs/dir.h> |
37 | #include <ufs/ext2fs/ext2fs_dinode.h> |
38 | #include <ufs/ext2fs/ext2fs_dir.h> |
39 | #include <ufs/ext2fs/ext2fs.h> |
40 | |
41 | #include <ufs/ufs/dinode.h> /* for IFMT & friends */ |
42 | |
43 | #include <stdio.h> |
44 | #include <stdlib.h> |
45 | #include <string.h> |
46 | #include <limits.h> |
47 | |
48 | #include "fsck.h" |
49 | #include "fsutil.h" |
50 | #include "extern.h" |
51 | |
52 | char *lfname = "lost+found"; |
53 | int lfmode = 01777; |
54 | struct ext2fs_dirtemplate emptydir = { 0, DIRBLKSIZ }; |
55 | struct ext2fs_dirtemplate dirhead = { |
56 | 0, 12, 1, EXT2_FT_DIR2, ".", |
57 | 0, DIRBLKSIZ - 12, 2, EXT2_FT_DIR2, ".." |
58 | }; |
59 | #undef DIRBLKSIZ |
60 | |
61 | static int expanddir(struct ext2fs_dinode *, char *); |
62 | static void freedir(ino_t, ino_t); |
63 | static struct ext2fs_direct *fsck_readdir(struct inodesc *); |
64 | static struct bufarea *getdirblk(daddr32_t, long); |
65 | static int lftempname(char *, ino_t); |
66 | static int mkentry(struct inodesc *); |
67 | static int chgino(struct inodesc *); |
68 | |
69 | /* |
70 | * Propagate connected state through the tree. |
71 | */ |
72 | void |
73 | propagate(void) |
74 | { |
75 | struct inoinfo **inpp, *inp, *pinp; |
76 | struct inoinfo **inpend; |
77 | |
78 | /* |
79 | * Create a list of children for each directory. |
80 | */ |
81 | inpend = &inpsort[inplast]; |
82 | for (inpp = inpsort; inpp < inpend; inpp++) { |
83 | inp = *inpp; |
84 | if (inp->i_parent == 0 || |
85 | inp->i_number == EXT2_ROOTINO((ufsino_t)2)) |
86 | continue; |
87 | pinp = getinoinfo(inp->i_parent); |
88 | inp->i_parentp = pinp; |
89 | inp->i_sibling = pinp->i_child; |
90 | pinp->i_child = inp; |
91 | } |
92 | inp = getinoinfo(EXT2_ROOTINO((ufsino_t)2)); |
93 | while (inp) { |
94 | statemap[inp->i_number] = DFOUND04; |
95 | if (inp->i_child && |
96 | statemap[inp->i_child->i_number] == DSTATE03) |
97 | inp = inp->i_child; |
98 | else if (inp->i_sibling) |
99 | inp = inp->i_sibling; |
100 | else |
101 | inp = inp->i_parentp; |
102 | } |
103 | } |
104 | |
105 | /* |
106 | * Scan each entry in a directory block. |
107 | */ |
108 | int |
109 | dirscan(struct inodesc *idesc) |
110 | { |
111 | struct ext2fs_direct *dp; |
112 | struct bufarea *bp; |
113 | int dsize, n; |
114 | long blksiz; |
115 | char *dbuf = NULL((void *)0); |
116 | |
117 | if ((dbuf = malloc(sblock.e2fs_bsize)) == NULL((void *)0)) { |
118 | fprintf(stderr(&__sF[2]), "out of memory"); |
119 | exit(8); |
120 | } |
121 | |
122 | if (idesc->id_type != DATA1) |
123 | errexit("wrong type to dirscan %d\n", idesc->id_type); |
124 | if (idesc->id_entryno == 0 && |
125 | (idesc->id_filesize & (sblock.e2fs_bsize - 1)) != 0) |
126 | idesc->id_filesize = roundup(idesc->id_filesize, sblock.e2fs_bsize)((((idesc->id_filesize)+((sblock.e2fs_bsize)-1))/(sblock.e2fs_bsize ))*(sblock.e2fs_bsize)); |
127 | blksiz = idesc->id_numfrags * sblock.e2fs_bsize; |
128 | if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { |
129 | idesc->id_filesize -= blksiz; |
130 | free(dbuf); |
131 | return (SKIP0x02); |
132 | } |
133 | idesc->id_loc = 0; |
134 | for (dp = fsck_readdir(idesc); dp != NULL((void *)0); dp = fsck_readdir(idesc)) { |
135 | dsize = letoh16(dp->e2d_reclen)((__uint16_t)(dp->e2d_reclen)); |
136 | memcpy(dbuf, dp, (size_t)dsize); |
137 | idesc->id_dirp = (struct ext2fs_direct *)dbuf; |
138 | if ((n = (*idesc->id_func)(idesc)) & ALTERED0x08) { |
139 | bp = getdirblk(idesc->id_blkno, blksiz); |
140 | memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, |
141 | (size_t)dsize); |
142 | dirty(bp)(bp)->b_dirty = 1; |
143 | sbdirty()copyback_sb(&sblk); sblk.b_dirty = 1; |
144 | } |
145 | if (n & STOP0x01) { |
146 | free(dbuf); |
147 | return (n); |
148 | } |
149 | } |
150 | free(dbuf); |
151 | return (idesc->id_filesize > 0 ? KEEPON0x04 : STOP0x01); |
152 | } |
153 | |
154 | /* |
155 | * get next entry in a directory. |
156 | */ |
157 | static struct ext2fs_direct * |
158 | fsck_readdir(struct inodesc *idesc) |
159 | { |
160 | struct ext2fs_direct *dp, *ndp; |
161 | struct bufarea *bp; |
162 | long size, blksiz, fix, dploc; |
163 | |
164 | blksiz = idesc->id_numfrags * sblock.e2fs_bsize; |
165 | bp = getdirblk(idesc->id_blkno, blksiz); |
166 | if (idesc->id_loc % sblock.e2fs_bsize == 0 && idesc->id_filesize > 0 && |
167 | idesc->id_loc < blksiz) { |
168 | dp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc); |
169 | if (dircheck(idesc, dp)) |
170 | goto dpok; |
171 | if (idesc->id_fix == IGNORE) |
172 | return (0); |
173 | fix = dofix(idesc, "DIRECTORY CORRUPTED"); |
174 | bp = getdirblk(idesc->id_blkno, blksiz); |
175 | dp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc); |
176 | dp->e2d_reclen = htole16(sblock.e2fs_bsize)((__uint16_t)(sblock.e2fs_bsize)); |
177 | dp->e2d_ino = 0; |
178 | dp->e2d_namlen = 0; |
179 | dp->e2d_type = 0; |
180 | dp->e2d_name[0] = '\0'; |
181 | if (fix) |
182 | dirty(bp)(bp)->b_dirty = 1; |
183 | idesc->id_loc += sblock.e2fs_bsize; |
184 | idesc->id_filesize -= sblock.e2fs_bsize; |
185 | return (dp); |
186 | } |
187 | dpok: |
188 | if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) |
189 | return NULL((void *)0); |
190 | dploc = idesc->id_loc; |
191 | dp = (struct ext2fs_direct *)(bp->b_un.b_buf + dploc); |
192 | idesc->id_loc += letoh16(dp->e2d_reclen)((__uint16_t)(dp->e2d_reclen)); |
193 | idesc->id_filesize -= letoh16(dp->e2d_reclen)((__uint16_t)(dp->e2d_reclen)); |
194 | if ((idesc->id_loc % sblock.e2fs_bsize) == 0) |
195 | return (dp); |
196 | ndp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc); |
197 | if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && |
198 | dircheck(idesc, ndp) == 0) { |
199 | size = sblock.e2fs_bsize - (idesc->id_loc % sblock.e2fs_bsize); |
200 | idesc->id_loc += size; |
201 | idesc->id_filesize -= size; |
202 | if (idesc->id_fix == IGNORE) |
203 | return (0); |
204 | fix = dofix(idesc, "DIRECTORY CORRUPTED"); |
205 | bp = getdirblk(idesc->id_blkno, blksiz); |
206 | dp = (struct ext2fs_direct *)(bp->b_un.b_buf + dploc); |
207 | dp->e2d_reclen = htole16(letoh16(dp->e2d_reclen) + size)((__uint16_t)(((__uint16_t)(dp->e2d_reclen)) + size)); |
208 | if (fix) |
209 | dirty(bp)(bp)->b_dirty = 1; |
210 | } |
211 | return (dp); |
212 | } |
213 | |
214 | /* |
215 | * Verify that a directory entry is valid. |
216 | * This is a superset of the checks made in the kernel. |
217 | */ |
218 | int |
219 | dircheck(struct inodesc *idesc, struct ext2fs_direct *dp) |
220 | { |
221 | int size; |
222 | char *cp; |
223 | int spaceleft; |
224 | u_int16_t reclen = letoh16(dp->e2d_reclen)((__uint16_t)(dp->e2d_reclen)); |
225 | |
226 | spaceleft = sblock.e2fs_bsize - (idesc->id_loc % sblock.e2fs_bsize); |
227 | if (letoh32(dp->e2d_ino)((__uint32_t)(dp->e2d_ino)) > maxino || |
228 | reclen == 0 || |
229 | reclen > spaceleft || |
230 | (reclen & 0x3) != 0) |
231 | return (0); |
232 | if (dp->e2d_ino == 0) |
233 | return (1); |
234 | if (sblock.e2fs.e2fs_rev < E2FS_REV11 || |
235 | (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002) == 0) |
236 | if (dp->e2d_type != 0) |
237 | return (1); |
238 | size = EXT2FS_DIRSIZ(dp->e2d_namlen)(( 8 + dp->e2d_namlen + 3) &~ 3); |
239 | if (reclen < size || |
240 | idesc->id_filesize < size || |
241 | dp->e2d_namlen > EXT2FS_MAXNAMLEN255) |
242 | return (0); |
243 | for (cp = dp->e2d_name, size = 0; size < dp->e2d_namlen; size++) |
244 | if (*cp == '\0' || (*cp++ == '/')) |
245 | return (0); |
246 | return (1); |
247 | } |
248 | |
249 | void |
250 | direrror(ino_t ino, char *errmesg) |
251 | { |
252 | |
253 | fileerror(ino, ino, errmesg); |
254 | } |
255 | |
256 | void |
257 | fileerror(ino_t cwd, ino_t ino, char *errmesg) |
258 | { |
259 | struct ext2fs_dinode *dp; |
260 | char pathbuf[PATH_MAX1024 + 1]; |
261 | |
262 | pwarn("%s ", errmesg); |
263 | pinode(ino); |
264 | printf("\n"); |
265 | getpathname(pathbuf, sizeof pathbuf, cwd, ino); |
266 | if ((ino < EXT2_FIRSTINO((ufsino_t)11) && ino != EXT2_ROOTINO((ufsino_t)2)) || ino > maxino) { |
267 | pfatal("NAME=%s\n", pathbuf); |
268 | return; |
269 | } |
270 | dp = ginode(ino); |
271 | if (ftypeok(dp)) |
272 | pfatal("%s=%s\n", |
273 | (letoh16(dp->e2di_mode)((__uint16_t)(dp->e2di_mode)) & IFMT0170000) == IFDIR0040000 ? "DIR" : "FILE", pathbuf); |
274 | else |
275 | pfatal("NAME=%s\n", pathbuf); |
276 | } |
277 | |
278 | void |
279 | adjust(struct inodesc *idesc, short lcnt) |
280 | { |
281 | struct ext2fs_dinode *dp; |
282 | |
283 | dp = ginode(idesc->id_number); |
284 | if (letoh16(dp->e2di_nlink)((__uint16_t)(dp->e2di_nlink)) == lcnt) { |
285 | if (linkup(idesc->id_number, (ino_t)0) == 0) |
286 | clri(idesc, "UNREF", 0); |
287 | } else { |
288 | pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : |
289 | ((letoh16(dp->e2di_mode)((__uint16_t)(dp->e2di_mode)) & IFMT0170000) == IFDIR0040000 ? "DIR" : "FILE")); |
290 | pinode(idesc->id_number); |
291 | printf(" COUNT %d SHOULD BE %d", |
292 | letoh16(dp->e2di_nlink)((__uint16_t)(dp->e2di_nlink)), letoh16(dp->e2di_nlink)((__uint16_t)(dp->e2di_nlink)) - lcnt); |
293 | if (preen) { |
294 | if (lcnt < 0) { |
295 | printf("\n"); |
296 | pfatal("LINK COUNT INCREASING"); |
297 | } |
298 | printf(" (ADJUSTED)\n"); |
299 | } |
300 | if (preen || reply("ADJUST") == 1) { |
301 | dp->e2di_nlink = htole16(letoh16(dp->e2di_nlink) - lcnt)((__uint16_t)(((__uint16_t)(dp->e2di_nlink)) - lcnt)); |
302 | inodirty(); |
303 | } |
304 | } |
305 | } |
306 | |
307 | static int |
308 | mkentry(struct inodesc *idesc) |
309 | { |
310 | struct ext2fs_direct *dirp = idesc->id_dirp; |
311 | struct ext2fs_direct newent; |
312 | int newlen, oldlen; |
313 | |
314 | newent.e2d_type = EXT2_FT_UNKNOWN0; |
315 | newent.e2d_namlen = strlen(idesc->id_name); |
316 | if (sblock.e2fs.e2fs_rev > E2FS_REV00 && |
317 | (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002)) |
318 | newent.e2d_type = inot2ext2dt(typemap[idesc->id_parent]); |
319 | newlen = EXT2FS_DIRSIZ(newent.e2d_namlen)(( 8 + newent.e2d_namlen + 3) &~ 3); |
320 | if (dirp->e2d_ino != 0) |
321 | oldlen = EXT2FS_DIRSIZ(dirp->e2d_namlen)(( 8 + dirp->e2d_namlen + 3) &~ 3); |
322 | else |
323 | oldlen = 0; |
324 | if (letoh16(dirp->e2d_reclen)((__uint16_t)(dirp->e2d_reclen)) - oldlen < newlen) |
325 | return (KEEPON0x04); |
326 | newent.e2d_reclen = htole16(letoh16(dirp->e2d_reclen) - oldlen)((__uint16_t)(((__uint16_t)(dirp->e2d_reclen)) - oldlen)); |
327 | dirp->e2d_reclen = htole16(oldlen)((__uint16_t)(oldlen)); |
328 | dirp = (struct ext2fs_direct *)(((char *)dirp) + oldlen); |
329 | dirp->e2d_ino = htole32(idesc->id_parent)((__uint32_t)(idesc->id_parent)); /* ino to be entered is in id_parent */ |
330 | dirp->e2d_reclen = newent.e2d_reclen; |
331 | dirp->e2d_namlen = newent.e2d_namlen; |
332 | dirp->e2d_type = newent.e2d_type; |
333 | memcpy(dirp->e2d_name, idesc->id_name, (size_t)(dirp->e2d_namlen)); |
334 | return (ALTERED0x08|STOP0x01); |
335 | } |
336 | |
337 | static int |
338 | chgino(struct inodesc *idesc) |
339 | { |
340 | struct ext2fs_direct *dirp = idesc->id_dirp; |
341 | u_int16_t namlen = dirp->e2d_namlen; |
342 | |
343 | if (strlen(idesc->id_name) != namlen || |
344 | strncmp(dirp->e2d_name, idesc->id_name, (int)namlen)) |
345 | return (KEEPON0x04); |
346 | dirp->e2d_ino = htole32(idesc->id_parent)((__uint32_t)(idesc->id_parent)); |
347 | if (sblock.e2fs.e2fs_rev > E2FS_REV00 && |
348 | (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002)) |
349 | dirp->e2d_type = inot2ext2dt(typemap[idesc->id_parent]); |
350 | else |
351 | dirp->e2d_type = 0; |
352 | return (ALTERED0x08|STOP0x01); |
353 | } |
354 | |
355 | int |
356 | linkup(ino_t orphan, ino_t parentdir) |
357 | { |
358 | struct ext2fs_dinode *dp; |
359 | int lostdir; |
360 | ino_t oldlfdir; |
361 | struct inodesc idesc; |
362 | char tempname[BUFSIZ1024]; |
363 | |
364 | memset(&idesc, 0, sizeof(struct inodesc)); |
365 | dp = ginode(orphan); |
366 | lostdir = (letoh16(dp->e2di_mode)((__uint16_t)(dp->e2di_mode)) & IFMT0170000) == IFDIR0040000; |
367 | pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); |
368 | pinode(orphan); |
369 | if (preen && inosize(dp) == 0) |
370 | return (0); |
371 | if (preen) |
372 | printf(" (RECONNECTED)\n"); |
373 | else |
374 | if (reply("RECONNECT") == 0) |
375 | return (0); |
376 | if (lfdir == 0) { |
377 | dp = ginode(EXT2_ROOTINO((ufsino_t)2)); |
378 | idesc.id_name = lfname; |
379 | idesc.id_type = DATA1; |
380 | idesc.id_func = findino; |
381 | idesc.id_number = EXT2_ROOTINO((ufsino_t)2); |
382 | if ((ckinode(dp, &idesc) & FOUND0x10) != 0) { |
383 | lfdir = idesc.id_parent; |
384 | } else { |
385 | pwarn("NO lost+found DIRECTORY"); |
386 | if (preen || reply("CREATE")) { |
387 | lfdir = allocdir(EXT2_ROOTINO((ufsino_t)2), (ino_t)0, lfmode); |
388 | if (lfdir != 0) { |
389 | if (makeentry(EXT2_ROOTINO((ufsino_t)2), lfdir, lfname) != 0) { |
390 | if (preen) |
391 | printf(" (CREATED)\n"); |
392 | } else { |
393 | freedir(lfdir, EXT2_ROOTINO((ufsino_t)2)); |
394 | lfdir = 0; |
395 | if (preen) |
396 | printf("\n"); |
397 | } |
398 | } |
399 | } |
400 | } |
401 | if (lfdir == 0) { |
402 | pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); |
403 | printf("\n\n"); |
404 | return (0); |
405 | } |
406 | } |
407 | dp = ginode(lfdir); |
408 | if ((letoh16(dp->e2di_mode)((__uint16_t)(dp->e2di_mode)) & IFMT0170000) != IFDIR0040000) { |
409 | pfatal("lost+found IS NOT A DIRECTORY"); |
410 | if (reply("REALLOCATE") == 0) |
411 | return (0); |
412 | oldlfdir = lfdir; |
413 | if ((lfdir = allocdir(EXT2_ROOTINO((ufsino_t)2), (ino_t)0, lfmode)) == 0) { |
414 | pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); |
415 | return (0); |
416 | } |
417 | if ((changeino(EXT2_ROOTINO((ufsino_t)2), lfname, lfdir) & ALTERED0x08) == 0) { |
418 | pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); |
419 | return (0); |
420 | } |
421 | inodirty(); |
422 | idesc.id_type = ADDR2; |
423 | idesc.id_func = pass4check; |
424 | idesc.id_number = oldlfdir; |
425 | adjust(&idesc, lncntp[oldlfdir] + 1); |
426 | lncntp[oldlfdir] = 0; |
427 | dp = ginode(lfdir); |
Value stored to 'dp' is never read | |
428 | } |
429 | if (statemap[lfdir] != DFOUND04) { |
430 | pfatal("SORRY. NO lost+found DIRECTORY\n\n"); |
431 | return (0); |
432 | } |
433 | (void)lftempname(tempname, orphan); |
434 | if (makeentry(lfdir, orphan, tempname) == 0) { |
435 | pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); |
436 | printf("\n\n"); |
437 | return (0); |
438 | } |
439 | lncntp[orphan]--; |
440 | if (lostdir) { |
441 | if ((changeino(orphan, "..", lfdir) & ALTERED0x08) == 0 && |
442 | parentdir != (ino_t)-1) |
443 | (void)makeentry(orphan, lfdir, ".."); |
444 | dp = ginode(lfdir); |
445 | dp->e2di_nlink = htole16(letoh16(dp->e2di_nlink) +1)((__uint16_t)(((__uint16_t)(dp->e2di_nlink)) +1)); |
446 | inodirty(); |
447 | lncntp[lfdir]++; |
448 | pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan); |
449 | if (parentdir != (ino_t)-1) |
450 | printf("PARENT WAS I=%llu\n", |
451 | (unsigned long long)parentdir); |
452 | if (preen == 0) |
453 | printf("\n"); |
454 | } |
455 | return (1); |
456 | } |
457 | |
458 | /* |
459 | * fix an entry in a directory. |
460 | */ |
461 | int |
462 | changeino(ino_t dir, char *name, ino_t newnum) |
463 | { |
464 | struct inodesc idesc; |
465 | |
466 | memset(&idesc, 0, sizeof(struct inodesc)); |
467 | idesc.id_type = DATA1; |
468 | idesc.id_func = chgino; |
469 | idesc.id_number = dir; |
470 | idesc.id_fix = DONTKNOW; |
471 | idesc.id_name = name; |
472 | idesc.id_parent = newnum; /* new value for name */ |
473 | return (ckinode(ginode(dir), &idesc)); |
474 | } |
475 | |
476 | /* |
477 | * make an entry in a directory |
478 | */ |
479 | int |
480 | makeentry(ino_t parent, ino_t ino, char *name) |
481 | { |
482 | struct ext2fs_dinode *dp; |
483 | struct inodesc idesc; |
484 | char pathbuf[PATH_MAX1024 + 1]; |
485 | |
486 | if ((parent < EXT2_FIRSTINO((ufsino_t)11) && parent != EXT2_ROOTINO((ufsino_t)2)) |
487 | || parent >= maxino || |
488 | (ino < EXT2_FIRSTINO((ufsino_t)11) && ino < EXT2_ROOTINO((ufsino_t)2)) || ino >= maxino) |
489 | return (0); |
490 | memset(&idesc, 0, sizeof(struct inodesc)); |
491 | idesc.id_type = DATA1; |
492 | idesc.id_func = mkentry; |
493 | idesc.id_number = parent; |
494 | idesc.id_parent = ino; /* this is the inode to enter */ |
495 | idesc.id_fix = DONTKNOW; |
496 | idesc.id_name = name; |
497 | dp = ginode(parent); |
498 | if (inosize(dp) % sblock.e2fs_bsize) { |
499 | inossize(dp, roundup(inosize(dp), sblock.e2fs_bsize)((((inosize(dp))+((sblock.e2fs_bsize)-1))/(sblock.e2fs_bsize) )*(sblock.e2fs_bsize))); |
500 | inodirty(); |
501 | } |
502 | if ((ckinode(dp, &idesc) & ALTERED0x08) != 0) |
503 | return (1); |
504 | getpathname(pathbuf, sizeof pathbuf, parent, parent); |
505 | dp = ginode(parent); |
506 | if (expanddir(dp, pathbuf) == 0) |
507 | return (0); |
508 | return (ckinode(dp, &idesc) & ALTERED0x08); |
509 | } |
510 | |
511 | /* |
512 | * Attempt to expand the size of a directory |
513 | */ |
514 | static int |
515 | expanddir(struct ext2fs_dinode *dp, char *name) |
516 | { |
517 | daddr32_t lastbn, newblk; |
518 | struct bufarea *bp; |
519 | char *firstblk; |
520 | |
521 | lastbn = lblkno(&sblock, inosize(dp))((inosize(dp)) >> (&sblock)->e2fs_bshift); |
522 | if (lastbn >= NDADDR12 - 1 || letoh32(dp->e2di_blocks[lastbn])((__uint32_t)(dp->e2di_blocks[lastbn])) == 0 || |
523 | inosize(dp) == 0) |
524 | return (0); |
525 | if ((newblk = allocblk()) == 0) |
526 | return (0); |
527 | dp->e2di_blocks[lastbn + 1] = dp->e2di_blocks[lastbn]; |
528 | dp->e2di_blocks[lastbn] = htole32(newblk)((__uint32_t)(newblk)); |
529 | inossize(dp, inosize(dp) + sblock.e2fs_bsize); |
530 | dp->e2di_nblock = htole32(letoh32(dp->e2di_nblock) + 1)((__uint32_t)(((__uint32_t)(dp->e2di_nblock)) + 1)); |
531 | bp = getdirblk(letoh32(dp->e2di_blocks[lastbn + 1])((__uint32_t)(dp->e2di_blocks[lastbn + 1])), |
532 | sblock.e2fs_bsize); |
533 | if (bp->b_errs) |
534 | goto bad; |
535 | if ((firstblk = malloc(sblock.e2fs_bsize)) == NULL((void *)0)) { |
536 | fprintf(stderr(&__sF[2]), "out of memory\n"); |
537 | exit(8); |
538 | } |
539 | memcpy(firstblk, bp->b_un.b_buf, sblock.e2fs_bsize); |
540 | bp = getdirblk(newblk, sblock.e2fs_bsize); |
541 | if (bp->b_errs) { |
542 | free(firstblk); |
543 | goto bad; |
544 | } |
545 | memcpy(bp->b_un.b_buf, firstblk, sblock.e2fs_bsize); |
546 | free(firstblk); |
547 | dirty(bp)(bp)->b_dirty = 1; |
548 | bp = getdirblk(letoh32(dp->e2di_blocks[lastbn + 1])((__uint32_t)(dp->e2di_blocks[lastbn + 1])), |
549 | sblock.e2fs_bsize); |
550 | if (bp->b_errs) |
551 | goto bad; |
552 | emptydir.dot_reclen = htole16(sblock.e2fs_bsize)((__uint16_t)(sblock.e2fs_bsize)); |
553 | memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir); |
554 | pwarn("NO SPACE LEFT IN %s", name); |
555 | if (preen) |
556 | printf(" (EXPANDED)\n"); |
557 | else if (reply("EXPAND") == 0) |
558 | goto bad; |
559 | dirty(bp)(bp)->b_dirty = 1; |
560 | inodirty(); |
561 | return (1); |
562 | bad: |
563 | dp->e2di_blocks[lastbn] = dp->e2di_blocks[lastbn + 1]; |
564 | dp->e2di_blocks[lastbn + 1] = 0; |
565 | dp->e2di_size = htole32(letoh32(dp->e2di_size) - sblock.e2fs_bsize)((__uint32_t)(((__uint32_t)(dp->e2di_size)) - sblock.e2fs_bsize )); |
566 | inossize(dp, inosize(dp) - sblock.e2fs_bsize); |
567 | dp->e2di_nblock = htole32(letoh32(dp->e2di_nblock) - 1)((__uint32_t)(((__uint32_t)(dp->e2di_nblock)) - 1)); |
568 | freeblk(newblk); |
569 | return (0); |
570 | } |
571 | |
572 | /* |
573 | * allocate a new directory |
574 | */ |
575 | int |
576 | allocdir(ino_t parent, ino_t request, int mode) |
577 | { |
578 | ino_t ino; |
579 | struct ext2fs_dinode *dp; |
580 | struct bufarea *bp; |
581 | struct ext2fs_dirtemplate *dirp; |
582 | |
583 | ino = allocino(request, IFDIR0040000|mode); |
584 | dirhead.dot_reclen = htole16(12)((__uint16_t)(12)); /* XXX */ |
585 | dirhead.dotdot_reclen = htole16(sblock.e2fs_bsize - 12)((__uint16_t)(sblock.e2fs_bsize - 12)); /* XXX */ |
586 | dirhead.dot_namlen = 1; |
587 | if (sblock.e2fs.e2fs_rev > E2FS_REV00 && |
588 | (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002)) |
589 | dirhead.dot_type = EXT2_FT_DIR2; |
590 | else |
591 | dirhead.dot_type = 0; |
592 | dirhead.dotdot_namlen = 2; |
593 | if (sblock.e2fs.e2fs_rev > E2FS_REV00 && |
594 | (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002)) |
595 | dirhead.dotdot_type = EXT2_FT_DIR2; |
596 | else |
597 | dirhead.dotdot_type = 0; |
598 | dirp = &dirhead; |
599 | dirp->dot_ino = htole32(ino)((__uint32_t)(ino)); |
600 | dirp->dotdot_ino = htole32(parent)((__uint32_t)(parent)); |
601 | dp = ginode(ino); |
602 | bp = getdirblk(letoh32(dp->e2di_blocks[0])((__uint32_t)(dp->e2di_blocks[0])), sblock.e2fs_bsize); |
603 | if (bp->b_errs) { |
604 | freeino(ino); |
605 | return (0); |
606 | } |
607 | memcpy(bp->b_un.b_buf, dirp, sizeof(struct ext2fs_dirtemplate)); |
608 | dirty(bp)(bp)->b_dirty = 1; |
609 | dp->e2di_nlink = htole16(2)((__uint16_t)(2)); |
610 | inodirty(); |
611 | if (ino == EXT2_ROOTINO((ufsino_t)2)) { |
612 | lncntp[ino] = letoh16(dp->e2di_nlink)((__uint16_t)(dp->e2di_nlink)); |
613 | cacheino(dp, ino); |
614 | return(ino); |
615 | } |
616 | if (statemap[parent] != DSTATE03 && statemap[parent] != DFOUND04) { |
617 | freeino(ino); |
618 | return (0); |
619 | } |
620 | cacheino(dp, ino); |
621 | statemap[ino] = statemap[parent]; |
622 | if (statemap[ino] == DSTATE03) { |
623 | lncntp[ino] = letoh16(dp->e2di_nlink)((__uint16_t)(dp->e2di_nlink)); |
624 | lncntp[parent]++; |
625 | } |
626 | dp = ginode(parent); |
627 | dp->e2di_nlink = htole16(letoh16(dp->e2di_nlink) + 1)((__uint16_t)(((__uint16_t)(dp->e2di_nlink)) + 1)); |
628 | inodirty(); |
629 | return (ino); |
630 | } |
631 | |
632 | /* |
633 | * free a directory inode |
634 | */ |
635 | static void |
636 | freedir(ino_t ino, ino_t parent) |
637 | { |
638 | struct ext2fs_dinode *dp; |
639 | |
640 | if (ino != parent) { |
641 | dp = ginode(parent); |
642 | dp->e2di_nlink = htole16(letoh16(dp->e2di_nlink) - 1)((__uint16_t)(((__uint16_t)(dp->e2di_nlink)) - 1)); |
643 | inodirty(); |
644 | } |
645 | freeino(ino); |
646 | } |
647 | |
648 | /* |
649 | * generate a temporary name for the lost+found directory. |
650 | */ |
651 | static int |
652 | lftempname(char *bufp, ino_t ino) |
653 | { |
654 | ino_t in; |
655 | char *cp; |
656 | int namlen; |
657 | |
658 | cp = bufp + 2; |
659 | for (in = maxino; in > 0; in /= 10) |
660 | cp++; |
661 | *--cp = 0; |
662 | namlen = cp - bufp; |
663 | in = ino; |
664 | while (cp > bufp) { |
665 | *--cp = (in % 10) + '0'; |
666 | in /= 10; |
667 | } |
668 | *cp = '#'; |
669 | return (namlen); |
670 | } |
671 | |
672 | /* |
673 | * Get a directory block. |
674 | * Insure that it is held until another is requested. |
675 | */ |
676 | static struct bufarea * |
677 | getdirblk(daddr32_t blkno, long size) |
678 | { |
679 | |
680 | if (pdirbp != 0) |
681 | pdirbp->b_flags &= ~B_INUSE1; |
682 | pdirbp = getdatablk(blkno, size); |
683 | return (pdirbp); |
684 | } |