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*54604Smckusick static char sccsid[] = "@(#)dir.c 5.22 (Berkeley) 07/02/92"; 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 }; 24*54604Smckusick struct dirtemplate dirhead = { 25*54604Smckusick 0, 12, DT_DIR, 1, ".", 26*54604Smckusick 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 27*54604Smckusick }; 28*54604Smckusick struct odirtemplate odirhead = { 29*54604Smckusick 0, 12, 1, ".", 30*54604Smckusick 0, DIRBLKSIZ - 12, 2, ".." 31*54604Smckusick }; 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); 87*54604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 88*54604Smckusick if (!newinofmt) { 89*54604Smckusick struct direct *tdp = (struct direct *)dbuf; 90*54604Smckusick u_char tmp; 91*54604Smckusick 92*54604Smckusick tmp = tdp->d_namlen; 93*54604Smckusick tdp->d_namlen = tdp->d_type; 94*54604Smckusick tdp->d_type = tmp; 95*54604Smckusick } 96*54604Smckusick # endif 9739973Smckusick idesc->id_dirp = (struct direct *)dbuf; 9816259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 99*54604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 100*54604Smckusick if (!newinofmt && !doinglevel2) { 101*54604Smckusick struct direct *tdp; 102*54604Smckusick u_char tmp; 103*54604Smckusick 104*54604Smckusick tdp = (struct direct *)dbuf; 105*54604Smckusick tmp = tdp->d_namlen; 106*54604Smckusick tdp->d_namlen = tdp->d_type; 107*54604Smckusick tdp->d_type = tmp; 108*54604Smckusick } 109*54604Smckusick # 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; 131*54604Smckusick 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; 14016259Smckusick idesc->id_loc += DIRBLKSIZ; 14116259Smckusick idesc->id_filesize -= DIRBLKSIZ; 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; 147*54604Smckusick dp->d_type = 0; 14816259Smckusick dp->d_namlen = 0; 14916259Smckusick dp->d_name[0] = '\0'; 15040570Smckusick if (fix) 15134225Smckusick dirty(bp); 15216259Smckusick return (dp); 15316259Smckusick } 15416259Smckusick dpok: 15516259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 15616259Smckusick return NULL; 157*54604Smckusick dploc = idesc->id_loc; 158*54604Smckusick dp = (struct direct *)(bp->b_un.b_buf + dploc); 15916259Smckusick idesc->id_loc += dp->d_reclen; 16016259Smckusick idesc->id_filesize -= dp->d_reclen; 16116259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 16216259Smckusick return (dp); 16339973Smckusick ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 16416259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 16516259Smckusick dircheck(idesc, ndp) == 0) { 16616259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 16716259Smckusick idesc->id_loc += size; 16816259Smckusick idesc->id_filesize -= size; 16940570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 17040570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 171*54604Smckusick dp = (struct direct *)(bp->b_un.b_buf + dploc); 17240570Smckusick dp->d_reclen += size; 17340570Smckusick if (fix) 17434225Smckusick dirty(bp); 17516259Smckusick } 17616259Smckusick return (dp); 17716259Smckusick } 17816259Smckusick 17916259Smckusick /* 18016259Smckusick * Verify that a directory entry is valid. 18116259Smckusick * This is a superset of the checks made in the kernel. 18216259Smckusick */ 18316259Smckusick dircheck(idesc, dp) 18416259Smckusick struct inodesc *idesc; 18539973Smckusick register struct direct *dp; 18616259Smckusick { 18716259Smckusick register int size; 18816259Smckusick register char *cp; 189*54604Smckusick u_char namlen, type; 19016259Smckusick int spaceleft; 19116259Smckusick 192*54604Smckusick size = DIRSIZ(!newinofmt, dp); 19316259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 194*54604Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 195*54604Smckusick if (!newinofmt) { 196*54604Smckusick type = dp->d_namlen; 197*54604Smckusick namlen = dp->d_type; 198*54604Smckusick } else { 199*54604Smckusick namlen = dp->d_namlen; 200*54604Smckusick type = dp->d_type; 201*54604Smckusick } 202*54604Smckusick # else 203*54604Smckusick namlen = dp->d_namlen; 204*54604Smckusick type = dp->d_type; 205*54604Smckusick # endif 20639973Smckusick if (dp->d_ino < maxino && 20716259Smckusick dp->d_reclen != 0 && 20816259Smckusick dp->d_reclen <= spaceleft && 20916259Smckusick (dp->d_reclen & 0x3) == 0 && 21016259Smckusick dp->d_reclen >= size && 21116259Smckusick idesc->id_filesize >= size && 212*54604Smckusick namlen <= MAXNAMLEN && 213*54604Smckusick type <= 15) { 21416259Smckusick if (dp->d_ino == 0) 21516259Smckusick return (1); 216*54604Smckusick for (cp = dp->d_name, size = 0; size < namlen; size++) 21740651Smckusick if (*cp == 0 || (*cp++ == '/')) 21816259Smckusick return (0); 21916259Smckusick if (*cp == 0) 22016259Smckusick return (1); 22116259Smckusick } 22216259Smckusick return (0); 22316259Smckusick } 22416259Smckusick 22539973Smckusick direrror(ino, errmesg) 22616259Smckusick ino_t ino; 22739973Smckusick char *errmesg; 22816259Smckusick { 22940022Smckusick 23040022Smckusick fileerror(ino, ino, errmesg); 23140022Smckusick } 23240022Smckusick 23340022Smckusick fileerror(cwd, ino, errmesg) 23440022Smckusick ino_t cwd, ino; 23540022Smckusick char *errmesg; 23640022Smckusick { 23739973Smckusick register struct dinode *dp; 23840022Smckusick char pathbuf[MAXPATHLEN + 1]; 23916259Smckusick 24039973Smckusick pwarn("%s ", errmesg); 24116259Smckusick pinode(ino); 24216259Smckusick printf("\n"); 24340022Smckusick getpathname(pathbuf, cwd, ino); 24439973Smckusick if (ino < ROOTINO || ino > maxino) { 24540022Smckusick pfatal("NAME=%s\n", pathbuf); 24617943Smckusick return; 24717943Smckusick } 24817943Smckusick dp = ginode(ino); 24917943Smckusick if (ftypeok(dp)) 25039973Smckusick pfatal("%s=%s\n", 25140022Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 25216259Smckusick else 25340022Smckusick pfatal("NAME=%s\n", pathbuf); 25416259Smckusick } 25516259Smckusick 25616259Smckusick adjust(idesc, lcnt) 25716259Smckusick register struct inodesc *idesc; 25816259Smckusick short lcnt; 25916259Smckusick { 26039973Smckusick register struct dinode *dp; 26116259Smckusick 26217943Smckusick dp = ginode(idesc->id_number); 26316259Smckusick if (dp->di_nlink == lcnt) { 26416259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 26516259Smckusick clri(idesc, "UNREF", 0); 26617936Smckusick } else { 26717930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 26839973Smckusick ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 26916259Smckusick pinode(idesc->id_number); 27016259Smckusick printf(" COUNT %d SHOULD BE %d", 27139973Smckusick dp->di_nlink, dp->di_nlink - lcnt); 27216259Smckusick if (preen) { 27316259Smckusick if (lcnt < 0) { 27416259Smckusick printf("\n"); 27517930Smckusick pfatal("LINK COUNT INCREASING"); 27616259Smckusick } 27716259Smckusick printf(" (ADJUSTED)\n"); 27816259Smckusick } 27916259Smckusick if (preen || reply("ADJUST") == 1) { 28016259Smckusick dp->di_nlink -= lcnt; 28116259Smckusick inodirty(); 28216259Smckusick } 28316259Smckusick } 28416259Smckusick } 28516259Smckusick 28616259Smckusick mkentry(idesc) 28716259Smckusick struct inodesc *idesc; 28816259Smckusick { 28939973Smckusick register struct direct *dirp = idesc->id_dirp; 29039973Smckusick struct direct newent; 29116259Smckusick int newlen, oldlen; 29216259Smckusick 29340022Smckusick newent.d_namlen = strlen(idesc->id_name); 294*54604Smckusick newlen = DIRSIZ(0, &newent); 29516259Smckusick if (dirp->d_ino != 0) 296*54604Smckusick oldlen = DIRSIZ(0, dirp); 29716259Smckusick else 29816259Smckusick oldlen = 0; 29916259Smckusick if (dirp->d_reclen - oldlen < newlen) 30016259Smckusick return (KEEPON); 30116259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 30216259Smckusick dirp->d_reclen = oldlen; 30316259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 30416259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 305*54604Smckusick if (newinofmt) 306*54604Smckusick dirp->d_type = typemap[idesc->id_parent]; 30716259Smckusick dirp->d_reclen = newent.d_reclen; 30840022Smckusick dirp->d_namlen = newent.d_namlen; 30944934Smckusick bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 31016259Smckusick return (ALTERED|STOP); 31116259Smckusick } 31216259Smckusick 31317957Smckusick chgino(idesc) 31416259Smckusick struct inodesc *idesc; 31516259Smckusick { 31639973Smckusick register struct direct *dirp = idesc->id_dirp; 31716259Smckusick 31839973Smckusick if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 31917957Smckusick return (KEEPON); 32039973Smckusick dirp->d_ino = idesc->id_parent; 321*54604Smckusick if (newinofmt) 322*54604Smckusick dirp->d_type = typemap[idesc->id_parent]; 32317957Smckusick return (ALTERED|STOP); 32416259Smckusick } 32516259Smckusick 32639973Smckusick linkup(orphan, parentdir) 32716259Smckusick ino_t orphan; 32839973Smckusick ino_t parentdir; 32916259Smckusick { 33039973Smckusick register struct dinode *dp; 33140022Smckusick int lostdir; 33217954Smckusick ino_t oldlfdir; 33316259Smckusick struct inodesc idesc; 33417954Smckusick char tempname[BUFSIZ]; 33517957Smckusick extern int pass4check(); 33616259Smckusick 33716259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 33817943Smckusick dp = ginode(orphan); 33939973Smckusick lostdir = (dp->di_mode & IFMT) == IFDIR; 34016259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 34116259Smckusick pinode(orphan); 34216259Smckusick if (preen && dp->di_size == 0) 34316259Smckusick return (0); 34416259Smckusick if (preen) 34516259Smckusick printf(" (RECONNECTED)\n"); 34616259Smckusick else 34716259Smckusick if (reply("RECONNECT") == 0) 34816259Smckusick return (0); 34916259Smckusick if (lfdir == 0) { 35017943Smckusick dp = ginode(ROOTINO); 35117930Smckusick idesc.id_name = lfname; 35216259Smckusick idesc.id_type = DATA; 35316259Smckusick idesc.id_func = findino; 35416259Smckusick idesc.id_number = ROOTINO; 35530354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 35617954Smckusick lfdir = idesc.id_parent; 35717954Smckusick } else { 35817954Smckusick pwarn("NO lost+found DIRECTORY"); 35917954Smckusick if (preen || reply("CREATE")) { 36039973Smckusick lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 36117992Smckusick if (lfdir != 0) { 36217992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 36317954Smckusick if (preen) 36417954Smckusick printf(" (CREATED)\n"); 36517954Smckusick } else { 36617992Smckusick freedir(lfdir, ROOTINO); 36717992Smckusick lfdir = 0; 36817954Smckusick if (preen) 36917954Smckusick printf("\n"); 37017954Smckusick } 37117954Smckusick } 37217954Smckusick } 37317954Smckusick } 37417943Smckusick if (lfdir == 0) { 37517954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 37616259Smckusick printf("\n\n"); 37716259Smckusick return (0); 37816259Smckusick } 37916259Smckusick } 38017943Smckusick dp = ginode(lfdir); 38139973Smckusick if ((dp->di_mode & IFMT) != IFDIR) { 38217957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 38317957Smckusick if (reply("REALLOCATE") == 0) 38417957Smckusick return (0); 38517957Smckusick oldlfdir = lfdir; 38639973Smckusick if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 38717957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 38817957Smckusick return (0); 38917957Smckusick } 39040022Smckusick if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 39117957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 39217957Smckusick return (0); 39317957Smckusick } 39417957Smckusick inodirty(); 39517957Smckusick idesc.id_type = ADDR; 39617957Smckusick idesc.id_func = pass4check; 39717957Smckusick idesc.id_number = oldlfdir; 39817957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 39917957Smckusick lncntp[oldlfdir] = 0; 40017957Smckusick dp = ginode(lfdir); 40117957Smckusick } 40217957Smckusick if (statemap[lfdir] != DFOUND) { 40317957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 40416259Smckusick return (0); 40516259Smckusick } 40640022Smckusick (void)lftempname(tempname, orphan); 40717992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 40816259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 40916259Smckusick printf("\n\n"); 41016259Smckusick return (0); 41116259Smckusick } 41216259Smckusick lncntp[orphan]--; 41316259Smckusick if (lostdir) { 41440022Smckusick if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 41540022Smckusick parentdir != (ino_t)-1) 41644934Smckusick (void)makeentry(orphan, lfdir, ".."); 41717943Smckusick dp = ginode(lfdir); 41817943Smckusick dp->di_nlink++; 41917943Smckusick inodirty(); 42017943Smckusick lncntp[lfdir]++; 42144934Smckusick pwarn("DIR I=%lu CONNECTED. ", orphan); 42240022Smckusick if (parentdir != (ino_t)-1) 42344934Smckusick printf("PARENT WAS I=%lu\n", parentdir); 42416259Smckusick if (preen == 0) 42516259Smckusick printf("\n"); 42616259Smckusick } 42716259Smckusick return (1); 42816259Smckusick } 42916259Smckusick 43016259Smckusick /* 43140022Smckusick * fix an entry in a directory. 43240022Smckusick */ 43340022Smckusick changeino(dir, name, newnum) 43440022Smckusick ino_t dir; 43540022Smckusick char *name; 43640022Smckusick ino_t newnum; 43740022Smckusick { 43840022Smckusick struct inodesc idesc; 43940022Smckusick 44040022Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 44140022Smckusick idesc.id_type = DATA; 44240022Smckusick idesc.id_func = chgino; 44340022Smckusick idesc.id_number = dir; 44440022Smckusick idesc.id_fix = DONTKNOW; 44540022Smckusick idesc.id_name = name; 44640022Smckusick idesc.id_parent = newnum; /* new value for name */ 44740022Smckusick return (ckinode(ginode(dir), &idesc)); 44840022Smckusick } 44940022Smckusick 45040022Smckusick /* 45117944Smckusick * make an entry in a directory 45217944Smckusick */ 45317992Smckusick makeentry(parent, ino, name) 45417992Smckusick ino_t parent, ino; 45517992Smckusick char *name; 45617992Smckusick { 45739973Smckusick struct dinode *dp; 45817992Smckusick struct inodesc idesc; 45940022Smckusick char pathbuf[MAXPATHLEN + 1]; 46017944Smckusick 46139973Smckusick if (parent < ROOTINO || parent >= maxino || 46239973Smckusick ino < ROOTINO || ino >= maxino) 46317992Smckusick return (0); 46439973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 46517992Smckusick idesc.id_type = DATA; 46617992Smckusick idesc.id_func = mkentry; 46717992Smckusick idesc.id_number = parent; 46817992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 46917992Smckusick idesc.id_fix = DONTKNOW; 47017992Smckusick idesc.id_name = name; 47117992Smckusick dp = ginode(parent); 47217993Smckusick if (dp->di_size % DIRBLKSIZ) { 47317993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 47417993Smckusick inodirty(); 47517993Smckusick } 47617992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 47717944Smckusick return (1); 47840022Smckusick getpathname(pathbuf, parent, parent); 47940022Smckusick dp = ginode(parent); 48040022Smckusick if (expanddir(dp, pathbuf) == 0) 48117944Smckusick return (0); 48217992Smckusick return (ckinode(dp, &idesc) & ALTERED); 48317944Smckusick } 48417944Smckusick 48517944Smckusick /* 48617944Smckusick * Attempt to expand the size of a directory 48717944Smckusick */ 48840022Smckusick expanddir(dp, name) 48939973Smckusick register struct dinode *dp; 49040022Smckusick char *name; 49117944Smckusick { 49217944Smckusick daddr_t lastbn, newblk; 49339973Smckusick register struct bufarea *bp; 49417944Smckusick char *cp, firstblk[DIRBLKSIZ]; 49517944Smckusick 49617944Smckusick lastbn = lblkno(&sblock, dp->di_size); 49741133Smckusick if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 49817944Smckusick return (0); 49917944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 50017944Smckusick return (0); 50117944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 50217944Smckusick dp->di_db[lastbn] = newblk; 50317944Smckusick dp->di_size += sblock.fs_bsize; 50417944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 50534225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 50644934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 50738375Smckusick if (bp->b_errs) 50817944Smckusick goto bad; 50934225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 51034225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 51138375Smckusick if (bp->b_errs) 51217944Smckusick goto bad; 51334225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 51434225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 51534225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 51617944Smckusick cp += DIRBLKSIZ) 51717944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 51834225Smckusick dirty(bp); 51934225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 52044934Smckusick (long)dblksize(&sblock, dp, lastbn + 1)); 52138375Smckusick if (bp->b_errs) 52217944Smckusick goto bad; 52334225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 52440022Smckusick pwarn("NO SPACE LEFT IN %s", name); 52517944Smckusick if (preen) 52617944Smckusick printf(" (EXPANDED)\n"); 52717944Smckusick else if (reply("EXPAND") == 0) 52817944Smckusick goto bad; 52934225Smckusick dirty(bp); 53017944Smckusick inodirty(); 53117944Smckusick return (1); 53217944Smckusick bad: 53317944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 53417944Smckusick dp->di_db[lastbn + 1] = 0; 53517944Smckusick dp->di_size -= sblock.fs_bsize; 53617944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 53717944Smckusick freeblk(newblk, sblock.fs_frag); 53817944Smckusick return (0); 53917944Smckusick } 54017944Smckusick 54117944Smckusick /* 54217954Smckusick * allocate a new directory 54317954Smckusick */ 54436827Smckusick allocdir(parent, request, mode) 54517954Smckusick ino_t parent, request; 54636827Smckusick int mode; 54717954Smckusick { 54817954Smckusick ino_t ino; 54917954Smckusick char *cp; 55039973Smckusick struct dinode *dp; 55139973Smckusick register struct bufarea *bp; 552*54604Smckusick struct dirtemplate *dirp; 55317954Smckusick 55436827Smckusick ino = allocino(request, IFDIR|mode); 555*54604Smckusick if (newinofmt) 556*54604Smckusick dirp = &dirhead; 557*54604Smckusick else 558*54604Smckusick dirp = (struct dirtemplate *)&odirhead; 559*54604Smckusick dirp->dot_ino = ino; 560*54604Smckusick dirp->dotdot_ino = parent; 56117954Smckusick dp = ginode(ino); 56234225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 56338375Smckusick if (bp->b_errs) { 56417954Smckusick freeino(ino); 56517954Smckusick return (0); 56617954Smckusick } 567*54604Smckusick bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); 56834225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 56934225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 57017954Smckusick cp += DIRBLKSIZ) 57117954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 57234225Smckusick dirty(bp); 57317954Smckusick dp->di_nlink = 2; 57417954Smckusick inodirty(); 57517954Smckusick if (ino == ROOTINO) { 57617954Smckusick lncntp[ino] = dp->di_nlink; 57750573Smckusick cacheino(dp, ino); 57817954Smckusick return(ino); 57917954Smckusick } 58017954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 58117954Smckusick freeino(ino); 58217954Smckusick return (0); 58317954Smckusick } 58450573Smckusick cacheino(dp, ino); 58517954Smckusick statemap[ino] = statemap[parent]; 58617954Smckusick if (statemap[ino] == DSTATE) { 58717954Smckusick lncntp[ino] = dp->di_nlink; 58817954Smckusick lncntp[parent]++; 58917954Smckusick } 59017954Smckusick dp = ginode(parent); 59117954Smckusick dp->di_nlink++; 59217954Smckusick inodirty(); 59317954Smckusick return (ino); 59417954Smckusick } 59517954Smckusick 59617954Smckusick /* 59717954Smckusick * free a directory inode 59817954Smckusick */ 59917954Smckusick freedir(ino, parent) 60017954Smckusick ino_t ino, parent; 60117954Smckusick { 60239973Smckusick struct dinode *dp; 60317954Smckusick 60417954Smckusick if (ino != parent) { 60517954Smckusick dp = ginode(parent); 60617954Smckusick dp->di_nlink--; 60717954Smckusick inodirty(); 60817954Smckusick } 60917954Smckusick freeino(ino); 61017954Smckusick } 61117954Smckusick 61217954Smckusick /* 61316259Smckusick * generate a temporary name for the lost+found directory. 61416259Smckusick */ 61516259Smckusick lftempname(bufp, ino) 61616259Smckusick char *bufp; 61716259Smckusick ino_t ino; 61816259Smckusick { 61916259Smckusick register ino_t in; 62016259Smckusick register char *cp; 62116259Smckusick int namlen; 62216259Smckusick 62316259Smckusick cp = bufp + 2; 62439973Smckusick for (in = maxino; in > 0; in /= 10) 62516259Smckusick cp++; 62616259Smckusick *--cp = 0; 62716259Smckusick namlen = cp - bufp; 62816259Smckusick in = ino; 62916259Smckusick while (cp > bufp) { 63016259Smckusick *--cp = (in % 10) + '0'; 63116259Smckusick in /= 10; 63216259Smckusick } 63316259Smckusick *cp = '#'; 63416259Smckusick return (namlen); 63516259Smckusick } 63634225Smckusick 63734225Smckusick /* 63834225Smckusick * Get a directory block. 63934225Smckusick * Insure that it is held until another is requested. 64034225Smckusick */ 64139973Smckusick struct bufarea * 64234225Smckusick getdirblk(blkno, size) 64334225Smckusick daddr_t blkno; 64434225Smckusick long size; 64534225Smckusick { 64634225Smckusick 64740648Smckusick if (pdirbp != 0) 64840648Smckusick pdirbp->b_flags &= ~B_INUSE; 64940648Smckusick pdirbp = getdatablk(blkno, size); 65040648Smckusick return (pdirbp); 65134225Smckusick } 652