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