122045Sdist /* 239976Smckusick * Copyright (c) 1980, 1986 The Regents of the University of California. 339976Smckusick * All rights reserved. 439976Smckusick * 542701Sbostic * %sccs.include.redist.c% 622045Sdist */ 722045Sdist 816259Smckusick #ifndef lint 9*53702Smckusick static char sccsid[] = "@(#)dir.c 5.21 (Berkeley) 05/27/92"; 1039976Smckusick #endif /* not lint */ 1116259Smckusick 1216259Smckusick #include <sys/param.h> 13*53702Smckusick #include <sys/time.h> 1451532Sbostic #include <ufs/ufs/dinode.h> 1516259Smckusick #define KERNEL 1651532Sbostic #include <ufs/ufs/dir.h> 1716259Smckusick #undef KERNEL 1851532Sbostic #include <ufs/ffs/fs.h> 1944934Smckusick #include <stdlib.h> 2044934Smckusick #include <string.h> 2116259Smckusick #include "fsck.h" 2216259Smckusick 2316259Smckusick char *lfname = "lost+found"; 2436827Smckusick int lfmode = 01777; 2517944Smckusick struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 2617954Smckusick struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." }; 2716259Smckusick 2839973Smckusick struct direct *fsck_readdir(); 2939973Smckusick struct bufarea *getdirblk(); 3016259Smckusick 3140022Smckusick /* 3240022Smckusick * Propagate connected state through the tree. 3340022Smckusick */ 3440022Smckusick propagate() 3516259Smckusick { 3640022Smckusick register struct inoinfo **inpp, *inp; 3740022Smckusick struct inoinfo **inpend; 3840022Smckusick long change; 3916259Smckusick 4040022Smckusick inpend = &inpsort[inplast]; 4140022Smckusick do { 4240022Smckusick change = 0; 4340022Smckusick for (inpp = inpsort; inpp < inpend; inpp++) { 4440022Smckusick inp = *inpp; 4540022Smckusick if (inp->i_parent == 0) 4640022Smckusick continue; 4740022Smckusick if (statemap[inp->i_parent] == DFOUND && 4840022Smckusick statemap[inp->i_number] == DSTATE) { 4940022Smckusick statemap[inp->i_number] = DFOUND; 5040022Smckusick change++; 5140022Smckusick } 5239980Smckusick } 5340022Smckusick } while (change > 0); 5416259Smckusick } 5516259Smckusick 5640022Smckusick /* 5740022Smckusick * Scan each entry in a directory block. 5840022Smckusick */ 5916259Smckusick dirscan(idesc) 6016259Smckusick register struct inodesc *idesc; 6116259Smckusick { 6239973Smckusick register struct direct *dp; 6339973Smckusick register struct bufarea *bp; 6416259Smckusick int dsize, n; 6516259Smckusick long blksiz; 6616259Smckusick char dbuf[DIRBLKSIZ]; 6716259Smckusick 6816259Smckusick if (idesc->id_type != DATA) 6916259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 7017993Smckusick if (idesc->id_entryno == 0 && 7117993Smckusick (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 7217993Smckusick idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 7316259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 7439973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 7516259Smckusick idesc->id_filesize -= blksiz; 7616259Smckusick return (SKIP); 7716259Smckusick } 7816259Smckusick idesc->id_loc = 0; 7916259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 8016259Smckusick dsize = dp->d_reclen; 8144934Smckusick bcopy((char *)dp, dbuf, (size_t)dsize); 8239973Smckusick idesc->id_dirp = (struct direct *)dbuf; 8316259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 8434225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 8540570Smckusick bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, 8644934Smckusick (size_t)dsize); 8734225Smckusick dirty(bp); 8830354Smckusick sbdirty(); 8916259Smckusick } 9016259Smckusick if (n & STOP) 9116259Smckusick return (n); 9216259Smckusick } 9316259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 9416259Smckusick } 9516259Smckusick 9616259Smckusick /* 9716259Smckusick * get next entry in a directory. 9816259Smckusick */ 9939973Smckusick struct direct * 10016259Smckusick fsck_readdir(idesc) 10116259Smckusick register struct inodesc *idesc; 10216259Smckusick { 10339973Smckusick register struct direct *dp, *ndp; 10439973Smckusick register struct bufarea *bp; 10540570Smckusick long size, blksiz, fix; 10616259Smckusick 10716259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 10834225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 10916259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 11016259Smckusick idesc->id_loc < blksiz) { 11139973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 11216259Smckusick if (dircheck(idesc, dp)) 11316259Smckusick goto dpok; 11416259Smckusick idesc->id_loc += DIRBLKSIZ; 11516259Smckusick idesc->id_filesize -= DIRBLKSIZ; 11640570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 11740570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 11840570Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 11916259Smckusick dp->d_reclen = DIRBLKSIZ; 12016259Smckusick dp->d_ino = 0; 12116259Smckusick dp->d_namlen = 0; 12216259Smckusick dp->d_name[0] = '\0'; 12340570Smckusick if (fix) 12434225Smckusick dirty(bp); 12516259Smckusick return (dp); 12616259Smckusick } 12716259Smckusick dpok: 12816259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 12916259Smckusick return NULL; 13039973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 13116259Smckusick idesc->id_loc += dp->d_reclen; 13216259Smckusick idesc->id_filesize -= dp->d_reclen; 13316259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 13416259Smckusick return (dp); 13539973Smckusick ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 13616259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 13716259Smckusick dircheck(idesc, ndp) == 0) { 13816259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 13916259Smckusick idesc->id_loc += size; 14016259Smckusick idesc->id_filesize -= size; 14140570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 14240570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 14340570Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 14440570Smckusick dp->d_reclen += size; 14540570Smckusick if (fix) 14634225Smckusick dirty(bp); 14716259Smckusick } 14816259Smckusick return (dp); 14916259Smckusick } 15016259Smckusick 15116259Smckusick /* 15216259Smckusick * Verify that a directory entry is valid. 15316259Smckusick * This is a superset of the checks made in the kernel. 15416259Smckusick */ 15516259Smckusick dircheck(idesc, dp) 15616259Smckusick struct inodesc *idesc; 15739973Smckusick register struct direct *dp; 15816259Smckusick { 15916259Smckusick register int size; 16016259Smckusick register char *cp; 16116259Smckusick int spaceleft; 16216259Smckusick 16316259Smckusick size = DIRSIZ(dp); 16416259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 16539973Smckusick if (dp->d_ino < maxino && 16616259Smckusick dp->d_reclen != 0 && 16716259Smckusick dp->d_reclen <= spaceleft && 16816259Smckusick (dp->d_reclen & 0x3) == 0 && 16916259Smckusick dp->d_reclen >= size && 17016259Smckusick idesc->id_filesize >= size && 17116259Smckusick dp->d_namlen <= MAXNAMLEN) { 17216259Smckusick if (dp->d_ino == 0) 17316259Smckusick return (1); 17416259Smckusick for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 17540651Smckusick if (*cp == 0 || (*cp++ == '/')) 17616259Smckusick return (0); 17716259Smckusick if (*cp == 0) 17816259Smckusick return (1); 17916259Smckusick } 18016259Smckusick return (0); 18116259Smckusick } 18216259Smckusick 18339973Smckusick direrror(ino, errmesg) 18416259Smckusick ino_t ino; 18539973Smckusick char *errmesg; 18616259Smckusick { 18740022Smckusick 18840022Smckusick fileerror(ino, ino, errmesg); 18940022Smckusick } 19040022Smckusick 19140022Smckusick fileerror(cwd, ino, errmesg) 19240022Smckusick ino_t cwd, ino; 19340022Smckusick char *errmesg; 19440022Smckusick { 19539973Smckusick register struct dinode *dp; 19640022Smckusick char pathbuf[MAXPATHLEN + 1]; 19716259Smckusick 19839973Smckusick pwarn("%s ", errmesg); 19916259Smckusick pinode(ino); 20016259Smckusick printf("\n"); 20140022Smckusick getpathname(pathbuf, cwd, ino); 20239973Smckusick if (ino < ROOTINO || ino > maxino) { 20340022Smckusick pfatal("NAME=%s\n", pathbuf); 20417943Smckusick return; 20517943Smckusick } 20617943Smckusick dp = ginode(ino); 20717943Smckusick if (ftypeok(dp)) 20839973Smckusick pfatal("%s=%s\n", 20940022Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 21016259Smckusick else 21140022Smckusick pfatal("NAME=%s\n", pathbuf); 21216259Smckusick } 21316259Smckusick 21416259Smckusick adjust(idesc, lcnt) 21516259Smckusick register struct inodesc *idesc; 21616259Smckusick short lcnt; 21716259Smckusick { 21839973Smckusick register struct dinode *dp; 21916259Smckusick 22017943Smckusick dp = ginode(idesc->id_number); 22116259Smckusick if (dp->di_nlink == lcnt) { 22216259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 22316259Smckusick clri(idesc, "UNREF", 0); 22417936Smckusick } else { 22517930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 22639973Smckusick ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 22716259Smckusick pinode(idesc->id_number); 22816259Smckusick printf(" COUNT %d SHOULD BE %d", 22939973Smckusick dp->di_nlink, dp->di_nlink - lcnt); 23016259Smckusick if (preen) { 23116259Smckusick if (lcnt < 0) { 23216259Smckusick printf("\n"); 23317930Smckusick pfatal("LINK COUNT INCREASING"); 23416259Smckusick } 23516259Smckusick printf(" (ADJUSTED)\n"); 23616259Smckusick } 23716259Smckusick if (preen || reply("ADJUST") == 1) { 23816259Smckusick dp->di_nlink -= lcnt; 23916259Smckusick inodirty(); 24016259Smckusick } 24116259Smckusick } 24216259Smckusick } 24316259Smckusick 24416259Smckusick mkentry(idesc) 24516259Smckusick struct inodesc *idesc; 24616259Smckusick { 24739973Smckusick register struct direct *dirp = idesc->id_dirp; 24839973Smckusick struct direct newent; 24916259Smckusick int newlen, oldlen; 25016259Smckusick 25140022Smckusick newent.d_namlen = strlen(idesc->id_name); 25216259Smckusick newlen = DIRSIZ(&newent); 25316259Smckusick if (dirp->d_ino != 0) 25416259Smckusick oldlen = DIRSIZ(dirp); 25516259Smckusick else 25616259Smckusick oldlen = 0; 25716259Smckusick if (dirp->d_reclen - oldlen < newlen) 25816259Smckusick return (KEEPON); 25916259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 26016259Smckusick dirp->d_reclen = oldlen; 26116259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 26216259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 26316259Smckusick dirp->d_reclen = newent.d_reclen; 26440022Smckusick dirp->d_namlen = newent.d_namlen; 26544934Smckusick bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 26616259Smckusick return (ALTERED|STOP); 26716259Smckusick } 26816259Smckusick 26917957Smckusick chgino(idesc) 27016259Smckusick struct inodesc *idesc; 27116259Smckusick { 27239973Smckusick register struct direct *dirp = idesc->id_dirp; 27316259Smckusick 27439973Smckusick if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 27517957Smckusick return (KEEPON); 27639973Smckusick dirp->d_ino = idesc->id_parent; 27717957Smckusick return (ALTERED|STOP); 27816259Smckusick } 27916259Smckusick 28039973Smckusick linkup(orphan, parentdir) 28116259Smckusick ino_t orphan; 28239973Smckusick ino_t parentdir; 28316259Smckusick { 28439973Smckusick register struct dinode *dp; 28540022Smckusick int lostdir; 28617954Smckusick ino_t oldlfdir; 28716259Smckusick struct inodesc idesc; 28817954Smckusick char tempname[BUFSIZ]; 28917957Smckusick extern int pass4check(); 29016259Smckusick 29116259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 29217943Smckusick dp = ginode(orphan); 29339973Smckusick lostdir = (dp->di_mode & IFMT) == IFDIR; 29416259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 29516259Smckusick pinode(orphan); 29616259Smckusick if (preen && dp->di_size == 0) 29716259Smckusick return (0); 29816259Smckusick if (preen) 29916259Smckusick printf(" (RECONNECTED)\n"); 30016259Smckusick else 30116259Smckusick if (reply("RECONNECT") == 0) 30216259Smckusick return (0); 30316259Smckusick if (lfdir == 0) { 30417943Smckusick dp = ginode(ROOTINO); 30517930Smckusick idesc.id_name = lfname; 30616259Smckusick idesc.id_type = DATA; 30716259Smckusick idesc.id_func = findino; 30816259Smckusick idesc.id_number = ROOTINO; 30930354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 31017954Smckusick lfdir = idesc.id_parent; 31117954Smckusick } else { 31217954Smckusick pwarn("NO lost+found DIRECTORY"); 31317954Smckusick if (preen || reply("CREATE")) { 31439973Smckusick lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 31517992Smckusick if (lfdir != 0) { 31617992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 31717954Smckusick if (preen) 31817954Smckusick printf(" (CREATED)\n"); 31917954Smckusick } else { 32017992Smckusick freedir(lfdir, ROOTINO); 32117992Smckusick lfdir = 0; 32217954Smckusick if (preen) 32317954Smckusick printf("\n"); 32417954Smckusick } 32517954Smckusick } 32617954Smckusick } 32717954Smckusick } 32817943Smckusick if (lfdir == 0) { 32917954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 33016259Smckusick printf("\n\n"); 33116259Smckusick return (0); 33216259Smckusick } 33316259Smckusick } 33417943Smckusick dp = ginode(lfdir); 33539973Smckusick if ((dp->di_mode & IFMT) != IFDIR) { 33617957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 33717957Smckusick if (reply("REALLOCATE") == 0) 33817957Smckusick return (0); 33917957Smckusick oldlfdir = lfdir; 34039973Smckusick if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 34117957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 34217957Smckusick return (0); 34317957Smckusick } 34440022Smckusick if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 34517957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 34617957Smckusick return (0); 34717957Smckusick } 34817957Smckusick inodirty(); 34917957Smckusick idesc.id_type = ADDR; 35017957Smckusick idesc.id_func = pass4check; 35117957Smckusick idesc.id_number = oldlfdir; 35217957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 35317957Smckusick lncntp[oldlfdir] = 0; 35417957Smckusick dp = ginode(lfdir); 35517957Smckusick } 35617957Smckusick if (statemap[lfdir] != DFOUND) { 35717957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 35816259Smckusick return (0); 35916259Smckusick } 36040022Smckusick (void)lftempname(tempname, orphan); 36117992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 36216259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 36316259Smckusick printf("\n\n"); 36416259Smckusick return (0); 36516259Smckusick } 36616259Smckusick lncntp[orphan]--; 36716259Smckusick if (lostdir) { 36840022Smckusick if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 36940022Smckusick parentdir != (ino_t)-1) 37044934Smckusick (void)makeentry(orphan, lfdir, ".."); 37117943Smckusick dp = ginode(lfdir); 37217943Smckusick dp->di_nlink++; 37317943Smckusick inodirty(); 37417943Smckusick lncntp[lfdir]++; 37544934Smckusick pwarn("DIR I=%lu CONNECTED. ", orphan); 37640022Smckusick if (parentdir != (ino_t)-1) 37744934Smckusick printf("PARENT WAS I=%lu\n", parentdir); 37816259Smckusick if (preen == 0) 37916259Smckusick printf("\n"); 38016259Smckusick } 38116259Smckusick return (1); 38216259Smckusick } 38316259Smckusick 38416259Smckusick /* 38540022Smckusick * fix an entry in a directory. 38640022Smckusick */ 38740022Smckusick changeino(dir, name, newnum) 38840022Smckusick ino_t dir; 38940022Smckusick char *name; 39040022Smckusick ino_t newnum; 39140022Smckusick { 39240022Smckusick struct inodesc idesc; 39340022Smckusick 39440022Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 39540022Smckusick idesc.id_type = DATA; 39640022Smckusick idesc.id_func = chgino; 39740022Smckusick idesc.id_number = dir; 39840022Smckusick idesc.id_fix = DONTKNOW; 39940022Smckusick idesc.id_name = name; 40040022Smckusick idesc.id_parent = newnum; /* new value for name */ 40140022Smckusick return (ckinode(ginode(dir), &idesc)); 40240022Smckusick } 40340022Smckusick 40440022Smckusick /* 40517944Smckusick * make an entry in a directory 40617944Smckusick */ 40717992Smckusick makeentry(parent, ino, name) 40817992Smckusick ino_t parent, ino; 40917992Smckusick char *name; 41017992Smckusick { 41139973Smckusick struct dinode *dp; 41217992Smckusick struct inodesc idesc; 41340022Smckusick char pathbuf[MAXPATHLEN + 1]; 41417944Smckusick 41539973Smckusick if (parent < ROOTINO || parent >= maxino || 41639973Smckusick ino < ROOTINO || ino >= maxino) 41717992Smckusick return (0); 41839973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 41917992Smckusick idesc.id_type = DATA; 42017992Smckusick idesc.id_func = mkentry; 42117992Smckusick idesc.id_number = parent; 42217992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 42317992Smckusick idesc.id_fix = DONTKNOW; 42417992Smckusick idesc.id_name = name; 42517992Smckusick dp = ginode(parent); 42617993Smckusick if (dp->di_size % DIRBLKSIZ) { 42717993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 42817993Smckusick inodirty(); 42917993Smckusick } 43017992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 43117944Smckusick return (1); 43240022Smckusick getpathname(pathbuf, parent, parent); 43340022Smckusick dp = ginode(parent); 43440022Smckusick if (expanddir(dp, pathbuf) == 0) 43517944Smckusick return (0); 43617992Smckusick return (ckinode(dp, &idesc) & ALTERED); 43717944Smckusick } 43817944Smckusick 43917944Smckusick /* 44017944Smckusick * Attempt to expand the size of a directory 44117944Smckusick */ 44240022Smckusick expanddir(dp, name) 44339973Smckusick register struct dinode *dp; 44440022Smckusick char *name; 44517944Smckusick { 44617944Smckusick daddr_t lastbn, newblk; 44739973Smckusick register struct bufarea *bp; 44817944Smckusick char *cp, firstblk[DIRBLKSIZ]; 44917944Smckusick 45017944Smckusick lastbn = lblkno(&sblock, dp->di_size); 45141133Smckusick if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 45217944Smckusick return (0); 45317944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 45417944Smckusick return (0); 45517944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 45617944Smckusick dp->di_db[lastbn] = newblk; 45717944Smckusick dp->di_size += sblock.fs_bsize; 45817944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 45934225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 46044934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 46138375Smckusick if (bp->b_errs) 46217944Smckusick goto bad; 46334225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 46434225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 46538375Smckusick if (bp->b_errs) 46617944Smckusick goto bad; 46734225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 46834225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 46934225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 47017944Smckusick cp += DIRBLKSIZ) 47117944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 47234225Smckusick dirty(bp); 47334225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 47444934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 47538375Smckusick if (bp->b_errs) 47617944Smckusick goto bad; 47734225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 47840022Smckusick pwarn("NO SPACE LEFT IN %s", name); 47917944Smckusick if (preen) 48017944Smckusick printf(" (EXPANDED)\n"); 48117944Smckusick else if (reply("EXPAND") == 0) 48217944Smckusick goto bad; 48334225Smckusick dirty(bp); 48417944Smckusick inodirty(); 48517944Smckusick return (1); 48617944Smckusick bad: 48717944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 48817944Smckusick dp->di_db[lastbn + 1] = 0; 48917944Smckusick dp->di_size -= sblock.fs_bsize; 49017944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 49117944Smckusick freeblk(newblk, sblock.fs_frag); 49217944Smckusick return (0); 49317944Smckusick } 49417944Smckusick 49517944Smckusick /* 49617954Smckusick * allocate a new directory 49717954Smckusick */ 49836827Smckusick allocdir(parent, request, mode) 49917954Smckusick ino_t parent, request; 50036827Smckusick int mode; 50117954Smckusick { 50217954Smckusick ino_t ino; 50317954Smckusick char *cp; 50439973Smckusick struct dinode *dp; 50539973Smckusick register struct bufarea *bp; 50617954Smckusick 50736827Smckusick ino = allocino(request, IFDIR|mode); 50817954Smckusick dirhead.dot_ino = ino; 50917954Smckusick dirhead.dotdot_ino = parent; 51017954Smckusick dp = ginode(ino); 51134225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 51238375Smckusick if (bp->b_errs) { 51317954Smckusick freeino(ino); 51417954Smckusick return (0); 51517954Smckusick } 51634225Smckusick bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead); 51734225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 51834225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 51917954Smckusick cp += DIRBLKSIZ) 52017954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 52134225Smckusick dirty(bp); 52217954Smckusick dp->di_nlink = 2; 52317954Smckusick inodirty(); 52417954Smckusick if (ino == ROOTINO) { 52517954Smckusick lncntp[ino] = dp->di_nlink; 52650573Smckusick cacheino(dp, ino); 52717954Smckusick return(ino); 52817954Smckusick } 52917954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 53017954Smckusick freeino(ino); 53117954Smckusick return (0); 53217954Smckusick } 53350573Smckusick cacheino(dp, ino); 53417954Smckusick statemap[ino] = statemap[parent]; 53517954Smckusick if (statemap[ino] == DSTATE) { 53617954Smckusick lncntp[ino] = dp->di_nlink; 53717954Smckusick lncntp[parent]++; 53817954Smckusick } 53917954Smckusick dp = ginode(parent); 54017954Smckusick dp->di_nlink++; 54117954Smckusick inodirty(); 54217954Smckusick return (ino); 54317954Smckusick } 54417954Smckusick 54517954Smckusick /* 54617954Smckusick * free a directory inode 54717954Smckusick */ 54817954Smckusick freedir(ino, parent) 54917954Smckusick ino_t ino, parent; 55017954Smckusick { 55139973Smckusick struct dinode *dp; 55217954Smckusick 55317954Smckusick if (ino != parent) { 55417954Smckusick dp = ginode(parent); 55517954Smckusick dp->di_nlink--; 55617954Smckusick inodirty(); 55717954Smckusick } 55817954Smckusick freeino(ino); 55917954Smckusick } 56017954Smckusick 56117954Smckusick /* 56216259Smckusick * generate a temporary name for the lost+found directory. 56316259Smckusick */ 56416259Smckusick lftempname(bufp, ino) 56516259Smckusick char *bufp; 56616259Smckusick ino_t ino; 56716259Smckusick { 56816259Smckusick register ino_t in; 56916259Smckusick register char *cp; 57016259Smckusick int namlen; 57116259Smckusick 57216259Smckusick cp = bufp + 2; 57339973Smckusick for (in = maxino; in > 0; in /= 10) 57416259Smckusick cp++; 57516259Smckusick *--cp = 0; 57616259Smckusick namlen = cp - bufp; 57716259Smckusick in = ino; 57816259Smckusick while (cp > bufp) { 57916259Smckusick *--cp = (in % 10) + '0'; 58016259Smckusick in /= 10; 58116259Smckusick } 58216259Smckusick *cp = '#'; 58316259Smckusick return (namlen); 58416259Smckusick } 58534225Smckusick 58634225Smckusick /* 58734225Smckusick * Get a directory block. 58834225Smckusick * Insure that it is held until another is requested. 58934225Smckusick */ 59039973Smckusick struct bufarea * 59134225Smckusick getdirblk(blkno, size) 59234225Smckusick daddr_t blkno; 59334225Smckusick long size; 59434225Smckusick { 59534225Smckusick 59640648Smckusick if (pdirbp != 0) 59740648Smckusick pdirbp->b_flags &= ~B_INUSE; 59840648Smckusick pdirbp = getdatablk(blkno, size); 59940648Smckusick return (pdirbp); 60034225Smckusick } 601