aboutsummaryrefslogtreecommitdiff
path: root/serverboot/file_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'serverboot/file_io.c')
-rw-r--r--serverboot/file_io.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/serverboot/file_io.c b/serverboot/file_io.c
new file mode 100644
index 00000000..99966f95
--- /dev/null
+++ b/serverboot/file_io.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ * MINIX FS patches: Csizmazia Balazs, University ELTE, Hungary
+ */
+/* This is just an icky kludgy "VFS layer" (harhar) for ffs and ext2 and minix. */
+
+#include "file_io.h"
+
+int
+open_file(master_device_port, path, fp)
+ mach_port_t master_device_port;
+ char * path;
+ struct file *fp;
+{
+ int rc;
+
+ if ((rc = ext2_open_file(master_device_port, path, fp))
+ != FS_INVALID_FS)
+ {
+ if (rc == 0)
+ fp->f_fstype = EXT2_FS;
+ return rc;
+ }
+ if ( (rc = minix_open_file(master_device_port, path, fp))
+ != FS_INVALID_FS )
+ {
+ if (rc == 0)
+ fp->f_fstype = MINIX_FS;
+ return rc;
+ }
+ fp->f_fstype = BSD_FFS;
+ return ffs_open_file(master_device_port, path, fp);
+}
+
+void
+close_file(fp)
+ register struct file *fp;
+{
+ switch (fp->f_fstype) {
+ case EXT2_FS:
+ ext2_close_file(fp);
+ return;
+ case MINIX_FS:
+ minix_close_file(fp);
+ return;
+ default:
+ ffs_close_file(fp);
+ return;
+ }
+}
+
+int
+read_file(fp, offset, start, size, resid)
+ register struct file *fp;
+ vm_offset_t offset;
+ vm_offset_t start;
+ vm_size_t size;
+ vm_size_t *resid; /* out */
+{
+ switch (fp->f_fstype) {
+ case EXT2_FS:
+ return ext2_read_file(fp, offset, start, size, resid);
+ case MINIX_FS:
+ return minix_read_file(fp, offset, start, size, resid);
+ default:
+ return ffs_read_file(fp, offset, start, size, resid);
+ }
+
+}
+
+int
+file_is_directory(struct file *f)
+{
+ switch (f->f_fstype) {
+ case EXT2_FS:
+ return ext2_file_is_directory(f);
+ case MINIX_FS:
+ return minix_file_is_directory(f);
+ default:
+ return ffs_file_is_directory(f);
+ }
+}
+
+int
+file_is_regular(struct file *f)
+{
+ switch (f->f_fstype) {
+ case EXT2_FS:
+ return ext2_file_is_regular(f);
+ case MINIX_FS:
+ return minix_file_is_regular(f);
+ default:
+ return ffs_file_is_regular(f);
+ }
+
+}
+
+int
+open_file_direct(dev, fdp, is_structured)
+ mach_port_t dev;
+ register struct file_direct *fdp;
+ boolean_t is_structured;
+{
+ int rc;
+
+
+ if ((rc = ext2_open_file_direct(dev, fdp, is_structured))
+ != FS_INVALID_FS)
+ {
+ if (rc == 0)
+ fdp->f_fstype = EXT2_FS;
+ return rc;
+ }
+ if ( (rc = minix_open_file_direct(dev, fdp, is_structured) )
+ != FS_INVALID_FS )
+ {
+ if (rc == 0)
+ fdp->f_fstype = MINIX_FS;
+ return rc;
+ }
+ fdp->f_fstype = BSD_FFS;
+ return ffs_open_file_direct(dev, fdp, is_structured);
+}
+
+int
+add_file_direct(fdp, fp)
+ register struct file_direct *fdp;
+ register struct file *fp;
+{
+ switch (fp->f_fstype) {
+ case EXT2_FS:
+ return ext2_add_file_direct(fdp, fp);
+ case MINIX_FS:
+ return minix_add_file_direct(fdp, fp);
+ default:
+ return ffs_add_file_direct(fdp, fp);
+ }
+}
+
+
+int
+remove_file_direct(fdp)
+ struct file_direct *fdp;
+{
+ switch (fdp->f_fstype) {
+ case EXT2_FS:
+ return ext2_remove_file_direct(fdp);
+ case MINIX_FS:
+ return minix_remove_file_direct(fdp);
+ default:
+ return ffs_remove_file_direct(fdp);
+ }
+}
+
+/*
+ * some other stuff, that was previously defined as macro
+ */
+
+int
+file_is_structured(fp)
+ register struct file *fp;
+{
+ switch (fp->f_fstype) {
+ case EXT2_FS:
+ return (fp)->u.ext2.ext2_fs != 0;
+ case MINIX_FS:
+ return (fp)->u.minix.minix_fs != 0;
+ default:
+ return (fp)->u.ffs.ffs_fs != 0;
+ }
+}
+
+/*
+ * Special read and write routines for default pager.
+ * Assume that all offsets and sizes are multiples
+ * of DEV_BSIZE.
+ */
+
+#define fdir_blkoff(fdp, offset) /* offset % fd_bsize */ \
+ ((offset) & ((fdp)->fd_bsize - 1))
+#define fdir_lblkno(fdp, offset) /* offset / fd_bsize */ \
+ ((offset) >> (fdp)->fd_bshift)
+
+#define fdir_fsbtodb(fdp, block) /* offset * fd_bsize / DEV_BSIZE */ \
+ ((block) << (fdp)->fd_fsbtodb)
+
+/*
+ * Read all or part of a data block, and
+ * return a pointer to the appropriate part.
+ * Caller must deallocate the block when done.
+ */
+int
+page_read_file_direct(fdp, offset, size, addr, size_read)
+ register struct file_direct *fdp;
+ vm_offset_t offset;
+ vm_size_t size;
+ vm_offset_t *addr; /* out */
+ mach_msg_type_number_t *size_read; /* out */
+{
+ vm_offset_t off;
+ register daddr_t file_block;
+ daddr_t disk_block;
+
+ if (offset % DEV_BSIZE != 0 ||
+ size % DEV_BSIZE != 0)
+ panic("page_read_file_direct");
+
+ if (offset >= (fdp->fd_size << fdp->fd_bshift))
+ return (FS_NOT_IN_FILE);
+
+ off = fdir_blkoff(fdp, offset);
+ file_block = fdir_lblkno(fdp, offset);
+
+ if (file_is_device(fdp)) {
+ disk_block = file_block;
+ } else {
+ disk_block = fdp->fd_blocks[file_block];
+ if (disk_block == 0)
+ return (FS_NOT_IN_FILE);
+
+ if (size > fdp->fd_bsize) {
+ /* Read only as much as is contiguous on disk. */
+ daddr_t b = file_block + 1;
+ while (b < file_block + fdp->fd_size &&
+ fdp->fd_blocks[b] == disk_block + fdir_fsbtodb(fdp, 1))
+ ++b;
+ size = (b - file_block) * fdp->fd_bsize;
+ }
+ }
+
+ return (device_read(fdp->fd_dev,
+ 0,
+ (recnum_t) (fdir_fsbtodb(fdp, disk_block) + btodb(off)),
+ (int) size,
+ (char **) addr,
+ size_read));
+}
+
+/*
+ * Write all or part of a data block, and
+ * return the amount written.
+ */
+int
+page_write_file_direct(fdp, offset, addr, size, size_written)
+ register struct file_direct *fdp;
+ vm_offset_t offset;
+ vm_offset_t addr;
+ vm_size_t size;
+ vm_offset_t *size_written; /* out */
+{
+ vm_offset_t off;
+ register daddr_t file_block;
+ daddr_t disk_block;
+ int rc, num_written;
+ vm_offset_t block_size;
+
+ if (offset % DEV_BSIZE != 0 ||
+ size % DEV_BSIZE != 0)
+ panic("page_write_file");
+
+ if (offset >= (fdp->fd_size << fdp->fd_bshift))
+ return (FS_NOT_IN_FILE);
+
+ off = fdir_blkoff(fdp, offset);
+ file_block = fdir_lblkno(fdp, offset);
+
+ if (file_is_device(fdp)) {
+ disk_block = file_block;
+ } else {
+ disk_block = fdp->fd_blocks[file_block];
+ if (disk_block == 0)
+ return (FS_NOT_IN_FILE);
+
+ if (size > fdp->fd_bsize) {
+ /* Write only as much as is contiguous on disk. */
+ daddr_t b = file_block + 1;
+ while (b < file_block + fdp->fd_size &&
+ fdp->fd_blocks[b] == disk_block + fdir_fsbtodb(fdp, 1))
+ ++b;
+ size = (b - file_block) * fdp->fd_bsize;
+ }
+ }
+
+ /*
+ * Write the data. Wait for completion to keep
+ * reads from getting ahead of writes and reading
+ * stale data.
+ */
+ rc = device_write(
+ fdp->fd_dev,
+ 0,
+ (recnum_t) (fdir_fsbtodb(fdp, disk_block) + btodb(off)),
+ (char *) addr,
+ size,
+ &num_written);
+ *size_written = num_written;
+ return rc;
+}