122045Sdist /* 261492Sbostic * Copyright (c) 1980, 1986, 1993 361492Sbostic * The Regents of the University of California. All rights reserved. 439976Smckusick * 542701Sbostic * %sccs.include.redist.c% 622045Sdist */ 722045Sdist 816259Smckusick #ifndef lint 9*68908Smckusick static char sccsid[] = "@(#)dir.c 8.7 (Berkeley) 04/27/95"; 1039976Smckusick #endif /* not lint */ 1116259Smckusick 1216259Smckusick #include <sys/param.h> 1353702Smckusick #include <sys/time.h> 14*68908Smckusick 1551532Sbostic #include <ufs/ufs/dinode.h> 1651532Sbostic #include <ufs/ufs/dir.h> 1751532Sbostic #include <ufs/ffs/fs.h> 18*68908Smckusick 19*68908Smckusick #include <err.h> 2044934Smckusick #include <string.h> 21*68908Smckusick 2216259Smckusick #include "fsck.h" 2316259Smckusick 2416259Smckusick char *lfname = "lost+found"; 2536827Smckusick int lfmode = 01777; 2617944Smckusick struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 2754604Smckusick struct dirtemplate dirhead = { 2854604Smckusick 0, 12, DT_DIR, 1, ".", 2954604Smckusick 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 3054604Smckusick }; 3154604Smckusick struct odirtemplate odirhead = { 3254604Smckusick 0, 12, 1, ".", 3354604Smckusick 0, DIRBLKSIZ - 12, 2, ".." 3454604Smckusick }; 3516259Smckusick 36*68908Smckusick static int chgino __P((struct inodesc *)); 37*68908Smckusick static int dircheck __P((struct inodesc *, struct direct *)); 38*68908Smckusick static int expanddir __P((struct dinode *dp, char *name)); 39*68908Smckusick static void freedir __P((ino_t ino, ino_t parent)); 40*68908Smckusick static struct direct *fsck_readdir __P((struct inodesc *)); 41*68908Smckusick static struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 42*68908Smckusick static int lftempname __P((char *bufp, ino_t ino)); 43*68908Smckusick static int mkentry __P((struct inodesc *)); 4416259Smckusick 4540022Smckusick /* 4640022Smckusick * Propagate connected state through the tree. 4740022Smckusick */ 48*68908Smckusick void 4940022Smckusick propagate() 5016259Smckusick { 5140022Smckusick register struct inoinfo **inpp, *inp; 5240022Smckusick struct inoinfo **inpend; 5340022Smckusick long change; 5416259Smckusick 5540022Smckusick inpend = &inpsort[inplast]; 5640022Smckusick do { 5740022Smckusick change = 0; 5840022Smckusick for (inpp = inpsort; inpp < inpend; inpp++) { 5940022Smckusick inp = *inpp; 6040022Smckusick if (inp->i_parent == 0) 6140022Smckusick continue; 6240022Smckusick if (statemap[inp->i_parent] == DFOUND && 6340022Smckusick statemap[inp->i_number] == DSTATE) { 6440022Smckusick statemap[inp->i_number] = DFOUND; 6540022Smckusick change++; 6640022Smckusick } 6739980Smckusick } 6840022Smckusick } while (change > 0); 6916259Smckusick } 7016259Smckusick 7140022Smckusick /* 7240022Smckusick * Scan each entry in a directory block. 7340022Smckusick */ 74*68908Smckusick int 7516259Smckusick dirscan(idesc) 7616259Smckusick register struct inodesc *idesc; 7716259Smckusick { 7839973Smckusick register struct direct *dp; 7939973Smckusick register struct bufarea *bp; 8016259Smckusick int dsize, n; 8116259Smckusick long blksiz; 8216259Smckusick char dbuf[DIRBLKSIZ]; 8316259Smckusick 8416259Smckusick if (idesc->id_type != DATA) 85*68908Smckusick errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 8617993Smckusick if (idesc->id_entryno == 0 && 8717993Smckusick (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 8817993Smckusick idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 8916259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 9039973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 9116259Smckusick idesc->id_filesize -= blksiz; 9216259Smckusick return (SKIP); 9316259Smckusick } 9416259Smckusick idesc->id_loc = 0; 9516259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 9616259Smckusick dsize = dp->d_reclen; 9744934Smckusick bcopy((char *)dp, dbuf, (size_t)dsize); 9854604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 9954604Smckusick if (!newinofmt) { 10054604Smckusick struct direct *tdp = (struct direct *)dbuf; 10154604Smckusick u_char tmp; 10254604Smckusick 10354604Smckusick tmp = tdp->d_namlen; 10454604Smckusick tdp->d_namlen = tdp->d_type; 10554604Smckusick tdp->d_type = tmp; 10654604Smckusick } 10754604Smckusick # endif 10839973Smckusick idesc->id_dirp = (struct direct *)dbuf; 10916259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 11054604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 11154604Smckusick if (!newinofmt && !doinglevel2) { 11254604Smckusick struct direct *tdp; 11354604Smckusick u_char tmp; 11454604Smckusick 11554604Smckusick tdp = (struct direct *)dbuf; 11654604Smckusick tmp = tdp->d_namlen; 11754604Smckusick tdp->d_namlen = tdp->d_type; 11854604Smckusick tdp->d_type = tmp; 11954604Smckusick } 12054604Smckusick # endif 12134225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 12240570Smckusick bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, 12344934Smckusick (size_t)dsize); 12434225Smckusick dirty(bp); 12530354Smckusick sbdirty(); 12616259Smckusick } 12716259Smckusick if (n & STOP) 12816259Smckusick return (n); 12916259Smckusick } 13016259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 13116259Smckusick } 13216259Smckusick 13316259Smckusick /* 13416259Smckusick * get next entry in a directory. 13516259Smckusick */ 136*68908Smckusick static struct direct * 13716259Smckusick fsck_readdir(idesc) 13816259Smckusick register struct inodesc *idesc; 13916259Smckusick { 14039973Smckusick register struct direct *dp, *ndp; 14139973Smckusick register struct bufarea *bp; 14254604Smckusick long size, blksiz, fix, dploc; 14316259Smckusick 14416259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 14534225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 14616259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 14716259Smckusick idesc->id_loc < blksiz) { 14839973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 14916259Smckusick if (dircheck(idesc, dp)) 15016259Smckusick goto dpok; 15167863Smckusick if (idesc->id_fix == IGNORE) 15267863Smckusick return (0); 15340570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 15440570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 15540570Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 15616259Smckusick dp->d_reclen = DIRBLKSIZ; 15716259Smckusick dp->d_ino = 0; 15854604Smckusick dp->d_type = 0; 15916259Smckusick dp->d_namlen = 0; 16016259Smckusick dp->d_name[0] = '\0'; 16140570Smckusick if (fix) 16234225Smckusick dirty(bp); 16359302Smckusick idesc->id_loc += DIRBLKSIZ; 16459302Smckusick idesc->id_filesize -= DIRBLKSIZ; 16516259Smckusick return (dp); 16616259Smckusick } 16716259Smckusick dpok: 16816259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 16916259Smckusick return NULL; 17054604Smckusick dploc = idesc->id_loc; 17154604Smckusick dp = (struct direct *)(bp->b_un.b_buf + dploc); 17216259Smckusick idesc->id_loc += dp->d_reclen; 17316259Smckusick idesc->id_filesize -= dp->d_reclen; 17416259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 17516259Smckusick return (dp); 17639973Smckusick ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 17716259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 17816259Smckusick dircheck(idesc, ndp) == 0) { 17916259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 18016259Smckusick idesc->id_loc += size; 18116259Smckusick idesc->id_filesize -= size; 18267863Smckusick if (idesc->id_fix == IGNORE) 18367863Smckusick return (0); 18440570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 18540570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 18654604Smckusick dp = (struct direct *)(bp->b_un.b_buf + dploc); 18740570Smckusick dp->d_reclen += size; 18840570Smckusick if (fix) 18934225Smckusick dirty(bp); 19016259Smckusick } 19116259Smckusick return (dp); 19216259Smckusick } 19316259Smckusick 19416259Smckusick /* 19516259Smckusick * Verify that a directory entry is valid. 19616259Smckusick * This is a superset of the checks made in the kernel. 19716259Smckusick */ 198*68908Smckusick static int 19916259Smckusick dircheck(idesc, dp) 20016259Smckusick struct inodesc *idesc; 20139973Smckusick register struct direct *dp; 20216259Smckusick { 20316259Smckusick register int size; 20416259Smckusick register char *cp; 20554604Smckusick u_char namlen, type; 20616259Smckusick int spaceleft; 20716259Smckusick 20868062Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 20968062Smckusick if (dp->d_ino >= maxino || 21068062Smckusick dp->d_reclen == 0 || 21168062Smckusick dp->d_reclen > spaceleft || 21268062Smckusick (dp->d_reclen & 0x3) != 0) 21368062Smckusick return (0); 21468062Smckusick if (dp->d_ino == 0) 21568062Smckusick return (1); 21654604Smckusick size = DIRSIZ(!newinofmt, dp); 21754604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 21854604Smckusick if (!newinofmt) { 21954604Smckusick type = dp->d_namlen; 22054604Smckusick namlen = dp->d_type; 22154604Smckusick } else { 22254604Smckusick namlen = dp->d_namlen; 22354604Smckusick type = dp->d_type; 22454604Smckusick } 22554604Smckusick # else 22654604Smckusick namlen = dp->d_namlen; 22754604Smckusick type = dp->d_type; 22854604Smckusick # endif 22968062Smckusick if (dp->d_reclen < size || 23068062Smckusick idesc->id_filesize < size || 23168062Smckusick namlen > MAXNAMLEN || 23268062Smckusick type > 15) 23368062Smckusick return (0); 23468062Smckusick for (cp = dp->d_name, size = 0; size < namlen; size++) 23568062Smckusick if (*cp == '\0' || (*cp++ == '/')) 23668062Smckusick return (0); 23768062Smckusick if (*cp != '\0') 23868062Smckusick return (0); 23968062Smckusick return (1); 24016259Smckusick } 24116259Smckusick 242*68908Smckusick void 24339973Smckusick direrror(ino, errmesg) 24416259Smckusick ino_t ino; 24539973Smckusick char *errmesg; 24616259Smckusick { 24740022Smckusick 24840022Smckusick fileerror(ino, ino, errmesg); 24940022Smckusick } 25040022Smckusick 251*68908Smckusick void 25240022Smckusick fileerror(cwd, ino, errmesg) 25340022Smckusick ino_t cwd, ino; 25440022Smckusick char *errmesg; 25540022Smckusick { 25639973Smckusick register struct dinode *dp; 25740022Smckusick char pathbuf[MAXPATHLEN + 1]; 25816259Smckusick 25939973Smckusick pwarn("%s ", errmesg); 26016259Smckusick pinode(ino); 26116259Smckusick printf("\n"); 26240022Smckusick getpathname(pathbuf, cwd, ino); 26339973Smckusick if (ino < ROOTINO || ino > maxino) { 26440022Smckusick pfatal("NAME=%s\n", pathbuf); 26517943Smckusick return; 26617943Smckusick } 26717943Smckusick dp = ginode(ino); 26817943Smckusick if (ftypeok(dp)) 26939973Smckusick pfatal("%s=%s\n", 27040022Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 27116259Smckusick else 27240022Smckusick pfatal("NAME=%s\n", pathbuf); 27316259Smckusick } 27416259Smckusick 275*68908Smckusick void 27616259Smckusick adjust(idesc, lcnt) 27716259Smckusick register struct inodesc *idesc; 278*68908Smckusick int lcnt; 27916259Smckusick { 28039973Smckusick register struct dinode *dp; 28116259Smckusick 28217943Smckusick dp = ginode(idesc->id_number); 28316259Smckusick if (dp->di_nlink == lcnt) { 28416259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 28516259Smckusick clri(idesc, "UNREF", 0); 28617936Smckusick } else { 28717930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 28839973Smckusick ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 28916259Smckusick pinode(idesc->id_number); 29016259Smckusick printf(" COUNT %d SHOULD BE %d", 29139973Smckusick dp->di_nlink, dp->di_nlink - lcnt); 29216259Smckusick if (preen) { 29316259Smckusick if (lcnt < 0) { 29416259Smckusick printf("\n"); 29517930Smckusick pfatal("LINK COUNT INCREASING"); 29616259Smckusick } 29716259Smckusick printf(" (ADJUSTED)\n"); 29816259Smckusick } 29916259Smckusick if (preen || reply("ADJUST") == 1) { 30016259Smckusick dp->di_nlink -= lcnt; 30116259Smckusick inodirty(); 30216259Smckusick } 30316259Smckusick } 30416259Smckusick } 30516259Smckusick 306*68908Smckusick static int 30716259Smckusick mkentry(idesc) 30816259Smckusick struct inodesc *idesc; 30916259Smckusick { 31039973Smckusick register struct direct *dirp = idesc->id_dirp; 31139973Smckusick struct direct newent; 31216259Smckusick int newlen, oldlen; 31316259Smckusick 31440022Smckusick newent.d_namlen = strlen(idesc->id_name); 31554604Smckusick newlen = DIRSIZ(0, &newent); 31616259Smckusick if (dirp->d_ino != 0) 31754604Smckusick oldlen = DIRSIZ(0, dirp); 31816259Smckusick else 31916259Smckusick oldlen = 0; 32016259Smckusick if (dirp->d_reclen - oldlen < newlen) 32116259Smckusick return (KEEPON); 32216259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 32316259Smckusick dirp->d_reclen = oldlen; 32416259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 32516259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 32668061Smckusick dirp->d_reclen = newent.d_reclen; 32768061Smckusick if (newinofmt) 32854604Smckusick dirp->d_type = typemap[idesc->id_parent]; 32968061Smckusick else 33068061Smckusick dirp->d_type = 0; 33168061Smckusick dirp->d_namlen = newent.d_namlen; 33267586Smckusick bcopy(idesc->id_name, dirp->d_name, (size_t)newent.d_namlen + 1); 33368061Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 33468061Smckusick /* 33568061Smckusick * If the entry was split, dirscan() will only reverse the byte 33668061Smckusick * order of the original entry, and not the new one, before 33768061Smckusick * writing it back out. So, we reverse the byte order here if 33868061Smckusick * necessary. 33968061Smckusick */ 34068061Smckusick if (oldlen != 0 && !newinofmt && !doinglevel2) { 34168061Smckusick u_char tmp; 34268061Smckusick 34368061Smckusick tmp = dirp->d_namlen; 34468061Smckusick dirp->d_namlen = dirp->d_type; 34568061Smckusick dirp->d_type = tmp; 34668061Smckusick } 34768061Smckusick # endif 34816259Smckusick return (ALTERED|STOP); 34916259Smckusick } 35016259Smckusick 351*68908Smckusick static int 35217957Smckusick chgino(idesc) 35316259Smckusick struct inodesc *idesc; 35416259Smckusick { 35539973Smckusick register struct direct *dirp = idesc->id_dirp; 35616259Smckusick 35739973Smckusick if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 35817957Smckusick return (KEEPON); 35939973Smckusick dirp->d_ino = idesc->id_parent; 36054604Smckusick if (newinofmt) 36154604Smckusick dirp->d_type = typemap[idesc->id_parent]; 36255074Smckusick else 36355074Smckusick dirp->d_type = 0; 36417957Smckusick return (ALTERED|STOP); 36516259Smckusick } 36616259Smckusick 367*68908Smckusick int 36839973Smckusick linkup(orphan, parentdir) 36916259Smckusick ino_t orphan; 37039973Smckusick ino_t parentdir; 37116259Smckusick { 37239973Smckusick register struct dinode *dp; 37340022Smckusick int lostdir; 37417954Smckusick ino_t oldlfdir; 37516259Smckusick struct inodesc idesc; 37617954Smckusick char tempname[BUFSIZ]; 37717957Smckusick extern int pass4check(); 37816259Smckusick 37916259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 38017943Smckusick dp = ginode(orphan); 38139973Smckusick lostdir = (dp->di_mode & IFMT) == IFDIR; 38216259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 38316259Smckusick pinode(orphan); 38416259Smckusick if (preen && dp->di_size == 0) 38516259Smckusick return (0); 38616259Smckusick if (preen) 38716259Smckusick printf(" (RECONNECTED)\n"); 38816259Smckusick else 38916259Smckusick if (reply("RECONNECT") == 0) 39016259Smckusick return (0); 39116259Smckusick if (lfdir == 0) { 39217943Smckusick dp = ginode(ROOTINO); 39317930Smckusick idesc.id_name = lfname; 39416259Smckusick idesc.id_type = DATA; 39516259Smckusick idesc.id_func = findino; 39616259Smckusick idesc.id_number = ROOTINO; 39730354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 39817954Smckusick lfdir = idesc.id_parent; 39917954Smckusick } else { 40017954Smckusick pwarn("NO lost+found DIRECTORY"); 40117954Smckusick if (preen || reply("CREATE")) { 40239973Smckusick lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 40317992Smckusick if (lfdir != 0) { 40417992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 40517954Smckusick if (preen) 40617954Smckusick printf(" (CREATED)\n"); 40717954Smckusick } else { 40817992Smckusick freedir(lfdir, ROOTINO); 40917992Smckusick lfdir = 0; 41017954Smckusick if (preen) 41117954Smckusick printf("\n"); 41217954Smckusick } 41317954Smckusick } 41417954Smckusick } 41517954Smckusick } 41617943Smckusick if (lfdir == 0) { 41717954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 41816259Smckusick printf("\n\n"); 41916259Smckusick return (0); 42016259Smckusick } 42116259Smckusick } 42217943Smckusick dp = ginode(lfdir); 42339973Smckusick if ((dp->di_mode & IFMT) != IFDIR) { 42417957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 42517957Smckusick if (reply("REALLOCATE") == 0) 42617957Smckusick return (0); 42717957Smckusick oldlfdir = lfdir; 42839973Smckusick if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 42917957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 43017957Smckusick return (0); 43117957Smckusick } 43240022Smckusick if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 43317957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 43417957Smckusick return (0); 43517957Smckusick } 43617957Smckusick inodirty(); 43717957Smckusick idesc.id_type = ADDR; 43817957Smckusick idesc.id_func = pass4check; 43917957Smckusick idesc.id_number = oldlfdir; 44017957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 44117957Smckusick lncntp[oldlfdir] = 0; 44217957Smckusick dp = ginode(lfdir); 44317957Smckusick } 44417957Smckusick if (statemap[lfdir] != DFOUND) { 44517957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 44616259Smckusick return (0); 44716259Smckusick } 44840022Smckusick (void)lftempname(tempname, orphan); 44917992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 45016259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 45116259Smckusick printf("\n\n"); 45216259Smckusick return (0); 45316259Smckusick } 45416259Smckusick lncntp[orphan]--; 45516259Smckusick if (lostdir) { 45640022Smckusick if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 45740022Smckusick parentdir != (ino_t)-1) 45844934Smckusick (void)makeentry(orphan, lfdir, ".."); 45917943Smckusick dp = ginode(lfdir); 46017943Smckusick dp->di_nlink++; 46117943Smckusick inodirty(); 46217943Smckusick lncntp[lfdir]++; 46344934Smckusick pwarn("DIR I=%lu CONNECTED. ", orphan); 46440022Smckusick if (parentdir != (ino_t)-1) 46544934Smckusick printf("PARENT WAS I=%lu\n", parentdir); 46616259Smckusick if (preen == 0) 46716259Smckusick printf("\n"); 46816259Smckusick } 46916259Smckusick return (1); 47016259Smckusick } 47116259Smckusick 47216259Smckusick /* 47340022Smckusick * fix an entry in a directory. 47440022Smckusick */ 475*68908Smckusick int 47640022Smckusick changeino(dir, name, newnum) 47740022Smckusick ino_t dir; 47840022Smckusick char *name; 47940022Smckusick ino_t newnum; 48040022Smckusick { 48140022Smckusick struct inodesc idesc; 48240022Smckusick 48340022Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 48440022Smckusick idesc.id_type = DATA; 48540022Smckusick idesc.id_func = chgino; 48640022Smckusick idesc.id_number = dir; 48740022Smckusick idesc.id_fix = DONTKNOW; 48840022Smckusick idesc.id_name = name; 48940022Smckusick idesc.id_parent = newnum; /* new value for name */ 49040022Smckusick return (ckinode(ginode(dir), &idesc)); 49140022Smckusick } 49240022Smckusick 49340022Smckusick /* 49417944Smckusick * make an entry in a directory 49517944Smckusick */ 496*68908Smckusick int 49717992Smckusick makeentry(parent, ino, name) 49817992Smckusick ino_t parent, ino; 49917992Smckusick char *name; 50017992Smckusick { 50139973Smckusick struct dinode *dp; 50217992Smckusick struct inodesc idesc; 50340022Smckusick char pathbuf[MAXPATHLEN + 1]; 50417944Smckusick 50539973Smckusick if (parent < ROOTINO || parent >= maxino || 50639973Smckusick ino < ROOTINO || ino >= maxino) 50717992Smckusick return (0); 50839973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 50917992Smckusick idesc.id_type = DATA; 51017992Smckusick idesc.id_func = mkentry; 51117992Smckusick idesc.id_number = parent; 51217992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 51317992Smckusick idesc.id_fix = DONTKNOW; 51417992Smckusick idesc.id_name = name; 51517992Smckusick dp = ginode(parent); 51617993Smckusick if (dp->di_size % DIRBLKSIZ) { 51717993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 51817993Smckusick inodirty(); 51917993Smckusick } 52017992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 52117944Smckusick return (1); 52240022Smckusick getpathname(pathbuf, parent, parent); 52340022Smckusick dp = ginode(parent); 52440022Smckusick if (expanddir(dp, pathbuf) == 0) 52517944Smckusick return (0); 52617992Smckusick return (ckinode(dp, &idesc) & ALTERED); 52717944Smckusick } 52817944Smckusick 52917944Smckusick /* 53017944Smckusick * Attempt to expand the size of a directory 53117944Smckusick */ 532*68908Smckusick static int 53340022Smckusick expanddir(dp, name) 53439973Smckusick register struct dinode *dp; 53540022Smckusick char *name; 53617944Smckusick { 53768548Smckusick ufs_daddr_t lastbn, newblk; 53839973Smckusick register struct bufarea *bp; 53917944Smckusick char *cp, firstblk[DIRBLKSIZ]; 54017944Smckusick 54117944Smckusick lastbn = lblkno(&sblock, dp->di_size); 54241133Smckusick if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 54317944Smckusick return (0); 54417944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 54517944Smckusick return (0); 54617944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 54717944Smckusick dp->di_db[lastbn] = newblk; 54817944Smckusick dp->di_size += sblock.fs_bsize; 54917944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 55034225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 55144934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 55238375Smckusick if (bp->b_errs) 55317944Smckusick goto bad; 55434225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 55534225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 55638375Smckusick if (bp->b_errs) 55717944Smckusick goto bad; 55834225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 55934225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 56034225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 56117944Smckusick cp += DIRBLKSIZ) 56217944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 56334225Smckusick dirty(bp); 56434225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 56544934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 56638375Smckusick if (bp->b_errs) 56717944Smckusick goto bad; 56834225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 56940022Smckusick pwarn("NO SPACE LEFT IN %s", name); 57017944Smckusick if (preen) 57117944Smckusick printf(" (EXPANDED)\n"); 57217944Smckusick else if (reply("EXPAND") == 0) 57317944Smckusick goto bad; 57434225Smckusick dirty(bp); 57517944Smckusick inodirty(); 57617944Smckusick return (1); 57717944Smckusick bad: 57817944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 57917944Smckusick dp->di_db[lastbn + 1] = 0; 58017944Smckusick dp->di_size -= sblock.fs_bsize; 58117944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 58217944Smckusick freeblk(newblk, sblock.fs_frag); 58317944Smckusick return (0); 58417944Smckusick } 58517944Smckusick 58617944Smckusick /* 58717954Smckusick * allocate a new directory 58817954Smckusick */ 589*68908Smckusick ino_t 59036827Smckusick allocdir(parent, request, mode) 59117954Smckusick ino_t parent, request; 59236827Smckusick int mode; 59317954Smckusick { 59417954Smckusick ino_t ino; 59517954Smckusick char *cp; 59639973Smckusick struct dinode *dp; 59739973Smckusick register struct bufarea *bp; 59854604Smckusick struct dirtemplate *dirp; 59917954Smckusick 60036827Smckusick ino = allocino(request, IFDIR|mode); 60154604Smckusick if (newinofmt) 60254604Smckusick dirp = &dirhead; 60354604Smckusick else 60454604Smckusick dirp = (struct dirtemplate *)&odirhead; 60554604Smckusick dirp->dot_ino = ino; 60654604Smckusick dirp->dotdot_ino = parent; 60717954Smckusick dp = ginode(ino); 60834225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 60938375Smckusick if (bp->b_errs) { 61017954Smckusick freeino(ino); 61117954Smckusick return (0); 61217954Smckusick } 61354604Smckusick bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); 61434225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 61534225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 61617954Smckusick cp += DIRBLKSIZ) 61717954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 61834225Smckusick dirty(bp); 61917954Smckusick dp->di_nlink = 2; 62017954Smckusick inodirty(); 62117954Smckusick if (ino == ROOTINO) { 62217954Smckusick lncntp[ino] = dp->di_nlink; 62350573Smckusick cacheino(dp, ino); 62417954Smckusick return(ino); 62517954Smckusick } 62617954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 62717954Smckusick freeino(ino); 62817954Smckusick return (0); 62917954Smckusick } 63050573Smckusick cacheino(dp, ino); 63117954Smckusick statemap[ino] = statemap[parent]; 63217954Smckusick if (statemap[ino] == DSTATE) { 63317954Smckusick lncntp[ino] = dp->di_nlink; 63417954Smckusick lncntp[parent]++; 63517954Smckusick } 63617954Smckusick dp = ginode(parent); 63717954Smckusick dp->di_nlink++; 63817954Smckusick inodirty(); 63917954Smckusick return (ino); 64017954Smckusick } 64117954Smckusick 64217954Smckusick /* 64317954Smckusick * free a directory inode 64417954Smckusick */ 645*68908Smckusick static void 64617954Smckusick freedir(ino, parent) 64717954Smckusick ino_t ino, parent; 64817954Smckusick { 64939973Smckusick struct dinode *dp; 65017954Smckusick 65117954Smckusick if (ino != parent) { 65217954Smckusick dp = ginode(parent); 65317954Smckusick dp->di_nlink--; 65417954Smckusick inodirty(); 65517954Smckusick } 65617954Smckusick freeino(ino); 65717954Smckusick } 65817954Smckusick 65917954Smckusick /* 66016259Smckusick * generate a temporary name for the lost+found directory. 66116259Smckusick */ 662*68908Smckusick static int 66316259Smckusick lftempname(bufp, ino) 66416259Smckusick char *bufp; 66516259Smckusick ino_t ino; 66616259Smckusick { 66716259Smckusick register ino_t in; 66816259Smckusick register char *cp; 66916259Smckusick int namlen; 67016259Smckusick 67116259Smckusick cp = bufp + 2; 67239973Smckusick for (in = maxino; in > 0; in /= 10) 67316259Smckusick cp++; 67416259Smckusick *--cp = 0; 67516259Smckusick namlen = cp - bufp; 67616259Smckusick in = ino; 67716259Smckusick while (cp > bufp) { 67816259Smckusick *--cp = (in % 10) + '0'; 67916259Smckusick in /= 10; 68016259Smckusick } 68116259Smckusick *cp = '#'; 68216259Smckusick return (namlen); 68316259Smckusick } 68434225Smckusick 68534225Smckusick /* 68634225Smckusick * Get a directory block. 68734225Smckusick * Insure that it is held until another is requested. 68834225Smckusick */ 689*68908Smckusick static struct bufarea * 69034225Smckusick getdirblk(blkno, size) 69168548Smckusick ufs_daddr_t blkno; 69234225Smckusick long size; 69334225Smckusick { 69434225Smckusick 69540648Smckusick if (pdirbp != 0) 69640648Smckusick pdirbp->b_flags &= ~B_INUSE; 69740648Smckusick pdirbp = getdatablk(blkno, size); 69840648Smckusick return (pdirbp); 69934225Smckusick } 700