122045Sdist /* 222045Sdist * Copyright (c) 1980 Regents of the University of California. 322045Sdist * All rights reserved. The Berkeley software License Agreement 422045Sdist * specifies the terms and conditions for redistribution. 522045Sdist */ 622045Sdist 716259Smckusick #ifndef lint 8*38375Smckusick static char sccsid[] = "@(#)dir.c 5.7 (Berkeley) 06/30/89"; 922045Sdist #endif not lint 1016259Smckusick 1116259Smckusick #include <sys/param.h> 1238336Smckusick #include <sys/time.h> 1338336Smckusick #include <sys/vnode.h> 1438336Smckusick #include <ufs/inode.h> 1538336Smckusick #include <ufs/fs.h> 1616259Smckusick #define KERNEL 1738336Smckusick #include <ufs/dir.h> 1816259Smckusick #undef KERNEL 1916259Smckusick #include "fsck.h" 2016259Smckusick 2116259Smckusick #define MINDIRSIZE (sizeof (struct dirtemplate)) 2216259Smckusick 2316259Smckusick char *endpathname = &pathname[BUFSIZ - 2]; 2416259Smckusick char *lfname = "lost+found"; 2536827Smckusick int lfmode = 01777; 2617944Smckusick struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 2717954Smckusick struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." }; 2816259Smckusick 2916259Smckusick DIRECT *fsck_readdir(); 3034225Smckusick BUFAREA *getdirblk(); 3116259Smckusick 3216259Smckusick descend(parentino, inumber) 3316259Smckusick struct inodesc *parentino; 3416259Smckusick ino_t inumber; 3516259Smckusick { 3616259Smckusick register DINODE *dp; 3716259Smckusick struct inodesc curino; 3816259Smckusick 3916259Smckusick bzero((char *)&curino, sizeof(struct inodesc)); 4017936Smckusick if (statemap[inumber] != DSTATE) 4117936Smckusick errexit("BAD INODE %d TO DESCEND", statemap[inumber]); 4217936Smckusick statemap[inumber] = DFOUND; 4317943Smckusick dp = ginode(inumber); 4416259Smckusick if (dp->di_size == 0) { 4516259Smckusick direrr(inumber, "ZERO LENGTH DIRECTORY"); 4616259Smckusick if (reply("REMOVE") == 1) 4717936Smckusick statemap[inumber] = DCLEAR; 4816259Smckusick return; 4916259Smckusick } 5016259Smckusick if (dp->di_size < MINDIRSIZE) { 5116259Smckusick direrr(inumber, "DIRECTORY TOO SHORT"); 5216259Smckusick dp->di_size = MINDIRSIZE; 5316259Smckusick if (reply("FIX") == 1) 5416259Smckusick inodirty(); 5516259Smckusick } 5621742Smckusick if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) { 5721742Smckusick pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d", 5821742Smckusick pathname, dp->di_size, DIRBLKSIZ); 5921742Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 6021742Smckusick if (preen) 6121742Smckusick printf(" (ADJUSTED)\n"); 6221742Smckusick if (preen || reply("ADJUST") == 1) 6321742Smckusick inodirty(); 6421742Smckusick } 6516259Smckusick curino.id_type = DATA; 6616259Smckusick curino.id_func = parentino->id_func; 6716259Smckusick curino.id_parent = parentino->id_number; 6816259Smckusick curino.id_number = inumber; 6916259Smckusick (void)ckinode(dp, &curino); 7030354Smckusick if (curino.id_entryno < 2) { 7130354Smckusick direrr(inumber, "NULL DIRECTORY"); 7230354Smckusick if (reply("REMOVE") == 1) 7330354Smckusick statemap[inumber] = DCLEAR; 7430354Smckusick } 7516259Smckusick } 7616259Smckusick 7716259Smckusick dirscan(idesc) 7816259Smckusick register struct inodesc *idesc; 7916259Smckusick { 8016259Smckusick register DIRECT *dp; 8134225Smckusick register BUFAREA *bp; 8216259Smckusick int dsize, n; 8316259Smckusick long blksiz; 8416259Smckusick char dbuf[DIRBLKSIZ]; 8516259Smckusick 8616259Smckusick if (idesc->id_type != DATA) 8716259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 8817993Smckusick if (idesc->id_entryno == 0 && 8917993Smckusick (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 9017993Smckusick idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 9116259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 9216259Smckusick if (outrange(idesc->id_blkno, idesc->id_numfrags)) { 9316259Smckusick idesc->id_filesize -= blksiz; 9416259Smckusick return (SKIP); 9516259Smckusick } 9616259Smckusick idesc->id_loc = 0; 9716259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 9816259Smckusick dsize = dp->d_reclen; 9916259Smckusick bcopy((char *)dp, dbuf, dsize); 10016259Smckusick idesc->id_dirp = (DIRECT *)dbuf; 10116259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 10234225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 10330354Smckusick bcopy(dbuf, (char *)dp, dsize); 10434225Smckusick dirty(bp); 10530354Smckusick sbdirty(); 10616259Smckusick } 10716259Smckusick if (n & STOP) 10816259Smckusick return (n); 10916259Smckusick } 11016259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 11116259Smckusick } 11216259Smckusick 11316259Smckusick /* 11416259Smckusick * get next entry in a directory. 11516259Smckusick */ 11616259Smckusick DIRECT * 11716259Smckusick fsck_readdir(idesc) 11816259Smckusick register struct inodesc *idesc; 11916259Smckusick { 12016259Smckusick register DIRECT *dp, *ndp; 12134225Smckusick register BUFAREA *bp; 12216259Smckusick long size, blksiz; 12316259Smckusick 12416259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 12534225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 12616259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 12716259Smckusick idesc->id_loc < blksiz) { 12834225Smckusick dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); 12916259Smckusick if (dircheck(idesc, dp)) 13016259Smckusick goto dpok; 13116259Smckusick idesc->id_loc += DIRBLKSIZ; 13216259Smckusick idesc->id_filesize -= DIRBLKSIZ; 13316259Smckusick dp->d_reclen = DIRBLKSIZ; 13416259Smckusick dp->d_ino = 0; 13516259Smckusick dp->d_namlen = 0; 13616259Smckusick dp->d_name[0] = '\0'; 13717930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 13834225Smckusick dirty(bp); 13916259Smckusick return (dp); 14016259Smckusick } 14116259Smckusick dpok: 14216259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 14316259Smckusick return NULL; 14434225Smckusick dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); 14516259Smckusick idesc->id_loc += dp->d_reclen; 14616259Smckusick idesc->id_filesize -= dp->d_reclen; 14716259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 14816259Smckusick return (dp); 14934225Smckusick ndp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); 15016259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 15116259Smckusick dircheck(idesc, ndp) == 0) { 15216259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 15316259Smckusick dp->d_reclen += size; 15416259Smckusick idesc->id_loc += size; 15516259Smckusick idesc->id_filesize -= size; 15617930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 15734225Smckusick dirty(bp); 15816259Smckusick } 15916259Smckusick return (dp); 16016259Smckusick } 16116259Smckusick 16216259Smckusick /* 16316259Smckusick * Verify that a directory entry is valid. 16416259Smckusick * This is a superset of the checks made in the kernel. 16516259Smckusick */ 16616259Smckusick dircheck(idesc, dp) 16716259Smckusick struct inodesc *idesc; 16816259Smckusick register DIRECT *dp; 16916259Smckusick { 17016259Smckusick register int size; 17116259Smckusick register char *cp; 17216259Smckusick int spaceleft; 17316259Smckusick 17416259Smckusick size = DIRSIZ(dp); 17516259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 17616259Smckusick if (dp->d_ino < imax && 17716259Smckusick dp->d_reclen != 0 && 17816259Smckusick dp->d_reclen <= spaceleft && 17916259Smckusick (dp->d_reclen & 0x3) == 0 && 18016259Smckusick dp->d_reclen >= size && 18116259Smckusick idesc->id_filesize >= size && 18216259Smckusick dp->d_namlen <= MAXNAMLEN) { 18316259Smckusick if (dp->d_ino == 0) 18416259Smckusick return (1); 18516259Smckusick for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 18616259Smckusick if (*cp == 0 || (*cp++ & 0200)) 18716259Smckusick return (0); 18816259Smckusick if (*cp == 0) 18916259Smckusick return (1); 19016259Smckusick } 19116259Smckusick return (0); 19216259Smckusick } 19316259Smckusick 19416259Smckusick direrr(ino, s) 19516259Smckusick ino_t ino; 19616259Smckusick char *s; 19716259Smckusick { 19816259Smckusick register DINODE *dp; 19916259Smckusick 20016259Smckusick pwarn("%s ", s); 20116259Smckusick pinode(ino); 20216259Smckusick printf("\n"); 20317943Smckusick if (ino < ROOTINO || ino > imax) { 20417943Smckusick pfatal("NAME=%s\n", pathname); 20517943Smckusick return; 20617943Smckusick } 20717943Smckusick dp = ginode(ino); 20817943Smckusick if (ftypeok(dp)) 20917930Smckusick pfatal("%s=%s\n", DIRCT(dp) ? "DIR" : "FILE", pathname); 21016259Smckusick else 21116259Smckusick pfatal("NAME=%s\n", pathname); 21216259Smckusick } 21316259Smckusick 21416259Smckusick adjust(idesc, lcnt) 21516259Smckusick register struct inodesc *idesc; 21616259Smckusick short lcnt; 21716259Smckusick { 21816259Smckusick register 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 : 22617930Smckusick (DIRCT(dp) ? "DIR" : "FILE")); 22716259Smckusick pinode(idesc->id_number); 22816259Smckusick printf(" COUNT %d SHOULD BE %d", 22916259Smckusick 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 { 24716259Smckusick register DIRECT *dirp = idesc->id_dirp; 24816259Smckusick DIRECT newent; 24916259Smckusick int newlen, oldlen; 25016259Smckusick 25116259Smckusick newent.d_namlen = 11; 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; 26417954Smckusick dirp->d_namlen = strlen(idesc->id_name); 26517954Smckusick bcopy(idesc->id_name, dirp->d_name, dirp->d_namlen + 1); 26616259Smckusick return (ALTERED|STOP); 26716259Smckusick } 26816259Smckusick 26917957Smckusick chgino(idesc) 27016259Smckusick struct inodesc *idesc; 27116259Smckusick { 27216259Smckusick register DIRECT *dirp = idesc->id_dirp; 27316259Smckusick 27417957Smckusick if (bcmp(dirp->d_name, idesc->id_name, dirp->d_namlen + 1)) 27517957Smckusick return (KEEPON); 27617957Smckusick dirp->d_ino = idesc->id_parent;; 27717957Smckusick return (ALTERED|STOP); 27816259Smckusick } 27916259Smckusick 28016259Smckusick linkup(orphan, pdir) 28116259Smckusick ino_t orphan; 28216259Smckusick ino_t pdir; 28316259Smckusick { 28416259Smckusick register DINODE *dp; 28516259Smckusick int lostdir, len; 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); 29317930Smckusick lostdir = DIRCT(dp); 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 pathp = pathname; 30416259Smckusick *pathp++ = '/'; 30516259Smckusick *pathp = '\0'; 30616259Smckusick if (lfdir == 0) { 30717943Smckusick dp = ginode(ROOTINO); 30817930Smckusick idesc.id_name = lfname; 30916259Smckusick idesc.id_type = DATA; 31016259Smckusick idesc.id_func = findino; 31116259Smckusick idesc.id_number = ROOTINO; 31230354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 31317954Smckusick lfdir = idesc.id_parent; 31417954Smckusick } else { 31517954Smckusick pwarn("NO lost+found DIRECTORY"); 31617954Smckusick if (preen || reply("CREATE")) { 31736827Smckusick lfdir = allocdir(ROOTINO, 0, lfmode); 31817992Smckusick if (lfdir != 0) { 31917992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 32017954Smckusick if (preen) 32117954Smckusick printf(" (CREATED)\n"); 32217954Smckusick } else { 32317992Smckusick freedir(lfdir, ROOTINO); 32417992Smckusick lfdir = 0; 32517954Smckusick if (preen) 32617954Smckusick printf("\n"); 32717954Smckusick } 32817954Smckusick } 32917954Smckusick } 33017954Smckusick } 33117943Smckusick if (lfdir == 0) { 33217954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 33316259Smckusick printf("\n\n"); 33416259Smckusick return (0); 33516259Smckusick } 33616259Smckusick } 33717943Smckusick dp = ginode(lfdir); 33817957Smckusick if (!DIRCT(dp)) { 33917957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 34017957Smckusick if (reply("REALLOCATE") == 0) 34117957Smckusick return (0); 34217957Smckusick oldlfdir = lfdir; 34336827Smckusick if ((lfdir = allocdir(ROOTINO, 0, lfmode)) == 0) { 34417957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 34517957Smckusick return (0); 34617957Smckusick } 34717957Smckusick idesc.id_type = DATA; 34817957Smckusick idesc.id_func = chgino; 34917957Smckusick idesc.id_number = ROOTINO; 35017957Smckusick idesc.id_parent = lfdir; /* new inumber for lost+found */ 35117957Smckusick idesc.id_name = lfname; 35217957Smckusick if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) { 35317957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 35417957Smckusick return (0); 35517957Smckusick } 35617957Smckusick inodirty(); 35717957Smckusick idesc.id_type = ADDR; 35817957Smckusick idesc.id_func = pass4check; 35917957Smckusick idesc.id_number = oldlfdir; 36017957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 36117957Smckusick lncntp[oldlfdir] = 0; 36217957Smckusick dp = ginode(lfdir); 36317957Smckusick } 36417957Smckusick if (statemap[lfdir] != DFOUND) { 36517957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 36616259Smckusick return (0); 36716259Smckusick } 36816259Smckusick len = strlen(lfname); 36916259Smckusick bcopy(lfname, pathp, len + 1); 37016259Smckusick pathp += len; 37117992Smckusick len = lftempname(tempname, orphan); 37217992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 37316259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 37416259Smckusick printf("\n\n"); 37516259Smckusick return (0); 37616259Smckusick } 37716259Smckusick lncntp[orphan]--; 37816259Smckusick *pathp++ = '/'; 37930155Smckusick bcopy(tempname, pathp, len + 1); 38017954Smckusick pathp += len; 38116259Smckusick if (lostdir) { 38216259Smckusick dp = ginode(orphan); 38316259Smckusick idesc.id_type = DATA; 38417957Smckusick idesc.id_func = chgino; 38516259Smckusick idesc.id_number = orphan; 38616259Smckusick idesc.id_fix = DONTKNOW; 38717957Smckusick idesc.id_name = ".."; 38817957Smckusick idesc.id_parent = lfdir; /* new value for ".." */ 38916259Smckusick (void)ckinode(dp, &idesc); 39017943Smckusick dp = ginode(lfdir); 39117943Smckusick dp->di_nlink++; 39217943Smckusick inodirty(); 39317943Smckusick lncntp[lfdir]++; 39416259Smckusick pwarn("DIR I=%u CONNECTED. ", orphan); 39516259Smckusick printf("PARENT WAS I=%u\n", pdir); 39616259Smckusick if (preen == 0) 39716259Smckusick printf("\n"); 39816259Smckusick } 39916259Smckusick return (1); 40016259Smckusick } 40116259Smckusick 40216259Smckusick /* 40317944Smckusick * make an entry in a directory 40417944Smckusick */ 40517992Smckusick makeentry(parent, ino, name) 40617992Smckusick ino_t parent, ino; 40717992Smckusick char *name; 40817992Smckusick { 40917944Smckusick DINODE *dp; 41017992Smckusick struct inodesc idesc; 41117944Smckusick 41217992Smckusick if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax) 41317992Smckusick return (0); 41417992Smckusick bzero(&idesc, sizeof(struct inodesc)); 41517992Smckusick idesc.id_type = DATA; 41617992Smckusick idesc.id_func = mkentry; 41717992Smckusick idesc.id_number = parent; 41817992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 41917992Smckusick idesc.id_fix = DONTKNOW; 42017992Smckusick idesc.id_name = name; 42117992Smckusick dp = ginode(parent); 42217993Smckusick if (dp->di_size % DIRBLKSIZ) { 42317993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 42417993Smckusick inodirty(); 42517993Smckusick } 42617992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 42717944Smckusick return (1); 42817944Smckusick if (expanddir(dp) == 0) 42917944Smckusick return (0); 43017992Smckusick return (ckinode(dp, &idesc) & ALTERED); 43117944Smckusick } 43217944Smckusick 43317944Smckusick /* 43417944Smckusick * Attempt to expand the size of a directory 43517944Smckusick */ 43617944Smckusick expanddir(dp) 43717944Smckusick register DINODE *dp; 43817944Smckusick { 43917944Smckusick daddr_t lastbn, newblk; 44034225Smckusick register BUFAREA *bp; 44117944Smckusick char *cp, firstblk[DIRBLKSIZ]; 44217944Smckusick 44317944Smckusick lastbn = lblkno(&sblock, dp->di_size); 44417944Smckusick if (lastbn >= NDADDR - 1) 44517944Smckusick return (0); 44617944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 44717944Smckusick return (0); 44817944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 44917944Smckusick dp->di_db[lastbn] = newblk; 45017944Smckusick dp->di_size += sblock.fs_bsize; 45117944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 45234225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 45334225Smckusick dblksize(&sblock, dp, lastbn + 1)); 454*38375Smckusick if (bp->b_errs) 45517944Smckusick goto bad; 45634225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 45734225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 458*38375Smckusick if (bp->b_errs) 45917944Smckusick goto bad; 46034225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 46134225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 46234225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 46317944Smckusick cp += DIRBLKSIZ) 46417944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 46534225Smckusick dirty(bp); 46634225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 46734225Smckusick dblksize(&sblock, dp, lastbn + 1)); 468*38375Smckusick if (bp->b_errs) 46917944Smckusick goto bad; 47034225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 47117944Smckusick pwarn("NO SPACE LEFT IN %s", pathname); 47217944Smckusick if (preen) 47317944Smckusick printf(" (EXPANDED)\n"); 47417944Smckusick else if (reply("EXPAND") == 0) 47517944Smckusick goto bad; 47634225Smckusick dirty(bp); 47717944Smckusick inodirty(); 47817944Smckusick return (1); 47917944Smckusick bad: 48017944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 48117944Smckusick dp->di_db[lastbn + 1] = 0; 48217944Smckusick dp->di_size -= sblock.fs_bsize; 48317944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 48417944Smckusick freeblk(newblk, sblock.fs_frag); 48517944Smckusick return (0); 48617944Smckusick } 48717944Smckusick 48817944Smckusick /* 48917954Smckusick * allocate a new directory 49017954Smckusick */ 49136827Smckusick allocdir(parent, request, mode) 49217954Smckusick ino_t parent, request; 49336827Smckusick int mode; 49417954Smckusick { 49517954Smckusick ino_t ino; 49617954Smckusick char *cp; 49717954Smckusick DINODE *dp; 49834225Smckusick register BUFAREA *bp; 49917954Smckusick 50036827Smckusick ino = allocino(request, IFDIR|mode); 50117954Smckusick dirhead.dot_ino = ino; 50217954Smckusick dirhead.dotdot_ino = parent; 50317954Smckusick dp = ginode(ino); 50434225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 505*38375Smckusick if (bp->b_errs) { 50617954Smckusick freeino(ino); 50717954Smckusick return (0); 50817954Smckusick } 50934225Smckusick bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead); 51034225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 51134225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 51217954Smckusick cp += DIRBLKSIZ) 51317954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 51434225Smckusick dirty(bp); 51517954Smckusick dp->di_nlink = 2; 51617954Smckusick inodirty(); 51717954Smckusick if (ino == ROOTINO) { 51817954Smckusick lncntp[ino] = dp->di_nlink; 51917954Smckusick return(ino); 52017954Smckusick } 52117954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 52217954Smckusick freeino(ino); 52317954Smckusick return (0); 52417954Smckusick } 52517954Smckusick statemap[ino] = statemap[parent]; 52617954Smckusick if (statemap[ino] == DSTATE) { 52717954Smckusick lncntp[ino] = dp->di_nlink; 52817954Smckusick lncntp[parent]++; 52917954Smckusick } 53017954Smckusick dp = ginode(parent); 53117954Smckusick dp->di_nlink++; 53217954Smckusick inodirty(); 53317954Smckusick return (ino); 53417954Smckusick } 53517954Smckusick 53617954Smckusick /* 53717954Smckusick * free a directory inode 53817954Smckusick */ 53917954Smckusick freedir(ino, parent) 54017954Smckusick ino_t ino, parent; 54117954Smckusick { 54217954Smckusick DINODE *dp; 54317954Smckusick 54417954Smckusick if (ino != parent) { 54517954Smckusick dp = ginode(parent); 54617954Smckusick dp->di_nlink--; 54717954Smckusick inodirty(); 54817954Smckusick } 54917954Smckusick freeino(ino); 55017954Smckusick } 55117954Smckusick 55217954Smckusick /* 55316259Smckusick * generate a temporary name for the lost+found directory. 55416259Smckusick */ 55516259Smckusick lftempname(bufp, ino) 55616259Smckusick char *bufp; 55716259Smckusick ino_t ino; 55816259Smckusick { 55916259Smckusick register ino_t in; 56016259Smckusick register char *cp; 56116259Smckusick int namlen; 56216259Smckusick 56316259Smckusick cp = bufp + 2; 56416259Smckusick for (in = imax; in > 0; in /= 10) 56516259Smckusick cp++; 56616259Smckusick *--cp = 0; 56716259Smckusick namlen = cp - bufp; 56816259Smckusick in = ino; 56916259Smckusick while (cp > bufp) { 57016259Smckusick *--cp = (in % 10) + '0'; 57116259Smckusick in /= 10; 57216259Smckusick } 57316259Smckusick *cp = '#'; 57416259Smckusick return (namlen); 57516259Smckusick } 57634225Smckusick 57734225Smckusick /* 57834225Smckusick * Get a directory block. 57934225Smckusick * Insure that it is held until another is requested. 58034225Smckusick */ 58134225Smckusick BUFAREA * 58234225Smckusick getdirblk(blkno, size) 58334225Smckusick daddr_t blkno; 58434225Smckusick long size; 58534225Smckusick { 58634225Smckusick static BUFAREA *pbp = 0; 58734225Smckusick 58834225Smckusick if (pbp != 0) 58934225Smckusick pbp->b_flags &= ~B_INUSE; 59034225Smckusick pbp = getdatablk(blkno, size); 59134225Smckusick return (pbp); 59234225Smckusick } 593