122045Sdist /* 239976Smckusick * Copyright (c) 1980, 1986 The Regents of the University of California. 339976Smckusick * All rights reserved. 439976Smckusick * 539976Smckusick * Redistribution and use in source and binary forms are permitted 639976Smckusick * provided that the above copyright notice and this paragraph are 739976Smckusick * duplicated in all such forms and that any documentation, 839976Smckusick * advertising materials, and other materials related to such 939976Smckusick * distribution and use acknowledge that the software was developed 1039976Smckusick * by the University of California, Berkeley. The name of the 1139976Smckusick * University may not be used to endorse or promote products derived 1239976Smckusick * from this software without specific prior written permission. 1339976Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439976Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539976Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622045Sdist */ 1722045Sdist 1816259Smckusick #ifndef lint 19*41133Smckusick static char sccsid[] = "@(#)dir.c 5.16 (Berkeley) 04/29/90"; 2039976Smckusick #endif /* not lint */ 2116259Smckusick 2216259Smckusick #include <sys/param.h> 2339383Smckusick #include <ufs/dinode.h> 2438336Smckusick #include <ufs/fs.h> 2516259Smckusick #define KERNEL 2638336Smckusick #include <ufs/dir.h> 2716259Smckusick #undef KERNEL 2816259Smckusick #include "fsck.h" 2916259Smckusick 3016259Smckusick char *lfname = "lost+found"; 3136827Smckusick int lfmode = 01777; 3217944Smckusick struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 3317954Smckusick struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." }; 3416259Smckusick 3539973Smckusick struct direct *fsck_readdir(); 3639973Smckusick struct bufarea *getdirblk(); 3716259Smckusick 3840022Smckusick /* 3940022Smckusick * Propagate connected state through the tree. 4040022Smckusick */ 4140022Smckusick propagate() 4216259Smckusick { 4340022Smckusick register struct inoinfo **inpp, *inp; 4440022Smckusick struct inoinfo **inpend; 4540022Smckusick long change; 4616259Smckusick 4740022Smckusick inpend = &inpsort[inplast]; 4840022Smckusick do { 4940022Smckusick change = 0; 5040022Smckusick for (inpp = inpsort; inpp < inpend; inpp++) { 5140022Smckusick inp = *inpp; 5240022Smckusick if (inp->i_parent == 0) 5340022Smckusick continue; 5440022Smckusick if (statemap[inp->i_parent] == DFOUND && 5540022Smckusick statemap[inp->i_number] == DSTATE) { 5640022Smckusick statemap[inp->i_number] = DFOUND; 5740022Smckusick change++; 5840022Smckusick } 5939980Smckusick } 6040022Smckusick } while (change > 0); 6116259Smckusick } 6216259Smckusick 6340022Smckusick /* 6440022Smckusick * Scan each entry in a directory block. 6540022Smckusick */ 6616259Smckusick dirscan(idesc) 6716259Smckusick register struct inodesc *idesc; 6816259Smckusick { 6939973Smckusick register struct direct *dp; 7039973Smckusick register struct bufarea *bp; 7116259Smckusick int dsize, n; 7216259Smckusick long blksiz; 7316259Smckusick char dbuf[DIRBLKSIZ]; 7416259Smckusick 7516259Smckusick if (idesc->id_type != DATA) 7616259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 7717993Smckusick if (idesc->id_entryno == 0 && 7817993Smckusick (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 7917993Smckusick idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 8016259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 8139973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 8216259Smckusick idesc->id_filesize -= blksiz; 8316259Smckusick return (SKIP); 8416259Smckusick } 8516259Smckusick idesc->id_loc = 0; 8616259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 8716259Smckusick dsize = dp->d_reclen; 8816259Smckusick bcopy((char *)dp, dbuf, dsize); 8939973Smckusick idesc->id_dirp = (struct direct *)dbuf; 9016259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 9134225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 9240570Smckusick bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, 9340570Smckusick dsize); 9434225Smckusick dirty(bp); 9530354Smckusick sbdirty(); 9616259Smckusick } 9716259Smckusick if (n & STOP) 9816259Smckusick return (n); 9916259Smckusick } 10016259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 10116259Smckusick } 10216259Smckusick 10316259Smckusick /* 10416259Smckusick * get next entry in a directory. 10516259Smckusick */ 10639973Smckusick struct direct * 10716259Smckusick fsck_readdir(idesc) 10816259Smckusick register struct inodesc *idesc; 10916259Smckusick { 11039973Smckusick register struct direct *dp, *ndp; 11139973Smckusick register struct bufarea *bp; 11240570Smckusick long size, blksiz, fix; 11316259Smckusick 11416259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 11534225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 11616259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 11716259Smckusick idesc->id_loc < blksiz) { 11839973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 11916259Smckusick if (dircheck(idesc, dp)) 12016259Smckusick goto dpok; 12116259Smckusick idesc->id_loc += DIRBLKSIZ; 12216259Smckusick idesc->id_filesize -= DIRBLKSIZ; 12340570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 12440570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 12540570Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 12616259Smckusick dp->d_reclen = DIRBLKSIZ; 12716259Smckusick dp->d_ino = 0; 12816259Smckusick dp->d_namlen = 0; 12916259Smckusick dp->d_name[0] = '\0'; 13040570Smckusick if (fix) 13134225Smckusick dirty(bp); 13216259Smckusick return (dp); 13316259Smckusick } 13416259Smckusick dpok: 13516259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 13616259Smckusick return NULL; 13739973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 13816259Smckusick idesc->id_loc += dp->d_reclen; 13916259Smckusick idesc->id_filesize -= dp->d_reclen; 14016259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 14116259Smckusick return (dp); 14239973Smckusick ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 14316259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 14416259Smckusick dircheck(idesc, ndp) == 0) { 14516259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 14616259Smckusick idesc->id_loc += size; 14716259Smckusick idesc->id_filesize -= size; 14840570Smckusick fix = dofix(idesc, "DIRECTORY CORRUPTED"); 14940570Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 15040570Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 15140570Smckusick dp->d_reclen += size; 15240570Smckusick if (fix) 15334225Smckusick dirty(bp); 15416259Smckusick } 15516259Smckusick return (dp); 15616259Smckusick } 15716259Smckusick 15816259Smckusick /* 15916259Smckusick * Verify that a directory entry is valid. 16016259Smckusick * This is a superset of the checks made in the kernel. 16116259Smckusick */ 16216259Smckusick dircheck(idesc, dp) 16316259Smckusick struct inodesc *idesc; 16439973Smckusick register struct direct *dp; 16516259Smckusick { 16616259Smckusick register int size; 16716259Smckusick register char *cp; 16816259Smckusick int spaceleft; 16916259Smckusick 17016259Smckusick size = DIRSIZ(dp); 17116259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 17239973Smckusick if (dp->d_ino < maxino && 17316259Smckusick dp->d_reclen != 0 && 17416259Smckusick dp->d_reclen <= spaceleft && 17516259Smckusick (dp->d_reclen & 0x3) == 0 && 17616259Smckusick dp->d_reclen >= size && 17716259Smckusick idesc->id_filesize >= size && 17816259Smckusick dp->d_namlen <= MAXNAMLEN) { 17916259Smckusick if (dp->d_ino == 0) 18016259Smckusick return (1); 18116259Smckusick for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 18240651Smckusick if (*cp == 0 || (*cp++ == '/')) 18316259Smckusick return (0); 18416259Smckusick if (*cp == 0) 18516259Smckusick return (1); 18616259Smckusick } 18716259Smckusick return (0); 18816259Smckusick } 18916259Smckusick 19039973Smckusick direrror(ino, errmesg) 19116259Smckusick ino_t ino; 19239973Smckusick char *errmesg; 19316259Smckusick { 19440022Smckusick 19540022Smckusick fileerror(ino, ino, errmesg); 19640022Smckusick } 19740022Smckusick 19840022Smckusick fileerror(cwd, ino, errmesg) 19940022Smckusick ino_t cwd, ino; 20040022Smckusick char *errmesg; 20140022Smckusick { 20239973Smckusick register struct dinode *dp; 20340022Smckusick char pathbuf[MAXPATHLEN + 1]; 20416259Smckusick 20539973Smckusick pwarn("%s ", errmesg); 20616259Smckusick pinode(ino); 20716259Smckusick printf("\n"); 20840022Smckusick getpathname(pathbuf, cwd, ino); 20939973Smckusick if (ino < ROOTINO || ino > maxino) { 21040022Smckusick pfatal("NAME=%s\n", pathbuf); 21117943Smckusick return; 21217943Smckusick } 21317943Smckusick dp = ginode(ino); 21417943Smckusick if (ftypeok(dp)) 21539973Smckusick pfatal("%s=%s\n", 21640022Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 21716259Smckusick else 21840022Smckusick pfatal("NAME=%s\n", pathbuf); 21916259Smckusick } 22016259Smckusick 22116259Smckusick adjust(idesc, lcnt) 22216259Smckusick register struct inodesc *idesc; 22316259Smckusick short lcnt; 22416259Smckusick { 22539973Smckusick register struct dinode *dp; 22616259Smckusick 22717943Smckusick dp = ginode(idesc->id_number); 22816259Smckusick if (dp->di_nlink == lcnt) { 22916259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 23016259Smckusick clri(idesc, "UNREF", 0); 23117936Smckusick } else { 23217930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 23339973Smckusick ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 23416259Smckusick pinode(idesc->id_number); 23516259Smckusick printf(" COUNT %d SHOULD BE %d", 23639973Smckusick dp->di_nlink, dp->di_nlink - lcnt); 23716259Smckusick if (preen) { 23816259Smckusick if (lcnt < 0) { 23916259Smckusick printf("\n"); 24017930Smckusick pfatal("LINK COUNT INCREASING"); 24116259Smckusick } 24216259Smckusick printf(" (ADJUSTED)\n"); 24316259Smckusick } 24416259Smckusick if (preen || reply("ADJUST") == 1) { 24516259Smckusick dp->di_nlink -= lcnt; 24616259Smckusick inodirty(); 24716259Smckusick } 24816259Smckusick } 24916259Smckusick } 25016259Smckusick 25116259Smckusick mkentry(idesc) 25216259Smckusick struct inodesc *idesc; 25316259Smckusick { 25439973Smckusick register struct direct *dirp = idesc->id_dirp; 25539973Smckusick struct direct newent; 25616259Smckusick int newlen, oldlen; 25716259Smckusick 25840022Smckusick newent.d_namlen = strlen(idesc->id_name); 25916259Smckusick newlen = DIRSIZ(&newent); 26016259Smckusick if (dirp->d_ino != 0) 26116259Smckusick oldlen = DIRSIZ(dirp); 26216259Smckusick else 26316259Smckusick oldlen = 0; 26416259Smckusick if (dirp->d_reclen - oldlen < newlen) 26516259Smckusick return (KEEPON); 26616259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 26716259Smckusick dirp->d_reclen = oldlen; 26816259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 26916259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 27016259Smckusick dirp->d_reclen = newent.d_reclen; 27140022Smckusick dirp->d_namlen = newent.d_namlen; 27239973Smckusick bcopy(idesc->id_name, dirp->d_name, (int)dirp->d_namlen + 1); 27316259Smckusick return (ALTERED|STOP); 27416259Smckusick } 27516259Smckusick 27617957Smckusick chgino(idesc) 27716259Smckusick struct inodesc *idesc; 27816259Smckusick { 27939973Smckusick register struct direct *dirp = idesc->id_dirp; 28016259Smckusick 28139973Smckusick if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 28217957Smckusick return (KEEPON); 28339973Smckusick dirp->d_ino = idesc->id_parent; 28417957Smckusick return (ALTERED|STOP); 28516259Smckusick } 28616259Smckusick 28739973Smckusick linkup(orphan, parentdir) 28816259Smckusick ino_t orphan; 28939973Smckusick ino_t parentdir; 29016259Smckusick { 29139973Smckusick register struct dinode *dp; 29240022Smckusick int lostdir; 29317954Smckusick ino_t oldlfdir; 29416259Smckusick struct inodesc idesc; 29517954Smckusick char tempname[BUFSIZ]; 29617957Smckusick extern int pass4check(); 29716259Smckusick 29816259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 29917943Smckusick dp = ginode(orphan); 30039973Smckusick lostdir = (dp->di_mode & IFMT) == IFDIR; 30116259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 30216259Smckusick pinode(orphan); 30316259Smckusick if (preen && dp->di_size == 0) 30416259Smckusick return (0); 30516259Smckusick if (preen) 30616259Smckusick printf(" (RECONNECTED)\n"); 30716259Smckusick else 30816259Smckusick if (reply("RECONNECT") == 0) 30916259Smckusick return (0); 31016259Smckusick if (lfdir == 0) { 31117943Smckusick dp = ginode(ROOTINO); 31217930Smckusick idesc.id_name = lfname; 31316259Smckusick idesc.id_type = DATA; 31416259Smckusick idesc.id_func = findino; 31516259Smckusick idesc.id_number = ROOTINO; 31630354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 31717954Smckusick lfdir = idesc.id_parent; 31817954Smckusick } else { 31917954Smckusick pwarn("NO lost+found DIRECTORY"); 32017954Smckusick if (preen || reply("CREATE")) { 32139973Smckusick lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 32217992Smckusick if (lfdir != 0) { 32317992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 32417954Smckusick if (preen) 32517954Smckusick printf(" (CREATED)\n"); 32617954Smckusick } else { 32717992Smckusick freedir(lfdir, ROOTINO); 32817992Smckusick lfdir = 0; 32917954Smckusick if (preen) 33017954Smckusick printf("\n"); 33117954Smckusick } 33217954Smckusick } 33317954Smckusick } 33417954Smckusick } 33517943Smckusick if (lfdir == 0) { 33617954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 33716259Smckusick printf("\n\n"); 33816259Smckusick return (0); 33916259Smckusick } 34016259Smckusick } 34117943Smckusick dp = ginode(lfdir); 34239973Smckusick if ((dp->di_mode & IFMT) != IFDIR) { 34317957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 34417957Smckusick if (reply("REALLOCATE") == 0) 34517957Smckusick return (0); 34617957Smckusick oldlfdir = lfdir; 34739973Smckusick if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 34817957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 34917957Smckusick return (0); 35017957Smckusick } 35140022Smckusick if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 35217957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 35317957Smckusick return (0); 35417957Smckusick } 35517957Smckusick inodirty(); 35617957Smckusick idesc.id_type = ADDR; 35717957Smckusick idesc.id_func = pass4check; 35817957Smckusick idesc.id_number = oldlfdir; 35917957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 36017957Smckusick lncntp[oldlfdir] = 0; 36117957Smckusick dp = ginode(lfdir); 36217957Smckusick } 36317957Smckusick if (statemap[lfdir] != DFOUND) { 36417957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 36516259Smckusick return (0); 36616259Smckusick } 36740022Smckusick (void)lftempname(tempname, orphan); 36817992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 36916259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 37016259Smckusick printf("\n\n"); 37116259Smckusick return (0); 37216259Smckusick } 37316259Smckusick lncntp[orphan]--; 37416259Smckusick if (lostdir) { 37540022Smckusick if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 37640022Smckusick parentdir != (ino_t)-1) 37740022Smckusick makeentry(orphan, lfdir, ".."); 37817943Smckusick dp = ginode(lfdir); 37917943Smckusick dp->di_nlink++; 38017943Smckusick inodirty(); 38117943Smckusick lncntp[lfdir]++; 38216259Smckusick pwarn("DIR I=%u CONNECTED. ", orphan); 38340022Smckusick if (parentdir != (ino_t)-1) 38440022Smckusick printf("PARENT WAS I=%u\n", parentdir); 38516259Smckusick if (preen == 0) 38616259Smckusick printf("\n"); 38716259Smckusick } 38816259Smckusick return (1); 38916259Smckusick } 39016259Smckusick 39116259Smckusick /* 39240022Smckusick * fix an entry in a directory. 39340022Smckusick */ 39440022Smckusick changeino(dir, name, newnum) 39540022Smckusick ino_t dir; 39640022Smckusick char *name; 39740022Smckusick ino_t newnum; 39840022Smckusick { 39940022Smckusick struct inodesc idesc; 40040022Smckusick 40140022Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 40240022Smckusick idesc.id_type = DATA; 40340022Smckusick idesc.id_func = chgino; 40440022Smckusick idesc.id_number = dir; 40540022Smckusick idesc.id_fix = DONTKNOW; 40640022Smckusick idesc.id_name = name; 40740022Smckusick idesc.id_parent = newnum; /* new value for name */ 40840022Smckusick return (ckinode(ginode(dir), &idesc)); 40940022Smckusick } 41040022Smckusick 41140022Smckusick /* 41217944Smckusick * make an entry in a directory 41317944Smckusick */ 41417992Smckusick makeentry(parent, ino, name) 41517992Smckusick ino_t parent, ino; 41617992Smckusick char *name; 41717992Smckusick { 41839973Smckusick struct dinode *dp; 41917992Smckusick struct inodesc idesc; 42040022Smckusick char pathbuf[MAXPATHLEN + 1]; 42117944Smckusick 42239973Smckusick if (parent < ROOTINO || parent >= maxino || 42339973Smckusick ino < ROOTINO || ino >= maxino) 42417992Smckusick return (0); 42539973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 42617992Smckusick idesc.id_type = DATA; 42717992Smckusick idesc.id_func = mkentry; 42817992Smckusick idesc.id_number = parent; 42917992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 43017992Smckusick idesc.id_fix = DONTKNOW; 43117992Smckusick idesc.id_name = name; 43217992Smckusick dp = ginode(parent); 43317993Smckusick if (dp->di_size % DIRBLKSIZ) { 43417993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 43517993Smckusick inodirty(); 43617993Smckusick } 43717992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 43817944Smckusick return (1); 43940022Smckusick getpathname(pathbuf, parent, parent); 44040022Smckusick dp = ginode(parent); 44140022Smckusick if (expanddir(dp, pathbuf) == 0) 44217944Smckusick return (0); 44317992Smckusick return (ckinode(dp, &idesc) & ALTERED); 44417944Smckusick } 44517944Smckusick 44617944Smckusick /* 44717944Smckusick * Attempt to expand the size of a directory 44817944Smckusick */ 44940022Smckusick expanddir(dp, name) 45039973Smckusick register struct dinode *dp; 45140022Smckusick char *name; 45217944Smckusick { 45317944Smckusick daddr_t lastbn, newblk; 45439973Smckusick register struct bufarea *bp; 45517944Smckusick char *cp, firstblk[DIRBLKSIZ]; 45617944Smckusick 45717944Smckusick lastbn = lblkno(&sblock, dp->di_size); 458*41133Smckusick if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 45917944Smckusick return (0); 46017944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 46117944Smckusick return (0); 46217944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 46317944Smckusick dp->di_db[lastbn] = newblk; 46417944Smckusick dp->di_size += sblock.fs_bsize; 46517944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 46634225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 46734225Smckusick dblksize(&sblock, dp, lastbn + 1)); 46838375Smckusick if (bp->b_errs) 46917944Smckusick goto bad; 47034225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 47134225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 47238375Smckusick if (bp->b_errs) 47317944Smckusick goto bad; 47434225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 47534225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 47634225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 47717944Smckusick cp += DIRBLKSIZ) 47817944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 47934225Smckusick dirty(bp); 48034225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 48134225Smckusick dblksize(&sblock, dp, lastbn + 1)); 48238375Smckusick if (bp->b_errs) 48317944Smckusick goto bad; 48434225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 48540022Smckusick pwarn("NO SPACE LEFT IN %s", name); 48617944Smckusick if (preen) 48717944Smckusick printf(" (EXPANDED)\n"); 48817944Smckusick else if (reply("EXPAND") == 0) 48917944Smckusick goto bad; 49034225Smckusick dirty(bp); 49117944Smckusick inodirty(); 49217944Smckusick return (1); 49317944Smckusick bad: 49417944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 49517944Smckusick dp->di_db[lastbn + 1] = 0; 49617944Smckusick dp->di_size -= sblock.fs_bsize; 49717944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 49817944Smckusick freeblk(newblk, sblock.fs_frag); 49917944Smckusick return (0); 50017944Smckusick } 50117944Smckusick 50217944Smckusick /* 50317954Smckusick * allocate a new directory 50417954Smckusick */ 50536827Smckusick allocdir(parent, request, mode) 50617954Smckusick ino_t parent, request; 50736827Smckusick int mode; 50817954Smckusick { 50917954Smckusick ino_t ino; 51017954Smckusick char *cp; 51139973Smckusick struct dinode *dp; 51239973Smckusick register struct bufarea *bp; 51317954Smckusick 51436827Smckusick ino = allocino(request, IFDIR|mode); 51517954Smckusick dirhead.dot_ino = ino; 51617954Smckusick dirhead.dotdot_ino = parent; 51717954Smckusick dp = ginode(ino); 51834225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 51938375Smckusick if (bp->b_errs) { 52017954Smckusick freeino(ino); 52117954Smckusick return (0); 52217954Smckusick } 52334225Smckusick bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead); 52434225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 52534225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 52617954Smckusick cp += DIRBLKSIZ) 52717954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 52834225Smckusick dirty(bp); 52917954Smckusick dp->di_nlink = 2; 53017954Smckusick inodirty(); 53117954Smckusick if (ino == ROOTINO) { 53217954Smckusick lncntp[ino] = dp->di_nlink; 53317954Smckusick return(ino); 53417954Smckusick } 53517954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 53617954Smckusick freeino(ino); 53717954Smckusick return (0); 53817954Smckusick } 53917954Smckusick statemap[ino] = statemap[parent]; 54017954Smckusick if (statemap[ino] == DSTATE) { 54117954Smckusick lncntp[ino] = dp->di_nlink; 54217954Smckusick lncntp[parent]++; 54317954Smckusick } 54417954Smckusick dp = ginode(parent); 54517954Smckusick dp->di_nlink++; 54617954Smckusick inodirty(); 54717954Smckusick return (ino); 54817954Smckusick } 54917954Smckusick 55017954Smckusick /* 55117954Smckusick * free a directory inode 55217954Smckusick */ 55317954Smckusick freedir(ino, parent) 55417954Smckusick ino_t ino, parent; 55517954Smckusick { 55639973Smckusick struct dinode *dp; 55717954Smckusick 55817954Smckusick if (ino != parent) { 55917954Smckusick dp = ginode(parent); 56017954Smckusick dp->di_nlink--; 56117954Smckusick inodirty(); 56217954Smckusick } 56317954Smckusick freeino(ino); 56417954Smckusick } 56517954Smckusick 56617954Smckusick /* 56716259Smckusick * generate a temporary name for the lost+found directory. 56816259Smckusick */ 56916259Smckusick lftempname(bufp, ino) 57016259Smckusick char *bufp; 57116259Smckusick ino_t ino; 57216259Smckusick { 57316259Smckusick register ino_t in; 57416259Smckusick register char *cp; 57516259Smckusick int namlen; 57616259Smckusick 57716259Smckusick cp = bufp + 2; 57839973Smckusick for (in = maxino; in > 0; in /= 10) 57916259Smckusick cp++; 58016259Smckusick *--cp = 0; 58116259Smckusick namlen = cp - bufp; 58216259Smckusick in = ino; 58316259Smckusick while (cp > bufp) { 58416259Smckusick *--cp = (in % 10) + '0'; 58516259Smckusick in /= 10; 58616259Smckusick } 58716259Smckusick *cp = '#'; 58816259Smckusick return (namlen); 58916259Smckusick } 59034225Smckusick 59134225Smckusick /* 59234225Smckusick * Get a directory block. 59334225Smckusick * Insure that it is held until another is requested. 59434225Smckusick */ 59539973Smckusick struct bufarea * 59634225Smckusick getdirblk(blkno, size) 59734225Smckusick daddr_t blkno; 59834225Smckusick long size; 59934225Smckusick { 60034225Smckusick 60140648Smckusick if (pdirbp != 0) 60240648Smckusick pdirbp->b_flags &= ~B_INUSE; 60340648Smckusick pdirbp = getdatablk(blkno, size); 60440648Smckusick return (pdirbp); 60534225Smckusick } 606