Example #1
0
int
readit(char *buffer, int count)
{
    int logno, off, size;
    int cnt2, bnum2;
    struct fs *fs_copy;
    int n = 0;

    if (poff + count > inode.i_size)
	count = inode.i_size - poff;
    while (count > 0 && poff < inode.i_size) {
	fs_copy = fs;
	off = blkoff(fs_copy, poff);
	logno = lblkno(fs_copy, poff);
	cnt2 = size = blksize(fs_copy, &inode, logno);
	bnum2 = fsbtodb(fs_copy, block_map(logno)) + boff;
	if (	(!off)  && (size <= count)) {
	    devread(buffer, bnum2, cnt2);
	} else {
	    size -= off;
	    if (size > count)
		size = count;
	    devread(iobuf, bnum2, cnt2);
	    bcopy(iobuf+off, buffer, size);
	}
	buffer += size;
	count -= size;
	poff += size;
	n += size;
    }
    return n;
}
Example #2
0
static int
ioread(void *addr, int count, int phys)
{
	int logno, off, size;

	while (count) {
		off = blkoff(fs, poff);
		logno = lblkno(fs, poff);
		cnt = size = blksize(fs, &inode, logno);
		bnum = block_map(logno);
		if (bnum == -1)
			return(1);
		bnum = fsbtodb(fs, bnum) + boff;
		size -= off;
		if (size > count)
			size = count;
		if (disk_read(bnum, cnt, (vm_offset_t)iobuf))
			return(1);
		if (phys)
			pcpy(iobuf+off,addr,size);
		else
			bcopy(iobuf+off,addr,size);
		addr = (char *)addr + size;
		count -= size;
		poff += size;
	}
	return(0);
}
Example #3
0
/*
 * Read a portion of a file into an internal buffer.
 * Return the location in the buffer and the amount in the buffer.
 */
static int
buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
{
	struct file *fp = (struct file *)f->f_fsdata;
	struct fs *fs = fp->f_fs;
	long off;
	indp_t file_block;
	size_t block_size;
	int rc;

	off = ufs_blkoff(fs, fp->f_seekp);
	file_block = ufs_lblkno(fs, fp->f_seekp);
#ifdef LIBSA_LFS
	block_size = dblksize(fs, &fp->f_di, file_block);
#else
	block_size = ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
#endif

	if (file_block != fp->f_buf_blkno) {
		indp_t disk_block = 0; /* XXX: gcc */
		rc = block_map(f, file_block, &disk_block);
		if (rc)
			return rc;

		if (disk_block == 0) {
			memset(fp->f_buf, 0, block_size);
			fp->f_buf_size = block_size;
		} else {
			twiddle();
			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
				FSBTODB(fs, disk_block),
				block_size, fp->f_buf, &fp->f_buf_size);
			if (rc)
				return rc;
		}

		fp->f_buf_blkno = file_block;
	}

	/*
	 * Return address of byte in buffer corresponding to
	 * offset, and size of remainder of buffer after that
	 * byte.
	 */
	*buf_p = fp->f_buf + off;
	*size_p = block_size - off;

	/*
	 * But truncate buffer at end of file.
	 */
	if (*size_p > fp->f_di.di_size - fp->f_seekp)
		*size_p = fp->f_di.di_size - fp->f_seekp;

	return 0;
}
Example #4
0
/*
 * Read a portion of a file into an internal buffer.  Return
 * the location in the buffer and the amount in the buffer.
 *
 * Parameters:
 *	buf_p:	out
 *	size_p:	out
 */
static int
buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
{
	struct file *fp = (struct file *)f->f_fsdata;
	struct fs *fs = fp->f_fs;
	long off;
	daddr_t file_block;
	daddr_t	disk_block;
	size_t block_size;
	int rc;

	off = blkoff(fs, fp->f_seekp);
	file_block = lblkno(fs, fp->f_seekp);
	block_size = dblksize(fs, &fp->f_di, file_block);

	if (file_block != fp->f_buf_blkno) {
		rc = block_map(f, file_block, &disk_block);
		if (rc)
			return (rc);

		if (fp->f_buf == NULL)
			fp->f_buf = malloc(fs->fs_bsize);

		if (disk_block == 0) {
			bzero(fp->f_buf, block_size);
			fp->f_buf_size = block_size;
		} else {
			twiddle();
			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
				fsbtodb(fs, disk_block),
				block_size, fp->f_buf, &fp->f_buf_size);
			if (rc)
				return (rc);
		}

		fp->f_buf_blkno = file_block;
	}

	/*
	 * Return address of byte in buffer corresponding to
	 * offset, and size of remainder of buffer after that
	 * byte.
	 */
	*buf_p = fp->f_buf + off;
	*size_p = block_size - off;

	/*
	 * But truncate buffer at end of file.
	 */
	if (*size_p > fp->f_di.di_size - fp->f_seekp)
		*size_p = fp->f_di.di_size - fp->f_seekp;

	return (0);
}
/*
 * Read a portion of a file into an internal buffer.
 * Return the location in the buffer and the amount in the buffer.
 */
static int
buf_read_file(struct open_file *f, void *v, size_t *size_p)
{
	char **buf_p = v;
	struct file *fp = (struct file *)f->f_fsdata;
	struct mfs_sblock *fs = fp->f_fs;
	long off;
	block_t file_block;
	block_t disk_block;
	size_t block_size;
	int rc;

	off = mfs_blkoff(fs, fp->f_seekp);
	file_block = mfs_lblkno(fs, fp->f_seekp);
	block_size = fs->mfs_block_size;

	if (file_block != fp->f_buf_blkno) {
		rc = block_map(f, file_block, &disk_block);
		if (rc)
			return rc;

		if (disk_block == 0) {
			memset(fp->f_buf, 0, block_size);
			fp->f_buf_size = block_size;
		} else {
			twiddle();
			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
				FSBTODB(fs, disk_block),
				block_size, fp->f_buf, &fp->f_buf_size);
			if (rc)
				return rc;
		}

		fp->f_buf_blkno = file_block;
	}

	/*
	 * Return address of byte in buffer corresponding to
	 * offset, and size of remainder of buffer after that
	 * byte.
	 */
	*buf_p = fp->f_buf + off;
	*size_p = block_size - off;

	/*
	 * But truncate buffer at end of file.
	 */
	if (*size_p > fp->f_di.mdi_size - fp->f_seekp)
		*size_p = fp->f_di.mdi_size - fp->f_seekp;

	return 0;
}
Example #6
0
/*
 * Read a portion of a file into an internal buffer.
 * Return the location in the buffer and the amount in the buffer.
 */
static int
buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
{
	struct file *fp = (struct file *)f->f_fsdata;
	struct m_ext2fs *fs = fp->f_fs;
	long off;
	indp_t file_block;
	indp_t disk_block = 0;	/* XXX: gcc */
	size_t block_size;
	int rc;

	off = ext2_blkoff(fs, fp->f_seekp);
	file_block = ext2_lblkno(fs, fp->f_seekp);
	block_size = fs->e2fs_bsize;	/* no fragment */

	if (file_block != fp->f_buf_blkno) {
		rc = block_map(f, file_block, &disk_block);
		if (rc)
			return rc;

		if (disk_block == 0) {
			memset(fp->f_buf, 0, block_size);
			fp->f_buf_size = block_size;
		} else {
			twiddle();
			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
				FSBTODB(fs, disk_block),
				block_size, fp->f_buf, &fp->f_buf_size);
			if (rc)
				return rc;
		}

		fp->f_buf_blkno = file_block;
	}

	/*
	 * Return address of byte in buffer corresponding to
	 * offset, and size of remainder of buffer after that
	 * byte.
	 */
	*buf_p = fp->f_buf + off;
	*size_p = block_size - off;

	/*
	 * But truncate buffer at end of file.
	 */
	/* XXX should handle LARGEFILE */
	if (*size_p > fp->f_di.e2di_size - fp->f_seekp)
		*size_p = fp->f_di.e2di_size - fp->f_seekp;

	return 0;
}
Example #7
0
/*
 * Reads from a regular file.
 */
PUBLIC ssize_t file_read(struct inode *i, void *buf, size_t n, off_t off)
{
	char *p;             /* Writing pointer.      */
	size_t blkoff;       /* Block offset.         */
	size_t chunk;        /* Data chunk size.      */
	block_t blk;         /* Working block number. */
	struct buffer *bbuf; /* Working block buffer. */
		
	p = buf;
	
	inode_lock(i);
	
	/* Read data. */
	do
	{
		blk = block_map(i, off, 0);
		
		/* End of file reached. */
		if (blk == BLOCK_NULL)
			goto out;
		
		bbuf = bread(i->dev, blk);
			
		blkoff = off % BLOCK_SIZE;
		
		/* Calculate read chunk size. */
		chunk = (n < BLOCK_SIZE - blkoff) ? n : BLOCK_SIZE - blkoff;
		if ((off_t)chunk > i->size - off)
		{
			chunk = i->size - off;
			if (chunk == 0)
			{
				brelse(bbuf);
				goto out;
			}
		}
		
		kmemcpy(p, (char *)bbuf->data + blkoff, chunk);
		brelse(bbuf);
		
		n -= chunk;
		off += chunk;
		p += chunk;
	} while (n > 0);

out:
	inode_touch(i);
	inode_unlock(i);
	return ((ssize_t)(p - (char *)buf));
}
Example #8
0
/*
 * Writes to a regular file.
 */
PUBLIC ssize_t file_write(struct inode *i, const void *buf, size_t n, off_t off)
{
	const char *p;       /* Reading pointer.      */
	size_t blkoff;       /* Block offset.         */
	size_t chunk;        /* Data chunk size.      */
	block_t blk;         /* Working block number. */
	struct buffer *bbuf; /* Working block buffer. */
		
	p = buf;
	
	inode_lock(i);
	
	/* Write data. */
	do
	{
		blk = block_map(i, off, 1);
		
		/* End of file reached. */
		if (blk == BLOCK_NULL)
			goto out;
		
		bbuf = bread(i->dev, blk);
		
		blkoff = off % BLOCK_SIZE;
		
		chunk = (n < BLOCK_SIZE - blkoff) ? n : BLOCK_SIZE - blkoff;
		kmemcpy((char *)bbuf->data + blkoff, buf, chunk);
		bbuf->flags |= BUFFER_DIRTY;
		brelse(bbuf);
		
		n -= chunk;
		off += chunk;
		p += chunk;
		
		/* Update file size. */
		if (off > i->size)
		{
			i->size = off;
			i->flags |= INODE_DIRTY;
		}
		
	} while (n > 0);

out:

	inode_touch(i);
	inode_unlock(i);
	return ((ssize_t)(p - (char *)buf));
}
Example #9
0
static int
find(char *path)
{
    char *rest, ch;
    int block, off, loc, ino = ROOTINO;
    struct dirent *dp;
    char list_only;

    list_only = (path[0] == '?' && path[1] == '\0');
 loop:
    devread(iobuf, fsbtodb(fs, ino_to_fsba(fs, ino)) + boff, fs->fs_bsize);
    bcopy((void *)&((struct dinode *)iobuf)[ino % fs->fs_inopb],
	  (void *)&inode.i_din,
	  sizeof (struct dinode));
    if (!*path)
	return 1;
    while (*path == '/')
	path++;
    if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
	return 0;
    for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
    *rest = 0;
    loc = 0;
    do {
	if (loc >= inode.i_size) {
	    if (list_only) {
		putchar('\n');
		return -1;
	    } else {
		return 0;
	    }
	}
	if (!(off = blkoff(fs, loc))) {
	    block = lblkno(fs, loc);
	    devread(iobuf, fsbtodb(fs, block_map(block)) + boff,
		    blksize(fs, &inode, block));
	}
	dp = (struct dirent *)(iobuf + off);
	loc += dp->d_reclen;
	if (dp->d_fileno && list_only) {
	    puts(dp->d_name);
	    putchar(' ');
	}
    } while (!dp->d_fileno || strcmp(path, dp->d_name));
    ino = dp->d_fileno;
    *(path = rest) = ch;
    goto loop;
}
Example #10
0
int
find(const char *path)
{
	const char *rest;
	int ch;
	int block, off, loc, ino = ROOTINO;
	struct dirent *dp;

	for (;;) {
		cnt = fs->fs_bsize;
		bnum = fsbtodb(fs,itod(fs,ino)) + boff;
		if (disk_read(bnum, cnt, (vm_offset_t)iobuf))
			return 0;
		bcopy((char *)&((struct dinode *)iobuf)[ino % fs->fs_inopb],
		      (char *)&inode.i_di,
		      sizeof (struct dinode));
		if (!*path)
			return 1;
		while (*path == '/')
			path++;
		if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
			return 0;
		for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
		loc = 0;
		for (;;) {
			if (loc >= inode.i_size)
				return 0;
			if (!(off = blkoff(fs, loc))) {
				block = lblkno(fs, loc);
				cnt = blksize(fs, &inode, block);
				bnum = fsbtodb(fs, block_map(block)) + boff;
				if (disk_read(bnum, cnt, (vm_offset_t)iobuf))
					return 0;
			}
			dp = (struct dirent *)(iobuf + off);
			loc += dp->d_reclen;
			if (dp->d_ino == 0)
				continue;
			if (strncmp(path, dp->d_name, rest - path) == 0 &&
			    dp->d_name[rest - path] == 0)
				break;
		}
		ino = dp->d_ino;
		path = rest;
	}
}
Example #11
0
unsigned long
ufs2_read (char *buf, unsigned long len, unsigned long write)
{
  unsigned long logno, off, size, ret = 0;
  grub_int64_t map;

  while (len && !errnum)
    {
      off = blkoff (SUPERBLOCK, filepos);
      logno = lblkno (SUPERBLOCK, filepos);
      size = blksize (SUPERBLOCK, INODE_UFS2, logno);

      if ((map = block_map (logno)) < 0)
	  break; 

      size -= off;

      if (size > len)
	  size = len;

      disk_read_func = disk_read_hook;

      devread (fsbtodb (SUPERBLOCK, map), off, size, buf, write);

      disk_read_func = NULL;

      if (buf)
	buf += size;
      len -= size;	/* len always >= 0 */
      filepos += size;
      ret += size;
    }

  if (errnum)
    ret = 0;

  return ret;
}
Example #12
0
int
ufs2_read (char *buf, int len)
{
  int logno, off, size, ret = 0;
  grub_int64_t map;

  while (len && !errnum)
    {
      off = blkoff (SUPERBLOCK, filepos);
      logno = lblkno (SUPERBLOCK, filepos);
      size = blksize (SUPERBLOCK, INODE_UFS2, logno);

      if ((map = block_map (logno)) < 0)
	break; 

      size -= off;

      if (size > len)
	size = len;

      disk_read_func = disk_read_hook;

      devread (fsbtodb (SUPERBLOCK, map), off, size, buf);

      disk_read_func = NULL;

      buf += size;
      len -= size;
      filepos += size;
      ret += size;
    }

  if (errnum)
    ret = 0;

  return ret;
}
Example #13
0
/*
 * Open a file.
 */
__compactcall int
ufs_open(const char *path, struct open_file *f)
{
#ifndef LIBSA_FS_SINGLECOMPONENT
	const char *cp, *ncp;
	int c;
#endif
	ino32_t inumber;
	struct file *fp;
	struct fs *fs;
	int rc;
#ifndef LIBSA_NO_FS_SYMLINK
	ino32_t parent_inumber;
	int nlinks = 0;
	char namebuf[MAXPATHLEN+1];
	char *buf;
#endif

	/* allocate file system specific data structure */
	fp = alloc(sizeof(struct file));
	memset(fp, 0, sizeof(struct file));
	f->f_fsdata = (void *)fp;

	/* allocate space and read super block */
	fs = alloc(SBLOCKSIZE);
	fp->f_fs = fs;
	twiddle();

#ifdef LIBSA_FFSv2
	rc = ffs_find_superblock(f, fs);
	if (rc)
		goto out;
#else
	{
		size_t buf_size;
		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
			SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
		if (rc)
			goto out;
		if (buf_size != SBLOCKSIZE ||
#ifdef LIBSA_FFS
		    fs->lfs_version != REQUIRED_LFS_VERSION ||
#endif
		    fs->fs_magic != FS_MAGIC) {
			rc = EINVAL;
			goto out;
		}
	}
#if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
	/*
	 * XXX	We should check the second superblock and use the eldest
	 *	of the two.  See comments near the top of lfs_mountfs()
	 *	in sys/ufs/lfs/lfs_vfsops.c.
	 *      This may need a LIBSA_LFS_SMALL check as well.
	 */
#endif
#endif

#ifdef LIBSA_FFSv1
	ffs_oldfscompat(fs);
#endif

	if (fs->fs_bsize > MAXBSIZE ||
	    (size_t)fs->fs_bsize < sizeof(struct fs)) {
		rc = EINVAL;
		goto out;
	}

	/*
	 * Calculate indirect block levels.
	 */
	{
		indp_t mult;
		int ln2;

		/*
		 * We note that the number of indirect blocks is always
		 * a power of 2.  This lets us use shifts and masks instead
		 * of divide and remainder and avoinds pulling in the
		 * 64bit division routine into the boot code.
		 */
		mult = UFS_NINDIR(fs);
#ifdef DEBUG
		if (mult & (mult - 1)) {
			/* Hummm was't a power of 2 */
			rc = EINVAL;
			goto out;
		}
#endif
		for (ln2 = 0; mult != 1; ln2++)
			mult >>= 1;

		fp->f_nishift = ln2;
	}

	/* alloc a block sized buffer used for all fs transfers */
	fp->f_buf = alloc(fs->fs_bsize);
	inumber = UFS_ROOTINO;
	if ((rc = read_inode(inumber, f)) != 0)
		goto out;

#ifndef LIBSA_FS_SINGLECOMPONENT
	cp = path;
	while (*cp) {

		/*
		 * Remove extra separators
		 */
		while (*cp == '/')
			cp++;
		if (*cp == '\0')
			break;

		/*
		 * Check that current node is a directory.
		 */
		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
			rc = ENOTDIR;
			goto out;
		}

		/*
		 * Get next component of path name.
		 */
		ncp = cp;
		while ((c = *cp) != '\0' && c != '/')
			cp++;

		/*
		 * Look up component in current directory.
		 * Save directory inumber in case we find a
		 * symbolic link.
		 */
#ifndef LIBSA_NO_FS_SYMLINK
		parent_inumber = inumber;
#endif
		rc = search_directory(ncp, cp - ncp, f, &inumber);
		if (rc)
			goto out;

		/*
		 * Open next component.
		 */
		if ((rc = read_inode(inumber, f)) != 0)
			goto out;

#ifndef LIBSA_NO_FS_SYMLINK
		/*
		 * Check for symbolic link.
		 */
		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
			int link_len = fp->f_di.di_size;
			int len;

			len = strlen(cp);

			if (link_len + len > MAXPATHLEN ||
			    ++nlinks > MAXSYMLINKS) {
				rc = ENOENT;
				goto out;
			}

			memmove(&namebuf[link_len], cp, len + 1);

			if (link_len < fs->fs_maxsymlinklen) {
				memcpy(namebuf, fp->f_di.di_db, link_len);
			} else {
				/*
				 * Read file for symbolic link
				 */
				size_t buf_size;
				indp_t	disk_block;

				buf = fp->f_buf;
				rc = block_map(f, (indp_t)0, &disk_block);
				if (rc)
					goto out;

				twiddle();
				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
					F_READ, FSBTODB(fs, disk_block),
					fs->fs_bsize, buf, &buf_size);
				if (rc)
					goto out;

				memcpy(namebuf, buf, link_len);
			}

			/*
			 * If relative pathname, restart at parent directory.
			 * If absolute pathname, restart at root.
			 */
			cp = namebuf;
			if (*cp != '/')
				inumber = parent_inumber;
			else
				inumber = (ino32_t)UFS_ROOTINO;

			if ((rc = read_inode(inumber, f)) != 0)
				goto out;
		}
#endif	/* !LIBSA_NO_FS_SYMLINK */
	}

	/*
	 * Found terminal component.
	 */
	rc = 0;

#else /* !LIBSA_FS_SINGLECOMPONENT */

	/* look up component in the current (root) directory */
	rc = search_directory(path, strlen(path), f, &inumber);
	if (rc)
		goto out;

	/* open it */
	rc = read_inode(inumber, f);

#endif /* !LIBSA_FS_SINGLECOMPONENT */

	fp->f_seekp = 0;		/* reset seek pointer */

out:
	if (rc)
		ufs_close(f);
#ifdef FSMOD		/* Only defined for lfs */
	else
		fsmod = FSMOD;
#endif
	return rc;
}
Example #14
0
/*
 * Open a file.
 */
static int
ext2fs_open(const char *upath, struct open_file *f)
{
	struct file *fp;
	struct ext2fs *fs;
	size_t buf_size;
	ino_t inumber, parent_inumber;
	int i, len, groups, bg_per_blk, blkgrps, mult;
	int nlinks = 0;
	int error = 0;
	char *cp, *ncp, *path = NULL, *buf = NULL;
	char namebuf[MAXPATHLEN+1];
	char c;

	/* allocate file system specific data structure */
	fp = malloc(sizeof(struct file));
	if (fp == NULL)
		return (ENOMEM);
	bzero(fp, sizeof(struct file));
	f->f_fsdata = (void *)fp;

	/* allocate space and read super block */
	fs = (struct ext2fs *)malloc(sizeof(*fs));
	fp->f_fs = fs;
	twiddle();
	error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
	    EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size);
	if (error)
		goto out;

	if (buf_size != EXT2_SBSIZE || fs->fs_magic != EXT2_MAGIC) {
		error = EINVAL;
		goto out;
	}

	/*
	 * compute in-core values for the superblock
	 */
	fs->fs_bshift = EXT2_MINBSHIFT + fs->fs_fd.fd_bsize;
	fs->fs_bsize = 1 << fs->fs_bshift;
	fs->fs_bmask = fs->fs_bsize - 1;

	fs->fs_fshift = EXT2_MINFSHIFT + fs->fs_fd.fd_fsize;
	fs->fs_fsize = 1 << fs->fs_fshift;
	fs->fs_fmask = fs->fs_fsize - 1;

	if (fs->fs_revision == EXT2_REV0) {
		fs->fs_isize = EXT2_R0_ISIZE;
		fs->fs_firstino = EXT2_R0_FIRSTINO;
	} else {
		fs->fs_isize = fs->fs_fd.fd_isize;
		fs->fs_firstino = fs->fs_fd.fd_firstino;
	}
	fs->fs_imask = fs->fs_isize - 1;
	fs->fs_ipb = fs->fs_bsize / fs->fs_isize;
	fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1;

	/*
	 * we have to load in the "group descriptors" here
	 */
	groups = howmany(fs->fs_blocks - fs->fs_firstblk, fs->fs_bpg);
	bg_per_blk = fs->fs_bsize / sizeof(struct ext2blkgrp);
	blkgrps = howmany(groups, bg_per_blk);
	len = blkgrps * fs->fs_bsize;

	fp->f_bg = malloc(len);
	twiddle();
	error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
	    EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len,
	    (char *)fp->f_bg, &buf_size);
	if (error)
		goto out;

	/*
	 * XXX
	 * validation of values?  (blocksize, descriptors, etc?)
	 */

	/*
	 * Calculate indirect block levels.
	 */
	mult = 1;
	for (i = 0; i < NIADDR; i++) {
		mult *= nindir(fs);
		fp->f_nindir[i] = mult;
	}

	inumber = EXT2_ROOTINO;
	if ((error = read_inode(inumber, f)) != 0)
		goto out;

	path = strdup(upath);
	if (path == NULL) {
		error = ENOMEM;
		goto out;
	}
	cp = path;
	while (*cp) {
		/*
		 * Remove extra separators
		 */
		while (*cp == '/')
			cp++;
		if (*cp == '\0')
			break;

		/*
		 * Check that current node is a directory.
		 */
		if (! S_ISDIR(fp->f_di.di_mode)) {
			error = ENOTDIR;
			goto out;
		}

		/*
		 * Get next component of path name.
		 */
		len = 0;

		ncp = cp;
		while ((c = *cp) != '\0' && c != '/') {
			if (++len > EXT2_MAXNAMLEN) {
				error = ENOENT;
				goto out;
			}
			cp++;
		}
		*cp = '\0';

		/*
		 * Look up component in current directory.
		 * Save directory inumber in case we find a
		 * symbolic link.
		 */
		parent_inumber = inumber;
		error = search_directory(ncp, f, &inumber);
		*cp = c;
		if (error)
			goto out;

		/*
		 * Open next component.
		 */
		if ((error = read_inode(inumber, f)) != 0)
			goto out;

		/*
		 * Check for symbolic link.
		 */
		if (S_ISLNK(fp->f_di.di_mode)) {
			int link_len = fp->f_di.di_size;
			int len;

			len = strlen(cp);
			if (link_len + len > MAXPATHLEN ||
			    ++nlinks > MAXSYMLINKS) {
				error = ENOENT;
				goto out;
			}

			bcopy(cp, &namebuf[link_len], len + 1);
			if (fp->f_di.di_nblk == 0) {
				bcopy(fp->f_di.di_shortlink,
				    namebuf, link_len);
			} else {
				/*
				 * Read file for symbolic link
				 */
				struct ext2fs *fs = fp->f_fs;
				daddr_t	disk_block;
				size_t buf_size;

				if (! buf)
					buf = malloc(fs->fs_bsize);
				error = block_map(f, (daddr_t)0, &disk_block);
				if (error)
					goto out;
				
				twiddle();
				error = (f->f_dev->dv_strategy)(f->f_devdata,
				    F_READ, fsb_to_db(fs, disk_block),
				    fs->fs_bsize, buf, &buf_size);
				if (error)
					goto out;

				bcopy((char *)buf, namebuf, link_len);
			}

			/*
			 * If relative pathname, restart at parent directory.
			 * If absolute pathname, restart at root.
			 */
			cp = namebuf;
			if (*cp != '/')
				inumber = parent_inumber;
			else
				inumber = (ino_t)EXT2_ROOTINO;

			if ((error = read_inode(inumber, f)) != 0)
				goto out;
		}
	}

	/*
	 * Found terminal component.
	 */
	error = 0;
out:
	if (buf)
		free(buf);
	if (path)
		free(path);
	if (error) {
		f->f_fsdata = NULL;
		if (fp->f_buf)
			free(fp->f_buf);
		free(fp->f_fs);
		free(fp);
	}
	return (error);
}
Example #15
0
/**
 * fsck_readi - same as libgfs2's gfs2_readi, but sets absolute block #
 *              of the first bit of data read.
 */
static int fsck_readi(struct gfs2_inode *ip, void *rbuf, uint64_t roffset,
	       unsigned int size, uint64_t *abs_block)
{
	struct gfs2_sbd *sdp;
	struct gfs2_buffer_head *lbh;
	uint64_t lblock, dblock;
	unsigned int o;
	uint32_t extlen = 0;
	unsigned int amount;
	int not_new = 0;
	int isdir;
	int copied = 0;

	if (ip == NULL)
		return 0;
	sdp = ip->i_sbd;
	isdir = !!(S_ISDIR(ip->i_di.di_mode));
	*abs_block = 0;
	if (roffset >= ip->i_di.di_size)
		return 0;
	if ((roffset + size) > ip->i_di.di_size)
		size = ip->i_di.di_size - roffset;
	if (!size)
		return 0;
	if (isdir) {
		o = roffset % sdp->sd_jbsize;
		lblock = roffset / sdp->sd_jbsize;
	} else {
		lblock = roffset >> sdp->sd_sb.sb_bsize_shift;
		o = roffset & (sdp->bsize - 1);
	}

	if (!ip->i_di.di_height) /* inode_is_stuffed */
		o += sizeof(struct gfs2_dinode);
	else if (isdir)
		o += sizeof(struct gfs2_meta_header);

	while (copied < size) {
		amount = size - copied;
		if (amount > sdp->bsize - o)
			amount = sdp->bsize - o;
		if (!extlen)
			block_map(ip, lblock, &not_new, &dblock, &extlen,
				  FALSE);
		if (dblock) {
			lbh = bread(sdp, dblock);
			if (*abs_block == 0)
				*abs_block = lbh->b_blocknr;
			dblock++;
			extlen--;
		} else
			lbh = NULL;
		if (lbh) {
			memcpy(rbuf, lbh->b_data + o, amount);
			brelse(lbh);
		} else {
			memset(rbuf, 0, amount);
		}
		copied += amount;
		lblock++;
		o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
	}
	return copied;
}
Example #16
0
/*
 * Open a file.
 */
static int
ufs_open(const char *upath, struct open_file *f)
{
	char *cp, *ncp;
	int c;
	ino_t inumber, parent_inumber;
	struct file *fp;
	struct fs *fs;
	int rc;
	size_t buf_size;
	int nlinks = 0;
	char namebuf[MAXPATHLEN+1];
	char *buf = NULL;
	char *path = NULL;

	/* allocate file system specific data structure */
	fp = malloc(sizeof(struct file));
	bzero(fp, sizeof(struct file));
	f->f_fsdata = (void *)fp;

	/* allocate space and read super block */
	fs = malloc(SBSIZE);
	fp->f_fs = fs;
	twiddle();
	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
		SBOFF / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size);
	if (rc)
		goto out;

	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
		rc = EINVAL;
		goto out;
	}
#ifdef COMPAT_UFS
	ffs_oldfscompat(fs);
#endif

	/*
	 * Calculate indirect block levels.
	 */
	{
		int omult;
		int mult;
		int level;

		omult = 0;
		mult = 1;
		for (level = 0; level < NIADDR; level++) {
			mult *= NINDIR(fs);
			if (mult < omult)
				mult = 0x7FFFFFFF;
			fp->f_nindir[level] = mult;
			omult = mult;
		}
	}

	inumber = ROOTINO;
	if ((rc = read_inode(inumber, f)) != 0)
		goto out;

	cp = path = strdup(upath);
	if (path == NULL) {
	    rc = ENOMEM;
	    goto out;
	}
	while (*cp) {

		/*
		 * Remove extra separators
		 */
		while (*cp == '/')
			cp++;
		if (*cp == '\0')
			break;

		/*
		 * Check that current node is a directory.
		 */
		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
			rc = ENOTDIR;
			goto out;
		}

		/*
		 * Get next component of path name.
		 */
		{
			int len = 0;

			ncp = cp;
			while ((c = *cp) != '\0' && c != '/') {
				if (++len > MAXNAMLEN) {
					rc = ENOENT;
					goto out;
				}
				cp++;
			}
			*cp = '\0';
		}

		/*
		 * Look up component in current directory.
		 * Save directory inumber in case we find a
		 * symbolic link.
		 */
		parent_inumber = inumber;
		rc = search_directory(ncp, f, &inumber);
		*cp = c;
		if (rc)
			goto out;

		/*
		 * Open next component.
		 */
		if ((rc = read_inode(inumber, f)) != 0)
			goto out;

		/*
		 * Check for symbolic link.
		 */
		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
			int link_len = fp->f_di.di_size;
			int len;

			len = strlen(cp);

			if (link_len + len > MAXPATHLEN ||
			    ++nlinks > MAXSYMLINKS) {
				rc = ENOENT;
				goto out;
			}

			bcopy(cp, &namebuf[link_len], len + 1);

			if (link_len < fs->fs_maxsymlinklen) {
				bcopy(fp->f_di.di_shortlink, namebuf,
				      (unsigned) link_len);
			} else {
				/*
				 * Read file for symbolic link
				 */
				size_t buf_size;
				daddr_t	disk_block;
				struct fs *fs = fp->f_fs;

				if (!buf)
					buf = malloc(fs->fs_bsize);
				rc = block_map(f, (daddr_t)0, &disk_block);
				if (rc)
					goto out;
				
				twiddle();
				rc = (f->f_dev->dv_strategy)(f->f_devdata,
					F_READ, fsbtodb(fs, disk_block),
					fs->fs_bsize, buf, &buf_size);
				if (rc)
					goto out;

				bcopy((char *)buf, namebuf, (unsigned)link_len);
			}

			/*
			 * If relative pathname, restart at parent directory.
			 * If absolute pathname, restart at root.
			 */
			cp = namebuf;
			if (*cp != '/')
				inumber = parent_inumber;
			else
				inumber = (ino_t)ROOTINO;

			if ((rc = read_inode(inumber, f)) != 0)
				goto out;
		}
	}

	/*
	 * Found terminal component.
	 */
	fp->f_seekp = 0;
	rc = 0;
out:
	if (buf)
		free(buf);
	if (path)
		free(path);
	if (rc) {
		f->f_fsdata = NULL;
		if (fp->f_buf)
			free(fp->f_buf);
		free(fp->f_fs);
		free(fp);
	}
	return (rc);
}
Example #17
0
/**
 * @brief Searches for a directory entry.
 * 
 * @details Searches for a directory entry named @p filename in the directory
 *          pointed to be @p dip. If @p create is not zero and such file entry
 *          does not exist, the entry is created.
 * 
 * @param dip      Directory where the directory entry shall be searched.
 * @param filename Name of the directory entry that shall be searched.
 * @param buf      Buffer where the directory entry is loaded.
 * @param create   Create directory entry?
 * 
 * @returns Upon successful completion, the directory entry is returned. In this
 *          case, @p buf is set to point to the (locked) buffer associated to
 *          the requested directory entry. However, upon failure, a #NULL
 *          pointer is returned instead.
 * 
 * @note @p dip must be locked.
 * @note @p filename must point to a valid location.
 * @note @p buf must point to a valid location
 */
PRIVATE struct d_dirent *dirent_search
(struct inode *dip, const char *filename, struct buffer **buf, int create)
{
	int i;              /* Working directory entry index.       */
	int entry;          /* Index of first free directory entry. */
	block_t blk;        /* Working block number.                */
	int nentries;       /* Number of directory entries.         */
	struct d_dirent *d; /* Directory entry.                     */
	
	nentries = dip->size/sizeof(struct d_dirent);
	
	/* Search from very first block. */
	i = 0;
	entry = -1;
	blk = dip->blocks[0];		
	(*buf) = NULL;
	d = NULL;
	/* Search directory entry. */
	while (i < nentries)
	{
		/*
		 * Skip invalid blocks. As directory entries
		 * are removed from a directory, a whole block
		 * may become free.
		 */
		if (blk == BLOCK_NULL)
		{
			i += BLOCK_SIZE/sizeof(struct d_dirent);
			blk = block_map(dip, i*sizeof(struct d_dirent), 0);
			continue;
		}
		
		/* Get buffer. */
		if ((*buf) == NULL)
		{
			(*buf) = bread(dip->dev, blk);
			d = (*buf)->data;
		}
		
		/* Get next block */
		else if ((char *)d >= BLOCK_SIZE + (char *) (*buf)->data)
		{
			brelse((*buf));
			(*buf) = NULL;
			blk = block_map(dip, i*sizeof(struct d_dirent), 0);
			continue;
		}
		
		/* Valid entry. */
		if (d->d_ino != INODE_NULL)
		{
			/* Found */
			if (!kstrncmp(d->d_name, filename, NAME_MAX))
			{
				/* Duplicated entry. */
				if (create)
				{
					brelse((*buf));
					d = NULL;
					curr_proc->errno = EEXIST;
				}
				
				return (d);
			}
		}

		/* Remember entry index. */
		else
			entry = i;
		
		d++; i++;	
	}
	
	/* House keeping. */
	if ((*buf) != NULL)
	{
		brelse((*buf));
		(*buf) = NULL;
	}
	
	/* Create entry. */
	if (create)
	{
		/* Expand directory. */
		if (entry < 0)
		{
			entry = nentries;
			
			blk = block_map(dip, entry*sizeof(struct d_dirent), 1);
			
			/* Failed to create entry. */
			if (blk == BLOCK_NULL)
			{
				curr_proc->errno = -ENOSPC;
				return (NULL);
			}
			
			dip->size += sizeof(struct d_dirent);
			inode_touch(dip);
		}
		
		else
			blk = block_map(dip, entry*sizeof(struct d_dirent), 0);
		
		(*buf) = bread(dip->dev, blk);
		entry %= (BLOCK_SIZE/sizeof(struct d_dirent));
		d = &((struct d_dirent *)((*buf)->data))[entry];
		
		return (d);
	}
	
	return (NULL);
}
int
ffs_dir (char *dirname)
{
  char *rest, ch;
  int block, off, loc, map, ino = ROOTINO;
  struct direct *dp;

/* main loop to find destination inode */
loop:

  /* load current inode (defaults to the root inode) */

	if (!devread (fsbtodb (SUPERBLOCK, itod (SUPERBLOCK, ino)),
								ino % (SUPERBLOCK->fs_inopb) * sizeof (struct dinode),
								sizeof (struct dinode), (char *) INODE))
			return 0;			/* XXX what return value? */

  /* if we have a real file (and we're not just printing possibilities),
     then this is where we want to exit */

  if (!*dirname || isspace (*dirname))
    {
      if ((INODE->i_mode & IFMT) != IFREG)
	{
	  errnum = ERR_BAD_FILETYPE;
	  return 0;
	}

      filemax = INODE->i_size;

      /* incomplete implementation requires this! */
      fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize;
      return 1;
    }

  /* continue with file/directory name interpretation */

  while (*dirname == '/')
    dirname++;

  if (!(INODE->i_size) || ((INODE->i_mode & IFMT) != IFDIR))
    {
      errnum = ERR_BAD_FILETYPE;
      return 0;
    }

  for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);

  *rest = 0;
  loc = 0;

  /* loop for reading a the entries in a directory */

  do
    {
      if (loc >= INODE->i_size)
	{
#if 0
	  putchar ('\n');
#endif

	  if (print_possibilities < 0)
	    return 1;

	  errnum = ERR_FILE_NOT_FOUND;
	  *rest = ch;
	  return 0;
	}

      if (!(off = blkoff (SUPERBLOCK, loc)))
	{
	  block = lblkno (SUPERBLOCK, loc);

	  if ((map = block_map (block)) < 0
	      || !devread (fsbtodb (SUPERBLOCK, map), 0,
			   blksize (SUPERBLOCK, INODE, block),
			   (char *) FSYS_BUF))
	    {
	      errnum = ERR_FSYS_CORRUPT;
	      *rest = ch;
	      return 0;
	    }
	}

      dp = (struct direct *) (FSYS_BUF + off);
      loc += dp->d_reclen;

#ifndef STAGE1_5
      if (dp->d_ino && print_possibilities && ch != '/'
	  && (!*dirname || substring (dirname, dp->d_name) <= 0))
	{
	  if (print_possibilities > 0)
	    print_possibilities = -print_possibilities;

	  print_a_completion (dp->d_name);
	}
#endif /* STAGE1_5 */
    }
  while (!dp->d_ino || (substring (dirname, dp->d_name) != 0
			|| (print_possibilities && ch != '/')));

  /* only get here if we have a matching directory entry */

  ino = dp->d_ino;
  *(dirname = rest) = ch;

  /* go back to main loop at top of function */
  goto loop;
}
Example #19
0
/*
 * Loads an ELF 32 executable.
 */
PRIVATE addr_t load_elf32(struct inode *inode)
{
	int i;                  /* Loop index.                    */
	addr_t addr;            /* Region address.                */
	addr_t entry;           /* Program entry point.           */
	struct elf32_fhdr *elf; /* ELF file header.               */
	struct elf32_phdr *seg; /* ELF Program header.            */
	block_t blk;            /* Working block number.          */
	buffer_t header;        /* File headers block buffer.     */
	struct region *reg;     /* Working memory region.         */
	struct pregion *preg;   /* Working process memory region. */
	
	blk = block_map(inode, 0, 0);
	
	/* Empty file. */
	if (blk == BLOCK_NULL)
	{
		curr_proc->errno = -ENOEXEC;
		return (0);
	}
	
	/* Read ELF file header. */
	header = bread(inode->dev, blk);
	elf = buffer_data(header);
	
	/* Bad ELF file. */
	if (!is_elf(elf))
	{
		brelse(header);
		curr_proc->errno = -ENOEXEC;
		return (0);
	}
	
	/* Bad ELF file. */
	if (elf->e_phoff + elf->e_phnum*elf->e_phentsize > BLOCK_SIZE)
	{
		brelse(header);
		curr_proc->errno = -ENOEXEC;
		return (0);
	}
	
	seg = (struct elf32_phdr *)((char *)buffer_data(header) + elf->e_phoff);
	
	/* Load segments. */
	for (i = 0; i < elf->e_phnum; i++)
	{
		/* Not loadable. */
		if (seg[i].p_type != PT_LOAD)
			continue;
		
		/* Broken executable. */
		if (seg[i].p_filesz > seg[i].p_memsz)
		{
			kprintf("broken executable");
			
			brelse(header);
			curr_proc->errno = -ENOEXEC;
			return (0);
		}
		
		addr = ALIGN(seg[i].p_vaddr, seg[i].p_align);
		
		/* Text section. */
		if (!(seg[i].p_flags ^ (PF_R | PF_X)))
		{
			preg = TEXT(curr_proc);
			reg = allocreg(S_IRUSR | S_IXUSR, seg[i].p_memsz, 0);
		}
		
		/* Data section. */
		else
		{
			preg = DATA(curr_proc);
			reg = allocreg(S_IRUSR | S_IWUSR, seg[i].p_memsz, 0);
		}
		
		/* Failed to allocate region. */
		if (reg == NULL)
		{
			brelse(header);
			curr_proc->errno = -ENOMEM;
			return (0);
		}
		
		/* Attach memory region. */
		if (attachreg(curr_proc, preg, addr, reg))
		{
			freereg(reg);
			brelse(header);
			curr_proc->errno = -ENOMEM;
			return (0);
		}
		
		loadreg(inode, reg, seg[i].p_offset, seg[i].p_filesz);
		
		unlockreg(reg);	
	}
	
	entry = elf->e_entry;
	
	brelse(header);
	
	return (entry);
}
Example #20
0
/*
 * Open a file.
 */
__compactcall int
ext2fs_open(const char *path, struct open_file *f)
{
#ifndef LIBSA_FS_SINGLECOMPONENT
	const char *cp, *ncp;
	int c;
#endif
	ino32_t inumber;
	struct file *fp;
	struct m_ext2fs *fs;
	int rc;
#ifndef LIBSA_NO_FS_SYMLINK
	ino32_t parent_inumber;
	int nlinks = 0;
	char namebuf[MAXPATHLEN+1];
	char *buf;
#endif

	/* allocate file system specific data structure */
	fp = alloc(sizeof(struct file));
	memset(fp, 0, sizeof(struct file));
	f->f_fsdata = (void *)fp;

	/* allocate space and read super block */
	fs = alloc(sizeof(*fs));
	memset(fs, 0, sizeof(*fs));
	fp->f_fs = fs;
	twiddle();

	rc = read_sblock(f, fs);
	if (rc)
		goto out;

#ifdef EXT2FS_DEBUG
	dump_sblock(fs);
#endif

	/* alloc a block sized buffer used for all fs transfers */
	fp->f_buf = alloc(fs->e2fs_bsize);

	/* read group descriptor blocks */
	fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
	rc = read_gdblock(f, fs);
	if (rc)
		goto out;

	/*
	 * Calculate indirect block levels.
	 */
	{
		indp_t mult;
		int ln2;

		/*
		 * We note that the number of indirect blocks is always
		 * a power of 2.  This lets us use shifts and masks instead
		 * of divide and remainder and avoinds pulling in the
		 * 64bit division routine into the boot code.
		 */
		mult = EXT2_NINDIR(fs);
#ifdef DEBUG
		if (!powerof2(mult)) {
			/* Hummm was't a power of 2 */
			rc = EINVAL;
			goto out;
		}
#endif
		for (ln2 = 0; mult != 1; ln2++)
			mult >>= 1;

		fp->f_nishift = ln2;
	}

	inumber = EXT2_ROOTINO;
	if ((rc = read_inode(inumber, f)) != 0)
		goto out;

#ifndef LIBSA_FS_SINGLECOMPONENT
	cp = path;
	while (*cp) {

		/*
		 * Remove extra separators
		 */
		while (*cp == '/')
			cp++;
		if (*cp == '\0')
			break;

		/*
		 * Check that current node is a directory.
		 */
		if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) {
			rc = ENOTDIR;
			goto out;
		}

		/*
		 * Get next component of path name.
		 */
		ncp = cp;
		while ((c = *cp) != '\0' && c != '/')
			cp++;

		/*
		 * Look up component in current directory.
		 * Save directory inumber in case we find a
		 * symbolic link.
		 */
#ifndef LIBSA_NO_FS_SYMLINK
		parent_inumber = inumber;
#endif
		rc = search_directory(ncp, cp - ncp, f, &inumber);
		if (rc)
			goto out;

		/*
		 * Open next component.
		 */
		if ((rc = read_inode(inumber, f)) != 0)
			goto out;

#ifndef LIBSA_NO_FS_SYMLINK
		/*
		 * Check for symbolic link.
		 */
		if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) {
			/* XXX should handle LARGEFILE */
			int link_len = fp->f_di.e2di_size;
			int len;

			len = strlen(cp);

			if (link_len + len > MAXPATHLEN ||
			    ++nlinks > MAXSYMLINKS) {
				rc = ENOENT;
				goto out;
			}

			memmove(&namebuf[link_len], cp, len + 1);

			if (link_len < EXT2_MAXSYMLINKLEN) {
				memcpy(namebuf, fp->f_di.e2di_blocks, link_len);
			} else {
				/*
				 * Read file for symbolic link
				 */
				size_t buf_size;
				indp_t	disk_block;

				buf = fp->f_buf;
				rc = block_map(f, (indp_t)0, &disk_block);
				if (rc)
					goto out;

				twiddle();
				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
					F_READ, FSBTODB(fs, disk_block),
					fs->e2fs_bsize, buf, &buf_size);
				if (rc)
					goto out;

				memcpy(namebuf, buf, link_len);
			}

			/*
			 * If relative pathname, restart at parent directory.
			 * If absolute pathname, restart at root.
			 */
			cp = namebuf;
			if (*cp != '/')
				inumber = parent_inumber;
			else
				inumber = (ino32_t)EXT2_ROOTINO;

			if ((rc = read_inode(inumber, f)) != 0)
				goto out;
		}
#endif	/* !LIBSA_NO_FS_SYMLINK */
	}

	/*
	 * Found terminal component.
	 */
	rc = 0;

#else /* !LIBSA_FS_SINGLECOMPONENT */

	/* look up component in the current (root) directory */
	rc = search_directory(path, strlen(path), f, &inumber);
	if (rc)
		goto out;

	/* open it */
	rc = read_inode(inumber, f);

#endif /* !LIBSA_FS_SINGLECOMPONENT */

	fp->f_seekp = 0;		/* reset seek pointer */

out:
	if (rc)
		ext2fs_close(f);
	else
		fsmod = "ext2fs";
	return rc;
}
Example #21
0
int
ufs2_dir (char *dirname)
{
  char *rest, ch;
  unsigned long block, off, loc, ino = ROOTINO;
  grub_int64_t map;
  struct direct *dp;
  int j, k;
  char ch1;
#ifdef GRUB_UTIL
  char tmp_name[512];
#else
  char *tmp_name = (char *)(NAME_BUF);	/* MAXNAMLEN is 255, so 512 byte buffer is needed. */
#endif

/* main loop to find destination inode */
loop:

  /* load current inode (defaults to the root inode) */

    if (!devread (fsbtodb (SUPERBLOCK, ino_to_fsba (SUPERBLOCK, ino)),
	    ino % (SUPERBLOCK->fs_inopb) * sizeof (struct ufs2_dinode),
	    sizeof (struct ufs2_dinode), (char *) INODE_UFS2, 0xedde0d90))
		    return 0;			/* XXX what return value? */

  /* if we have a real file (and we're not just printing possibilities),
     then this is where we want to exit */

  if (!*dirname || isspace (*dirname))
    {
      if ((INODE_UFS2->di_mode & IFMT) != IFREG)
	{
	  errnum = ERR_BAD_FILETYPE;
	  return 0;
	}

      filemax = INODE_UFS2->di_size;

      /* incomplete implementation requires this! */
      fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize;
      return 1;
    }

  /* continue with file/directory name interpretation */

  while (*dirname == '/')
    dirname++;

  if (!(INODE_UFS2->di_size) || ((INODE_UFS2->di_mode & IFMT) != IFDIR))
    {
      errnum = ERR_BAD_FILETYPE;
      return 0;
    }

  //for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
  for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++)
  {
	if (ch == '\\')
	{
		rest++;
		if (! (ch = *rest))
			break;
	}
  }

  *rest = 0;
  loc = 0;

  /* loop for reading a the entries in a directory */

  do
    {
      if (loc >= INODE_UFS2->di_size)
	{
	  if (print_possibilities < 0)
	    return 1;

	  errnum = ERR_FILE_NOT_FOUND;
	  *rest = ch;
	  return 0;
	}

      if (!(off = blkoff (SUPERBLOCK, loc)))
	{
	  block = lblkno (SUPERBLOCK, loc);

	  if ((map = block_map (block)) < 0
	      || !devread (fsbtodb (SUPERBLOCK, map), 0,
			   blksize (SUPERBLOCK, INODE_UFS2, block),
			   (char *) FSYS_BUF, 0xedde0d90))
	    {
	      errnum = ERR_FSYS_CORRUPT;
	      *rest = ch;
	      return 0;
	    }
	}

      dp = (struct direct *) (FSYS_BUF + off);
      loc += dp->d_reclen;

	/* copy dp->name to tmp_name, and quote the spaces with a '\\' */
	for (j = 0, k = 0; j < dp->d_namlen; j++)
	{
		if (! (ch1 = dp->d_name[j]))
			break;
		if (ch1 == ' ')
			tmp_name[k++] = '\\';
		tmp_name[k++] = ch1;
	}
	tmp_name[k] = 0;

#ifndef STAGE1_5
      if (dp->d_ino && print_possibilities && ch != '/'
	  && (!*dirname || substring (dirname, tmp_name, 0) <= 0))
	{
	  if (print_possibilities > 0)
	    print_possibilities = -print_possibilities;

	  print_a_completion (tmp_name);
	}
#endif /* STAGE1_5 */
    }
  while (!dp->d_ino || (substring (dirname, dp->d_name, 0) != 0
			|| (print_possibilities && ch != '/')));

  /* only get here if we have a matching directory entry */

  ino = dp->d_ino;
  *(dirname = rest) = ch;

  /* go back to main loop at top of function */
  goto loop;
}