/* * 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; }