summaryrefslogtreecommitdiff
path: root/ufs-fsck
diff options
context:
space:
mode:
Diffstat (limited to 'ufs-fsck')
-rw-r--r--ufs-fsck/dir.c226
1 files changed, 204 insertions, 22 deletions
diff --git a/ufs-fsck/dir.c b/ufs-fsck/dir.c
index 150719ca..565c0d3f 100644
--- a/ufs-fsck/dir.c
+++ b/ufs-fsck/dir.c
@@ -18,16 +18,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include "fsck.h"
/* This routine is used in pass 1 to initialize DIRARRAY and DIRSORTED.
Copy information from DP (for number NUMBER) into a newly allocated
dirinfo structure and add it to the arrays. */
+void
record_directory (struct dinode *dp, ino_t number)
{
u_int blks;
struct dirinfo *dnp;
- blks = howmany (dp->di_size, sblock.fs_bsize);
+ blks = howmany (dp->di_size, sblock->fs_bsize);
if (blks > NDADDR)
blks = NDADDR * NIADDR;
blks *= sizeof (daddr_t);
@@ -35,7 +37,7 @@ record_directory (struct dinode *dp, ino_t number)
dnp->i_number = number;
dnp->i_parent = dnp->i_dotdot = 0;
- dnp->i_isize = dnp->di_size;
+ dnp->i_isize = dnp->i_isize;
dnp->i_numblks = blks * sizeof (daddr_t);
bcopy (dp->di_db, dnp->i_blks, blks);
@@ -81,9 +83,12 @@ validdir (ino_t dir, char *action)
pfatal ("CANNOT %s I=%d; BAD BLOCKS\n", action, dir);
return 0;
- case FILE:
+ case REG:
pfatal ("CANNOT %s I=%d; NOT DIRECTORY\n", action, dir);
return 0;
+
+ default:
+ errexit ("ILLEGAL STATE");
}
}
@@ -126,12 +131,12 @@ searchdir (ino_t dir, char *name, ino_t *ino)
int
checkdirblock (daddr_t bno, int nfrags)
{
- void *buf = alloca (nfrags * sblock.fs_fsize);
+ void *buf = alloca (nfrags * sblock->fs_fsize);
void *bufp;
- readblock (fsbtodb (bno), buf, fsbtodb (nfrags));
+ readblock (fsbtodb (sblock, bno), buf, nfrags * sblock->fs_fsize);
for (bufp = buf;
- bufp - buf < nflags * sblock.fs_fsize;
+ bufp - buf < nfrags * sblock->fs_fsize;
bufp += DIRBLKSIZ)
{
check1block (bufp);
@@ -143,7 +148,7 @@ searchdir (ino_t dir, char *name, ino_t *ino)
*ino = 0;
- if (!validdir (dir))
+ if (!validdir (dir, "READ"))
return;
getinode (dir, &dino);
@@ -160,12 +165,13 @@ changeino (ino_t dir, char *name, ino_t ino)
{
struct dinode dino;
int len;
+ int madechange;
/* Scan through a directory block looking for NAME;
if we find it then change the inode pointer to point
at INO and return 1; if we don't find it then return 0. */
int
- check1block (void *bufp)
+ check1block (void *buf)
{
struct directory_entry *dp;
@@ -174,7 +180,7 @@ changeino (ino_t dir, char *name, ino_t ino)
{
if (dp->d_reclen == 0
|| dp->d_reclen + (void *)dp - buf > DIRBLKSIZ)
- return;
+ return 0;
if (dp->d_ino == 0 || dp->d_ino > maxino)
continue;
if (dp->d_namlen != len)
@@ -183,6 +189,7 @@ changeino (ino_t dir, char *name, ino_t ino)
continue;
dp->d_ino = ino;
+ madechange = 1;
return 1;
}
return 0;
@@ -194,29 +201,204 @@ changeino (ino_t dir, char *name, ino_t ino)
int
checkdirblock (daddr_t bno, int nfrags)
{
- void *buf = alloca (nfrags * sblock.fs_fsize);
+ void *buf = alloca (nfrags * sblock->fs_fsize);
void *bufp;
- readblock (fsbtodb (bno), buf, fsbtodb (nfrags));
+ readblock (fsbtodb (sblock, bno), buf, nfrags * sblock->fs_fsize);
for (bufp = buf;
- bufp - buf < nflags * sblock.fs_fsize;
+ bufp - buf < nfrags * sblock->fs_fsize;
bufp += DIRBLKSIZ)
{
if (check1block (bufp))
{
- writeblock (fsbtodb (bno), buf, fsbtodb (nfrags));
+ writeblock (fsbtodb (sblock, bno), buf,
+ nfrags * sblock->fs_fsize);
return 0;
}
}
return 1;
}
- if (!validdir (dir))
+ if (!validdir (dir, "REWRITE"))
return 0;
getinode (dir, &dino);
len = strlen (name);
+ madechange = 0;
datablocks_iterate (&dino, checkdirblock);
+ return madechange;
+}
+
+/* Attempt to expand the size of a directory. Return
+ 1 if we succeeded. */
+static int
+expanddir (struct dinode *dp)
+{
+ daddr_t lastbn, newblk;
+ char *cp, buf[sblock->fs_bsize];
+
+ lastbn = lblkno (sblock, dp->di_size);
+ if (blkoff (sblock, dp->di_size) && lastbn >= NDADDR - 1)
+ return 0;
+ else if (!blkoff (sblock, dp->di_size) && lastbn >= NDADDR)
+ return 0;
+ else if (blkoff (sblock, dp->di_size) && !dp->di_db[lastbn])
+ return 0;
+ else if (!blkoff (sblock, dp->di_size) && dp->di_db[lastbn])
+ return 0;
+
+ newblk = allocblk (sblock->fs_frag);
+ if (!newblk)
+ return 0;
+
+ if (blkoff (sblock, dp->di_size))
+ dp->di_db[lastbn + 1] = dp->di_db[lastbn];
+ dp->di_db[lastbn] = newblk;
+ dp->di_size += sblock->fs_bsize;
+ dp->di_blocks += sblock->fs_bsize / DEV_BSIZE;
+
+ for (cp = buf; cp < buf + sblock->fs_bsize; cp += DIRBLKSIZ)
+ {
+ struct directory_entry *dir = (struct directory_entry *) cp;
+ dir->d_ino = 0;
+ dir->d_reclen = DIRBLKSIZ;
+ }
+
+ writeblock (fsbtodb (sblock, newblk), buf, sblock->fs_bsize);
+ return 1;
+}
+
+/* Add a new link into directory DIR with name NAME and target
+ INO. Return 1 if we succeeded and 0 if we failed. It is
+ an error to call this routine if NAME is already present
+ in DIR. */
+int
+makeentry (ino_t dir, ino_t ino, char *name)
+{
+ int len;
+ struct dinode dino;
+ int needed;
+ int madeentry;
+
+ /* Read a directory block and see if it contains room for the
+ new entry. If so, add it and return 1; otherwise return 0. */
+ int
+ check1block (void *buf)
+ {
+ struct directory_entry *dp;
+
+ for (dp = buf; (void *)dp - buf < DIRBLKSIZ;
+ dp = (struct directory_entry *) ((void *)dp + dp->d_reclen))
+ {
+ if (dp->d_reclen == 0
+ || dp->d_reclen + (void *)dp - buf > DIRBLKSIZ)
+ return 0;
+ if (dp->d_ino && dp->d_reclen - DIRSIZ (dp->d_namlen) >= needed)
+ {
+ struct directory_entry *newdp;
+ newdp = (struct directory_entry *)
+ ((void *)dp + DIRSIZ (DIRECT_NAMLEN (dp)));
+
+ newdp->d_reclen = dp->d_reclen - DIRSIZ (DIRECT_NAMLEN (dp));
+ DIRECT_NAMLEN (newdp) = len;
+ newdp->d_ino = ino;
+ if (direct_symlink_extension)
+ newdp->d_type = typemap[ino];
+ bcopy (name, newdp->d_name, len + 1);
+
+ dp->d_reclen -= newdp->d_reclen;
+ madeentry = 1;
+ return 1;
+ }
+ else if (!dp->d_ino && dp->d_reclen >= needed)
+ {
+ DIRECT_NAMLEN (dp) = len;
+ dp->d_ino = ino;
+ if (direct_symlink_extension)
+ dp->d_type = typemap[ino];
+ bcopy (name, dp->d_name, len + 1);
+ madeentry = 1;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ /* Read part of a directory and look to see if it
+ contains NAME. Return 1 if we should keep looking
+ at more blocks. */
+ int
+ checkdirblock (daddr_t bno, int nfrags)
+ {
+ void *buf = alloca (nfrags * sblock->fs_fsize);
+ void *bufp;
+
+ readblock (fsbtodb (sblock, bno), buf, nfrags * sblock->fs_fsize);
+ for (bufp = buf;
+ bufp - buf < nfrags * sblock->fs_fsize;
+ bufp += DIRBLKSIZ)
+ {
+ if (check1block (bufp))
+ {
+ writeblock (fsbtodb (sblock, bno), buf,
+ nfrags * sblock->fs_fsize);
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ if (!validdir (dir, "MODIFY"))
+ return 0;
+
+ getinode (dir, &dino);
+ len = strlen (name);
+ needed = DIRSIZ (len);
+ madeentry = 0;
+ datablocks_iterate (&dino, checkdirblock);
+ if (!madeentry)
+ {
+ /* Attempt to expand the directory. */
+ pwarn ("NO SPACE LEFT IN DIR INO=%d", dir);
+ if (preen || reply ("EXPAND"))
+ {
+ if (expanddir (&dino))
+ {
+ if (preen)
+ printf (" (EXPANDED)");
+ datablock_iterate (&dino, checkdirblock);
+ }
+ else
+ pfatal ("CANNOT EXPAND DIRECTORY");
+ }
+ }
+ return madeentry;
+}
+
+/* Create a directory node whose parent is to be PARENT, whose inode
+ is REQUEST, and whose mode is to be MODE. If REQUEST is zero, then
+ allocate any inode. Initialze the contents of the
+ directory. Return the inode of the new directory. */
+ino_t
+allocdir (ino_t parent, ino_t request, mode_t mode)
+{
+ ino_t ino;
+
+ ino = allocino (request, (mode & IFMT) == IFDIR);
+ if (!ino)
+ return 0;
+ if (!makeentry (ino, ino, "."))
+ goto bad;
+ if (!makeentry (ino, ino, ".."))
+ goto bad;
+
+ linkfound[ino]++;
+ linkfound[parent]++;
+ return ino;
+
+ bad:
+ freeino (ino);
+ return 0;
}
/* Link node INO into lost+found. If PARENT is positive then INO is
@@ -226,7 +408,7 @@ void
linkup (ino_t ino, ino_t parent)
{
struct dinode lfdino;
- char tempnam[MAXNAMLEN];
+ char tempname[MAXNAMLEN];
if (lfdir == 0)
{
@@ -263,7 +445,7 @@ linkup (ino_t ino, ino_t parent)
}
getinode (lfdir, &lfdino);
- if ((DI_MODE (&lfdino) & IFMT) != IFDIR)
+ if ((lfdino.di_model & IFMT) != IFDIR)
{
ino_t oldlfdir;
@@ -307,14 +489,14 @@ linkup (ino_t ino, ino_t parent)
}
linkfound[ino]++;
- if (parent >= 0)
+ if (parent != -1)
{
/* Reset `..' in ino */
if (parent)
{
if (!changeino (ino, "..", lfdir))
{
- pfatal ("CANNOT ADJUST .. link I=%lu", ino);
+ pfatal ("CANNOT ADJUST .. link I=%u", ino);
return;
}
/* Forget about link to old parent */
@@ -322,7 +504,7 @@ linkup (ino_t ino, ino_t parent)
}
else if (!makeentry (ino, lfdir, ".."))
{
- pfatal ("CANNOT CREAT .. link I=%lu", ino);
+ pfatal ("CANNOT CREAT .. link I=%u", ino);
return;
}
@@ -333,9 +515,9 @@ linkup (ino_t ino, ino_t parent)
lfdino.di_nlink++;
write_inode (lfdir, &lfdino);
- pwarn ("DIR I=%lu CONNECTED. ", ino);
- if (parentdir)
- printf ("PARENT WAS I=%lu\n", parentdir);
+ pwarn ("DIR I=%u CONNECTED. ", ino);
+ if (parent)
+ printf ("PARENT WAS I=%u\n", parent);
if (!preen)
printf ("\n");
}