4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / sbin / fsck / dir.c
CommitLineData
76797561 1/*
21e5ab9a
KB
2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
fe32782c 4 *
70ab3c27 5 * %sccs.include.redist.c%
76797561
DF
6 */
7
250baf55 8#ifndef lint
21e5ab9a 9static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) %G%";
fe32782c 10#endif /* not lint */
250baf55
KM
11
12#include <sys/param.h>
b82067db 13#include <sys/time.h>
558b3a30 14#include <ufs/ufs/dinode.h>
558b3a30 15#include <ufs/ufs/dir.h>
558b3a30 16#include <ufs/ffs/fs.h>
d72e970b
KM
17#include <stdlib.h>
18#include <string.h>
250baf55
KM
19#include "fsck.h"
20
250baf55 21char *lfname = "lost+found";
c689da7b 22int lfmode = 01777;
3e2a23ca 23struct dirtemplate emptydir = { 0, DIRBLKSIZ };
a2b71878
KM
24struct dirtemplate dirhead = {
25 0, 12, DT_DIR, 1, ".",
26 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
27};
28struct odirtemplate odirhead = {
29 0, 12, 1, ".",
30 0, DIRBLKSIZ - 12, 2, ".."
31};
250baf55 32
569ec282
KM
33struct direct *fsck_readdir();
34struct bufarea *getdirblk();
250baf55 35
eaf7fbaa
KM
36/*
37 * Propagate connected state through the tree.
38 */
39propagate()
250baf55 40{
eaf7fbaa
KM
41 register struct inoinfo **inpp, *inp;
42 struct inoinfo **inpend;
43 long change;
250baf55 44
eaf7fbaa
KM
45 inpend = &inpsort[inplast];
46 do {
47 change = 0;
48 for (inpp = inpsort; inpp < inpend; inpp++) {
49 inp = *inpp;
50 if (inp->i_parent == 0)
51 continue;
52 if (statemap[inp->i_parent] == DFOUND &&
53 statemap[inp->i_number] == DSTATE) {
54 statemap[inp->i_number] = DFOUND;
55 change++;
56 }
57117c0f 57 }
eaf7fbaa 58 } while (change > 0);
250baf55
KM
59}
60
eaf7fbaa
KM
61/*
62 * Scan each entry in a directory block.
63 */
250baf55
KM
64dirscan(idesc)
65 register struct inodesc *idesc;
66{
569ec282
KM
67 register struct direct *dp;
68 register struct bufarea *bp;
250baf55
KM
69 int dsize, n;
70 long blksiz;
71 char dbuf[DIRBLKSIZ];
72
73 if (idesc->id_type != DATA)
74 errexit("wrong type to dirscan %d\n", idesc->id_type);
042f816f
KM
75 if (idesc->id_entryno == 0 &&
76 (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
77 idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
250baf55 78 blksiz = idesc->id_numfrags * sblock.fs_fsize;
569ec282 79 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
250baf55
KM
80 idesc->id_filesize -= blksiz;
81 return (SKIP);
82 }
83 idesc->id_loc = 0;
84 for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
85 dsize = dp->d_reclen;
d72e970b 86 bcopy((char *)dp, dbuf, (size_t)dsize);
a2b71878
KM
87# if (BYTE_ORDER == LITTLE_ENDIAN)
88 if (!newinofmt) {
89 struct direct *tdp = (struct direct *)dbuf;
90 u_char tmp;
91
92 tmp = tdp->d_namlen;
93 tdp->d_namlen = tdp->d_type;
94 tdp->d_type = tmp;
95 }
96# endif
569ec282 97 idesc->id_dirp = (struct direct *)dbuf;
250baf55 98 if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
a2b71878
KM
99# if (BYTE_ORDER == LITTLE_ENDIAN)
100 if (!newinofmt && !doinglevel2) {
101 struct direct *tdp;
102 u_char tmp;
103
104 tdp = (struct direct *)dbuf;
105 tmp = tdp->d_namlen;
106 tdp->d_namlen = tdp->d_type;
107 tdp->d_type = tmp;
108 }
109# endif
adc5a10c 110 bp = getdirblk(idesc->id_blkno, blksiz);
da7246cd 111 bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize,
d72e970b 112 (size_t)dsize);
adc5a10c 113 dirty(bp);
315f1422 114 sbdirty();
250baf55
KM
115 }
116 if (n & STOP)
117 return (n);
118 }
119 return (idesc->id_filesize > 0 ? KEEPON : STOP);
120}
121
122/*
123 * get next entry in a directory.
124 */
569ec282 125struct direct *
250baf55
KM
126fsck_readdir(idesc)
127 register struct inodesc *idesc;
128{
569ec282
KM
129 register struct direct *dp, *ndp;
130 register struct bufarea *bp;
a2b71878 131 long size, blksiz, fix, dploc;
250baf55
KM
132
133 blksiz = idesc->id_numfrags * sblock.fs_fsize;
adc5a10c 134 bp = getdirblk(idesc->id_blkno, blksiz);
250baf55
KM
135 if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
136 idesc->id_loc < blksiz) {
569ec282 137 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
250baf55
KM
138 if (dircheck(idesc, dp))
139 goto dpok;
da7246cd
KM
140 fix = dofix(idesc, "DIRECTORY CORRUPTED");
141 bp = getdirblk(idesc->id_blkno, blksiz);
142 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
250baf55
KM
143 dp->d_reclen = DIRBLKSIZ;
144 dp->d_ino = 0;
a2b71878 145 dp->d_type = 0;
250baf55
KM
146 dp->d_namlen = 0;
147 dp->d_name[0] = '\0';
da7246cd 148 if (fix)
adc5a10c 149 dirty(bp);
94cf96fd
KM
150 idesc->id_loc += DIRBLKSIZ;
151 idesc->id_filesize -= DIRBLKSIZ;
250baf55
KM
152 return (dp);
153 }
154dpok:
155 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
156 return NULL;
a2b71878
KM
157 dploc = idesc->id_loc;
158 dp = (struct direct *)(bp->b_un.b_buf + dploc);
250baf55
KM
159 idesc->id_loc += dp->d_reclen;
160 idesc->id_filesize -= dp->d_reclen;
161 if ((idesc->id_loc % DIRBLKSIZ) == 0)
162 return (dp);
569ec282 163 ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
250baf55
KM
164 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
165 dircheck(idesc, ndp) == 0) {
166 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
250baf55
KM
167 idesc->id_loc += size;
168 idesc->id_filesize -= size;
da7246cd
KM
169 fix = dofix(idesc, "DIRECTORY CORRUPTED");
170 bp = getdirblk(idesc->id_blkno, blksiz);
a2b71878 171 dp = (struct direct *)(bp->b_un.b_buf + dploc);
da7246cd
KM
172 dp->d_reclen += size;
173 if (fix)
adc5a10c 174 dirty(bp);
250baf55
KM
175 }
176 return (dp);
177}
178
179/*
180 * Verify that a directory entry is valid.
181 * This is a superset of the checks made in the kernel.
182 */
183dircheck(idesc, dp)
184 struct inodesc *idesc;
569ec282 185 register struct direct *dp;
250baf55
KM
186{
187 register int size;
188 register char *cp;
a2b71878 189 u_char namlen, type;
250baf55
KM
190 int spaceleft;
191
a2b71878 192 size = DIRSIZ(!newinofmt, dp);
250baf55 193 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
a2b71878
KM
194# if (BYTE_ORDER == LITTLE_ENDIAN)
195 if (!newinofmt) {
196 type = dp->d_namlen;
197 namlen = dp->d_type;
198 } else {
199 namlen = dp->d_namlen;
200 type = dp->d_type;
201 }
202# else
203 namlen = dp->d_namlen;
204 type = dp->d_type;
205# endif
569ec282 206 if (dp->d_ino < maxino &&
250baf55
KM
207 dp->d_reclen != 0 &&
208 dp->d_reclen <= spaceleft &&
209 (dp->d_reclen & 0x3) == 0 &&
210 dp->d_reclen >= size &&
211 idesc->id_filesize >= size &&
a2b71878
KM
212 namlen <= MAXNAMLEN &&
213 type <= 15) {
250baf55
KM
214 if (dp->d_ino == 0)
215 return (1);
a2b71878 216 for (cp = dp->d_name, size = 0; size < namlen; size++)
94b53fb0 217 if (*cp == 0 || (*cp++ == '/'))
250baf55
KM
218 return (0);
219 if (*cp == 0)
220 return (1);
221 }
222 return (0);
223}
224
569ec282 225direrror(ino, errmesg)
250baf55 226 ino_t ino;
569ec282 227 char *errmesg;
250baf55 228{
eaf7fbaa
KM
229
230 fileerror(ino, ino, errmesg);
231}
232
233fileerror(cwd, ino, errmesg)
234 ino_t cwd, ino;
235 char *errmesg;
236{
569ec282 237 register struct dinode *dp;
eaf7fbaa 238 char pathbuf[MAXPATHLEN + 1];
250baf55 239
569ec282 240 pwarn("%s ", errmesg);
250baf55
KM
241 pinode(ino);
242 printf("\n");
eaf7fbaa 243 getpathname(pathbuf, cwd, ino);
569ec282 244 if (ino < ROOTINO || ino > maxino) {
eaf7fbaa 245 pfatal("NAME=%s\n", pathbuf);
39c18287
KM
246 return;
247 }
248 dp = ginode(ino);
249 if (ftypeok(dp))
569ec282 250 pfatal("%s=%s\n",
eaf7fbaa 251 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
250baf55 252 else
eaf7fbaa 253 pfatal("NAME=%s\n", pathbuf);
250baf55
KM
254}
255
256adjust(idesc, lcnt)
257 register struct inodesc *idesc;
258 short lcnt;
259{
569ec282 260 register struct dinode *dp;
250baf55 261
39c18287 262 dp = ginode(idesc->id_number);
250baf55
KM
263 if (dp->di_nlink == lcnt) {
264 if (linkup(idesc->id_number, (ino_t)0) == 0)
265 clri(idesc, "UNREF", 0);
993a756c 266 } else {
7718c0e6 267 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
569ec282 268 ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
250baf55
KM
269 pinode(idesc->id_number);
270 printf(" COUNT %d SHOULD BE %d",
569ec282 271 dp->di_nlink, dp->di_nlink - lcnt);
250baf55
KM
272 if (preen) {
273 if (lcnt < 0) {
274 printf("\n");
7718c0e6 275 pfatal("LINK COUNT INCREASING");
250baf55
KM
276 }
277 printf(" (ADJUSTED)\n");
278 }
279 if (preen || reply("ADJUST") == 1) {
280 dp->di_nlink -= lcnt;
281 inodirty();
282 }
283 }
284}
285
286mkentry(idesc)
287 struct inodesc *idesc;
288{
569ec282
KM
289 register struct direct *dirp = idesc->id_dirp;
290 struct direct newent;
250baf55
KM
291 int newlen, oldlen;
292
eaf7fbaa 293 newent.d_namlen = strlen(idesc->id_name);
a2b71878 294 newlen = DIRSIZ(0, &newent);
250baf55 295 if (dirp->d_ino != 0)
a2b71878 296 oldlen = DIRSIZ(0, dirp);
250baf55
KM
297 else
298 oldlen = 0;
299 if (dirp->d_reclen - oldlen < newlen)
300 return (KEEPON);
301 newent.d_reclen = dirp->d_reclen - oldlen;
302 dirp->d_reclen = oldlen;
303 dirp = (struct direct *)(((char *)dirp) + oldlen);
304 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
a2b71878
KM
305 if (newinofmt)
306 dirp->d_type = typemap[idesc->id_parent];
5ea8a7e3
KM
307 else
308 dirp->d_type = 0;
250baf55 309 dirp->d_reclen = newent.d_reclen;
eaf7fbaa 310 dirp->d_namlen = newent.d_namlen;
d72e970b 311 bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
250baf55
KM
312 return (ALTERED|STOP);
313}
314
59e3daa2 315chgino(idesc)
250baf55
KM
316 struct inodesc *idesc;
317{
569ec282 318 register struct direct *dirp = idesc->id_dirp;
250baf55 319
569ec282 320 if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
59e3daa2 321 return (KEEPON);
569ec282 322 dirp->d_ino = idesc->id_parent;
a2b71878
KM
323 if (newinofmt)
324 dirp->d_type = typemap[idesc->id_parent];
5ea8a7e3
KM
325 else
326 dirp->d_type = 0;
59e3daa2 327 return (ALTERED|STOP);
250baf55
KM
328}
329
569ec282 330linkup(orphan, parentdir)
250baf55 331 ino_t orphan;
569ec282 332 ino_t parentdir;
250baf55 333{
569ec282 334 register struct dinode *dp;
eaf7fbaa 335 int lostdir;
ebd05fde 336 ino_t oldlfdir;
250baf55 337 struct inodesc idesc;
ebd05fde 338 char tempname[BUFSIZ];
59e3daa2 339 extern int pass4check();
250baf55
KM
340
341 bzero((char *)&idesc, sizeof(struct inodesc));
39c18287 342 dp = ginode(orphan);
569ec282 343 lostdir = (dp->di_mode & IFMT) == IFDIR;
250baf55
KM
344 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
345 pinode(orphan);
346 if (preen && dp->di_size == 0)
347 return (0);
348 if (preen)
349 printf(" (RECONNECTED)\n");
350 else
351 if (reply("RECONNECT") == 0)
352 return (0);
250baf55 353 if (lfdir == 0) {
39c18287 354 dp = ginode(ROOTINO);
7718c0e6 355 idesc.id_name = lfname;
250baf55
KM
356 idesc.id_type = DATA;
357 idesc.id_func = findino;
358 idesc.id_number = ROOTINO;
315f1422 359 if ((ckinode(dp, &idesc) & FOUND) != 0) {
ebd05fde
KM
360 lfdir = idesc.id_parent;
361 } else {
362 pwarn("NO lost+found DIRECTORY");
363 if (preen || reply("CREATE")) {
569ec282 364 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
ca1a30be
KM
365 if (lfdir != 0) {
366 if (makeentry(ROOTINO, lfdir, lfname) != 0) {
ebd05fde
KM
367 if (preen)
368 printf(" (CREATED)\n");
369 } else {
ca1a30be
KM
370 freedir(lfdir, ROOTINO);
371 lfdir = 0;
ebd05fde
KM
372 if (preen)
373 printf("\n");
374 }
375 }
376 }
377 }
39c18287 378 if (lfdir == 0) {
ebd05fde 379 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
250baf55
KM
380 printf("\n\n");
381 return (0);
382 }
383 }
39c18287 384 dp = ginode(lfdir);
569ec282 385 if ((dp->di_mode & IFMT) != IFDIR) {
59e3daa2
KM
386 pfatal("lost+found IS NOT A DIRECTORY");
387 if (reply("REALLOCATE") == 0)
388 return (0);
389 oldlfdir = lfdir;
569ec282 390 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {
59e3daa2
KM
391 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
392 return (0);
393 }
eaf7fbaa 394 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
59e3daa2
KM
395 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
396 return (0);
397 }
398 inodirty();
399 idesc.id_type = ADDR;
400 idesc.id_func = pass4check;
401 idesc.id_number = oldlfdir;
402 adjust(&idesc, lncntp[oldlfdir] + 1);
403 lncntp[oldlfdir] = 0;
404 dp = ginode(lfdir);
405 }
406 if (statemap[lfdir] != DFOUND) {
407 pfatal("SORRY. NO lost+found DIRECTORY\n\n");
250baf55
KM
408 return (0);
409 }
eaf7fbaa 410 (void)lftempname(tempname, orphan);
ca1a30be 411 if (makeentry(lfdir, orphan, tempname) == 0) {
250baf55
KM
412 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
413 printf("\n\n");
414 return (0);
415 }
416 lncntp[orphan]--;
250baf55 417 if (lostdir) {
eaf7fbaa
KM
418 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
419 parentdir != (ino_t)-1)
d72e970b 420 (void)makeentry(orphan, lfdir, "..");
39c18287
KM
421 dp = ginode(lfdir);
422 dp->di_nlink++;
423 inodirty();
424 lncntp[lfdir]++;
d72e970b 425 pwarn("DIR I=%lu CONNECTED. ", orphan);
eaf7fbaa 426 if (parentdir != (ino_t)-1)
d72e970b 427 printf("PARENT WAS I=%lu\n", parentdir);
250baf55
KM
428 if (preen == 0)
429 printf("\n");
430 }
431 return (1);
432}
433
eaf7fbaa
KM
434/*
435 * fix an entry in a directory.
436 */
437changeino(dir, name, newnum)
438 ino_t dir;
439 char *name;
440 ino_t newnum;
441{
442 struct inodesc idesc;
443
444 bzero((char *)&idesc, sizeof(struct inodesc));
445 idesc.id_type = DATA;
446 idesc.id_func = chgino;
447 idesc.id_number = dir;
448 idesc.id_fix = DONTKNOW;
449 idesc.id_name = name;
450 idesc.id_parent = newnum; /* new value for name */
451 return (ckinode(ginode(dir), &idesc));
452}
453
3e2a23ca
KM
454/*
455 * make an entry in a directory
456 */
ca1a30be
KM
457makeentry(parent, ino, name)
458 ino_t parent, ino;
459 char *name;
3e2a23ca 460{
569ec282 461 struct dinode *dp;
ca1a30be 462 struct inodesc idesc;
eaf7fbaa 463 char pathbuf[MAXPATHLEN + 1];
3e2a23ca 464
569ec282
KM
465 if (parent < ROOTINO || parent >= maxino ||
466 ino < ROOTINO || ino >= maxino)
ca1a30be 467 return (0);
569ec282 468 bzero((char *)&idesc, sizeof(struct inodesc));
ca1a30be
KM
469 idesc.id_type = DATA;
470 idesc.id_func = mkentry;
471 idesc.id_number = parent;
472 idesc.id_parent = ino; /* this is the inode to enter */
473 idesc.id_fix = DONTKNOW;
474 idesc.id_name = name;
475 dp = ginode(parent);
042f816f
KM
476 if (dp->di_size % DIRBLKSIZ) {
477 dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
478 inodirty();
479 }
ca1a30be 480 if ((ckinode(dp, &idesc) & ALTERED) != 0)
3e2a23ca 481 return (1);
eaf7fbaa
KM
482 getpathname(pathbuf, parent, parent);
483 dp = ginode(parent);
484 if (expanddir(dp, pathbuf) == 0)
3e2a23ca 485 return (0);
ca1a30be 486 return (ckinode(dp, &idesc) & ALTERED);
3e2a23ca
KM
487}
488
489/*
490 * Attempt to expand the size of a directory
491 */
eaf7fbaa 492expanddir(dp, name)
569ec282 493 register struct dinode *dp;
eaf7fbaa 494 char *name;
3e2a23ca
KM
495{
496 daddr_t lastbn, newblk;
569ec282 497 register struct bufarea *bp;
3e2a23ca
KM
498 char *cp, firstblk[DIRBLKSIZ];
499
500 lastbn = lblkno(&sblock, dp->di_size);
de1c32f8 501 if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
3e2a23ca
KM
502 return (0);
503 if ((newblk = allocblk(sblock.fs_frag)) == 0)
504 return (0);
505 dp->di_db[lastbn + 1] = dp->di_db[lastbn];
506 dp->di_db[lastbn] = newblk;
507 dp->di_size += sblock.fs_bsize;
508 dp->di_blocks += btodb(sblock.fs_bsize);
adc5a10c 509 bp = getdirblk(dp->di_db[lastbn + 1],
d72e970b 510 (long)dblksize(&sblock, dp, lastbn + 1));
3e1e0aa6 511 if (bp->b_errs)
3e2a23ca 512 goto bad;
adc5a10c
KM
513 bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
514 bp = getdirblk(newblk, sblock.fs_bsize);
3e1e0aa6 515 if (bp->b_errs)
3e2a23ca 516 goto bad;
adc5a10c
KM
517 bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
518 for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
519 cp < &bp->b_un.b_buf[sblock.fs_bsize];
3e2a23ca
KM
520 cp += DIRBLKSIZ)
521 bcopy((char *)&emptydir, cp, sizeof emptydir);
adc5a10c
KM
522 dirty(bp);
523 bp = getdirblk(dp->di_db[lastbn + 1],
d72e970b 524 (long)dblksize(&sblock, dp, lastbn + 1));
3e1e0aa6 525 if (bp->b_errs)
3e2a23ca 526 goto bad;
adc5a10c 527 bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
eaf7fbaa 528 pwarn("NO SPACE LEFT IN %s", name);
3e2a23ca
KM
529 if (preen)
530 printf(" (EXPANDED)\n");
531 else if (reply("EXPAND") == 0)
532 goto bad;
adc5a10c 533 dirty(bp);
3e2a23ca
KM
534 inodirty();
535 return (1);
536bad:
537 dp->di_db[lastbn] = dp->di_db[lastbn + 1];
538 dp->di_db[lastbn + 1] = 0;
539 dp->di_size -= sblock.fs_bsize;
540 dp->di_blocks -= btodb(sblock.fs_bsize);
541 freeblk(newblk, sblock.fs_frag);
542 return (0);
543}
544
ebd05fde
KM
545/*
546 * allocate a new directory
547 */
c689da7b 548allocdir(parent, request, mode)
ebd05fde 549 ino_t parent, request;
c689da7b 550 int mode;
ebd05fde
KM
551{
552 ino_t ino;
553 char *cp;
569ec282
KM
554 struct dinode *dp;
555 register struct bufarea *bp;
a2b71878 556 struct dirtemplate *dirp;
ebd05fde 557
c689da7b 558 ino = allocino(request, IFDIR|mode);
a2b71878
KM
559 if (newinofmt)
560 dirp = &dirhead;
561 else
562 dirp = (struct dirtemplate *)&odirhead;
563 dirp->dot_ino = ino;
564 dirp->dotdot_ino = parent;
ebd05fde 565 dp = ginode(ino);
adc5a10c 566 bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
3e1e0aa6 567 if (bp->b_errs) {
ebd05fde
KM
568 freeino(ino);
569 return (0);
570 }
a2b71878 571 bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate));
adc5a10c
KM
572 for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
573 cp < &bp->b_un.b_buf[sblock.fs_fsize];
ebd05fde
KM
574 cp += DIRBLKSIZ)
575 bcopy((char *)&emptydir, cp, sizeof emptydir);
adc5a10c 576 dirty(bp);
ebd05fde
KM
577 dp->di_nlink = 2;
578 inodirty();
579 if (ino == ROOTINO) {
580 lncntp[ino] = dp->di_nlink;
84aff739 581 cacheino(dp, ino);
ebd05fde
KM
582 return(ino);
583 }
584 if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
585 freeino(ino);
586 return (0);
587 }
84aff739 588 cacheino(dp, ino);
ebd05fde
KM
589 statemap[ino] = statemap[parent];
590 if (statemap[ino] == DSTATE) {
591 lncntp[ino] = dp->di_nlink;
592 lncntp[parent]++;
593 }
594 dp = ginode(parent);
595 dp->di_nlink++;
596 inodirty();
597 return (ino);
598}
599
600/*
601 * free a directory inode
602 */
603freedir(ino, parent)
604 ino_t ino, parent;
605{
569ec282 606 struct dinode *dp;
ebd05fde
KM
607
608 if (ino != parent) {
609 dp = ginode(parent);
610 dp->di_nlink--;
611 inodirty();
612 }
613 freeino(ino);
614}
615
250baf55
KM
616/*
617 * generate a temporary name for the lost+found directory.
618 */
619lftempname(bufp, ino)
620 char *bufp;
621 ino_t ino;
622{
623 register ino_t in;
624 register char *cp;
625 int namlen;
626
627 cp = bufp + 2;
569ec282 628 for (in = maxino; in > 0; in /= 10)
250baf55
KM
629 cp++;
630 *--cp = 0;
631 namlen = cp - bufp;
632 in = ino;
633 while (cp > bufp) {
634 *--cp = (in % 10) + '0';
635 in /= 10;
636 }
637 *cp = '#';
638 return (namlen);
639}
adc5a10c
KM
640
641/*
642 * Get a directory block.
643 * Insure that it is held until another is requested.
644 */
569ec282 645struct bufarea *
adc5a10c
KM
646getdirblk(blkno, size)
647 daddr_t blkno;
648 long size;
649{
adc5a10c 650
037ceef0
KM
651 if (pdirbp != 0)
652 pdirbp->b_flags &= ~B_INUSE;
653 pdirbp = getdatablk(blkno, size);
654 return (pdirbp);
adc5a10c 655}