122045Sdist /* 222045Sdist * Copyright (c) 1980 Regents of the University of California. 322045Sdist * All rights reserved. The Berkeley software License Agreement 422045Sdist * specifies the terms and conditions for redistribution. 522045Sdist */ 622045Sdist 716259Smckusick #ifndef lint 8*34225Smckusick static char sccsid[] = "@(#)dir.c 5.4 (Berkeley) 05/07/88"; 922045Sdist #endif not lint 1016259Smckusick 1116259Smckusick #include <sys/param.h> 1216259Smckusick #include <sys/inode.h> 1316259Smckusick #include <sys/fs.h> 1416259Smckusick #define KERNEL 1516259Smckusick #include <sys/dir.h> 1616259Smckusick #undef KERNEL 1716259Smckusick #include "fsck.h" 1816259Smckusick 1916259Smckusick #define MINDIRSIZE (sizeof (struct dirtemplate)) 2016259Smckusick 2116259Smckusick char *endpathname = &pathname[BUFSIZ - 2]; 2216259Smckusick char *lfname = "lost+found"; 2317944Smckusick struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 2417954Smckusick struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." }; 2516259Smckusick 2616259Smckusick DIRECT *fsck_readdir(); 27*34225Smckusick BUFAREA *getdirblk(); 2816259Smckusick 2916259Smckusick descend(parentino, inumber) 3016259Smckusick struct inodesc *parentino; 3116259Smckusick ino_t inumber; 3216259Smckusick { 3316259Smckusick register DINODE *dp; 3416259Smckusick struct inodesc curino; 3516259Smckusick 3616259Smckusick bzero((char *)&curino, sizeof(struct inodesc)); 3717936Smckusick if (statemap[inumber] != DSTATE) 3817936Smckusick errexit("BAD INODE %d TO DESCEND", statemap[inumber]); 3917936Smckusick statemap[inumber] = DFOUND; 4017943Smckusick dp = ginode(inumber); 4116259Smckusick if (dp->di_size == 0) { 4216259Smckusick direrr(inumber, "ZERO LENGTH DIRECTORY"); 4316259Smckusick if (reply("REMOVE") == 1) 4417936Smckusick statemap[inumber] = DCLEAR; 4516259Smckusick return; 4616259Smckusick } 4716259Smckusick if (dp->di_size < MINDIRSIZE) { 4816259Smckusick direrr(inumber, "DIRECTORY TOO SHORT"); 4916259Smckusick dp->di_size = MINDIRSIZE; 5016259Smckusick if (reply("FIX") == 1) 5116259Smckusick inodirty(); 5216259Smckusick } 5321742Smckusick if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) { 5421742Smckusick pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d", 5521742Smckusick pathname, dp->di_size, DIRBLKSIZ); 5621742Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5721742Smckusick if (preen) 5821742Smckusick printf(" (ADJUSTED)\n"); 5921742Smckusick if (preen || reply("ADJUST") == 1) 6021742Smckusick inodirty(); 6121742Smckusick } 6216259Smckusick curino.id_type = DATA; 6316259Smckusick curino.id_func = parentino->id_func; 6416259Smckusick curino.id_parent = parentino->id_number; 6516259Smckusick curino.id_number = inumber; 6616259Smckusick (void)ckinode(dp, &curino); 6730354Smckusick if (curino.id_entryno < 2) { 6830354Smckusick direrr(inumber, "NULL DIRECTORY"); 6930354Smckusick if (reply("REMOVE") == 1) 7030354Smckusick statemap[inumber] = DCLEAR; 7130354Smckusick } 7216259Smckusick } 7316259Smckusick 7416259Smckusick dirscan(idesc) 7516259Smckusick register struct inodesc *idesc; 7616259Smckusick { 7716259Smckusick register DIRECT *dp; 78*34225Smckusick register BUFAREA *bp; 7916259Smckusick int dsize, n; 8016259Smckusick long blksiz; 8116259Smckusick char dbuf[DIRBLKSIZ]; 8216259Smckusick 8316259Smckusick if (idesc->id_type != DATA) 8416259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 8517993Smckusick if (idesc->id_entryno == 0 && 8617993Smckusick (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 8717993Smckusick idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 8816259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 8916259Smckusick if (outrange(idesc->id_blkno, idesc->id_numfrags)) { 9016259Smckusick idesc->id_filesize -= blksiz; 9116259Smckusick return (SKIP); 9216259Smckusick } 9316259Smckusick idesc->id_loc = 0; 9416259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 9516259Smckusick dsize = dp->d_reclen; 9616259Smckusick bcopy((char *)dp, dbuf, dsize); 9716259Smckusick idesc->id_dirp = (DIRECT *)dbuf; 9816259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 99*34225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 10030354Smckusick bcopy(dbuf, (char *)dp, dsize); 101*34225Smckusick dirty(bp); 10230354Smckusick sbdirty(); 10316259Smckusick } 10416259Smckusick if (n & STOP) 10516259Smckusick return (n); 10616259Smckusick } 10716259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 10816259Smckusick } 10916259Smckusick 11016259Smckusick /* 11116259Smckusick * get next entry in a directory. 11216259Smckusick */ 11316259Smckusick DIRECT * 11416259Smckusick fsck_readdir(idesc) 11516259Smckusick register struct inodesc *idesc; 11616259Smckusick { 11716259Smckusick register DIRECT *dp, *ndp; 118*34225Smckusick register BUFAREA *bp; 11916259Smckusick long size, blksiz; 12016259Smckusick 12116259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 122*34225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 12316259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 12416259Smckusick idesc->id_loc < blksiz) { 125*34225Smckusick dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); 12616259Smckusick if (dircheck(idesc, dp)) 12716259Smckusick goto dpok; 12816259Smckusick idesc->id_loc += DIRBLKSIZ; 12916259Smckusick idesc->id_filesize -= DIRBLKSIZ; 13016259Smckusick dp->d_reclen = DIRBLKSIZ; 13116259Smckusick dp->d_ino = 0; 13216259Smckusick dp->d_namlen = 0; 13316259Smckusick dp->d_name[0] = '\0'; 13417930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 135*34225Smckusick dirty(bp); 13616259Smckusick return (dp); 13716259Smckusick } 13816259Smckusick dpok: 13916259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 14016259Smckusick return NULL; 141*34225Smckusick dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); 14216259Smckusick idesc->id_loc += dp->d_reclen; 14316259Smckusick idesc->id_filesize -= dp->d_reclen; 14416259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 14516259Smckusick return (dp); 146*34225Smckusick ndp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc); 14716259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 14816259Smckusick dircheck(idesc, ndp) == 0) { 14916259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 15016259Smckusick dp->d_reclen += size; 15116259Smckusick idesc->id_loc += size; 15216259Smckusick idesc->id_filesize -= size; 15317930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 154*34225Smckusick dirty(bp); 15516259Smckusick } 15616259Smckusick return (dp); 15716259Smckusick } 15816259Smckusick 15916259Smckusick /* 16016259Smckusick * Verify that a directory entry is valid. 16116259Smckusick * This is a superset of the checks made in the kernel. 16216259Smckusick */ 16316259Smckusick dircheck(idesc, dp) 16416259Smckusick struct inodesc *idesc; 16516259Smckusick register DIRECT *dp; 16616259Smckusick { 16716259Smckusick register int size; 16816259Smckusick register char *cp; 16916259Smckusick int spaceleft; 17016259Smckusick 17116259Smckusick size = DIRSIZ(dp); 17216259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 17316259Smckusick if (dp->d_ino < imax && 17416259Smckusick dp->d_reclen != 0 && 17516259Smckusick dp->d_reclen <= spaceleft && 17616259Smckusick (dp->d_reclen & 0x3) == 0 && 17716259Smckusick dp->d_reclen >= size && 17816259Smckusick idesc->id_filesize >= size && 17916259Smckusick dp->d_namlen <= MAXNAMLEN) { 18016259Smckusick if (dp->d_ino == 0) 18116259Smckusick return (1); 18216259Smckusick for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 18316259Smckusick if (*cp == 0 || (*cp++ & 0200)) 18416259Smckusick return (0); 18516259Smckusick if (*cp == 0) 18616259Smckusick return (1); 18716259Smckusick } 18816259Smckusick return (0); 18916259Smckusick } 19016259Smckusick 19116259Smckusick direrr(ino, s) 19216259Smckusick ino_t ino; 19316259Smckusick char *s; 19416259Smckusick { 19516259Smckusick register DINODE *dp; 19616259Smckusick 19716259Smckusick pwarn("%s ", s); 19816259Smckusick pinode(ino); 19916259Smckusick printf("\n"); 20017943Smckusick if (ino < ROOTINO || ino > imax) { 20117943Smckusick pfatal("NAME=%s\n", pathname); 20217943Smckusick return; 20317943Smckusick } 20417943Smckusick dp = ginode(ino); 20517943Smckusick if (ftypeok(dp)) 20617930Smckusick pfatal("%s=%s\n", DIRCT(dp) ? "DIR" : "FILE", pathname); 20716259Smckusick else 20816259Smckusick pfatal("NAME=%s\n", pathname); 20916259Smckusick } 21016259Smckusick 21116259Smckusick adjust(idesc, lcnt) 21216259Smckusick register struct inodesc *idesc; 21316259Smckusick short lcnt; 21416259Smckusick { 21516259Smckusick register DINODE *dp; 21616259Smckusick 21717943Smckusick dp = ginode(idesc->id_number); 21816259Smckusick if (dp->di_nlink == lcnt) { 21916259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 22016259Smckusick clri(idesc, "UNREF", 0); 22117936Smckusick } else { 22217930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 22317930Smckusick (DIRCT(dp) ? "DIR" : "FILE")); 22416259Smckusick pinode(idesc->id_number); 22516259Smckusick printf(" COUNT %d SHOULD BE %d", 22616259Smckusick dp->di_nlink, dp->di_nlink-lcnt); 22716259Smckusick if (preen) { 22816259Smckusick if (lcnt < 0) { 22916259Smckusick printf("\n"); 23017930Smckusick pfatal("LINK COUNT INCREASING"); 23116259Smckusick } 23216259Smckusick printf(" (ADJUSTED)\n"); 23316259Smckusick } 23416259Smckusick if (preen || reply("ADJUST") == 1) { 23516259Smckusick dp->di_nlink -= lcnt; 23616259Smckusick inodirty(); 23716259Smckusick } 23816259Smckusick } 23916259Smckusick } 24016259Smckusick 24116259Smckusick mkentry(idesc) 24216259Smckusick struct inodesc *idesc; 24316259Smckusick { 24416259Smckusick register DIRECT *dirp = idesc->id_dirp; 24516259Smckusick DIRECT newent; 24616259Smckusick int newlen, oldlen; 24716259Smckusick 24816259Smckusick newent.d_namlen = 11; 24916259Smckusick newlen = DIRSIZ(&newent); 25016259Smckusick if (dirp->d_ino != 0) 25116259Smckusick oldlen = DIRSIZ(dirp); 25216259Smckusick else 25316259Smckusick oldlen = 0; 25416259Smckusick if (dirp->d_reclen - oldlen < newlen) 25516259Smckusick return (KEEPON); 25616259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 25716259Smckusick dirp->d_reclen = oldlen; 25816259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 25916259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 26016259Smckusick dirp->d_reclen = newent.d_reclen; 26117954Smckusick dirp->d_namlen = strlen(idesc->id_name); 26217954Smckusick bcopy(idesc->id_name, dirp->d_name, dirp->d_namlen + 1); 26316259Smckusick return (ALTERED|STOP); 26416259Smckusick } 26516259Smckusick 26617957Smckusick chgino(idesc) 26716259Smckusick struct inodesc *idesc; 26816259Smckusick { 26916259Smckusick register DIRECT *dirp = idesc->id_dirp; 27016259Smckusick 27117957Smckusick if (bcmp(dirp->d_name, idesc->id_name, dirp->d_namlen + 1)) 27217957Smckusick return (KEEPON); 27317957Smckusick dirp->d_ino = idesc->id_parent;; 27417957Smckusick return (ALTERED|STOP); 27516259Smckusick } 27616259Smckusick 27716259Smckusick linkup(orphan, pdir) 27816259Smckusick ino_t orphan; 27916259Smckusick ino_t pdir; 28016259Smckusick { 28116259Smckusick register DINODE *dp; 28216259Smckusick int lostdir, len; 28317954Smckusick ino_t oldlfdir; 28416259Smckusick struct inodesc idesc; 28517954Smckusick char tempname[BUFSIZ]; 28617957Smckusick extern int pass4check(); 28716259Smckusick 28816259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 28917943Smckusick dp = ginode(orphan); 29017930Smckusick lostdir = DIRCT(dp); 29116259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 29216259Smckusick pinode(orphan); 29316259Smckusick if (preen && dp->di_size == 0) 29416259Smckusick return (0); 29516259Smckusick if (preen) 29616259Smckusick printf(" (RECONNECTED)\n"); 29716259Smckusick else 29816259Smckusick if (reply("RECONNECT") == 0) 29916259Smckusick return (0); 30016259Smckusick pathp = pathname; 30116259Smckusick *pathp++ = '/'; 30216259Smckusick *pathp = '\0'; 30316259Smckusick if (lfdir == 0) { 30417943Smckusick dp = ginode(ROOTINO); 30517930Smckusick idesc.id_name = lfname; 30616259Smckusick idesc.id_type = DATA; 30716259Smckusick idesc.id_func = findino; 30816259Smckusick idesc.id_number = ROOTINO; 30930354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 31017954Smckusick lfdir = idesc.id_parent; 31117954Smckusick } else { 31217954Smckusick pwarn("NO lost+found DIRECTORY"); 31317954Smckusick if (preen || reply("CREATE")) { 31417992Smckusick lfdir = allocdir(ROOTINO, 0); 31517992Smckusick if (lfdir != 0) { 31617992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 31717954Smckusick if (preen) 31817954Smckusick printf(" (CREATED)\n"); 31917954Smckusick } else { 32017992Smckusick freedir(lfdir, ROOTINO); 32117992Smckusick lfdir = 0; 32217954Smckusick if (preen) 32317954Smckusick printf("\n"); 32417954Smckusick } 32517954Smckusick } 32617954Smckusick } 32717954Smckusick } 32817943Smckusick if (lfdir == 0) { 32917954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 33016259Smckusick printf("\n\n"); 33116259Smckusick return (0); 33216259Smckusick } 33316259Smckusick } 33417943Smckusick dp = ginode(lfdir); 33517957Smckusick if (!DIRCT(dp)) { 33617957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 33717957Smckusick if (reply("REALLOCATE") == 0) 33817957Smckusick return (0); 33917957Smckusick oldlfdir = lfdir; 34017957Smckusick if ((lfdir = allocdir(ROOTINO, 0)) == 0) { 34117957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 34217957Smckusick return (0); 34317957Smckusick } 34417957Smckusick idesc.id_type = DATA; 34517957Smckusick idesc.id_func = chgino; 34617957Smckusick idesc.id_number = ROOTINO; 34717957Smckusick idesc.id_parent = lfdir; /* new inumber for lost+found */ 34817957Smckusick idesc.id_name = lfname; 34917957Smckusick if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) { 35017957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 35117957Smckusick return (0); 35217957Smckusick } 35317957Smckusick inodirty(); 35417957Smckusick idesc.id_type = ADDR; 35517957Smckusick idesc.id_func = pass4check; 35617957Smckusick idesc.id_number = oldlfdir; 35717957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 35817957Smckusick lncntp[oldlfdir] = 0; 35917957Smckusick dp = ginode(lfdir); 36017957Smckusick } 36117957Smckusick if (statemap[lfdir] != DFOUND) { 36217957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 36316259Smckusick return (0); 36416259Smckusick } 36516259Smckusick len = strlen(lfname); 36616259Smckusick bcopy(lfname, pathp, len + 1); 36716259Smckusick pathp += len; 36817992Smckusick len = lftempname(tempname, orphan); 36917992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 37016259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 37116259Smckusick printf("\n\n"); 37216259Smckusick return (0); 37316259Smckusick } 37416259Smckusick lncntp[orphan]--; 37516259Smckusick *pathp++ = '/'; 37630155Smckusick bcopy(tempname, pathp, len + 1); 37717954Smckusick pathp += len; 37816259Smckusick if (lostdir) { 37916259Smckusick dp = ginode(orphan); 38016259Smckusick idesc.id_type = DATA; 38117957Smckusick idesc.id_func = chgino; 38216259Smckusick idesc.id_number = orphan; 38316259Smckusick idesc.id_fix = DONTKNOW; 38417957Smckusick idesc.id_name = ".."; 38517957Smckusick idesc.id_parent = lfdir; /* new value for ".." */ 38616259Smckusick (void)ckinode(dp, &idesc); 38717943Smckusick dp = ginode(lfdir); 38817943Smckusick dp->di_nlink++; 38917943Smckusick inodirty(); 39017943Smckusick lncntp[lfdir]++; 39116259Smckusick pwarn("DIR I=%u CONNECTED. ", orphan); 39216259Smckusick printf("PARENT WAS I=%u\n", pdir); 39316259Smckusick if (preen == 0) 39416259Smckusick printf("\n"); 39516259Smckusick } 39616259Smckusick return (1); 39716259Smckusick } 39816259Smckusick 39916259Smckusick /* 40017944Smckusick * make an entry in a directory 40117944Smckusick */ 40217992Smckusick makeentry(parent, ino, name) 40317992Smckusick ino_t parent, ino; 40417992Smckusick char *name; 40517992Smckusick { 40617944Smckusick DINODE *dp; 40717992Smckusick struct inodesc idesc; 40817944Smckusick 40917992Smckusick if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax) 41017992Smckusick return (0); 41117992Smckusick bzero(&idesc, sizeof(struct inodesc)); 41217992Smckusick idesc.id_type = DATA; 41317992Smckusick idesc.id_func = mkentry; 41417992Smckusick idesc.id_number = parent; 41517992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 41617992Smckusick idesc.id_fix = DONTKNOW; 41717992Smckusick idesc.id_name = name; 41817992Smckusick dp = ginode(parent); 41917993Smckusick if (dp->di_size % DIRBLKSIZ) { 42017993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 42117993Smckusick inodirty(); 42217993Smckusick } 42317992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 42417944Smckusick return (1); 42517944Smckusick if (expanddir(dp) == 0) 42617944Smckusick return (0); 42717992Smckusick return (ckinode(dp, &idesc) & ALTERED); 42817944Smckusick } 42917944Smckusick 43017944Smckusick /* 43117944Smckusick * Attempt to expand the size of a directory 43217944Smckusick */ 43317944Smckusick expanddir(dp) 43417944Smckusick register DINODE *dp; 43517944Smckusick { 43617944Smckusick daddr_t lastbn, newblk; 437*34225Smckusick register BUFAREA *bp; 43817944Smckusick char *cp, firstblk[DIRBLKSIZ]; 43917944Smckusick 44017944Smckusick lastbn = lblkno(&sblock, dp->di_size); 44117944Smckusick if (lastbn >= NDADDR - 1) 44217944Smckusick return (0); 44317944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 44417944Smckusick return (0); 44517944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 44617944Smckusick dp->di_db[lastbn] = newblk; 44717944Smckusick dp->di_size += sblock.fs_bsize; 44817944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 449*34225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 450*34225Smckusick dblksize(&sblock, dp, lastbn + 1)); 451*34225Smckusick if (bp->b_errs != NULL) 45217944Smckusick goto bad; 453*34225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 454*34225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 455*34225Smckusick if (bp->b_errs != NULL) 45617944Smckusick goto bad; 457*34225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 458*34225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 459*34225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 46017944Smckusick cp += DIRBLKSIZ) 46117944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 462*34225Smckusick dirty(bp); 463*34225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 464*34225Smckusick dblksize(&sblock, dp, lastbn + 1)); 465*34225Smckusick if (bp->b_errs != NULL) 46617944Smckusick goto bad; 467*34225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 46817944Smckusick pwarn("NO SPACE LEFT IN %s", pathname); 46917944Smckusick if (preen) 47017944Smckusick printf(" (EXPANDED)\n"); 47117944Smckusick else if (reply("EXPAND") == 0) 47217944Smckusick goto bad; 473*34225Smckusick dirty(bp); 47417944Smckusick inodirty(); 47517944Smckusick return (1); 47617944Smckusick bad: 47717944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 47817944Smckusick dp->di_db[lastbn + 1] = 0; 47917944Smckusick dp->di_size -= sblock.fs_bsize; 48017944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 48117944Smckusick freeblk(newblk, sblock.fs_frag); 48217944Smckusick return (0); 48317944Smckusick } 48417944Smckusick 48517944Smckusick /* 48617954Smckusick * allocate a new directory 48717954Smckusick */ 48817954Smckusick allocdir(parent, request) 48917954Smckusick ino_t parent, request; 49017954Smckusick { 49117954Smckusick ino_t ino; 49217954Smckusick char *cp; 49317954Smckusick DINODE *dp; 494*34225Smckusick register BUFAREA *bp; 49517954Smckusick 49617954Smckusick ino = allocino(request, IFDIR|0755); 49717954Smckusick dirhead.dot_ino = ino; 49817954Smckusick dirhead.dotdot_ino = parent; 49917954Smckusick dp = ginode(ino); 500*34225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 501*34225Smckusick if (bp->b_errs != NULL) { 50217954Smckusick freeino(ino); 50317954Smckusick return (0); 50417954Smckusick } 505*34225Smckusick bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead); 506*34225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 507*34225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 50817954Smckusick cp += DIRBLKSIZ) 50917954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 510*34225Smckusick dirty(bp); 51117954Smckusick dp->di_nlink = 2; 51217954Smckusick inodirty(); 51317954Smckusick if (ino == ROOTINO) { 51417954Smckusick lncntp[ino] = dp->di_nlink; 51517954Smckusick return(ino); 51617954Smckusick } 51717954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 51817954Smckusick freeino(ino); 51917954Smckusick return (0); 52017954Smckusick } 52117954Smckusick statemap[ino] = statemap[parent]; 52217954Smckusick if (statemap[ino] == DSTATE) { 52317954Smckusick lncntp[ino] = dp->di_nlink; 52417954Smckusick lncntp[parent]++; 52517954Smckusick } 52617954Smckusick dp = ginode(parent); 52717954Smckusick dp->di_nlink++; 52817954Smckusick inodirty(); 52917954Smckusick return (ino); 53017954Smckusick } 53117954Smckusick 53217954Smckusick /* 53317954Smckusick * free a directory inode 53417954Smckusick */ 53517954Smckusick freedir(ino, parent) 53617954Smckusick ino_t ino, parent; 53717954Smckusick { 53817954Smckusick DINODE *dp; 53917954Smckusick 54017954Smckusick if (ino != parent) { 54117954Smckusick dp = ginode(parent); 54217954Smckusick dp->di_nlink--; 54317954Smckusick inodirty(); 54417954Smckusick } 54517954Smckusick freeino(ino); 54617954Smckusick } 54717954Smckusick 54817954Smckusick /* 54916259Smckusick * generate a temporary name for the lost+found directory. 55016259Smckusick */ 55116259Smckusick lftempname(bufp, ino) 55216259Smckusick char *bufp; 55316259Smckusick ino_t ino; 55416259Smckusick { 55516259Smckusick register ino_t in; 55616259Smckusick register char *cp; 55716259Smckusick int namlen; 55816259Smckusick 55916259Smckusick cp = bufp + 2; 56016259Smckusick for (in = imax; in > 0; in /= 10) 56116259Smckusick cp++; 56216259Smckusick *--cp = 0; 56316259Smckusick namlen = cp - bufp; 56416259Smckusick in = ino; 56516259Smckusick while (cp > bufp) { 56616259Smckusick *--cp = (in % 10) + '0'; 56716259Smckusick in /= 10; 56816259Smckusick } 56916259Smckusick *cp = '#'; 57016259Smckusick return (namlen); 57116259Smckusick } 572*34225Smckusick 573*34225Smckusick /* 574*34225Smckusick * Get a directory block. 575*34225Smckusick * Insure that it is held until another is requested. 576*34225Smckusick */ 577*34225Smckusick BUFAREA * 578*34225Smckusick getdirblk(blkno, size) 579*34225Smckusick daddr_t blkno; 580*34225Smckusick long size; 581*34225Smckusick { 582*34225Smckusick static BUFAREA *pbp = 0; 583*34225Smckusick 584*34225Smckusick if (pbp != 0) 585*34225Smckusick pbp->b_flags &= ~B_INUSE; 586*34225Smckusick pbp = getdatablk(blkno, size); 587*34225Smckusick return (pbp); 588*34225Smckusick } 589