diff options
Diffstat (limited to 'serverboot/file_io.c')
-rw-r--r-- | serverboot/file_io.c | 317 |
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; +} |