de56cf8a7b5dc12774eb9e9a9ae7bc3b6d9c967b
[openafs.git] / src / vfsck / dir.c
1 /*
2  * Copyright (c) 1980, 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #include <roken.h>
22
23 #include <ctype.h>
24
25 #define VICE                    /* allow us to put our changes in at will */
26
27 #ifdef  AFS_OSF_ENV
28 #include <sys/vnode.h>
29 #include <sys/mount.h>
30 #include <ufs/inode.h>
31 #include <ufs/fs.h>
32 #define _BSD
33 #define _KERNEL
34 #include <ufs/dir.h>
35 #undef  _KERNEL
36 #undef  _BSD
37 #else /* AFS_OSF_ENV */
38 #ifdef AFS_VFSINCL_ENV
39 #define VFS
40 #include <sys/vnode.h>
41 #ifdef    AFS_SUN5_ENV
42 #include <sys/fs/ufs_inode.h>
43 #include <sys/fs/ufs_fs.h>
44 #define _KERNEL
45 #include <sys/fs/ufs_fsdir.h>
46 #undef _KERNEL
47 #else
48 #include <ufs/inode.h>
49 #include <ufs/fs.h>
50 #define KERNEL
51 #include <ufs/fsdir.h>
52 #undef KERNEL
53 #endif
54
55 #else /* AFS_VFSINCL_ENV */
56 #include <sys/inode.h>
57 #ifdef  AFS_HPUX_ENV
58 #define LONGFILENAMES   1
59 #include <sys/sysmacros.h>
60 #include <sys/ino.h>
61 #define DIRSIZ_MACRO
62 #ifdef HAVE_USR_OLD_USR_INCLUDE_NDIR_H
63 #include </usr/old/usr/include/ndir.h>
64 #else
65 #include <ndir.h>
66 #endif
67 #else
68 #define KERNEL
69 #include <sys/dir.h>
70 #undef KERNEL
71 #endif
72 #include <sys/fs.h>
73 #endif /* AFS_VFSINCL_ENV */
74 #endif /* AFS_OSF_ENV */
75
76 #ifdef AFS_SUN_ENV
77 #ifdef  AFS_SUN5_ENV
78 #include <sys/mnttab.h>
79 #include <sys/mntent.h>
80 #else
81 #include <mntent.h>
82 #endif
83 #endif
84 #include "fsck.h"
85
86
87 #ifdef  AFS_HPUX_ENV
88 struct dirtemplate_lfn {
89     afs_uint32 dot_ino;
90     short dot_reclen;
91     short dot_namlen;
92     char dot_name[4];           /* must be multiple of 4 */
93     afs_uint32 dotdot_ino;
94     short dotdot_reclen;
95     short dotdot_namlen;
96     char dotdot_name[4];        /* ditto */
97 };
98 #define dirtemplate dirtemplate_lfn
99 #endif
100
101 #define MINDIRSIZE      (sizeof (struct dirtemplate))
102
103 char *endpathname = &pathname[BUFSIZ - 2];
104 char *lfname = "lost+found";
105 int lfmode = 01777;
106 struct dirtemplate emptydir = { 0, DIRBLKSIZ };
107 struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." };
108
109 struct direct *fsck_readdir();
110 struct bufarea *getdirblk();
111
112 descend(parentino, inumber)
113      struct inodesc *parentino;
114      ino_t inumber;
115 {
116     struct dinode *dp;
117     struct inodesc curino;
118
119     memset(&curino, 0, sizeof(struct inodesc));
120     if (statemap[inumber] != DSTATE)
121         errexit("BAD INODE %d TO DESCEND", statemap[inumber]);
122 #if defined(ACLS) && defined(AFS_HPUX_ENV)
123     /*
124      * keep any continuation inode information
125      */
126     if (statemap[inumber] & HASCINODE)
127         statemap[inumber] = HASCINODE | DFOUND;
128     else
129         statemap[inumber] = DFOUND;
130 #else /* no ACLS */
131     statemap[inumber] = DFOUND;
132 #endif /* ACLS */
133     dp = ginode(inumber);
134     if (dp->di_size == 0) {
135         direrror(inumber, "ZERO LENGTH DIRECTORY");
136         if (reply("REMOVE") == 1)
137 #if defined(ACLS) && defined(AFS_HPUX_ENV)
138             /*
139              * keep any continuation inode information
140              */
141             if (statemap[inumber] & HASCINODE)
142                 statemap[inumber] = HASCINODE | DCLEAR;
143             else
144                 statemap[inumber] = DCLEAR;
145 #else /* no ACLS */
146             statemap[inumber] = DCLEAR;
147 #endif /* ACLS */
148         return;
149     }
150     if (dp->di_size < MINDIRSIZE) {
151         direrror(inumber, "DIRECTORY TOO SHORT");
152         dp->di_size = MINDIRSIZE;
153         if (reply("FIX") == 1)
154             inodirty();
155     }
156 #if     !defined(AFS_HPUX_ENV)
157     /* For remaining 4.2 systems.  We shouldn't convert
158      * dir size, since Unix 4.2 kernels won't maintain this, and we'll have a
159      * lot of spurious directory conversions scaring people */
160     if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) {
161         pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d", pathname,
162               dp->di_size, DIRBLKSIZ);
163         dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
164         if (preen)
165             printf(" (ADJUSTED)\n");
166         if (preen || reply("ADJUST") == 1)
167             inodirty();
168     }
169 #endif
170     curino.id_type = DATA;
171     curino.id_func = parentino->id_func;
172     curino.id_parent = parentino->id_number;
173     curino.id_number = inumber;
174     (void)ckinode(dp, &curino);
175     if (curino.id_entryno < 2) {
176         direrror(inumber, "NULL DIRECTORY");
177         if (reply("REMOVE") == 1)
178             statemap[inumber] = DCLEAR;
179     }
180 }
181
182 dirscan(idesc)
183      struct inodesc *idesc;
184 {
185     struct direct *dp;
186     struct bufarea *bp;
187     int dsize, n;
188     long blksiz;
189     char dbuf[DIRBLKSIZ];
190
191     if (idesc->id_type != DATA)
192         errexit("wrong type to dirscan %d\n", idesc->id_type);
193     if (idesc->id_entryno == 0 && (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
194         idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
195     blksiz = idesc->id_numfrags * sblock.fs_fsize;
196
197     if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
198         idesc->id_filesize -= blksiz;
199         return (SKIP);
200     }
201     idesc->id_loc = 0;
202     for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
203         dsize = dp->d_reclen;
204         memcpy(dbuf, (char *)dp, dsize);
205         idesc->id_dirp = (struct direct *)dbuf;
206         if ((n = (*idesc->id_func) (idesc)) & ALTERED) {
207             bp = getdirblk(idesc->id_blkno, blksiz);
208             memcpy((char *)dp, dbuf, dsize);
209             dirty(bp);
210             sbdirty();
211         }
212         if (n & STOP)
213             return (n);
214     }
215     return (idesc->id_filesize > 0 ? KEEPON : STOP);
216 }
217
218 /*
219  * get next entry in a directory.
220  */
221 struct direct *
222 fsck_readdir(idesc)
223      struct inodesc *idesc;
224 {
225     struct direct *dp, *ndp;
226     struct bufarea *bp;
227     long size, blksiz;
228
229     blksiz = idesc->id_numfrags * sblock.fs_fsize;
230     bp = getdirblk(idesc->id_blkno, blksiz);
231     if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0
232         && idesc->id_loc < blksiz) {
233         dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
234         if (dircheck(idesc, dp)) {
235             goto dpok;
236         }
237         idesc->id_loc += DIRBLKSIZ;
238         idesc->id_filesize -= DIRBLKSIZ;
239         dp->d_reclen = DIRBLKSIZ;
240         dp->d_ino = 0;
241         dp->d_namlen = 0;
242         dp->d_name[0] = '\0';
243         if (dofix(idesc, "DIRECTORY CORRUPTED"))
244             dirty(bp);
245         return (dp);
246     }
247   dpok:
248     if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
249         return NULL;
250     dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
251     idesc->id_loc += dp->d_reclen;
252     idesc->id_filesize -= dp->d_reclen;
253     if ((idesc->id_loc % DIRBLKSIZ) == 0)
254         return (dp);
255     ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
256     if (idesc->id_loc < blksiz && idesc->id_filesize > 0
257         && dircheck(idesc, ndp) == 0) {
258         size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
259         dp->d_reclen += size;
260         idesc->id_loc += size;
261         idesc->id_filesize -= size;
262         if (dofix(idesc, "DIRECTORY CORRUPTED"))
263             dirty(bp);
264     }
265     return (dp);
266 }
267
268 /*
269  * Verify that a directory entry is valid.
270  * This is a superset of the checks made in the kernel.
271  */
272 dircheck(idesc, dp)
273      struct inodesc *idesc;
274      struct direct *dp;
275 {
276     int size;
277     char *cp;
278     int spaceleft;
279
280     size = DIRSIZ(dp);
281     spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
282     if (dp->d_ino < maxino && dp->d_reclen != 0 && dp->d_reclen <= spaceleft
283         && (dp->d_reclen & 0x3) == 0 && dp->d_reclen >= size
284         && idesc->id_filesize >= size && dp->d_namlen <= MAXNAMLEN) {
285         if (dp->d_ino == 0)
286             return (1);
287         for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
288 #if     defined(Next) || defined(AFS_SUN5_ENV)
289             if (*cp == 0)
290                 return (0);
291             else
292                 ++cp;
293 #else
294             if (*cp == 0 || (*cp++ & 0200)) {
295                 return (0);
296             }
297 #endif
298         if (*cp == 0)
299             return (1);
300     }
301     return (0);
302 }
303
304 direrror(ino, errmesg)
305      ino_t ino;
306      char *errmesg;
307 {
308     struct dinode *dp;
309
310     pwarn("%s ", errmesg);
311     pinode(ino);
312     printf("\n");
313     if (ino < ROOTINO || ino > maxino) {
314         pfatal("NAME=%s\n", pathname);
315         return;
316     }
317     dp = ginode(ino);
318     if (ftypeok(dp))
319         pfatal("%s=%s\n", (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE",
320                pathname);
321     else
322         pfatal("NAME=%s\n", pathname);
323 }
324
325 adjust(idesc, lcnt)
326      struct inodesc *idesc;
327      short lcnt;
328 {
329     struct dinode *dp;
330
331     dp = ginode(idesc->id_number);
332     if (dp->di_nlink == lcnt) {
333         if (linkup(idesc->id_number, (ino_t) 0) == 0)
334             clri(idesc, "UNREF", 0);
335     } else {
336         pwarn("LINK COUNT %s",
337               (lfdir == idesc->id_number) ? lfname : ((dp->di_mode & IFMT) ==
338                                                       IFDIR ? "DIR" :
339                                                       "FILE"));
340         pinode(idesc->id_number);
341         printf(" COUNT %d SHOULD BE %d", dp->di_nlink, dp->di_nlink - lcnt);
342         if (preen) {
343             if (lcnt < 0) {
344                 printf("\n");
345                 pfatal("LINK COUNT INCREASING");
346             }
347             printf(" (ADJUSTED)\n");
348         }
349         if (preen || reply("ADJUST") == 1) {
350             dp->di_nlink -= lcnt;
351             inodirty();
352         }
353     }
354 }
355
356 mkentry(idesc)
357      struct inodesc *idesc;
358 {
359     struct direct *dirp = idesc->id_dirp;
360     struct direct newent;
361     int newlen, oldlen;
362
363     newent.d_namlen = 11;
364     newlen = DIRSIZ(&newent);
365     if (dirp->d_ino != 0)
366         oldlen = DIRSIZ(dirp);
367     else
368         oldlen = 0;
369     if (dirp->d_reclen - oldlen < newlen)
370         return (KEEPON);
371     newent.d_reclen = dirp->d_reclen - oldlen;
372     dirp->d_reclen = oldlen;
373     dirp = (struct direct *)(((char *)dirp) + oldlen);
374     dirp->d_ino = idesc->id_parent;     /* ino to be entered is in id_parent */
375     dirp->d_reclen = newent.d_reclen;
376     dirp->d_namlen = strlen(idesc->id_name);
377     memcpy(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1);
378     return (ALTERED | STOP);
379 }
380
381 chgino(idesc)
382      struct inodesc *idesc;
383 {
384     struct direct *dirp = idesc->id_dirp;
385
386     if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
387         return (KEEPON);
388     dirp->d_ino = idesc->id_parent;
389     return (ALTERED | STOP);
390 }
391
392 linkup(orphan, parentdir)
393      ino_t orphan;
394      ino_t parentdir;
395 {
396     struct dinode *dp;
397     int lostdir, len;
398     ino_t oldlfdir;
399     struct inodesc idesc;
400     char tempname[BUFSIZ];
401     extern int pass4check();
402
403     memset(&idesc, 0, sizeof(struct inodesc));
404     dp = ginode(orphan);
405     lostdir = (dp->di_mode & IFMT) == IFDIR;
406     pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
407     pinode(orphan);
408     if (preen && dp->di_size == 0)
409         return (0);
410     if (preen)
411         printf(" (RECONNECTED)\n");
412     else if (reply("RECONNECT") == 0)
413         return (0);
414     pathp = pathname;
415     *pathp++ = '/';
416     *pathp = '\0';
417     if (lfdir == 0) {
418         dp = ginode(ROOTINO);
419         idesc.id_name = lfname;
420         idesc.id_type = DATA;
421         idesc.id_func = findino;
422         idesc.id_number = ROOTINO;
423         if ((ckinode(dp, &idesc) & FOUND) != 0) {
424             lfdir = idesc.id_parent;
425         } else {
426             pwarn("NO lost+found DIRECTORY");
427             if (preen || reply("CREATE")) {
428                 lfdir = allocdir(ROOTINO, (ino_t) 0, lfmode);
429                 if (lfdir != 0) {
430                     if (makeentry(ROOTINO, lfdir, lfname) != 0) {
431                         if (preen)
432                             printf(" (CREATED)\n");
433                     } else {
434                         freedir(lfdir, ROOTINO);
435                         lfdir = 0;
436                         if (preen)
437                             printf("\n");
438                     }
439                 }
440             }
441         }
442         if (lfdir == 0) {
443             pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
444             printf("\n\n");
445             return (0);
446         }
447     }
448     dp = ginode(lfdir);
449     if ((dp->di_mode & IFMT) != IFDIR) {
450         pfatal("lost+found IS NOT A DIRECTORY");
451         if (reply("REALLOCATE") == 0)
452             return (0);
453         oldlfdir = lfdir;
454         if ((lfdir = allocdir(ROOTINO, (ino_t) 0, lfmode)) == 0) {
455             pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
456             return (0);
457         }
458         idesc.id_type = DATA;
459         idesc.id_func = chgino;
460         idesc.id_number = ROOTINO;
461         idesc.id_parent = lfdir;        /* new inumber for lost+found */
462         idesc.id_name = lfname;
463         if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) {
464             pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
465             return (0);
466         }
467         inodirty();
468         idesc.id_type = ADDR;
469         idesc.id_func = pass4check;
470         idesc.id_number = oldlfdir;
471         adjust(&idesc, lncntp[oldlfdir] + 1);
472         lncntp[oldlfdir] = 0;
473         dp = ginode(lfdir);
474     }
475     if (statemap[lfdir] != DFOUND) {
476         pfatal("SORRY. NO lost+found DIRECTORY\n\n");
477         return (0);
478     }
479     len = strlen(lfname);
480     memcpy(pathp, lfname, len + 1);
481     pathp += len;
482     len = lftempname(tempname, orphan);
483     if (makeentry(lfdir, orphan, tempname) == 0) {
484         pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
485         printf("\n\n");
486         return (0);
487     }
488     lncntp[orphan]--;
489     *pathp++ = '/';
490     memcpy(pathp, tempname, len + 1);
491     pathp += len;
492     if (lostdir) {
493         dp = ginode(orphan);
494         idesc.id_type = DATA;
495         idesc.id_func = chgino;
496         idesc.id_number = orphan;
497         idesc.id_fix = DONTKNOW;
498         idesc.id_name = "..";
499         idesc.id_parent = lfdir;        /* new value for ".." */
500         (void)ckinode(dp, &idesc);
501         dp = ginode(lfdir);
502         dp->di_nlink++;
503         inodirty();
504         lncntp[lfdir]++;
505         pwarn("DIR I=%u CONNECTED. ", orphan);
506         printf("PARENT WAS I=%u\n", parentdir);
507         if (preen == 0)
508             printf("\n");
509     }
510     return (1);
511 }
512
513 /*
514  * make an entry in a directory
515  */
516 makeentry(parent, ino, name)
517      ino_t parent, ino;
518      char *name;
519 {
520     struct dinode *dp;
521     struct inodesc idesc;
522
523     if (parent < ROOTINO || parent >= maxino || ino < ROOTINO
524         || ino >= maxino)
525         return (0);
526     memset(&idesc, 0, sizeof(struct inodesc));
527     idesc.id_type = DATA;
528     idesc.id_func = mkentry;
529     idesc.id_number = parent;
530     idesc.id_parent = ino;      /* this is the inode to enter */
531     idesc.id_fix = DONTKNOW;
532     idesc.id_name = name;
533     dp = ginode(parent);
534     if (dp->di_size % DIRBLKSIZ) {
535         dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
536         inodirty();
537     }
538     if ((ckinode(dp, &idesc) & ALTERED) != 0)
539         return (1);
540     if (expanddir(dp) == 0)
541         return (0);
542     return (ckinode(dp, &idesc) & ALTERED);
543 }
544
545 /*
546  * Attempt to expand the size of a directory
547  */
548 expanddir(dp)
549      struct dinode *dp;
550 {
551     daddr_t lastbn, newblk;
552     struct bufarea *bp;
553     char *cp, firstblk[DIRBLKSIZ];
554
555     lastbn = lblkno(&sblock, dp->di_size);
556     if (lastbn >= NDADDR - 1)
557         return (0);
558     if ((newblk = allocblk(sblock.fs_frag)) == 0)
559         return (0);
560     dp->di_db[lastbn + 1] = dp->di_db[lastbn];
561     dp->di_db[lastbn] = newblk;
562     dp->di_size += (UOFF_T) sblock.fs_bsize;
563     dp->di_blocks += btodb(sblock.fs_bsize);
564     bp = getdirblk(dp->di_db[lastbn + 1], dblksize(&sblock, dp, lastbn + 1));
565     if (bp->b_errs)
566         goto bad;
567     memcpy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
568     bp = getdirblk(newblk, sblock.fs_bsize);
569     if (bp->b_errs)
570         goto bad;
571     memcpy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
572     for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
573          cp < &bp->b_un.b_buf[sblock.fs_bsize]; cp += DIRBLKSIZ)
574         memcpy(cp, (char *)&emptydir, sizeof emptydir);
575     dirty(bp);
576     bp = getdirblk(dp->di_db[lastbn + 1], dblksize(&sblock, dp, lastbn + 1));
577     if (bp->b_errs)
578         goto bad;
579     memcpy(bp->b_un.b_buf, (char *)&emptydir, sizeof emptydir);
580     pwarn("NO SPACE LEFT IN %s", pathname);
581     if (preen)
582         printf(" (EXPANDED)\n");
583     else if (reply("EXPAND") == 0)
584         goto bad;
585     dirty(bp);
586     inodirty();
587     return (1);
588   bad:
589     dp->di_db[lastbn] = dp->di_db[lastbn + 1];
590     dp->di_db[lastbn + 1] = 0;
591     dp->di_size -= (UOFF_T) sblock.fs_bsize;
592     dp->di_blocks -= btodb(sblock.fs_bsize);
593     freeblk(newblk, sblock.fs_frag);
594     return (0);
595 }
596
597 /*
598  * allocate a new directory
599  */
600 allocdir(parent, request, mode)
601      ino_t parent, request;
602      int mode;
603 {
604     ino_t ino;
605     char *cp;
606     struct dinode *dp;
607     struct bufarea *bp;
608
609     ino = allocino(request, IFDIR | mode);
610     dirhead.dot_ino = ino;
611     dirhead.dotdot_ino = parent;
612     dp = ginode(ino);
613     bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
614     if (bp->b_errs) {
615         freeino(ino);
616         return (0);
617     }
618     memcpy(bp->b_un.b_buf, (char *)&dirhead, sizeof dirhead);
619     for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
620          cp < &bp->b_un.b_buf[sblock.fs_fsize]; cp += DIRBLKSIZ)
621         memcpy(cp, (char *)&emptydir, sizeof emptydir);
622     dirty(bp);
623     dp->di_nlink = 2;
624     inodirty();
625 #ifdef  AFS_SUN5_ENVX
626     if (!inocached(ino)) {
627         if (debug)
628             printf("inode %d added to directory cache\n", ino);
629         cacheino(dp, ino);
630     } else {
631         /*
632          * re-using an old directory inode
633          */
634         inp = getinoinfo(ino);
635         inp->i_isize = dp->di_size;
636         inp->i_numblks = dp->di_blocks * sizeof(daddr_t);
637         inp->i_parent = parent;
638         memcpy((char *)&inp->i_blks[0], (char *)&dp->di_db[0],
639                (int)inp->i_numblks);
640     }
641 #endif
642     if (ino == ROOTINO) {
643         lncntp[ino] = dp->di_nlink;
644         return (ino);
645     }
646     if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
647         freeino(ino);
648         return (0);
649     }
650     statemap[ino] = statemap[parent];
651     if (statemap[ino] == DSTATE) {
652         lncntp[ino] = dp->di_nlink;
653         lncntp[parent]++;
654     }
655     dp = ginode(parent);
656     dp->di_nlink++;
657     inodirty();
658     return (ino);
659 }
660
661 /*
662  * free a directory inode
663  */
664 freedir(ino, parent)
665      ino_t ino, parent;
666 {
667     struct dinode *dp;
668
669     if (ino != parent) {
670         dp = ginode(parent);
671         dp->di_nlink--;
672         inodirty();
673     }
674     freeino(ino);
675 }
676
677 /*
678  * generate a temporary name for the lost+found directory.
679  */
680 lftempname(bufp, ino)
681      char *bufp;
682      ino_t ino;
683 {
684     ino_t in;
685     char *cp;
686     int namlen;
687
688     cp = bufp + 2;
689     for (in = maxino; in > 0; in /= 10)
690         cp++;
691     *--cp = 0;
692     namlen = cp - bufp;
693     in = ino;
694     while (cp > bufp) {
695         *--cp = (in % 10) + '0';
696         in /= 10;
697     }
698     *cp = '#';
699     return (namlen);
700 }
701
702 /*
703  * Get a directory block.
704  * Insure that it is held until another is requested.
705  */
706 struct bufarea *
707 getdirblk(blkno, size)
708      daddr_t blkno;
709      long size;
710 {
711     if (mlk_pbp != 0)
712         mlk_pbp->b_flags &= ~B_INUSE;
713     mlk_pbp = getdatablk(blkno, size);
714     return (mlk_pbp);
715 }