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*39980Smckusick static char sccsid[] = "@(#)dir.c 5.11 (Berkeley) 02/01/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 #define MINDIRSIZE (sizeof (struct dirtemplate)) 3116259Smckusick 3216259Smckusick char *endpathname = &pathname[BUFSIZ - 2]; 3316259Smckusick char *lfname = "lost+found"; 3436827Smckusick int lfmode = 01777; 3517944Smckusick struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 3617954Smckusick struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." }; 3716259Smckusick 3839973Smckusick struct direct *fsck_readdir(); 3939973Smckusick struct bufarea *getdirblk(); 4016259Smckusick 4116259Smckusick descend(parentino, inumber) 4216259Smckusick struct inodesc *parentino; 4316259Smckusick ino_t inumber; 4416259Smckusick { 4539973Smckusick register struct dinode *dp; 4616259Smckusick struct inodesc curino; 4716259Smckusick 4816259Smckusick bzero((char *)&curino, sizeof(struct inodesc)); 4917936Smckusick if (statemap[inumber] != DSTATE) 5017936Smckusick errexit("BAD INODE %d TO DESCEND", statemap[inumber]); 5117936Smckusick statemap[inumber] = DFOUND; 52*39980Smckusick dp = getcacheino(inumber); 5316259Smckusick if (dp->di_size == 0) { 5439973Smckusick direrror(inumber, "ZERO LENGTH DIRECTORY"); 5516259Smckusick if (reply("REMOVE") == 1) 5617936Smckusick statemap[inumber] = DCLEAR; 5716259Smckusick return; 5816259Smckusick } 5916259Smckusick if (dp->di_size < MINDIRSIZE) { 6039973Smckusick direrror(inumber, "DIRECTORY TOO SHORT"); 6116259Smckusick dp->di_size = MINDIRSIZE; 62*39980Smckusick if (reply("FIX") == 1) { 63*39980Smckusick dp = ginode(inumber); 64*39980Smckusick dp->di_size = MINDIRSIZE; 6516259Smckusick inodirty(); 66*39980Smckusick } 6716259Smckusick } 6821742Smckusick if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) { 6921742Smckusick pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d", 7021742Smckusick pathname, dp->di_size, DIRBLKSIZ); 7121742Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 7221742Smckusick if (preen) 7321742Smckusick printf(" (ADJUSTED)\n"); 74*39980Smckusick if (preen || reply("ADJUST") == 1) { 75*39980Smckusick dp = ginode(inumber); 76*39980Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 7721742Smckusick inodirty(); 78*39980Smckusick } 7921742Smckusick } 8016259Smckusick curino.id_type = DATA; 8116259Smckusick curino.id_func = parentino->id_func; 8216259Smckusick curino.id_parent = parentino->id_number; 8316259Smckusick curino.id_number = inumber; 8416259Smckusick (void)ckinode(dp, &curino); 8530354Smckusick if (curino.id_entryno < 2) { 8639973Smckusick direrror(inumber, "NULL DIRECTORY"); 8730354Smckusick if (reply("REMOVE") == 1) 8830354Smckusick statemap[inumber] = DCLEAR; 8930354Smckusick } 9016259Smckusick } 9116259Smckusick 9216259Smckusick dirscan(idesc) 9316259Smckusick register struct inodesc *idesc; 9416259Smckusick { 9539973Smckusick register struct direct *dp; 9639973Smckusick register struct bufarea *bp; 9716259Smckusick int dsize, n; 9816259Smckusick long blksiz; 9916259Smckusick char dbuf[DIRBLKSIZ]; 10016259Smckusick 10116259Smckusick if (idesc->id_type != DATA) 10216259Smckusick errexit("wrong type to dirscan %d\n", idesc->id_type); 10317993Smckusick if (idesc->id_entryno == 0 && 10417993Smckusick (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 10517993Smckusick idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 10616259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 10739973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 10816259Smckusick idesc->id_filesize -= blksiz; 10916259Smckusick return (SKIP); 11016259Smckusick } 11116259Smckusick idesc->id_loc = 0; 11216259Smckusick for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 11316259Smckusick dsize = dp->d_reclen; 11416259Smckusick bcopy((char *)dp, dbuf, dsize); 11539973Smckusick idesc->id_dirp = (struct direct *)dbuf; 11616259Smckusick if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 11734225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 11830354Smckusick bcopy(dbuf, (char *)dp, dsize); 11934225Smckusick dirty(bp); 12030354Smckusick sbdirty(); 12116259Smckusick } 12216259Smckusick if (n & STOP) 12316259Smckusick return (n); 12416259Smckusick } 12516259Smckusick return (idesc->id_filesize > 0 ? KEEPON : STOP); 12616259Smckusick } 12716259Smckusick 12816259Smckusick /* 12916259Smckusick * get next entry in a directory. 13016259Smckusick */ 13139973Smckusick struct direct * 13216259Smckusick fsck_readdir(idesc) 13316259Smckusick register struct inodesc *idesc; 13416259Smckusick { 13539973Smckusick register struct direct *dp, *ndp; 13639973Smckusick register struct bufarea *bp; 13716259Smckusick long size, blksiz; 13816259Smckusick 13916259Smckusick blksiz = idesc->id_numfrags * sblock.fs_fsize; 14034225Smckusick bp = getdirblk(idesc->id_blkno, blksiz); 14116259Smckusick if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 14216259Smckusick idesc->id_loc < blksiz) { 14339973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 14416259Smckusick if (dircheck(idesc, dp)) 14516259Smckusick goto dpok; 14616259Smckusick idesc->id_loc += DIRBLKSIZ; 14716259Smckusick idesc->id_filesize -= DIRBLKSIZ; 14816259Smckusick dp->d_reclen = DIRBLKSIZ; 14916259Smckusick dp->d_ino = 0; 15016259Smckusick dp->d_namlen = 0; 15116259Smckusick dp->d_name[0] = '\0'; 15217930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 15334225Smckusick dirty(bp); 15416259Smckusick return (dp); 15516259Smckusick } 15616259Smckusick dpok: 15716259Smckusick if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 15816259Smckusick return NULL; 15939973Smckusick dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 16016259Smckusick idesc->id_loc += dp->d_reclen; 16116259Smckusick idesc->id_filesize -= dp->d_reclen; 16216259Smckusick if ((idesc->id_loc % DIRBLKSIZ) == 0) 16316259Smckusick return (dp); 16439973Smckusick ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 16516259Smckusick if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 16616259Smckusick dircheck(idesc, ndp) == 0) { 16716259Smckusick size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 16816259Smckusick dp->d_reclen += size; 16916259Smckusick idesc->id_loc += size; 17016259Smckusick idesc->id_filesize -= size; 17117930Smckusick if (dofix(idesc, "DIRECTORY CORRUPTED")) 17234225Smckusick dirty(bp); 17316259Smckusick } 17416259Smckusick return (dp); 17516259Smckusick } 17616259Smckusick 17716259Smckusick /* 17816259Smckusick * Verify that a directory entry is valid. 17916259Smckusick * This is a superset of the checks made in the kernel. 18016259Smckusick */ 18116259Smckusick dircheck(idesc, dp) 18216259Smckusick struct inodesc *idesc; 18339973Smckusick register struct direct *dp; 18416259Smckusick { 18516259Smckusick register int size; 18616259Smckusick register char *cp; 18716259Smckusick int spaceleft; 18816259Smckusick 18916259Smckusick size = DIRSIZ(dp); 19016259Smckusick spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 19139973Smckusick if (dp->d_ino < maxino && 19216259Smckusick dp->d_reclen != 0 && 19316259Smckusick dp->d_reclen <= spaceleft && 19416259Smckusick (dp->d_reclen & 0x3) == 0 && 19516259Smckusick dp->d_reclen >= size && 19616259Smckusick idesc->id_filesize >= size && 19716259Smckusick dp->d_namlen <= MAXNAMLEN) { 19816259Smckusick if (dp->d_ino == 0) 19916259Smckusick return (1); 20016259Smckusick for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) 20116259Smckusick if (*cp == 0 || (*cp++ & 0200)) 20216259Smckusick return (0); 20316259Smckusick if (*cp == 0) 20416259Smckusick return (1); 20516259Smckusick } 20616259Smckusick return (0); 20716259Smckusick } 20816259Smckusick 20939973Smckusick direrror(ino, errmesg) 21016259Smckusick ino_t ino; 21139973Smckusick char *errmesg; 21216259Smckusick { 21339973Smckusick register struct dinode *dp; 21416259Smckusick 21539973Smckusick pwarn("%s ", errmesg); 21616259Smckusick pinode(ino); 21716259Smckusick printf("\n"); 21839973Smckusick if (ino < ROOTINO || ino > maxino) { 21917943Smckusick pfatal("NAME=%s\n", pathname); 22017943Smckusick return; 22117943Smckusick } 22217943Smckusick dp = ginode(ino); 22317943Smckusick if (ftypeok(dp)) 22439973Smckusick pfatal("%s=%s\n", 22539973Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathname); 22616259Smckusick else 22716259Smckusick pfatal("NAME=%s\n", pathname); 22816259Smckusick } 22916259Smckusick 23016259Smckusick adjust(idesc, lcnt) 23116259Smckusick register struct inodesc *idesc; 23216259Smckusick short lcnt; 23316259Smckusick { 23439973Smckusick register struct dinode *dp; 23516259Smckusick 23617943Smckusick dp = ginode(idesc->id_number); 23716259Smckusick if (dp->di_nlink == lcnt) { 23816259Smckusick if (linkup(idesc->id_number, (ino_t)0) == 0) 23916259Smckusick clri(idesc, "UNREF", 0); 24017936Smckusick } else { 24117930Smckusick pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 24239973Smckusick ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 24316259Smckusick pinode(idesc->id_number); 24416259Smckusick printf(" COUNT %d SHOULD BE %d", 24539973Smckusick dp->di_nlink, dp->di_nlink - lcnt); 24616259Smckusick if (preen) { 24716259Smckusick if (lcnt < 0) { 24816259Smckusick printf("\n"); 24917930Smckusick pfatal("LINK COUNT INCREASING"); 25016259Smckusick } 25116259Smckusick printf(" (ADJUSTED)\n"); 25216259Smckusick } 25316259Smckusick if (preen || reply("ADJUST") == 1) { 25416259Smckusick dp->di_nlink -= lcnt; 25516259Smckusick inodirty(); 25616259Smckusick } 25716259Smckusick } 25816259Smckusick } 25916259Smckusick 26016259Smckusick mkentry(idesc) 26116259Smckusick struct inodesc *idesc; 26216259Smckusick { 26339973Smckusick register struct direct *dirp = idesc->id_dirp; 26439973Smckusick struct direct newent; 26516259Smckusick int newlen, oldlen; 26616259Smckusick 26716259Smckusick newent.d_namlen = 11; 26816259Smckusick newlen = DIRSIZ(&newent); 26916259Smckusick if (dirp->d_ino != 0) 27016259Smckusick oldlen = DIRSIZ(dirp); 27116259Smckusick else 27216259Smckusick oldlen = 0; 27316259Smckusick if (dirp->d_reclen - oldlen < newlen) 27416259Smckusick return (KEEPON); 27516259Smckusick newent.d_reclen = dirp->d_reclen - oldlen; 27616259Smckusick dirp->d_reclen = oldlen; 27716259Smckusick dirp = (struct direct *)(((char *)dirp) + oldlen); 27816259Smckusick dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 27916259Smckusick dirp->d_reclen = newent.d_reclen; 28017954Smckusick dirp->d_namlen = strlen(idesc->id_name); 28139973Smckusick bcopy(idesc->id_name, dirp->d_name, (int)dirp->d_namlen + 1); 28216259Smckusick return (ALTERED|STOP); 28316259Smckusick } 28416259Smckusick 28517957Smckusick chgino(idesc) 28616259Smckusick struct inodesc *idesc; 28716259Smckusick { 28839973Smckusick register struct direct *dirp = idesc->id_dirp; 28916259Smckusick 29039973Smckusick if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 29117957Smckusick return (KEEPON); 29239973Smckusick dirp->d_ino = idesc->id_parent; 29317957Smckusick return (ALTERED|STOP); 29416259Smckusick } 29516259Smckusick 29639973Smckusick linkup(orphan, parentdir) 29716259Smckusick ino_t orphan; 29839973Smckusick ino_t parentdir; 29916259Smckusick { 30039973Smckusick register struct dinode *dp; 30116259Smckusick int lostdir, len; 30217954Smckusick ino_t oldlfdir; 30316259Smckusick struct inodesc idesc; 30417954Smckusick char tempname[BUFSIZ]; 30517957Smckusick extern int pass4check(); 30616259Smckusick 30716259Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 30817943Smckusick dp = ginode(orphan); 30939973Smckusick lostdir = (dp->di_mode & IFMT) == IFDIR; 31016259Smckusick pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 31116259Smckusick pinode(orphan); 31216259Smckusick if (preen && dp->di_size == 0) 31316259Smckusick return (0); 31416259Smckusick if (preen) 31516259Smckusick printf(" (RECONNECTED)\n"); 31616259Smckusick else 31716259Smckusick if (reply("RECONNECT") == 0) 31816259Smckusick return (0); 31916259Smckusick pathp = pathname; 32016259Smckusick *pathp++ = '/'; 32116259Smckusick *pathp = '\0'; 32216259Smckusick if (lfdir == 0) { 32317943Smckusick dp = ginode(ROOTINO); 32417930Smckusick idesc.id_name = lfname; 32516259Smckusick idesc.id_type = DATA; 32616259Smckusick idesc.id_func = findino; 32716259Smckusick idesc.id_number = ROOTINO; 32830354Smckusick if ((ckinode(dp, &idesc) & FOUND) != 0) { 32917954Smckusick lfdir = idesc.id_parent; 33017954Smckusick } else { 33117954Smckusick pwarn("NO lost+found DIRECTORY"); 33217954Smckusick if (preen || reply("CREATE")) { 33339973Smckusick lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 33417992Smckusick if (lfdir != 0) { 33517992Smckusick if (makeentry(ROOTINO, lfdir, lfname) != 0) { 33617954Smckusick if (preen) 33717954Smckusick printf(" (CREATED)\n"); 33817954Smckusick } else { 33917992Smckusick freedir(lfdir, ROOTINO); 34017992Smckusick lfdir = 0; 34117954Smckusick if (preen) 34217954Smckusick printf("\n"); 34317954Smckusick } 34417954Smckusick } 34517954Smckusick } 34617954Smckusick } 34717943Smckusick if (lfdir == 0) { 34817954Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 34916259Smckusick printf("\n\n"); 35016259Smckusick return (0); 35116259Smckusick } 35216259Smckusick } 35317943Smckusick dp = ginode(lfdir); 35439973Smckusick if ((dp->di_mode & IFMT) != IFDIR) { 35517957Smckusick pfatal("lost+found IS NOT A DIRECTORY"); 35617957Smckusick if (reply("REALLOCATE") == 0) 35717957Smckusick return (0); 35817957Smckusick oldlfdir = lfdir; 35939973Smckusick if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 36017957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 36117957Smckusick return (0); 36217957Smckusick } 36317957Smckusick idesc.id_type = DATA; 36417957Smckusick idesc.id_func = chgino; 36517957Smckusick idesc.id_number = ROOTINO; 36617957Smckusick idesc.id_parent = lfdir; /* new inumber for lost+found */ 36717957Smckusick idesc.id_name = lfname; 36817957Smckusick if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) { 36917957Smckusick pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 37017957Smckusick return (0); 37117957Smckusick } 37217957Smckusick inodirty(); 37317957Smckusick idesc.id_type = ADDR; 37417957Smckusick idesc.id_func = pass4check; 37517957Smckusick idesc.id_number = oldlfdir; 37617957Smckusick adjust(&idesc, lncntp[oldlfdir] + 1); 37717957Smckusick lncntp[oldlfdir] = 0; 37817957Smckusick dp = ginode(lfdir); 37917957Smckusick } 38017957Smckusick if (statemap[lfdir] != DFOUND) { 38117957Smckusick pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 38216259Smckusick return (0); 38316259Smckusick } 38416259Smckusick len = strlen(lfname); 38516259Smckusick bcopy(lfname, pathp, len + 1); 38616259Smckusick pathp += len; 38717992Smckusick len = lftempname(tempname, orphan); 38817992Smckusick if (makeentry(lfdir, orphan, tempname) == 0) { 38916259Smckusick pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 39016259Smckusick printf("\n\n"); 39116259Smckusick return (0); 39216259Smckusick } 39316259Smckusick lncntp[orphan]--; 39416259Smckusick *pathp++ = '/'; 39530155Smckusick bcopy(tempname, pathp, len + 1); 39617954Smckusick pathp += len; 39716259Smckusick if (lostdir) { 39816259Smckusick dp = ginode(orphan); 39916259Smckusick idesc.id_type = DATA; 40017957Smckusick idesc.id_func = chgino; 40116259Smckusick idesc.id_number = orphan; 40216259Smckusick idesc.id_fix = DONTKNOW; 40317957Smckusick idesc.id_name = ".."; 40417957Smckusick idesc.id_parent = lfdir; /* new value for ".." */ 40516259Smckusick (void)ckinode(dp, &idesc); 40617943Smckusick dp = ginode(lfdir); 40717943Smckusick dp->di_nlink++; 40817943Smckusick inodirty(); 40917943Smckusick lncntp[lfdir]++; 41016259Smckusick pwarn("DIR I=%u CONNECTED. ", orphan); 41139973Smckusick printf("PARENT WAS I=%u\n", parentdir); 41216259Smckusick if (preen == 0) 41316259Smckusick printf("\n"); 41416259Smckusick } 41516259Smckusick return (1); 41616259Smckusick } 41716259Smckusick 41816259Smckusick /* 41917944Smckusick * make an entry in a directory 42017944Smckusick */ 42117992Smckusick makeentry(parent, ino, name) 42217992Smckusick ino_t parent, ino; 42317992Smckusick char *name; 42417992Smckusick { 42539973Smckusick struct dinode *dp; 42617992Smckusick struct inodesc idesc; 42717944Smckusick 42839973Smckusick if (parent < ROOTINO || parent >= maxino || 42939973Smckusick ino < ROOTINO || ino >= maxino) 43017992Smckusick return (0); 43139973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 43217992Smckusick idesc.id_type = DATA; 43317992Smckusick idesc.id_func = mkentry; 43417992Smckusick idesc.id_number = parent; 43517992Smckusick idesc.id_parent = ino; /* this is the inode to enter */ 43617992Smckusick idesc.id_fix = DONTKNOW; 43717992Smckusick idesc.id_name = name; 43817992Smckusick dp = ginode(parent); 43917993Smckusick if (dp->di_size % DIRBLKSIZ) { 44017993Smckusick dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 44117993Smckusick inodirty(); 44217993Smckusick } 44317992Smckusick if ((ckinode(dp, &idesc) & ALTERED) != 0) 44417944Smckusick return (1); 44517944Smckusick if (expanddir(dp) == 0) 44617944Smckusick return (0); 44717992Smckusick return (ckinode(dp, &idesc) & ALTERED); 44817944Smckusick } 44917944Smckusick 45017944Smckusick /* 45117944Smckusick * Attempt to expand the size of a directory 45217944Smckusick */ 45317944Smckusick expanddir(dp) 45439973Smckusick register struct dinode *dp; 45517944Smckusick { 45617944Smckusick daddr_t lastbn, newblk; 45739973Smckusick register struct bufarea *bp; 45817944Smckusick char *cp, firstblk[DIRBLKSIZ]; 45917944Smckusick 46017944Smckusick lastbn = lblkno(&sblock, dp->di_size); 46117944Smckusick if (lastbn >= NDADDR - 1) 46217944Smckusick return (0); 46317944Smckusick if ((newblk = allocblk(sblock.fs_frag)) == 0) 46417944Smckusick return (0); 46517944Smckusick dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 46617944Smckusick dp->di_db[lastbn] = newblk; 46717944Smckusick dp->di_size += sblock.fs_bsize; 46817944Smckusick dp->di_blocks += btodb(sblock.fs_bsize); 46934225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 47034225Smckusick dblksize(&sblock, dp, lastbn + 1)); 47138375Smckusick if (bp->b_errs) 47217944Smckusick goto bad; 47334225Smckusick bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 47434225Smckusick bp = getdirblk(newblk, sblock.fs_bsize); 47538375Smckusick if (bp->b_errs) 47617944Smckusick goto bad; 47734225Smckusick bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 47834225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 47934225Smckusick cp < &bp->b_un.b_buf[sblock.fs_bsize]; 48017944Smckusick cp += DIRBLKSIZ) 48117944Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 48234225Smckusick dirty(bp); 48334225Smckusick bp = getdirblk(dp->di_db[lastbn + 1], 48434225Smckusick dblksize(&sblock, dp, lastbn + 1)); 48538375Smckusick if (bp->b_errs) 48617944Smckusick goto bad; 48734225Smckusick bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 48817944Smckusick pwarn("NO SPACE LEFT IN %s", pathname); 48917944Smckusick if (preen) 49017944Smckusick printf(" (EXPANDED)\n"); 49117944Smckusick else if (reply("EXPAND") == 0) 49217944Smckusick goto bad; 49334225Smckusick dirty(bp); 49417944Smckusick inodirty(); 49517944Smckusick return (1); 49617944Smckusick bad: 49717944Smckusick dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 49817944Smckusick dp->di_db[lastbn + 1] = 0; 49917944Smckusick dp->di_size -= sblock.fs_bsize; 50017944Smckusick dp->di_blocks -= btodb(sblock.fs_bsize); 50117944Smckusick freeblk(newblk, sblock.fs_frag); 50217944Smckusick return (0); 50317944Smckusick } 50417944Smckusick 50517944Smckusick /* 50617954Smckusick * allocate a new directory 50717954Smckusick */ 50836827Smckusick allocdir(parent, request, mode) 50917954Smckusick ino_t parent, request; 51036827Smckusick int mode; 51117954Smckusick { 51217954Smckusick ino_t ino; 51317954Smckusick char *cp; 51439973Smckusick struct dinode *dp; 51539973Smckusick register struct bufarea *bp; 51617954Smckusick 51736827Smckusick ino = allocino(request, IFDIR|mode); 51817954Smckusick dirhead.dot_ino = ino; 51917954Smckusick dirhead.dotdot_ino = parent; 52017954Smckusick dp = ginode(ino); 52134225Smckusick bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 52238375Smckusick if (bp->b_errs) { 52317954Smckusick freeino(ino); 52417954Smckusick return (0); 52517954Smckusick } 52634225Smckusick bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead); 52734225Smckusick for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 52834225Smckusick cp < &bp->b_un.b_buf[sblock.fs_fsize]; 52917954Smckusick cp += DIRBLKSIZ) 53017954Smckusick bcopy((char *)&emptydir, cp, sizeof emptydir); 53134225Smckusick dirty(bp); 53217954Smckusick dp->di_nlink = 2; 53317954Smckusick inodirty(); 53417954Smckusick if (ino == ROOTINO) { 53517954Smckusick lncntp[ino] = dp->di_nlink; 53617954Smckusick return(ino); 53717954Smckusick } 53817954Smckusick if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 53917954Smckusick freeino(ino); 54017954Smckusick return (0); 54117954Smckusick } 54217954Smckusick statemap[ino] = statemap[parent]; 54317954Smckusick if (statemap[ino] == DSTATE) { 54417954Smckusick lncntp[ino] = dp->di_nlink; 54517954Smckusick lncntp[parent]++; 54617954Smckusick } 54717954Smckusick dp = ginode(parent); 54817954Smckusick dp->di_nlink++; 54917954Smckusick inodirty(); 55017954Smckusick return (ino); 55117954Smckusick } 55217954Smckusick 55317954Smckusick /* 55417954Smckusick * free a directory inode 55517954Smckusick */ 55617954Smckusick freedir(ino, parent) 55717954Smckusick ino_t ino, parent; 55817954Smckusick { 55939973Smckusick struct dinode *dp; 56017954Smckusick 56117954Smckusick if (ino != parent) { 56217954Smckusick dp = ginode(parent); 56317954Smckusick dp->di_nlink--; 56417954Smckusick inodirty(); 56517954Smckusick } 56617954Smckusick freeino(ino); 56717954Smckusick } 56817954Smckusick 56917954Smckusick /* 57016259Smckusick * generate a temporary name for the lost+found directory. 57116259Smckusick */ 57216259Smckusick lftempname(bufp, ino) 57316259Smckusick char *bufp; 57416259Smckusick ino_t ino; 57516259Smckusick { 57616259Smckusick register ino_t in; 57716259Smckusick register char *cp; 57816259Smckusick int namlen; 57916259Smckusick 58016259Smckusick cp = bufp + 2; 58139973Smckusick for (in = maxino; in > 0; in /= 10) 58216259Smckusick cp++; 58316259Smckusick *--cp = 0; 58416259Smckusick namlen = cp - bufp; 58516259Smckusick in = ino; 58616259Smckusick while (cp > bufp) { 58716259Smckusick *--cp = (in % 10) + '0'; 58816259Smckusick in /= 10; 58916259Smckusick } 59016259Smckusick *cp = '#'; 59116259Smckusick return (namlen); 59216259Smckusick } 59334225Smckusick 59434225Smckusick /* 59534225Smckusick * Get a directory block. 59634225Smckusick * Insure that it is held until another is requested. 59734225Smckusick */ 59839973Smckusick struct bufarea * 59934225Smckusick getdirblk(blkno, size) 60034225Smckusick daddr_t blkno; 60134225Smckusick long size; 60234225Smckusick { 60339973Smckusick static struct bufarea *pbp = 0; 60434225Smckusick 60534225Smckusick if (pbp != 0) 60634225Smckusick pbp->b_flags &= ~B_INUSE; 60734225Smckusick pbp = getdatablk(blkno, size); 60834225Smckusick return (pbp); 60934225Smckusick } 610