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*68548Smckusick static char sccsid[] = "@(#)dir.c 8.6 (Berkeley) 03/21/95"; 1039976Smckusick #endif /* not lint */ 1116259Smckusick 1216259Smckusick #include <sys/param.h> 1353702Smckusick #include <sys/time.h> 1451532Sbostic #include <ufs/ufs/dinode.h> 1551532Sbostic #include <ufs/ufs/dir.h> 1651532Sbostic #include <ufs/ffs/fs.h> 1744934Smckusick #include <stdlib.h> 1844934Smckusick #include <string.h> 1916259Smckusick #include "fsck.h" 2016259Smckusick 2116259Smckusick char *lfname = "lost+found"; 2236827Smckusick int lfmode = 01777; 2317944Smckusick struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 2454604Smckusick struct dirtemplate dirhead = { 2554604Smckusick 0, 12, DT_DIR, 1, ".", 2654604Smckusick 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 2754604Smckusick }; 2854604Smckusick struct odirtemplate odirhead = { 2954604Smckusick 0, 12, 1, ".", 3054604Smckusick 0, DIRBLKSIZ - 12, 2, ".." 3154604Smckusick }; 3216259Smckusick 3339973Smckusick struct direct *fsck_readdir(); 3439973Smckusick struct bufarea *getdirblk(); 3516259Smckusick 3640022Smckusick /* 3740022Smckusick * Propagate connected state through the tree. 3840022Smckusick */ 3940022Smckusick propagate() 4016259Smckusick { 4140022Smckusick register struct inoinfo **inpp, *inp; 4240022Smckusick struct inoinfo **inpend; 4340022Smckusick long change; 4416259Smckusick 4540022Smckusick inpend = &inpsort[inplast]; 4640022Smckusick do { 4740022Smckusick change = 0; 4840022Smckusick for (inpp = inpsort; inpp < inpend; inpp++) { 4940022Smckusick inp = *inpp; 5040022Smckusick if (inp->i_parent == 0) 5140022Smckusick continue; 5240022Smckusick if (statemap[inp->i_parent] == DFOUND && 5340022Smckusick statemap[inp->i_number] == DSTATE) { 5440022Smckusick statemap[inp->i_number] = DFOUND; 5540022Smckusick change++; 5640022Smckusick } 5739980Smckusick } 5840022Smckusick } while (change > 0); 5916259Smckusick } 6016259Smckusick 6140022Smckusick /* 6240022Smckusick * Scan each entry in a directory block. 6340022Smckusick */ 6416259Smckusick dirscan(idesc) 6516259Smckusick register struct inodesc *idesc; 6616259Smckusick { 6739973Smckusick register struct direct *dp; 6839973Smckusick register struct bufarea *bp; 6916259Smckusick int dsize, n; 7016259Smckusick long blksiz; 7116259Smckusick char dbuf[DIRBLKSIZ]; 7216259Smckusick 7316259Smckusick if (idesc->id_type != DATA) 7416259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 7517993Smckusick if (idesc->id_entryno == 0 && 7617993Smckusick (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 7717993Smckusick idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 7816259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 7939973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 8016259Smckusick idesc->id_filesize -= blksiz; 8116259Smckusick return (SKIP); 8216259Smckusick } 8316259Smckusick idesc->id_loc = 0; 8416259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 8516259Smckusick dsize = dp->d_reclen; 8644934Smckusick bcopy((char *)dp, dbuf, (size_t)dsize); 8754604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 8854604Smckusick if (!newinofmt) { 8954604Smckusick struct direct *tdp = (struct direct *)dbuf; 9054604Smckusick u_char tmp; 9154604Smckusick 9254604Smckusick tmp = tdp->d_namlen; 9354604Smckusick tdp->d_namlen = tdp->d_type; 9454604Smckusick tdp->d_type = tmp; 9554604Smckusick } 9654604Smckusick # endif 9739973Smckusick idesc->id_dirp = (struct direct *)dbuf; 9816259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 9954604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 10054604Smckusick if (!newinofmt && !doinglevel2) { 10154604Smckusick struct direct *tdp; 10254604Smckusick u_char tmp; 10354604Smckusick 10454604Smckusick tdp = (struct direct *)dbuf; 10554604Smckusick tmp = tdp->d_namlen; 10654604Smckusick tdp->d_namlen = tdp->d_type; 10754604Smckusick tdp->d_type = tmp; 10854604Smckusick } 10954604Smckusick # endif 11034225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 11140570Smckusick bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, 11244934Smckusick (size_t)dsize); 11334225Smckusick dirty(bp); 11430354Smckusick sbdirty(); 11516259Smckusick } 11616259Smckusick if (n & STOP) 11716259Smckusick return (n); 11816259Smckusick } 11916259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 12016259Smckusick } 12116259Smckusick 12216259Smckusick /* 12316259Smckusick * get next entry in a directory. 12416259Smckusick */ 12539973Smckusick struct direct * 12616259Smckusick fsck_readdir(idesc) 12716259Smckusick register struct inodesc *idesc; 12816259Smckusick { 12939973Smckusick register struct direct *dp, *ndp; 13039973Smckusick register struct bufarea *bp; 13154604Smckusick long size, blksiz, fix, dploc; 13216259Smckusick 13316259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 13434225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 13516259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 13616259Smckusick idesc->id_loc < blksiz) { 13739973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 13816259Smckusick if (dircheck(idesc, dp)) 13916259Smckusick goto dpok; 14067863Smckusick if (idesc->id_fix == IGNORE) 14167863Smckusick return (0); 14240570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 14340570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 14440570Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 14516259Smckusick dp->d_reclen = DIRBLKSIZ; 14616259Smckusick dp->d_ino = 0; 14754604Smckusick dp->d_type = 0; 14816259Smckusick dp->d_namlen = 0; 14916259Smckusick dp->d_name[0] = '\0'; 15040570Smckusick if (fix) 15134225Smckusick dirty(bp); 15259302Smckusick idesc->id_loc += DIRBLKSIZ; 15359302Smckusick idesc->id_filesize -= DIRBLKSIZ; 15416259Smckusick return (dp); 15516259Smckusick } 15616259Smckusick dpok: 15716259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 15816259Smckusick return NULL; 15954604Smckusick dploc = idesc->id_loc; 16054604Smckusick dp = (struct direct *)(bp->b_un.b_buf + dploc); 16116259Smckusick idesc->id_loc += dp->d_reclen; 16216259Smckusick idesc->id_filesize -= dp->d_reclen; 16316259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 16416259Smckusick return (dp); 16539973Smckusick ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 16616259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 16716259Smckusick dircheck(idesc, ndp) == 0) { 16816259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 16916259Smckusick idesc->id_loc += size; 17016259Smckusick idesc->id_filesize -= size; 17167863Smckusick if (idesc->id_fix == IGNORE) 17267863Smckusick return (0); 17340570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 17440570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 17554604Smckusick dp = (struct direct *)(bp->b_un.b_buf + dploc); 17640570Smckusick dp->d_reclen += size; 17740570Smckusick if (fix) 17834225Smckusick dirty(bp); 17916259Smckusick } 18016259Smckusick return (dp); 18116259Smckusick } 18216259Smckusick 18316259Smckusick /* 18416259Smckusick * Verify that a directory entry is valid. 18516259Smckusick * This is a superset of the checks made in the kernel. 18616259Smckusick */ 18716259Smckusick dircheck(idesc, dp) 18816259Smckusick struct inodesc *idesc; 18939973Smckusick register struct direct *dp; 19016259Smckusick { 19116259Smckusick register int size; 19216259Smckusick register char *cp; 19354604Smckusick u_char namlen, type; 19416259Smckusick int spaceleft; 19516259Smckusick 19668062Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 19768062Smckusick if (dp->d_ino >= maxino || 19868062Smckusick dp->d_reclen == 0 || 19968062Smckusick dp->d_reclen > spaceleft || 20068062Smckusick (dp->d_reclen & 0x3) != 0) 20168062Smckusick return (0); 20268062Smckusick if (dp->d_ino == 0) 20368062Smckusick return (1); 20454604Smckusick size = DIRSIZ(!newinofmt, dp); 20554604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 20654604Smckusick if (!newinofmt) { 20754604Smckusick type = dp->d_namlen; 20854604Smckusick namlen = dp->d_type; 20954604Smckusick } else { 21054604Smckusick namlen = dp->d_namlen; 21154604Smckusick type = dp->d_type; 21254604Smckusick } 21354604Smckusick # else 21454604Smckusick namlen = dp->d_namlen; 21554604Smckusick type = dp->d_type; 21654604Smckusick # endif 21768062Smckusick if (dp->d_reclen < size || 21868062Smckusick idesc->id_filesize < size || 21968062Smckusick namlen > MAXNAMLEN || 22068062Smckusick type > 15) 22168062Smckusick return (0); 22268062Smckusick for (cp = dp->d_name, size = 0; size < namlen; size++) 22368062Smckusick if (*cp == '\0' || (*cp++ == '/')) 22468062Smckusick return (0); 22568062Smckusick if (*cp != '\0') 22668062Smckusick return (0); 22768062Smckusick return (1); 22816259Smckusick } 22916259Smckusick 23039973Smckusick direrror(ino, errmesg) 23116259Smckusick ino_t ino; 23239973Smckusick char *errmesg; 23316259Smckusick { 23440022Smckusick 23540022Smckusick fileerror(ino, ino, errmesg); 23640022Smckusick } 23740022Smckusick 23840022Smckusick fileerror(cwd, ino, errmesg) 23940022Smckusick ino_t cwd, ino; 24040022Smckusick char *errmesg; 24140022Smckusick { 24239973Smckusick register struct dinode *dp; 24340022Smckusick char pathbuf[MAXPATHLEN + 1]; 24416259Smckusick 24539973Smckusick pwarn("%s ", errmesg); 24616259Smckusick pinode(ino); 24716259Smckusick printf("\n"); 24840022Smckusick getpathname(pathbuf, cwd, ino); 24939973Smckusick if (ino < ROOTINO || ino > maxino) { 25040022Smckusick pfatal("NAME=%s\n", pathbuf); 25117943Smckusick return; 25217943Smckusick } 25317943Smckusick dp = ginode(ino); 25417943Smckusick if (ftypeok(dp)) 25539973Smckusick pfatal("%s=%s\n", 25640022Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 25716259Smckusick else 25840022Smckusick pfatal("NAME=%s\n", pathbuf); 25916259Smckusick } 26016259Smckusick 26116259Smckusick adjust(idesc, lcnt) 26216259Smckusick register struct inodesc *idesc; 26316259Smckusick short lcnt; 26416259Smckusick { 26539973Smckusick register struct dinode *dp; 26616259Smckusick 26717943Smckusick dp = ginode(idesc->id_number); 26816259Smckusick if (dp->di_nlink == lcnt) { 26916259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 27016259Smckusick clri(idesc, "UNREF", 0); 27117936Smckusick } else { 27217930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 27339973Smckusick ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 27416259Smckusick pinode(idesc->id_number); 27516259Smckusick printf(" COUNT %d SHOULD BE %d", 27639973Smckusick dp->di_nlink, dp->di_nlink - lcnt); 27716259Smckusick if (preen) { 27816259Smckusick if (lcnt < 0) { 27916259Smckusick printf("\n"); 28017930Smckusick pfatal("LINK COUNT INCREASING"); 28116259Smckusick } 28216259Smckusick printf(" (ADJUSTED)\n"); 28316259Smckusick } 28416259Smckusick if (preen || reply("ADJUST") == 1) { 28516259Smckusick dp->di_nlink -= lcnt; 28616259Smckusick inodirty(); 28716259Smckusick } 28816259Smckusick } 28916259Smckusick } 29016259Smckusick 29116259Smckusick mkentry(idesc) 29216259Smckusick struct inodesc *idesc; 29316259Smckusick { 29439973Smckusick register struct direct *dirp = idesc->id_dirp; 29539973Smckusick struct direct newent; 29616259Smckusick int newlen, oldlen; 29716259Smckusick 29840022Smckusick newent.d_namlen = strlen(idesc->id_name); 29954604Smckusick newlen = DIRSIZ(0, &newent); 30016259Smckusick if (dirp->d_ino != 0) 30154604Smckusick oldlen = DIRSIZ(0, dirp); 30216259Smckusick else 30316259Smckusick oldlen = 0; 30416259Smckusick if (dirp->d_reclen - oldlen < newlen) 30516259Smckusick return (KEEPON); 30616259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 30716259Smckusick dirp->d_reclen = oldlen; 30816259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 30916259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 31068061Smckusick dirp->d_reclen = newent.d_reclen; 31168061Smckusick if (newinofmt) 31254604Smckusick dirp->d_type = typemap[idesc->id_parent]; 31368061Smckusick else 31468061Smckusick dirp->d_type = 0; 31568061Smckusick dirp->d_namlen = newent.d_namlen; 31667586Smckusick bcopy(idesc->id_name, dirp->d_name, (size_t)newent.d_namlen + 1); 31768061Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 31868061Smckusick /* 31968061Smckusick * If the entry was split, dirscan() will only reverse the byte 32068061Smckusick * order of the original entry, and not the new one, before 32168061Smckusick * writing it back out. So, we reverse the byte order here if 32268061Smckusick * necessary. 32368061Smckusick */ 32468061Smckusick if (oldlen != 0 && !newinofmt && !doinglevel2) { 32568061Smckusick u_char tmp; 32668061Smckusick 32768061Smckusick tmp = dirp->d_namlen; 32868061Smckusick dirp->d_namlen = dirp->d_type; 32968061Smckusick dirp->d_type = tmp; 33068061Smckusick } 33168061Smckusick # endif 33216259Smckusick return (ALTERED|STOP); 33316259Smckusick } 33416259Smckusick 33517957Smckusick chgino(idesc) 33616259Smckusick struct inodesc *idesc; 33716259Smckusick { 33839973Smckusick register struct direct *dirp = idesc->id_dirp; 33916259Smckusick 34039973Smckusick if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 34117957Smckusick return (KEEPON); 34239973Smckusick dirp->d_ino = idesc->id_parent; 34354604Smckusick if (newinofmt) 34454604Smckusick dirp->d_type = typemap[idesc->id_parent]; 34555074Smckusick else 34655074Smckusick dirp->d_type = 0; 34717957Smckusick return (ALTERED|STOP); 34816259Smckusick } 34916259Smckusick 35039973Smckusick linkup(orphan, parentdir) 35116259Smckusick ino_t orphan; 35239973Smckusick ino_t parentdir; 35316259Smckusick { 35439973Smckusick register struct dinode *dp; 35540022Smckusick int lostdir; 35617954Smckusick ino_t oldlfdir; 35716259Smckusick struct inodesc idesc; 35817954Smckusick char tempname[BUFSIZ]; 35917957Smckusick extern int pass4check(); 36016259Smckusick 36116259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 36217943Smckusick dp = ginode(orphan); 36339973Smckusick lostdir = (dp->di_mode & IFMT) == IFDIR; 36416259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 36516259Smckusick pinode(orphan); 36616259Smckusick if (preen && dp->di_size == 0) 36716259Smckusick return (0); 36816259Smckusick if (preen) 36916259Smckusick printf(" (RECONNECTED)\n"); 37016259Smckusick else 37116259Smckusick if (reply("RECONNECT") == 0) 37216259Smckusick return (0); 37316259Smckusick if (lfdir == 0) { 37417943Smckusick dp = ginode(ROOTINO); 37517930Smckusick idesc.id_name = lfname; 37616259Smckusick idesc.id_type = DATA; 37716259Smckusick idesc.id_func = findino; 37816259Smckusick idesc.id_number = ROOTINO; 37930354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 38017954Smckusick lfdir = idesc.id_parent; 38117954Smckusick } else { 38217954Smckusick pwarn("NO lost+found DIRECTORY"); 38317954Smckusick if (preen || reply("CREATE")) { 38439973Smckusick lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 38517992Smckusick if (lfdir != 0) { 38617992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 38717954Smckusick if (preen) 38817954Smckusick printf(" (CREATED)\n"); 38917954Smckusick } else { 39017992Smckusick freedir(lfdir, ROOTINO); 39117992Smckusick lfdir = 0; 39217954Smckusick if (preen) 39317954Smckusick printf("\n"); 39417954Smckusick } 39517954Smckusick } 39617954Smckusick } 39717954Smckusick } 39817943Smckusick if (lfdir == 0) { 39917954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 40016259Smckusick printf("\n\n"); 40116259Smckusick return (0); 40216259Smckusick } 40316259Smckusick } 40417943Smckusick dp = ginode(lfdir); 40539973Smckusick if ((dp->di_mode & IFMT) != IFDIR) { 40617957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 40717957Smckusick if (reply("REALLOCATE") == 0) 40817957Smckusick return (0); 40917957Smckusick oldlfdir = lfdir; 41039973Smckusick if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 41117957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 41217957Smckusick return (0); 41317957Smckusick } 41440022Smckusick if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 41517957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 41617957Smckusick return (0); 41717957Smckusick } 41817957Smckusick inodirty(); 41917957Smckusick idesc.id_type = ADDR; 42017957Smckusick idesc.id_func = pass4check; 42117957Smckusick idesc.id_number = oldlfdir; 42217957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 42317957Smckusick lncntp[oldlfdir] = 0; 42417957Smckusick dp = ginode(lfdir); 42517957Smckusick } 42617957Smckusick if (statemap[lfdir] != DFOUND) { 42717957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 42816259Smckusick return (0); 42916259Smckusick } 43040022Smckusick (void)lftempname(tempname, orphan); 43117992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 43216259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 43316259Smckusick printf("\n\n"); 43416259Smckusick return (0); 43516259Smckusick } 43616259Smckusick lncntp[orphan]--; 43716259Smckusick if (lostdir) { 43840022Smckusick if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 43940022Smckusick parentdir != (ino_t)-1) 44044934Smckusick (void)makeentry(orphan, lfdir, ".."); 44117943Smckusick dp = ginode(lfdir); 44217943Smckusick dp->di_nlink++; 44317943Smckusick inodirty(); 44417943Smckusick lncntp[lfdir]++; 44544934Smckusick pwarn("DIR I=%lu CONNECTED. ", orphan); 44640022Smckusick if (parentdir != (ino_t)-1) 44744934Smckusick printf("PARENT WAS I=%lu\n", parentdir); 44816259Smckusick if (preen == 0) 44916259Smckusick printf("\n"); 45016259Smckusick } 45116259Smckusick return (1); 45216259Smckusick } 45316259Smckusick 45416259Smckusick /* 45540022Smckusick * fix an entry in a directory. 45640022Smckusick */ 45740022Smckusick changeino(dir, name, newnum) 45840022Smckusick ino_t dir; 45940022Smckusick char *name; 46040022Smckusick ino_t newnum; 46140022Smckusick { 46240022Smckusick struct inodesc idesc; 46340022Smckusick 46440022Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 46540022Smckusick idesc.id_type = DATA; 46640022Smckusick idesc.id_func = chgino; 46740022Smckusick idesc.id_number = dir; 46840022Smckusick idesc.id_fix = DONTKNOW; 46940022Smckusick idesc.id_name = name; 47040022Smckusick idesc.id_parent = newnum; /* new value for name */ 47140022Smckusick return (ckinode(ginode(dir), &idesc)); 47240022Smckusick } 47340022Smckusick 47440022Smckusick /* 47517944Smckusick * make an entry in a directory 47617944Smckusick */ 47717992Smckusick makeentry(parent, ino, name) 47817992Smckusick ino_t parent, ino; 47917992Smckusick char *name; 48017992Smckusick { 48139973Smckusick struct dinode *dp; 48217992Smckusick struct inodesc idesc; 48340022Smckusick char pathbuf[MAXPATHLEN + 1]; 48417944Smckusick 48539973Smckusick if (parent < ROOTINO || parent >= maxino || 48639973Smckusick ino < ROOTINO || ino >= maxino) 48717992Smckusick return (0); 48839973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 48917992Smckusick idesc.id_type = DATA; 49017992Smckusick idesc.id_func = mkentry; 49117992Smckusick idesc.id_number = parent; 49217992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 49317992Smckusick idesc.id_fix = DONTKNOW; 49417992Smckusick idesc.id_name = name; 49517992Smckusick dp = ginode(parent); 49617993Smckusick if (dp->di_size % DIRBLKSIZ) { 49717993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 49817993Smckusick inodirty(); 49917993Smckusick } 50017992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 50117944Smckusick return (1); 50240022Smckusick getpathname(pathbuf, parent, parent); 50340022Smckusick dp = ginode(parent); 50440022Smckusick if (expanddir(dp, pathbuf) == 0) 50517944Smckusick return (0); 50617992Smckusick return (ckinode(dp, &idesc) & ALTERED); 50717944Smckusick } 50817944Smckusick 50917944Smckusick /* 51017944Smckusick * Attempt to expand the size of a directory 51117944Smckusick */ 51240022Smckusick expanddir(dp, name) 51339973Smckusick register struct dinode *dp; 51440022Smckusick char *name; 51517944Smckusick { 516*68548Smckusick ufs_daddr_t lastbn, newblk; 51739973Smckusick register struct bufarea *bp; 51817944Smckusick char *cp, firstblk[DIRBLKSIZ]; 51917944Smckusick 52017944Smckusick lastbn = lblkno(&sblock, dp->di_size); 52141133Smckusick if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 52217944Smckusick return (0); 52317944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 52417944Smckusick return (0); 52517944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 52617944Smckusick dp->di_db[lastbn] = newblk; 52717944Smckusick dp->di_size += sblock.fs_bsize; 52817944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 52934225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 53044934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 53138375Smckusick if (bp->b_errs) 53217944Smckusick goto bad; 53334225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 53434225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 53538375Smckusick if (bp->b_errs) 53617944Smckusick goto bad; 53734225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 53834225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 53934225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 54017944Smckusick cp += DIRBLKSIZ) 54117944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 54234225Smckusick dirty(bp); 54334225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 54444934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 54538375Smckusick if (bp->b_errs) 54617944Smckusick goto bad; 54734225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 54840022Smckusick pwarn("NO SPACE LEFT IN %s", name); 54917944Smckusick if (preen) 55017944Smckusick printf(" (EXPANDED)\n"); 55117944Smckusick else if (reply("EXPAND") == 0) 55217944Smckusick goto bad; 55334225Smckusick dirty(bp); 55417944Smckusick inodirty(); 55517944Smckusick return (1); 55617944Smckusick bad: 55717944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 55817944Smckusick dp->di_db[lastbn + 1] = 0; 55917944Smckusick dp->di_size -= sblock.fs_bsize; 56017944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 56117944Smckusick freeblk(newblk, sblock.fs_frag); 56217944Smckusick return (0); 56317944Smckusick } 56417944Smckusick 56517944Smckusick /* 56617954Smckusick * allocate a new directory 56717954Smckusick */ 56836827Smckusick allocdir(parent, request, mode) 56917954Smckusick ino_t parent, request; 57036827Smckusick int mode; 57117954Smckusick { 57217954Smckusick ino_t ino; 57317954Smckusick char *cp; 57439973Smckusick struct dinode *dp; 57539973Smckusick register struct bufarea *bp; 57654604Smckusick struct dirtemplate *dirp; 57717954Smckusick 57836827Smckusick ino = allocino(request, IFDIR|mode); 57954604Smckusick if (newinofmt) 58054604Smckusick dirp = &dirhead; 58154604Smckusick else 58254604Smckusick dirp = (struct dirtemplate *)&odirhead; 58354604Smckusick dirp->dot_ino = ino; 58454604Smckusick dirp->dotdot_ino = parent; 58517954Smckusick dp = ginode(ino); 58634225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 58738375Smckusick if (bp->b_errs) { 58817954Smckusick freeino(ino); 58917954Smckusick return (0); 59017954Smckusick } 59154604Smckusick bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); 59234225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 59334225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 59417954Smckusick cp += DIRBLKSIZ) 59517954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 59634225Smckusick dirty(bp); 59717954Smckusick dp->di_nlink = 2; 59817954Smckusick inodirty(); 59917954Smckusick if (ino == ROOTINO) { 60017954Smckusick lncntp[ino] = dp->di_nlink; 60150573Smckusick cacheino(dp, ino); 60217954Smckusick return(ino); 60317954Smckusick } 60417954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 60517954Smckusick freeino(ino); 60617954Smckusick return (0); 60717954Smckusick } 60850573Smckusick cacheino(dp, ino); 60917954Smckusick statemap[ino] = statemap[parent]; 61017954Smckusick if (statemap[ino] == DSTATE) { 61117954Smckusick lncntp[ino] = dp->di_nlink; 61217954Smckusick lncntp[parent]++; 61317954Smckusick } 61417954Smckusick dp = ginode(parent); 61517954Smckusick dp->di_nlink++; 61617954Smckusick inodirty(); 61717954Smckusick return (ino); 61817954Smckusick } 61917954Smckusick 62017954Smckusick /* 62117954Smckusick * free a directory inode 62217954Smckusick */ 62317954Smckusick freedir(ino, parent) 62417954Smckusick ino_t ino, parent; 62517954Smckusick { 62639973Smckusick struct dinode *dp; 62717954Smckusick 62817954Smckusick if (ino != parent) { 62917954Smckusick dp = ginode(parent); 63017954Smckusick dp->di_nlink--; 63117954Smckusick inodirty(); 63217954Smckusick } 63317954Smckusick freeino(ino); 63417954Smckusick } 63517954Smckusick 63617954Smckusick /* 63716259Smckusick * generate a temporary name for the lost+found directory. 63816259Smckusick */ 63916259Smckusick lftempname(bufp, ino) 64016259Smckusick char *bufp; 64116259Smckusick ino_t ino; 64216259Smckusick { 64316259Smckusick register ino_t in; 64416259Smckusick register char *cp; 64516259Smckusick int namlen; 64616259Smckusick 64716259Smckusick cp = bufp + 2; 64839973Smckusick for (in = maxino; in > 0; in /= 10) 64916259Smckusick cp++; 65016259Smckusick *--cp = 0; 65116259Smckusick namlen = cp - bufp; 65216259Smckusick in = ino; 65316259Smckusick while (cp > bufp) { 65416259Smckusick *--cp = (in % 10) + '0'; 65516259Smckusick in /= 10; 65616259Smckusick } 65716259Smckusick *cp = '#'; 65816259Smckusick return (namlen); 65916259Smckusick } 66034225Smckusick 66134225Smckusick /* 66234225Smckusick * Get a directory block. 66334225Smckusick * Insure that it is held until another is requested. 66434225Smckusick */ 66539973Smckusick struct bufarea * 66634225Smckusick getdirblk(blkno, size) 667*68548Smckusick ufs_daddr_t blkno; 66834225Smckusick long size; 66934225Smckusick { 67034225Smckusick 67140648Smckusick if (pdirbp != 0) 67240648Smckusick pdirbp->b_flags &= ~B_INUSE; 67340648Smckusick pdirbp = getdatablk(blkno, size); 67440648Smckusick return (pdirbp); 67534225Smckusick } 676