summaryrefslogtreecommitdiff
path: root/ufs-fsck/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'ufs-fsck/dir.c')
-rw-r--r--ufs-fsck/dir.c567
1 files changed, 0 insertions, 567 deletions
diff --git a/ufs-fsck/dir.c b/ufs-fsck/dir.c
deleted file mode 100644
index 85757b16..00000000
--- a/ufs-fsck/dir.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/* Directory management subroutines
- Copyright (C) 1994,96,99,2002 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- 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);
- if (blks > NDADDR)
- blks = NDADDR + NIADDR;
- blks *= sizeof (daddr_t);
- dnp = malloc (sizeof (struct dirinfo) + blks);
-
- dnp->i_number = number;
- dnp->i_parent = dnp->i_dotdot = 0;
- dnp->i_isize = dp->di_size;
- dnp->i_numblks = blks;
- bcopy (dp->di_db, dnp->i_blks, blks);
-
- if (dirarrayused == dirarraysize)
- {
- if (dirarraysize == 0)
- {
- dirarraysize = 100;
- dirarray = malloc (dirarraysize * sizeof (struct dirinfo *));
- dirsorted = malloc (dirarraysize * sizeof (struct dirinfo *));
- }
- else
- {
- dirarraysize *= 2;
- dirarray = realloc (dirarray,
- dirarraysize * sizeof (struct dirinfo *));
- dirsorted = realloc (dirsorted,
- dirarraysize * sizeof (struct dirinfo *));
- }
- }
- dirarray[dirarrayused] = dnp;
- dirsorted[dirarrayused] = dnp;
- dirarrayused++;
-}
-
-/* Return the cached dirinfo structure for directory INO. */
-struct dirinfo *
-lookup_directory (ino_t ino)
-{
- int i;
-
- for (i = 0; i < dirarrayused; i++)
- if (dirarray[i]->i_number == ino)
- return dirarray[i];
-
- errexit ("Cannot find cached directory I=%Ld\n", ino);
-}
-
-/* Check to see if DIR is really a readable directory; if it
- isn't, then bail with an appropriate message and return 0;
- else return 1. MSG identifies the action contemplated */
-static int
-validdir (ino_t dir, char *action)
-{
- switch (inodestate[dir])
- {
- case DIRECTORY:
- case DIRECTORY|DIR_REF:
- return 1;
-
- case UNALLOC:
- warning (1, "CANNOT %s I=%Ld; NOT ALLOCATED", action, dir);
- return 0;
-
- case BADDIR:
- warning (1, "CANNOT %s I=%Ld; BAD BLOCKS", action, dir);
- return 0;
-
- case REG:
- warning (1, "CANNOT %s I=%Ld; NOT DIRECTORY", action, dir);
- return 0;
-
- default:
- errexit ("ILLEGAL STATE");
- }
-}
-
-/* Search directory DIR for name NAME. If NAME is found, then
- set *INO to the inode of the entry; otherwise clear INO. Returns 1 if all
- was normal, or 0 if there was some error doing the search. */
-int
-searchdir (ino_t dir, char *name, ino_t *ino)
-{
- struct dinode dino;
- int len;
-
- /* Scan through one directory block and see if it
- contains NAME. */
- void
- 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;
-
- if (dp->d_ino == 0 || dp->d_ino > maxino)
- continue;
-
- if (DIRECT_NAMLEN (dp) == len && strcmp (dp->d_name, name) == 0)
- {
- *ino = dp->d_ino;
- return;
- }
- }
- }
-
- /* 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, off_t offset)
- {
- 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
- && offset + (bufp - buf) + DIRBLKSIZ <= dino.di_size;
- bufp += DIRBLKSIZ)
- {
- check1block (bufp);
- if (*ino)
- return 0;
- }
- return 1;
- }
-
- *ino = 0;
-
- if (!validdir (dir, "READ"))
- return 0;
-
- getinode (dir, &dino);
-
- len = strlen (name);
- datablocks_iterate (&dino, checkdirblock);
-
- return 1;
-}
-
-/* Change the existing entry in DIR for name NAME to be
- inode INO. Return 1 if the entry was found and
- replaced, else return 0. */
-int
-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 *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 == 0 || dp->d_ino > maxino)
- continue;
-
- if (DIRECT_NAMLEN (dp) == len && strcmp (dp->d_name, name) == 0)
- {
- dp->d_ino = ino;
- madechange = 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, off_t offset)
- {
- 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
- && offset + (bufp - buf) + DIRBLKSIZ <= dino.di_size;
- bufp += DIRBLKSIZ)
- {
- if (check1block (bufp))
- {
- writeblock (fsbtodb (sblock, bno), buf,
- nfrags * sblock->fs_fsize);
- return 0;
- }
- }
- return 1;
- }
-
- 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 (DIRECT_NAMLEN (dp)) >= 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, off_t offset)
- {
- 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
- && offset + (bufp - buf) + DIRBLKSIZ <= dino.di_size;
- 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. */
- problem (0, "NO SPACE LEFT IN DIR INO=%Ld", dir);
- if (preen || reply ("EXPAND"))
- {
- if (expanddir (&dino))
- {
- write_inode (ino, &dino);
- datablocks_iterate (&dino, checkdirblock);
- pfix ("EXPANDED");
- }
- else
- {
- pfail (0);
- warning (1, "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;
-
- mode |= IFDIR;
-
- ino = allocino (request, mode);
- if (!ino)
- return 0;
- if (!makeentry (ino, ino, "."))
- goto bad;
- if (!makeentry (ino, parent, ".."))
- 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
- a directory, and PARENT is the number of `..' as found in INO.
- If PARENT is zero then INO is a directory without any .. entry.
- If the node could be linked, return 1; else return 0. */
-int
-linkup (ino_t ino, ino_t parent)
-{
- int search_failed;
- struct dinode lfdino;
- char *tempname;
- ino_t foo;
-
- if (lfdir == 0)
- {
- if (!searchdir (ROOTINO, lfname, &lfdir))
- {
- warning (1, "FAILURE SEARCHING FOR `%s'", lfname);
- return 0;
- }
- if (lfdir == 0)
- {
- problem (0, "NO `%s' DIRECTORY", lfname);
- if (preen || reply ("CREATE"))
- {
- lfdir = allocdir (ROOTINO, 0, lfmode);
- if (lfdir != 0)
- {
- if (! makeentry (ROOTINO, lfdir, lfname))
- {
- freeino (lfdir);
- linkfound[ROOTINO]--;
- lfdir = 0;
- }
- }
- }
- if (lfdir)
- pfix ("CREATED");
- else
- {
- pfail (0);
- warning (1, "SORRY, CANNOT CREATE `%s' DIRECTORY", lfname);
- return 0;
- }
- }
- }
-
- getinode (lfdir, &lfdino);
- if ((lfdino.di_model & IFMT) != IFDIR)
- {
- ino_t oldlfdir;
-
- problem (1, "`%s' IS NOT A DIRECTORY", lfname);
- if (! reply ("REALLOCATE"))
- return 0;
-
- oldlfdir = lfdir;
-
- lfdir = allocdir (ROOTINO, 0, lfmode);
- if (!lfdir)
- {
- warning (1, "SORRY, CANNOT CREATE `%s' DIRECTORY", lfname);
- return 0;
- }
- if (!changeino (ROOTINO, lfname, lfdir))
- {
- warning (1, "SORRY, CANNOT CREATE `%s' DIRECTORY", lfname);
- return 0;
- }
-
- /* One less link to the old one */
- linkfound[oldlfdir]--;
-
- getinode (lfdir, &lfdino);
- }
-
- if (inodestate[lfdir] != DIRECTORY && inodestate[lfdir] != (DIRECTORY|DIR_REF))
- {
- warning (1, "SORRY. `%s' DIRECTORY NOT ALLOCATED", lfname);
- return 0;
- }
-
- asprintf (&tempname, "#%Ld", ino);
- search_failed = !searchdir (lfdir, tempname, &foo);
- while (foo)
- {
- char *newname;
- asprintf (&newname, "%sa", tempname);
- free (tempname);
- tempname = newname;
- search_failed = !searchdir (lfdir, tempname, &foo);
- }
- if (search_failed)
- {
- warning (1, "FAILURE SEARCHING FOR `%s' IN `%s'", tempname, lfname);
- free (tempname);
- return 0;
- }
- if (!makeentry (lfdir, ino, tempname))
- {
- free (tempname);
- warning (1, "SORRY, NO SPACE IN `%s' DIRECTORY", lfname);
- return 0;
- }
- free (tempname);
- linkfound[ino]++;
-
- if (parent != -1)
- {
- /* Reset `..' in ino */
- if (parent)
- {
- if (!changeino (ino, "..", lfdir))
- {
- warning (1, "CANNOT ADJUST `..' LINK I=%Ld", ino);
- return 0;
- }
- /* Forget about link to old parent */
- linkfound[parent]--;
- }
- else if (!makeentry (ino, lfdir, ".."))
- {
- warning (1, "CANNOT CREAT `..' LINK I=%Ld", ino);
- return 0;
- }
-
- /* Account for link to lost+found; update inode directly
- here to avoid confusing warning later. */
- linkfound[lfdir]++;
- linkcount[lfdir]++;
- lfdino.di_nlink++;
- write_inode (lfdir, &lfdino);
-
- if (parent)
- warning (0, "DIR I=%Ld CONNECTED; PARENT WAS I=%Ld", ino, parent);
- else
- warning (0, "DIR I=%Ld CONNECTED", ino);
- }
- return 1;
-}