From: Thomas Veerman Date: Thu, 1 Oct 2009 14:00:27 +0000 (+0000) Subject: Initial import of ISOFS by Jacopo Urbani X-Git-Tag: v3.1.5~53 X-Git-Url: http://zhaoyanbai.com/repos/Bv9ARM.ch11.html?a=commitdiff_plain;h=471ad9384f120d037abd158f6d3bbff9be58f026;p=minix.git Initial import of ISOFS by Jacopo Urbani --- diff --git a/servers/iso9660fs/Makefile b/servers/iso9660fs/Makefile new file mode 100644 index 000000000..1b82eeb01 --- /dev/null +++ b/servers/iso9660fs/Makefile @@ -0,0 +1,38 @@ +# Makefile for ISO9660 fs +SERVER = isofs +NR_BUFS = 100 + +# directories +u = /usr +i = $u/include +s = $i/sys +h = $i/minix + +# programs, flags, etc. +CC = exec cc +CFLAGS = -I$i $(EXTRA_OPTS) $(CPROFILE) -DNR_BUFS=$(NR_BUFS) +LDFLAGS = -i +LIBS = -lsysutil -lsys -ltimers + +OBJ = main.o table.o mount.o super.o inode.o device.o \ + utility.o misc.o path.o read.o stadir.o cache.o \ + protect.o + +# build local binary +all build: $(SERVER) +$(SERVER): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + install -S 64k $(SERVER) + +install: $(SERVER) + install $(SERVER) /sbin/$(SERVER) + +# clean up local files +clean: + rm -f $(SERVER) *.o *.bak *~ + +depend: + mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend \ No newline at end of file diff --git a/servers/iso9660fs/buf.h b/servers/iso9660fs/buf.h new file mode 100644 index 000000000..f61880f64 --- /dev/null +++ b/servers/iso9660fs/buf.h @@ -0,0 +1,23 @@ +#include /* need struct direct */ +#include + +PUBLIC struct buf { + union { + char b__data[_MAX_BLOCK_SIZE]; /* ordinary user data */ + struct direct b__dir[NR_DIR_ENTRIES(_MAX_BLOCK_SIZE)];/* directory block */ + } b; + + block_t b_blocknr; /* block number of its (minor) device */ + char b_count; /* number of users of this buffer */ +} buf[NR_BUFS]; + +/* A block is free if b_dev == NO_DEV. */ + +#define NIL_BUF ((struct buf *) 0) /* indicates absence of a buffer */ + +/* These defs make it possible to use to bp->b_data instead of bp->b.b__data */ +#define b_data b.b__data +#define b_dir b.b__dir + +#define INODE_BLOCK 0 /* inode block */ +#define DIRECTORY_BLOCK 1 /* directory block */ diff --git a/servers/iso9660fs/cache.c b/servers/iso9660fs/cache.c new file mode 100644 index 000000000..b393f7e68 --- /dev/null +++ b/servers/iso9660fs/cache.c @@ -0,0 +1,115 @@ +/* The file system maintains a buffer cache to reduce the number of disk + * accesses needed. Whenever a read or write to the disk is done, a check is + * first made to see if the block is in the cache. This file manages the + * cache. + * + * The entry points into this file are: + * get_block: request to fetch a block for reading or writing from cache + * put_block: return a block previously requested with get_block + * + * Private functions: + * read_block: read physically the block + */ + +#include "inc.h" +#include +#include +#include "buf.h" + +FORWARD _PROTOTYPE(int read_block, (struct buf *)); + +PUBLIC struct buf *bp_to_pickup = buf; /* This is a pointer to the next node in the + * buffer cache to pick up*/ + +/*===========================================================================* + * get_block * + *===========================================================================*/ +PUBLIC struct buf *get_block(block) +register block_t block; /* which block is wanted? */ +{ + int b; + register struct buf *bp, *free_bp; + + free_bp = NIL_BUF; + + /* Find if the block is already loaded */ + for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) + if (bp->b_blocknr == block) { + /* Block found. Increment count and return it */ + bp->b_count++; + return bp; + } else + if (bp == bp_to_pickup) { + if (bp->b_count == 0) + free_bp = bp; + else /* Increment the node to pickup */ + if (bp_to_pickup < &buf[NR_BUFS] - 1) + bp_to_pickup++; + else + bp_to_pickup = buf; + } + + if (free_bp == NIL_BUF && + bp_to_pickup == buf && + bp_to_pickup->b_count == 0) + free_bp = bp_to_pickup; + + if (free_bp != NIL_BUF) { + /* Set fields of data structure */ + free_bp->b_blocknr = block; + if (read_block(free_bp) != OK) return NIL_BUF; + free_bp->b_count = 1; + + if (bp_to_pickup < &buf[NR_BUFS] - 1) + bp_to_pickup++; + else + bp_to_pickup = buf; + + return free_bp; + } else { + /* No free blocks. Return NIL_BUF */ + return NIL_BUF; + } +} + +/*===========================================================================* + * put_block * + *===========================================================================*/ +PUBLIC void put_block(bp) +register struct buf *bp; /* pointer to the buffer to be released */ +{ + if (bp == NIL_BUF) return; /* it is easier to check here than in caller */ + + bp->b_count--; /* there is one use fewer now */ +} + +/*===========================================================================* + * read_block * + *===========================================================================*/ +PRIVATE int read_block(bp) +register struct buf *bp; /* buffer pointer */ +{ + int r, op; + u64_t pos; + int block_size; + + block_size = v_pri.logical_block_size_l; /* The block size is indicated by + * the superblock */ + + + pos = mul64u(bp->b_blocknr, block_size); /* get absolute position */ + op = MFS_DEV_READ; /* flag to read */ + r = block_dev_io(op, fs_dev, SELF_E, bp->b_data, pos, block_size, 0); + if (r != block_size) { + if (r >= 0) r = END_OF_FILE; + if (r != END_OF_FILE) + printf("ISO9660FS(%d) I/O error on device %d/%d, block %ld\n", + SELF_E, (fs_dev>>MAJOR)&BYTE, (fs_dev>>MINOR)&BYTE, + bp->b_blocknr); + + rdwt_err = r; + return EINVAL; + } + + return OK; +} diff --git a/servers/iso9660fs/const.h b/servers/iso9660fs/const.h new file mode 100644 index 000000000..43e2a69a5 --- /dev/null +++ b/servers/iso9660fs/const.h @@ -0,0 +1,66 @@ +/* In this file are declared all the constant used by the server. */ + +#define WRITE_LOG(TEXT) printf("iso9660fs: " TEXT "\n"); + +#define ISO9660_STANDARD_ID "CD001" /* Standard code for ISO9660 filesystems */ + +#define NR_DIR_RECORDS 256 /* Number of dir records to use at the same + * time. */ +#define NR_ATTR_RECS 256 /* Number of extended attributes that is + * possible to use at the same time */ +/* #define NR_ID_INODES 1024 */ /* The ISO9660 doesn't save the inode numbers. + * There is a table that assign to every inode + * a particular id. This number defines the + * maximum number of ids the finesystem can + * handle */ + +#define NO_ADDRESS -1 /* Error constants */ +#define NO_FREE_INODES -1 + +#define PATH_PENULTIMATE 001 /* parse_path stops at last but one name */ +#define PATH_NONSYMBOLIC 004 /* parse_path scans final name if symbolic */ + +#define DIR_ENTRY_SIZE sizeof (struct direct) +#define NR_DIR_ENTRIES(b) ((b)/DIR_ENTRY_SIZE) + +/* Below there are constant of the ISO9660 fs */ + +#define ISO9660_SUPER_BLOCK_POSITION (32768) +#define ISO9660_MIN_BLOCK_SIZE 2048 + +/* SIZES FIELDS ISO9660 STRUCTURES */ +#define ISO9660_SIZE_STANDARD_ID 5 +#define ISO9660_SIZE_BOOT_SYS_ID 32 +#define ISO9660_SIZE_BOOT_ID 32 + +#define ISO9660_SIZE_SYS_ID 32 +#define ISO9660_SIZE_VOLUME_ID 32 +#define ISO9660_SIZE_VOLUME_SET_ID 128 +#define ISO9660_SIZE_PUBLISHER_ID 128 +#define ISO9660_SIZE_DATA_PREP_ID 128 +#define ISO9660_SIZE_APPL_ID 128 +#define ISO9660_SIZE_COPYRIGHT_FILE_ID 37 +#define ISO9660_SIZE_ABSTRACT_FILE_ID 37 +#define ISO9660_SIZE_BIBL_FILE_ID 37 + +#define ISO9660_SIZE_VOL_CRE_DATE 17 +#define ISO9660_SIZE_VOL_MOD_DATE 17 +#define ISO9660_SIZE_VOL_EXP_DATE 17 +#define ISO9660_SIZE_VOL_EFF_DATE 17 + +#define ISO9660_SIZE_ESCAPE_SQC 32 +#define ISO9660_SIZE_PART_ID 32 + +#define ISO9660_SIZE_SYSTEM_USE 64 + +/* maximum size of length of name file used in dir records */ +#define ISO9660_MAX_FILE_ID_LEN 32 + +#define MFS_DEV_READ 10001 +#define MFS_DEV_WRITE 10002 +#define MFS_DEV_SCATTER 10003 +#define MFS_DEV_GATHER 10004 + +#define END_OF_FILE (-104) /* eof detected */ + +#define offsetof(type, field) ((size_t)(&((type *)0)->field)) diff --git a/servers/iso9660fs/device.c b/servers/iso9660fs/device.c new file mode 100644 index 000000000..1ffa70e8b --- /dev/null +++ b/servers/iso9660fs/device.c @@ -0,0 +1,344 @@ + +/* This file handles the direct communication to the device */ +#include "inc.h" +#include + +PRIVATE int dummyproc; + +FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t, cp_grant_id_t *, + int *, cp_grant_id_t *, int, + endpoint_t *, void **, int *, + vir_bytes)); + +FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *, + int)); +FORWARD _PROTOTYPE( int gen_opcl, (endpoint_t driver_e, int op, + Dev_t dev, int proc_e, int flags)); +FORWARD _PROTOTYPE( int gen_io, (int task_nr, message *mess_ptr)); + +/*===========================================================================* + * fs_new_driver * + *===========================================================================*/ +PUBLIC int fs_new_driver(void) +{ + /* New driver endpoint for this device */ + driver_endpoints[(fs_m_in.REQ_DEV >> MAJOR) & BYTE].driver_e = + fs_m_in.REQ_DRIVER_E; + return OK; +} + + +/*===========================================================================* + * safe_io_conversion * + *===========================================================================*/ +PRIVATE int safe_io_conversion(driver, gid, op, gids, gids_size, + io_ept, buf, vec_grants, bytes) +endpoint_t driver; +cp_grant_id_t *gid; +int *op; +cp_grant_id_t *gids; +int gids_size; +endpoint_t *io_ept; +void **buf; +int *vec_grants; +vir_bytes bytes; +{ + int access = 0, size; + int j; + iovec_t *v; + static iovec_t new_iovec[NR_IOREQS]; + + /* Number of grants allocated in vector I/O. */ + *vec_grants = 0; + + /* Driver can handle it - change request to a safe one. */ + + *gid = GRANT_INVALID; + + switch(*op) { + case MFS_DEV_READ: + case MFS_DEV_WRITE: + /* Change to safe op. */ + *op = *op == MFS_DEV_READ ? DEV_READ_S : DEV_WRITE_S; + + if((*gid=cpf_grant_direct(driver, (vir_bytes) *buf, + bytes, *op == DEV_READ_S ? CPF_WRITE : + CPF_READ)) < 0) { + panic(__FILE__, + "cpf_grant_magic of buffer failed\n", NO_NUM); + } + + break; + case MFS_DEV_GATHER: + case MFS_DEV_SCATTER: + /* Change to safe op. */ + *op = *op == MFS_DEV_GATHER ? + DEV_GATHER_S : DEV_SCATTER_S; + + /* Grant access to my new i/o vector. */ + if((*gid = cpf_grant_direct(driver, + (vir_bytes) new_iovec, bytes * sizeof(iovec_t), + CPF_READ | CPF_WRITE)) < 0) { + panic(__FILE__, + "cpf_grant_direct of vector failed", NO_NUM); + } + v = (iovec_t *) *buf; + /* Grant access to i/o buffers. */ + for(j = 0; j < bytes; j++) { + if(j >= NR_IOREQS) + panic(__FILE__, "vec too big", bytes); + new_iovec[j].iov_addr = gids[j] = + cpf_grant_direct(driver, (vir_bytes) + v[j].iov_addr, v[j].iov_size, + *op == DEV_GATHER_S ? CPF_WRITE : CPF_READ); + if(!GRANT_VALID(gids[j])) { + panic(__FILE__, "mfs: grant to iovec buf failed", + NO_NUM); + } + new_iovec[j].iov_size = v[j].iov_size; + (*vec_grants)++; + } + + /* Set user's vector to the new one. */ + *buf = new_iovec; + break; + } + + /* If we have converted to a safe operation, I/O + * endpoint becomes FS if it wasn't already. + */ + if(GRANT_VALID(*gid)) { + *io_ept = SELF_E; + return 1; + } + + /* Not converted to a safe operation (because there is no + * copying involved in this operation). + */ + return 0; +} + +/*===========================================================================* + * safe_io_cleanup * + *===========================================================================*/ +PRIVATE void safe_io_cleanup(gid, gids, gids_size) +cp_grant_id_t gid; +cp_grant_id_t *gids; +int gids_size; +{ +/* Free resources (specifically, grants) allocated by safe_io_conversion(). */ + int j; + + cpf_revoke(gid); + + for(j = 0; j < gids_size; j++) + cpf_revoke(gids[j]); + + return; +} + +/*===========================================================================* + * dev_open * + *===========================================================================*/ +PUBLIC int dev_open(driver_e, dev, proc, flags) +endpoint_t driver_e; +dev_t dev; /* device to open */ +int proc; /* process to open for */ +int flags; /* mode bits and flags */ +{ + int major, r; + + /* Determine the major device number call the device class specific + * open/close routine. (This is the only routine that must check the + * device number for being in range. All others can trust this check.) + */ + major = (dev >> MAJOR) & BYTE; + if (major >= NR_DEVICES) major = 0; + r = gen_opcl(driver_e, DEV_OPEN, dev, proc, flags); + if (r == SUSPEND) panic(__FILE__,"suspend on open from", NO_NUM); + return(r); +} + +/*===========================================================================* + * block_dev_io * + *===========================================================================*/ +PUBLIC int block_dev_io(op, dev, proc_e, buf, pos, bytes, flags) +int op; /* MFS_DEV_READ, MFS_DEV_WRITE, etc. */ +dev_t dev; /* major-minor device number */ +int proc_e; /* in whose address space is buf? */ +void *buf; /* virtual address of the buffer */ +u64_t pos; /* byte position */ +int bytes; /* how many bytes to transfer */ +int flags; /* special flags, like O_NONBLOCK */ +{ +/* Read or write from a device. The parameter 'dev' tells which one. */ + struct dmap *dp; + int r, safe; + message m; + iovec_t *v; + cp_grant_id_t gid = GRANT_INVALID; + int vec_grants; + int op_used; + void *buf_used; + static cp_grant_id_t gids[NR_IOREQS]; + endpoint_t driver_e; + + /* Determine driver endpoint for this device */ + driver_e = driver_endpoints[(dev >> MAJOR) & BYTE].driver_e; + + /* See if driver is roughly valid. */ + if (driver_e == NONE) { + printf("ISO9660FS(%d) block_dev_io: no driver for dev %x\n", SELF_E, dev); + return EDSTDIED; + } + + /* The io vector copying relies on this I/O being for FS itself. */ + if(proc_e != SELF_E) { + printf("ISO9660FS(%d) doing block_dev_io for non-self %d\n", SELF_E, proc_e); + panic(__FILE__, "doing block_dev_io for non-self", proc_e); + } + + /* By default, these are right. */ + m.IO_ENDPT = proc_e; + m.ADDRESS = buf; + buf_used = buf; + + /* Convert parameters to 'safe mode'. */ + op_used = op; + safe = safe_io_conversion(driver_e, &gid, + &op_used, gids, NR_IOREQS, &m.IO_ENDPT, &buf_used, + &vec_grants, bytes); + + /* Set up rest of the message. */ + if (safe) m.IO_GRANT = (char *) gid; + + m.m_type = op_used; + m.DEVICE = (dev >> MINOR) & BYTE; + m.POSITION = ex64lo(pos); + m.COUNT = bytes; + m.HIGHPOS = ex64hi(pos); + + /* Call the task. */ + r = sendrec(driver_e, &m); + + /* As block I/O never SUSPENDs, safe cleanup must be done whether + * the I/O succeeded or not. */ + if (safe) safe_io_cleanup(gid, gids, vec_grants); + + /* RECOVERY: + * - send back dead driver number + * - VFS unmaps it, waits for new driver + * - VFS sends the new driver endp for the FS proc and the request again + */ + if (r != OK) { + if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) { + printf("ISO9660FS(%d) dead driver %d\n", SELF_E, driver_e); + driver_endpoints[(dev >> MAJOR) & BYTE].driver_e = NONE; + return r; + /*dmap_unmap_by_endpt(task_nr); <- in the VFS proc... */ + } + else if (r == ELOCKED) { + printf("ISO9660FS(%d) ELOCKED talking to %d\n", SELF_E, driver_e); + return r; + } + else + panic(__FILE__,"call_task: can't send/receive", r); + } else { + /* Did the process we did the sendrec() for get a result? */ + if (m.REP_ENDPT != proc_e) { + printf("I9660FS(%d) strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n", SELF_E, m.m_source, m.m_type, proc_e, m.REP_ENDPT); + r = EIO; + } + } + + /* Task has completed. See if call completed. */ + if (m.REP_STATUS == SUSPEND) { + panic(__FILE__, "ISO9660FS block_dev_io: driver returned SUSPEND", NO_NUM); + } + + if(buf != buf_used && r == OK) { + memcpy(buf, buf_used, bytes * sizeof(iovec_t)); + } + + return(m.REP_STATUS); +} + +/*===========================================================================* + * gen_opcl * + *===========================================================================*/ +PRIVATE int gen_opcl(driver_e, op, dev, proc_e, flags) +endpoint_t driver_e; +int op; /* operation, DEV_OPEN or DEV_CLOSE */ +dev_t dev; /* device to open or close */ +int proc_e; /* process to open/close for */ +int flags; /* mode bits and flags */ +{ +/* Called from the dmap struct in table.c on opens & closes of special files.*/ + message dev_mess; + + dev_mess.m_type = op; + dev_mess.DEVICE = (dev >> MINOR) & BYTE; + dev_mess.IO_ENDPT = proc_e; + dev_mess.COUNT = flags; + + /* Call the task. */ + gen_io(driver_e, &dev_mess); + + return(dev_mess.REP_STATUS); +} + + +/*===========================================================================* + * gen_io * + *===========================================================================*/ +PRIVATE int gen_io(task_nr, mess_ptr) +int task_nr; /* which task to call */ +message *mess_ptr; /* pointer to message for task */ +{ +/* All file system I/O ultimately comes down to I/O on major/minor device + * pairs. These lead to calls on the following routines via the dmap table. + */ + + int r, proc_e; + + proc_e = mess_ptr->IO_ENDPT; + + r = sendrec(task_nr, mess_ptr); + if (r != OK) { + if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) { + printf("fs: dead driver %d\n", task_nr); + panic(__FILE__, "should handle crashed drivers", + NO_NUM); + /* dmap_unmap_by_endpt(task_nr); */ + return r; + } + if (r == ELOCKED) { + printf("fs: ELOCKED talking to %d\n", task_nr); + return r; + } + panic(__FILE__,"call_task: can't send/receive", r); + } + + /* Did the process we did the sendrec() for get a result? */ + if (mess_ptr->REP_ENDPT != proc_e) { + printf( + "fs: strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n", + mess_ptr->m_source, + mess_ptr->m_type, + proc_e, + mess_ptr->REP_ENDPT); + return EIO; + } + + return OK; +} + +/*===========================================================================* + * dev_close * + *===========================================================================*/ +PUBLIC void dev_close(driver_e, dev) +endpoint_t driver_e; +dev_t dev; /* device to close */ +{ + (void) gen_opcl(driver_e, DEV_CLOSE, dev, 0, 0); +} diff --git a/servers/iso9660fs/drivers.h b/servers/iso9660fs/drivers.h new file mode 100644 index 000000000..2878aca2c --- /dev/null +++ b/servers/iso9660fs/drivers.h @@ -0,0 +1,9 @@ +#include + +/* Driver endpoints for major devices. Only the block devices + * are mapped here, it's a subset of the mapping in the VFS */ + +EXTERN struct driver_endpoints { + endpoint_t driver_e; +} driver_endpoints[NR_DEVICES]; + diff --git a/servers/iso9660fs/glo.h b/servers/iso9660fs/glo.h new file mode 100644 index 000000000..5c93a5987 --- /dev/null +++ b/servers/iso9660fs/glo.h @@ -0,0 +1,34 @@ +/* EXTERN should be extern except for the table file */ +#ifdef _TABLE +#undef EXTERN +#define EXTERN +#endif + +/* The following variables are used for returning results to the caller. */ + +EXTERN int err_code; /* temporary storage for error number */ +EXTERN int rdwt_err; /* status of last disk i/o request */ + +EXTERN _PROTOTYPE (int (*fs_call_vec[]), (void) ); /* fs call table */ + +EXTERN message fs_m_in; /* contains the input message of the request */ +EXTERN message fs_m_out; /* contains the output message of the + * request */ +EXTERN int FS_STATE; + +EXTERN uid_t caller_uid; +EXTERN gid_t caller_gid; + +EXTERN int req_nr; /* request number to the server */ + +EXTERN int SELF_E; /* process number */ + +EXTERN short path_processed; /* number of characters processed */ +EXTERN char user_path[PATH_MAX+1]; /* pathname to be processed */ +EXTERN char *vfs_slink_storage; +EXTERN int symloop; + +EXTERN dev_t fs_dev; /* the device that is handled by this FS proc */ +EXTERN char fs_dev_label[16]; /* Name of the device driver that is handled */ + +EXTERN int use_getuptime2; /* Should be removed togetherwith boottime */ diff --git a/servers/iso9660fs/inc.h b/servers/iso9660fs/inc.h new file mode 100644 index 000000000..683ab65a3 --- /dev/null +++ b/servers/iso9660fs/inc.h @@ -0,0 +1,33 @@ + +#define _SYSTEM 1 /* get OK and negative error codes */ +#define _MINIX 1 /* tell headers to include MINIX stuff */ + +#define VERBOSE 0 /* display diagnostics */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "proto.h" +#include "super.h" +#include "glo.h" +#include "drivers.h" diff --git a/servers/iso9660fs/inode.c b/servers/iso9660fs/inode.c new file mode 100644 index 000000000..2289aad49 --- /dev/null +++ b/servers/iso9660fs/inode.c @@ -0,0 +1,318 @@ + +/* This file contains all the function that handle the dir records + * (inodes) for the ISO9660 filesystem.*/ + +#include "inc.h" +#include "buf.h" +#include + +/*===========================================================================* + * fs_getnode * + *===========================================================================*/ +PUBLIC int fs_getnode() +{ +/* Increase the inode's counter specified in the request message + */ + struct dir_record *dir; + + /* Get the dir record by the id */ + dir = get_dir_record(fs_m_in.REQ_INODE_NR); + if (dir == NULL) + return EINVAL; + + /* Transfer back the inode's details */ + fs_m_out.m_source = fs_dev; + fs_m_out.RES_INODE_NR = fs_m_in.REQ_INODE_NR; + fs_m_out.RES_MODE = dir->d_mode; + fs_m_out.RES_FILE_SIZE = dir->d_file_size; + fs_m_out.RES_DEV = (Dev_t)fs_dev; + fs_m_out.RES_UID = 0; + fs_m_out.RES_GID = 0; + + return OK; +} + +/*===========================================================================* + * fs_putnode * + *===========================================================================*/ +PUBLIC int fs_putnode() +{ +/* Find the inode specified by the request message and decrease its counter. + */ + int count; + struct dir_record *dir = (void *)0; + +/* if (fs_m_in.REQ_INODE_INDEX >= 0 && */ +/* fs_m_in.REQ_INODE_INDEX <= NR_DIR_RECORDS && */ +/* ID_DIR_RECORD((dir_records + fs_m_in.REQ_INODE_INDEX)) == fs_m_in.REQ_INODE_NR) { */ +/* dir = &dir_records[fs_m_in.REQ_INODE_INDEX]; */ +/* /\* In this case the dir record by the dir record table *\/ */ +/* } else { */ + dir = get_dir_record(fs_m_in.REQ_INODE_NR); + /* Get dir record increased the counter. We must decrease it releasing + * it */ + release_dir_record(dir); + + if (dir == (void *)0) { + panic(__FILE__, "fs_putnode failed", NO_NUM); + } + + count= fs_m_in.REQ_COUNT; /* I will check that the values of the count + * are the same */ + + if (count <= 0) { + printf("put_inode: bad value for count: %d\n", count); + panic(__FILE__, "fs_putnode failed", NO_NUM); + return EINVAL; + } + if (count > dir->d_count) { + printf("put_inode: count too high: %d > %d\n", count, dir->d_count); + panic(__FILE__, "fs_putnode failed", NO_NUM); + return EINVAL; + } + + if (dir->d_count > 1) + dir->d_count = dir->d_count - count + 1; /* If the dir record should be released this + operation will bring the counter to 1. + The next function will further decreases it + releasing it completely. */ + + release_dir_record(dir); /* I finally release it */ + + return OK; +} + +/* Release a dir record (decrement the counter) */ +PUBLIC int release_dir_record(dir) + register struct dir_record *dir; +{ + if (dir == NULL) + return EINVAL; + + if (--dir->d_count == 0) { + if (dir->ext_attr != NULL) + dir->ext_attr->count = 0; + dir->ext_attr = NULL; + dir->d_mountpoint = FALSE; + /* This if checks we remove the good dir record and not another one + * associated to the same id.*/ +/* if (dir->id != NULL && dir->id->h_dir_record == dir) */ +/* dir->id->h_dir_record = NULL; */ + + dir->d_prior = NULL; + if (dir->d_next != NULL) + release_dir_record(dir); + dir->d_next = NULL; + } +return OK; +} + +/* Get a free dir record */ +PUBLIC struct dir_record *get_free_dir_record(void) +{ + struct dir_record *dir; + + for(dir = dir_records;dir<&dir_records[NR_ATTR_RECS]; dir++) { + if (dir->d_count == 0) { /* The record is free */ + dir->d_count = 1; /* Set count to 1 */ + dir->ext_attr = NULL; + return dir; + } + } + return NULL; +} + +/* This function is a wrapper. It calls dir_record_by_id */ +PUBLIC struct dir_record *get_dir_record(id_dir_record) + ino_t id_dir_record; +{ + struct dir_record *dir = NULL; + u32_t address; + int i; + + /* Search through the cache if the inode is still present */ + for(i = 0; i < NR_DIR_RECORDS && dir == NULL; ++i) { + if (dir_records[i].d_ino_nr == id_dir_record && dir_records[i].d_count > 0) { + dir = dir_records + i; + dir->d_count++; + } + } + + if (dir == NULL) { + address = (u32_t)id_dir_record; + dir = load_dir_record_from_disk(address); + } + + if (dir == NULL) + return NULL; + else + return dir; +} + +/* Get a free extended attribute structure in a similar way than the dir + * record */ +PUBLIC struct ext_attr_rec *get_free_ext_attr(void) { + struct ext_attr_rec *dir; + for(dir = ext_attr_recs;dir<&ext_attr_recs[NR_ATTR_RECS]; dir++) { + if (dir->count == 0) { /* The record is free */ + dir->count = 1; + return dir; + } + } + return NULL; +} + +/* Fill an extent structure from the data read on the device */ +PUBLIC int create_ext_attr(struct ext_attr_rec *ext,char *buffer) +{ + if (ext == NULL) return EINVAL; + + /* In input we have a stream of bytes that are physically read from the + * device. This stream of data is copied in the data structure. */ + memcpy(&ext->own_id,buffer,sizeof(u32_t)); + memcpy(&ext->group_id,buffer + 4,sizeof(u32_t)); + memcpy(&ext->permissions,buffer + 8,sizeof(u16_t)); + memcpy(&ext->file_cre_date,buffer + 10,ISO9660_SIZE_VOL_CRE_DATE); + memcpy(&ext->file_mod_date,buffer + 27,ISO9660_SIZE_VOL_MOD_DATE); + memcpy(&ext->file_exp_date,buffer + 44,ISO9660_SIZE_VOL_EXP_DATE); + memcpy(&ext->file_eff_date,buffer + 61,ISO9660_SIZE_VOL_EFF_DATE); + memcpy(&ext->rec_format,buffer + 78,sizeof(u8_t)); + memcpy(&ext->rec_attrs,buffer + 79,sizeof(u8_t)); + memcpy(&ext->rec_length,buffer + 80,sizeof(u32_t)); + memcpy(&ext->system_id,buffer + 84,ISO9660_SIZE_SYS_ID); + memcpy(&ext->system_use,buffer + 116,ISO9660_SIZE_SYSTEM_USE); + memcpy(&ext->ext_attr_rec_ver,buffer + 180,sizeof(u8_t)); + memcpy(&ext->len_esc_seq,buffer + 181,sizeof(u8_t)); + + return OK; +} + +/* Fills a dir record structure from the data read on the device */ +/* If the flag assign id is active it will return the id associated; + * otherwise it will return OK. */ +PUBLIC int create_dir_record(dir,buffer,address) + struct dir_record *dir; + char *buffer; + u32_t address; +{ + short size; + + size = buffer[0]; + if (dir == NULL) return EINVAL; + + /* The data structure dir record is filled with the stream of data + * that is read. */ + dir->length = size; + dir->ext_attr_rec_length = *((u8_t*)buffer + 1); + memcpy(&dir->loc_extent_l,buffer + 2,sizeof(u32_t)); + memcpy(&dir->loc_extent_m,buffer + 6,sizeof(u32_t)); + memcpy(&dir->data_length_l,buffer + 10,sizeof(u32_t)); + memcpy(&dir->data_length_m,buffer + 14,sizeof(u32_t)); + memcpy(dir->rec_date,buffer + 18, sizeof(dir->rec_date)); + dir->file_flags = *((u8_t*)buffer + 25); + dir->file_unit_size = *((u8_t*)buffer + 26); + dir->inter_gap_size = *((u8_t*)buffer + 27); + dir->vol_seq_number = *((u8_t*)buffer + 28); + dir->length_file_id = *((u8_t*)buffer + 32); + memcpy(dir->file_id,buffer + 33,dir->length_file_id); + dir->ext_attr = NULL; + + /* set memory attrs */ + if ((dir->file_flags & D_TYPE) == D_DIRECTORY) + dir->d_mode = I_DIRECTORY; + else + dir->d_mode = I_REGULAR; + + /* I set the rights to read only ones. Equals for all the users */ + dir->d_mode |= R_BIT | X_BIT; + dir->d_mode |= R_BIT << 3 | X_BIT << 3; + dir->d_mode |= R_BIT << 6 | X_BIT << 6; + + dir->d_mountpoint = FALSE; + dir->d_next = NULL; + dir->d_prior = NULL; + dir->d_file_size = dir->data_length_l; + + /* Set physical address of the dir record */ + dir->d_phy_addr = address; + dir->d_ino_nr = (ino_t)address; /* u32_t e ino_t are the same datatype so + * the cast is safe */ +/* if (assign_id == ASSIGN_ID) { */ +/* assign_id_to_dir_record(dir); */ +/* return ID_DIR_RECORD(dir->id); */ +/* } else */ + return OK; +} + +/* This function load a particular dir record from a specific address + * on the device */ +PUBLIC struct dir_record *load_dir_record_from_disk(address) + u32_t address; +{ + int block_nr, offset, block_size, new_pos; + struct buf *bp; + struct dir_record *dir, *dir_next, *dir_parent, *dir_tmp; + char name[NAME_MAX + 1]; + char old_name[NAME_MAX + 1]; + u32_t new_address, size; + + block_size = v_pri.logical_block_size_l; /* Block size */ + block_nr = address / block_size; /* Block number from the address */ + offset = address % block_size; /* Offset starting from the block */ + + bp = get_block(block_nr); /* Read the block from the device */ + if (bp == NIL_BUF) + return NULL; + + dir = get_free_dir_record(); /* Get a free record */ + if (dir == NULL) + return NULL; + + /* Fullfill the dir record with the data read from the device */ + create_dir_record(dir,bp->b_data + offset, address); + + /* In case the file is composed of more file sections I load also the next in the structure */ + new_pos = offset + dir->length; + dir_parent = dir; + new_address = address + dir->length; + while (new_pos < block_size) { + dir_next = get_free_dir_record(); + create_dir_record(dir_next, bp->b_data + new_pos, new_address); + if (dir_next->length > 0) { + strncpy(name,dir_next->file_id,dir_next->length_file_id); + name[dir_next->length_file_id] = '\0'; + strncpy(old_name,dir_parent->file_id,dir_parent->length_file_id); + old_name[dir_parent->length_file_id] = '\0'; + + if (strcmp(name,old_name) == 0) { + dir_parent->d_next = dir_next; + dir_next->d_prior = dir_parent; + + /* Link the dir records */ + dir_tmp = dir_next; + size = dir_tmp->data_length_l; + + /* Update the file size */ + while (dir_tmp->d_prior != NULL) { + dir_tmp = dir_tmp->d_prior; + size += dir_tmp->data_length_l; + dir_tmp->d_file_size = size; + } + + new_pos += dir_parent->length; + new_address += dir_next->length; + dir_parent = dir_next; + } else { /* This is another inode. */ + release_dir_record(dir_next); + new_pos = block_size; + } + } else { /* record not valid */ + release_dir_record(dir_next); + new_pos = block_size; /* Exit from the while */ + } + + } + + put_block(bp); /* Release the block read. */ + return dir; +} diff --git a/servers/iso9660fs/inode.h b/servers/iso9660fs/inode.h new file mode 100644 index 000000000..da1a8da5f --- /dev/null +++ b/servers/iso9660fs/inode.h @@ -0,0 +1,67 @@ +#include "const.h" + +PUBLIC struct dir_record { + u8_t length; /* The length of the record */ + u8_t ext_attr_rec_length; + u32_t loc_extent_l; /* The same data (in this case loc_extent)is */ + u32_t loc_extent_m; /* saved in two ways. The first puts the le- */ + u32_t data_length_l; /* ast significant byte first, the second */ + u32_t data_length_m; /* does the opposite */ + u8_t rec_date[7]; /* => recording date */ + u8_t file_flags; /* => flags of the file */ + u8_t file_unit_size; /* set of blocks in interleave mode */ + u8_t inter_gap_size; /* gap between file units in interleave mode */ + u32_t vol_seq_number; /* volume sequence number: not used */ + u8_t length_file_id; /* Length name file */ + char file_id[ISO9660_MAX_FILE_ID_LEN]; /* file name */ + struct ext_attr_rec *ext_attr; + + /* Memory attrs */ + u8_t d_count; /* Count if the dir_record is in use or not */ + mode_t d_mode; /* file type, protection, etc. */ +/* struct hash_idi_entry *id; */ /* id associated */ + u32_t d_phy_addr; /* physical address of this dir record */ + ino_t d_ino_nr; /* inode number (identical to the address) */ + char d_mountpoint; /* true if mounted on */ + struct dir_record *d_next; /* In case the file consists in more file sections + this points to the next one */ + struct dir_record *d_prior; /* The same as before, this points to the dir parent */ + u32_t d_file_size; /* Total size of the file */ + +} dir_records[NR_DIR_RECORDS]; + +PUBLIC struct ext_attr_rec { + u32_t own_id; + u32_t group_id; + u16_t permissions; + char file_cre_date[ISO9660_SIZE_VOL_CRE_DATE]; + char file_mod_date[ISO9660_SIZE_VOL_MOD_DATE]; + char file_exp_date[ISO9660_SIZE_VOL_EXP_DATE]; + char file_eff_date[ISO9660_SIZE_VOL_EFF_DATE]; + u8_t rec_format; + u8_t rec_attrs; + u32_t rec_length; + char system_id[ISO9660_SIZE_SYS_ID]; + char system_use[ISO9660_SIZE_SYSTEM_USE]; + u8_t ext_attr_rec_ver; + u8_t len_esc_seq; + + int count; +} ext_attr_recs[NR_ATTR_RECS]; + +#define D_DIRECTORY 0x2 +#define D_TYPE 0x8E + +/* Vector with all the ids of the dir records */ +/* PUBLIC struct hash_idi_entry { */ +/* u32_t h_phy_addr; */ +/* struct dir_record *h_dir_record; */ +/* } hash_idi[NR_ID_INODES]; */ + +/* PUBLIC int size_hash_idi; */ + +/* #define ID_DIR_RECORD(id) id - hash_idi + 1 */ +#define ID_DIR_RECORD(dir) dir->d_ino_nr + +/* #define ASSIGN_ID 1 */ +/* #define NOT_ASSIGN_ID 0 */ diff --git a/servers/iso9660fs/main.c b/servers/iso9660fs/main.c new file mode 100644 index 000000000..b41b79e36 --- /dev/null +++ b/servers/iso9660fs/main.c @@ -0,0 +1,122 @@ + + +/* This file contains the main directory for the server. It waits for a + * request and then send a response. */ + +#include "inc.h" +#include +#include "const.h" +#include "glo.h" + +/* Declare some local functions. */ +FORWARD _PROTOTYPE(void init_server, (void) ); +FORWARD _PROTOTYPE(void get_work, (message *m_in) ); + +/*===========================================================================* + * main * + *===========================================================================*/ +PUBLIC int main(void) { + int who_e, ind, error; + message m; + + /* Initialize the server, then go to work. */ + init_server(); + + fs_m_in.m_type = FS_READY; + + if (send(FS_PROC_NR, &fs_m_in) != OK) { + printf("ISO9660FS(%d): Error sending login to VFS\n", SELF_E); + return -1; + } + +#if 0 + if (fs_m_in.m_type != REQ_READSUPER_O && fs_m_in.m_type != REQ_READSUPER_S) { + printf("ISO9660FS(%d): Invalid login reply\n", SELF_E); + return -1; + } else { + if (fs_m_in.m_type == REQ_READSUPER_S) + fs_m_out.m_type = fs_readsuper_s(); + else + fs_m_out.m_type = fs_readsuper(); + reply(FS_PROC_NR, &fs_m_out); + if (fs_m_out.m_type != OK) return -1; + } +#endif + + for (;;) { + + /* Wait for request message. */ + get_work(&fs_m_in); + error = OK; + + caller_uid = -1; /* To trap errors */ + caller_gid = -1; + + who_e = fs_m_in.m_source; /* source of the request */ + + if (who_e != FS_PROC_NR) { /* If the message is not for us just + * continue */ + continue; + } + + req_nr = fs_m_in.m_type; + + if (req_nr < VFS_BASE) { + fs_m_in.m_type += VFS_BASE; + req_nr = fs_m_in.m_type; + } + + ind= req_nr-VFS_BASE; + + if (ind < 0 || ind >= NREQS) { + printf("iso9660fs: bad request %d\n", req_nr); + printf("ind = %d\n", ind); + error = EINVAL; + } + else + error = (*fs_call_vec[ind])(); /* Process the request calling + * the appropriate function. */ + + fs_m_out.m_type = error; + reply(who_e, &fs_m_out); /* returns the response to VFS */ + + } +} + +/*===========================================================================* + * init_server * + *===========================================================================*/ +PRIVATE void init_server(void) +{ + int i; + + /* Init driver mapping */ + for (i = 0; i < NR_DEVICES; ++i) + driver_endpoints[i].driver_e = NONE; + /* SELF_E will contain the id of this process */ + SELF_E = getprocnr(); +/* hash_init(); */ /* Init the table with the ids */ + setenv("TZ","",1); /* Used to calculate the time */ +} + +/*===========================================================================* + * get_work * + *===========================================================================*/ +PRIVATE void get_work(m_in) +message *m_in; /* pointer to message */ +{ + int s; /* receive status */ + if (OK != (s = receive(ANY, m_in))) /* wait for message */ + panic("I9660FS","receive failed", s); +} + +/*===========================================================================* + * reply * + *===========================================================================*/ +PUBLIC void reply(who, m_out) +int who; +message *m_out; /* report result */ +{ + if (OK != send(who, m_out)) /* send the message */ + printf("I9660FS(%d) was unable to send reply\n", SELF_E); +} diff --git a/servers/iso9660fs/misc.c b/servers/iso9660fs/misc.c new file mode 100644 index 000000000..457bf3f3b --- /dev/null +++ b/servers/iso9660fs/misc.c @@ -0,0 +1,14 @@ +/* Some misc functions */ + +#include "inc.h" +#include +#include + +/*===========================================================================* + * fs_sync * + *===========================================================================*/ +PUBLIC int fs_sync() /* Calling of syncing the filesystem. No action + * is taken */ +{ + return(OK); /* sync() can't fail */ +} diff --git a/servers/iso9660fs/mount.c b/servers/iso9660fs/mount.c new file mode 100644 index 000000000..b4706240f --- /dev/null +++ b/servers/iso9660fs/mount.c @@ -0,0 +1,151 @@ +#include "inc.h" +#include +#include +#include +#include + +#include "const.h" +#include "glo.h" + +/* Function of mounting and unmounting for ISO9660 */ + +/* Reads the super inode. This function is requested at the mounting of the + * filesystem. */ +/*===========================================================================* + * fs_readsuper * + *===========================================================================*/ +PUBLIC int fs_readsuper() { + + int r = OK; + + fs_dev = fs_m_in.REQ_DEV; + + driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e = fs_m_in.REQ_DRIVER_E; + vfs_slink_storage = fs_m_in.REQ_SLINK_STORAGE; + + r = read_vds(&v_pri, fs_dev); /* This function reads the super block on the + * device and save it in v_pri */ + + if (r != OK) return(r); + + /* Return some root inode properties */ + fs_m_out.RES_INODE_NR = ID_DIR_RECORD(v_pri.dir_rec_root); + fs_m_out.RES_MODE = I_DIRECTORY; + fs_m_out.RES_FILE_SIZE = v_pri.dir_rec_root->d_file_size; + + /* and some partition properties */ + fs_m_out.RES_MAXSIZE = v_pri.volume_space_size_l; /* Volume space */ + fs_m_out.RES_BLOCKSIZE = v_pri.logical_block_size_l; /* block size */ + + return r; +} + +/*===========================================================================* + * fs_readsuper_s * + *===========================================================================*/ +PUBLIC int fs_readsuper_s() { + + cp_grant_id_t label_gid; + size_t label_len; + int r = OK; + unsigned long tasknr; + endpoint_t driver_e; + + fs_dev = fs_m_in.REQ_DEV; + + label_gid= fs_m_in.REQ_GRANT2; + label_len= fs_m_in.REQ_PATH_LEN; + + if (label_len > sizeof(fs_dev_label)) { + printf("iso9660fs:fs_readsuper: label too long\n"); + return EINVAL; + } + + r= sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label, + label_len, D); + if (r != OK) { + printf("iso9660fs: fs_readsuper: safecopyfrom failed: %d\n", r); + return EINVAL; + } + + r= ds_retrieve_u32(fs_dev_label, &tasknr); + if (r != OK) { + printf("mfs:fs_readsuper: ds_retrieve_u32 failed for '%s': %d\n", + fs_dev_label, r); + return EINVAL; + } + + driver_e= tasknr; + + /* Map the driver endpoint for this major */ + driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e = driver_e; + + if (dev_open(driver_e, fs_dev, driver_e, + fs_m_in.REQ_READONLY ? R_BIT : (R_BIT|W_BIT)) != OK) { + return(EINVAL); + } + + r = read_vds(&v_pri, fs_dev); /* This function reads the super block on the + * device and save it in v_pri */ + + if (r != OK) + return(r); + + /* Return some root inode properties */ + fs_m_out.RES_INODE_NR = ID_DIR_RECORD(v_pri.dir_rec_root); + fs_m_out.RES_MODE = v_pri.dir_rec_root->d_mode; + fs_m_out.RES_FILE_SIZE = v_pri.dir_rec_root->d_file_size; + fs_m_out.RES_UID = 0; /* root */ + fs_m_out.RES_GID = 0; /* operator */ + + /* and some partition properties */ + fs_m_out.RES_MAXSIZE = v_pri.volume_space_size_l; /* Volume space */ + fs_m_out.RES_BLOCKSIZE = v_pri.logical_block_size_l; /* block size */ + + return r; +} + +/*===========================================================================* + * fs_mountpoint_s * + *===========================================================================*/ +PUBLIC int fs_mountpoint_s() { +/* This function looks up the mount point, it checks the condition whether + * the partition can be mounted on the inode or not. + */ + + register struct dir_record *rip; + int r = OK; + mode_t bits; + + /* Temporarily open the file. */ + if ((rip = get_dir_record(fs_m_in.REQ_INODE_NR)) == NULL) { + printf("ISO9660FS(%d) get_inode by fs_mountpoint() failed\n", SELF_E); + return(EINVAL); + } + + if (rip->d_mountpoint) + r= EBUSY; + + /* If the inode is not a dir returns error */ + if ((rip->d_mode & I_TYPE) != I_DIRECTORY) + r = ENOTDIR; + + release_dir_record(rip); + + if (r == OK) + rip->d_mountpoint = TRUE; + + return r; +} + +/* Unmount the filesystem */ +/*===========================================================================* + * fs_unmount * + *===========================================================================*/ +PUBLIC int fs_unmount(void) { + release_v_pri(&v_pri); /* Release the super block */ + + dev_close(driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e, fs_dev); + + return OK; +} diff --git a/servers/iso9660fs/path.c b/servers/iso9660fs/path.c new file mode 100644 index 000000000..4c79d60b8 --- /dev/null +++ b/servers/iso9660fs/path.c @@ -0,0 +1,667 @@ +#include "inc.h" +#include +#include +#include + +#include "buf.h" + +FORWARD _PROTOTYPE(char *get_name, (char *old_name, char string [NAME_MAX])); +FORWARD _PROTOTYPE( char *get_name_s, (char *name, char string[NAME_MAX+1]) ); +FORWARD _PROTOTYPE( int parse_path_s, (ino_t dir_ino, ino_t root_ino, + int flags, struct dir_record **res_inop, + size_t *offsetp)); +FORWARD _PROTOTYPE( int advance_s, (struct dir_record *dirp, + char string[NAME_MAX], struct dir_record **resp)); + +/* Lookup is a function used to ``look up" a particular path. It is called + * very often. */ +/*===========================================================================* + * lookup * + *===========================================================================*/ +PUBLIC int lookup() +{ + char string[PATH_MAX]; + int s_error, flags; + int len; + struct dir_record *dir; + + string[0] = '\0'; + + /* Check length. */ + len = fs_m_in.REQ_PATH_LEN; + if(len > sizeof(user_path)) return E2BIG; /* too big for buffer */ + if(len < 1) return EINVAL; /* too small for \0 */ + + /* Copy the pathname and set up caller's user and group id */ + err_code = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, SELF, + (vir_bytes) user_path, (phys_bytes) len); + if (err_code != OK) { + printf("i9660fs:%s:%d: sys_datacopy failed: %d\n", __FILE__, __LINE__, err_code); + return err_code; + } + + /* Verify this is a null-terminated path. */ + if(user_path[len-1] != '\0') { + printf("i9660fs:lookup: didn't get null-terminated string.\n"); + return EINVAL; + } + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + flags = fs_m_in.REQ_FLAGS; + + /* Clear RES_OFFSET for ENOENT */ + fs_m_out.RES_OFFSET= 0; + + /* Lookup inode */ + dir = parse_path(user_path, string, flags); + + /* Copy back the last name if it is required */ + if (err_code != OK || (flags & PATH_PENULTIMATE)) { + s_error = sys_datacopy(SELF_E, (vir_bytes) string, FS_PROC_NR, + (vir_bytes) fs_m_in.REQ_USER_ADDR, (phys_bytes) NAME_MAX); + if (s_error != OK) { + printf("i9660fs:%s:%d: sys_datacopy failed: %d\n", + __FILE__, __LINE__, s_error); + return s_error; + } + } + + /* Error or mount point encountered */ + if (dir == NULL) { + if (err_code != EENTERMOUNT) + fs_m_out.RES_INODE_NR = 0; /* signal no inode */ + return err_code; + } + + fs_m_out.RES_INODE_NR = ID_DIR_RECORD(dir); + fs_m_out.RES_MODE = dir->d_mode; + fs_m_out.RES_FILE_SIZE = dir->d_file_size; + + /* Drop inode (path parse increased the counter) */ + release_dir_record(dir); + + return err_code; +} + +/*===========================================================================* + * fs_lookup_s * + *===========================================================================*/ +PUBLIC int fs_lookup_s() { + cp_grant_id_t grant; + int r, r1, len, flags; + size_t offset, size; + ino_t dir_ino, root_ino; + struct dir_record *dir; + + grant= fs_m_in.REQ_L_GRANT; + size= fs_m_in.REQ_L_PATH_SIZE; /* Size of the buffer */ + len = fs_m_in.REQ_L_PATH_LEN; /* including terminating nul */ + offset= fs_m_in.REQ_L_PATH_OFF; /* offset in buffer */ + dir_ino= fs_m_in.REQ_L_DIR_INO; + root_ino= fs_m_in.REQ_L_ROOT_INO; + flags = fs_m_in.REQ_L_FLAGS; + caller_uid = fs_m_in.REQ_L_UID; + caller_gid = fs_m_in.REQ_L_GID; + + /* Check length. */ + if(len > sizeof(user_path)) return E2BIG; /* too big for buffer */ + if(len < 1)return EINVAL; /* too small */ + + /* Copy the pathname and set up caller's user and group id */ + r = sys_safecopyfrom(FS_PROC_NR, grant, offset, + (vir_bytes) user_path, (phys_bytes) len, D); + + if (r != OK) { + printf("iso9660fs:fs_lookup_s: sys_safecopyfrom failed: %d\n", r); + return r; + } + + /* Verify this is a null-terminated path. */ + if(user_path[len-1] != '\0') { + printf("iso9660fs:fs_lookup_s: didn't get null-terminated string.\n"); + return EINVAL; + } + + /* Lookup inode */ + dir = NULL; + r = parse_path_s(dir_ino, root_ino, flags, &dir, &offset); + + if (r == ELEAVEMOUNT) { + /* Report offset and the error */ + fs_m_out.RES_OFFSET = offset; + fs_m_out.RES_SYMLOOP = 0; + if (dir) panic(__FILE__, "fs_lookup_s: dir should be clear", + (unsigned)dir); + return r; + } + + if (r != OK && r != EENTERMOUNT) { + if (dir) + panic(__FILE__, "fs_lookup_s: dir should be clear", + (unsigned)dir); + return r; + } + + fs_m_out.RES_OFFSET = offset; + fs_m_out.RES_INODE_NR = ID_DIR_RECORD(dir); + fs_m_out.RES_MODE = dir->d_mode; + fs_m_out.RES_FILE_SIZE = dir->d_file_size; + fs_m_out.RES_SYMLOOP2 = 0; + fs_m_out.RES_UID = 0; /* root */ + fs_m_out.RES_GID = 0; /* operator */ + +/* /\* Drop inode (path parse increased the counter) *\/ */ +/* release_dir_record(dir); */ + + if (r == EENTERMOUNT) + release_dir_record(dir); + + return r; +} + +/* The search dir actually performs the operation of searching for the + * compoent ``string" in ldir_ptr. It returns the response and the number of + * the inode in numb. */ +/*===========================================================================* + * search_dir * + *===========================================================================*/ +PUBLIC int search_dir(ldir_ptr,string,numb) + register struct dir_record *ldir_ptr; /* dir record parent */ + char string[NAME_MAX]; /* component to search for */ + ino_t *numb; /* pointer to new dir record */ +{ + struct dir_record *dir_tmp; + register struct buf *bp,*bp2; + int pos,r,len; + char* comma_pos = NULL; + char tmp_string[NAME_MAX]; + + /* This function search a particular element (in string) in a inode and + * return its number */ + + /* Initialize the tmp array */ + memset(tmp_string,'\0',NAME_MAX); + + if ((ldir_ptr->d_mode & I_TYPE) != I_DIRECTORY) { + return(ENOTDIR); + } + + r = OK; + + if (strcmp(string,".") == 0) { + *numb = ID_DIR_RECORD(ldir_ptr); + return OK; + } + + if (strcmp(string,"..") == 0 && ldir_ptr->loc_extent_l == v_pri.dir_rec_root->loc_extent_l) { + *numb = ROOT_INO_NR; +/* *numb = ID_DIR_RECORD(ldir_ptr); */ + return OK; + } + + /* Read the dir's content */ + pos = ldir_ptr->ext_attr_rec_length; + bp = get_block(ldir_ptr->loc_extent_l); + + if (bp == NIL_BUF) + return EINVAL; + + while (pos < v_pri.logical_block_size_l) { + if ((dir_tmp = get_free_dir_record()) == NULL) { + put_block(bp); + return EINVAL; + } + + if (create_dir_record(dir_tmp,bp->b_data + pos, + ldir_ptr->loc_extent_l*v_pri.logical_block_size_l + pos) == EINVAL) + return EINVAL; + + if (dir_tmp->length == 0) { + release_dir_record(dir_tmp); + put_block(bp); + return EINVAL; + } + + memcpy(tmp_string,dir_tmp->file_id,dir_tmp->length_file_id); + comma_pos = strchr(tmp_string,';'); + if (comma_pos != NULL) + *comma_pos = 0; + else + tmp_string[dir_tmp->length_file_id] = 0; + if (tmp_string[strlen(tmp_string) - 1] == '.') + tmp_string[strlen(tmp_string) - 1] = '\0'; + + if (strcmp(tmp_string,string) == 0 || + (dir_tmp->file_id[0] == 1 && strcmp(string,"..") == 0)) { + + /* If the element is found or we are searchig for... */ + + if (dir_tmp->loc_extent_l == dir_records->loc_extent_l) { + /* In this case the inode is a root because the parent + * points to the same location than the inode. */ + *numb = 1; + release_dir_record(dir_tmp); + put_block(bp); + return OK; + } + + if (dir_tmp->ext_attr_rec_length != 0) { + dir_tmp->ext_attr = get_free_ext_attr(); + create_ext_attr(dir_tmp->ext_attr,bp->b_data); + } + + *numb = ID_DIR_RECORD(dir_tmp); + release_dir_record(dir_tmp); + put_block(bp); + + return OK; + } + + pos += dir_tmp->length; + release_dir_record(dir_tmp); + } + + put_block(bp); + return EINVAL; +} + +/* Parse path will parse a particular path and return the final dir record. + * The final component of this path will be returned in string. It works in + * two ways: the first is PATH_PENULTIMATE and it returns the last dir of the + * path while the second is PATH_NON_SYMBOLIC where it returns the last + * component of the path. */ +/*===========================================================================* + * parse_path * + *===========================================================================*/ +PUBLIC struct dir_record *parse_path(path, string, action) +char *path; /* the path name to be parsed */ +char string[NAME_MAX]; /* the final component is returned here */ +int action; /* action on last part of path */ +{ +/* This is the actual code for last_dir and eat_path. Return the inode of + * the last directory and the name of object within that directory, or the + * inode of the last object (an empty name will be returned). Names are + * returned in string. If string is null the name is discarded. The action + * code determines how "last" is defined. If an error occurs, NIL_INODE + * will be returned with an error code in err_code. + */ + + char *new_name; + char lstring[NAME_MAX]; + struct dir_record *start_dir, *chroot_dir, *old_dir, *dir; + + /* Find starting inode inode according to the request message */ + if ((start_dir = get_dir_record(fs_m_in.REQ_INODE_NR)) == NULL) { + printf("I9660FS: couldn't find starting inode req_nr: %d %s\n", req_nr, + user_path); + err_code = ENOENT; + printf("%s, %d\n", __FILE__, __LINE__); + return NULL; + } + + /* Set user and group ID */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* No characters were processed yet */ + path_processed = 0; + + /* Current number of symlinks encountered */ + symloop = fs_m_in.REQ_SYMLOOP; + + if (*path == '\0') { + return start_dir; + } + + if (string == (char *) 0) string = lstring; + + /* Scan the path component by component. */ + while (TRUE) { + int slashes = 0; + /* Extract one component. Skip slashes first. */ + while (path[slashes] == '/') { + slashes++; + path_processed++; + } + fs_m_out.RES_OFFSET = path_processed; /* For ENOENT */ + + if ((new_name = get_name(path+slashes, string)) == (char*) 0) { + release_dir_record(start_dir); /* bad path in user space */ + return(NULL); + } + + if (*new_name == '\0' && (action & PATH_PENULTIMATE)) { + if ((start_dir->file_flags & I_TYPE) ==I_DIRECTORY) { + return(start_dir); /* normal exit */ + } else { + /* last file of path prefix is not a directory */ + release_dir_record(start_dir); + err_code = ENOTDIR; + return(NULL); + } + } + + /* There is more path. Keep parsing. */ + old_dir = start_dir; + start_dir = advance(&old_dir, string); + + if (start_dir == NULL) { + if (*new_name == '\0' && (action & PATH_NONSYMBOLIC) != 0) { + return(old_dir); + } + else if (err_code == ENOENT) { + return(old_dir); + } + else { + release_dir_record(old_dir); + return(NULL); + } + } + + if (*new_name != '\0') { + release_dir_record(old_dir); + path = new_name; + continue; + } + + /* Either last name reached or symbolic link is opaque */ + if ((action & PATH_NONSYMBOLIC) != 0) { + release_dir_record(start_dir); + return(old_dir); + } else { + release_dir_record(old_dir); + return(start_dir); + } + } +} + +/* Parse the path in user_path, starting at dir_ino. If the path is the empty + * string, just return dir_ino. It is upto the caller to treat an empty + * path in a special way. Otherwise, if the path consists of just one or + * more slash ('/') characters, the path is replaced with ".". Otherwise, + * just look up the first (or only) component in path after skipping any + * leading slashes. + */ +/*===========================================================================* + * parse_path_s * + *===========================================================================*/ +PRIVATE int parse_path_s(dir_ino, root_ino, flags, res_inop, offsetp) +ino_t dir_ino; +ino_t root_ino; +int flags; +struct dir_record **res_inop; +size_t *offsetp; +{ + int r; + char string[NAME_MAX+1]; + char *cp, *ncp; + struct dir_record *start_dir, *old_dir; + + /* Find starting inode inode according to the request message */ + if ((start_dir = get_dir_record(dir_ino)) == NULL) { + printf("I9660FS: couldn't find starting inode req_nr: %d %s\n", req_nr, + user_path); + printf("%s, %d\n", __FILE__, __LINE__); + return ENOENT; + } + + cp = user_path; + + /* Scan the path component by component. */ + while (TRUE) { + if (cp[0] == '\0') { + /* Empty path */ + *res_inop= start_dir; + *offsetp += cp-user_path; + + /* Return EENTERMOUNT if we are at a mount point */ + if (start_dir->d_mountpoint) + return EENTERMOUNT; + + return OK; + } + + if (cp[0] == '/') { + /* Special case code. If the remaining path consists of just + * slashes, we need to look up '.' + */ + while(cp[0] == '/') + cp++; + if (cp[0] == '\0') { + strcpy(string, "."); + ncp = cp; + } + else + ncp = get_name_s(cp, string); + } else + /* Just get the first component */ + ncp = get_name_s(cp, string); + + /* Special code for '..'. A process is not allowed to leave a chrooted + * environment. A lookup of '..' at the root of a mounted filesystem + * has to return ELEAVEMOUNT. + */ + if (strcmp(string, "..") == 0) { + + /* This condition is not necessary since it will never be the root filesystem */ + /* if (start_dir == dir_records) { */ + /* cp = ncp; */ + /* continue; /\* Just ignore the '..' at a process' */ + /* * root. */ + /* *\/ */ + /* } */ + + if (start_dir == dir_records) { + /* Climbing up mountpoint */ + release_dir_record(start_dir); + *res_inop = NULL; + *offsetp += cp-user_path; + return ELEAVEMOUNT; + } + } else { + /* Only check for a mount point if we are not looking for '..'. */ + if (start_dir->d_mountpoint) { + *res_inop= start_dir; + *offsetp += cp-user_path; + return EENTERMOUNT; + } + } + + /* There is more path. Keep parsing. */ + old_dir = start_dir; + + r = advance_s(old_dir, string, &start_dir); + + if (r != OK) { + release_dir_record(old_dir); + return r; + } + + release_dir_record(old_dir); + cp = ncp; + } +} + +/* This function will return the componsent in ``string" looking in the dir + * pdirp... */ +/*===========================================================================* + * advance * + *===========================================================================*/ +PUBLIC struct dir_record *advance(pdirp, string) +struct dir_record **pdirp; /* inode for directory to be searched */ +char string[NAME_MAX]; /* component name to look for */ +{ +/* Given a directory and a component of a path, look up the component in + * the directory, find the inode, open it, and return a pointer to its inode + * slot. If it can't be done, return NULL. + */ + + register struct dir_record *rip, *dirp; + int r, inumb; + dev_t mnt_dev; + ino_t numb; + + dirp = *pdirp; + + /* If 'string' is empty, yield same inode straight away. */ + if (string[0] == '\0') { + return dirp; + } + + /* Check for NULL. */ + if (dirp == NULL) { + return(NULL); + } + + /* If 'string' is not present in the directory, signal error. */ + if ( (r = search_dir(dirp, string, &numb)) != OK) { + err_code = r; + return(NULL); + } + + /* The component has been found in the directory. Get inode. */ + if ( (rip = get_dir_record((int) numb)) == NULL) { + return(NULL); + } + + return(rip); +} + +/*===========================================================================* + * advance_s * + *===========================================================================*/ +PRIVATE int advance_s(dirp, string, resp) +struct dir_record *dirp; /* inode for directory to be searched */ +char string[NAME_MAX]; /* component name to look for */ +struct dir_record **resp; /* resulting inode */ +{ +/* Given a directory and a component of a path, look up the component in + * the directory, find the inode, open it, and return a pointer to its inode + * slot. + */ + + register struct dir_record *rip = NULL; + int r, inumb; + dev_t mnt_dev; + ino_t numb; + + /* If 'string' is empty, yield same inode straight away. */ + if (string[0] == '\0') { + return ENOENT; + } + + /* Check for NULL. */ + if (dirp == NULL) { + return EINVAL; + } + + /* If 'string' is not present in the directory, signal error. */ + if ( (r = search_dir(dirp, string, &numb)) != OK) { + return r; + } + + /* The component has been found in the directory. Get inode. */ + if ( (rip = get_dir_record((int) numb)) == NULL) { + return(err_code); + } + + *resp= rip; + return OK; +} + +/*===========================================================================* + * get_name * + *===========================================================================*/ +PRIVATE char *get_name(old_name, string) +char *old_name; /* path name to parse */ +char string[NAME_MAX]; /* component extracted from 'old_name' */ +{ +/* Given a pointer to a path name in fs space, 'old_name', copy the next + * component to 'string' and pad with zeros. A pointer to that part of + * the name as yet unparsed is returned. Roughly speaking, + * 'get_name' = 'old_name' - 'string'. + * + * This routine follows the standard convention that /usr/ast, /usr//ast, + * //usr///ast and /usr/ast/ are all equivalent. + */ + + register int c; + register char *np, *rnp; + + np = string; /* 'np' points to current position */ + rnp = old_name; /* 'rnp' points to unparsed string */ + + c = *rnp; + /* Copy the unparsed path, 'old_name', to the array, 'string'. */ + while ( rnp < &old_name[PATH_MAX] && c != '/' && c != '\0') { + if (np < &string[NAME_MAX]) *np++ = c; + c = *++rnp; /* advance to next character */ + path_processed++; /* count characters */ + } + + /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */ + while (c == '/' && rnp < &old_name[PATH_MAX]) { + c = *++rnp; + path_processed++; /* count characters */ + } + + if (np < &string[NAME_MAX]) *np = '\0'; /* Terminate string */ + + if (rnp >= &old_name[PATH_MAX]) { + err_code = ENAMETOOLONG; + return((char *) 0); + } + return(rnp); +} + +/*===========================================================================* + * get_name_s * + *===========================================================================*/ +PRIVATE char *get_name_s(path_name, string) +char *path_name; /* path name to parse */ +char string[NAME_MAX+1]; /* component extracted from 'old_name' */ +{ +/* Given a pointer to a path name in fs space, 'path_name', copy the first + * component to 'string' (truncated if necessary, always nul terminated). + * A pointer to the string after the first component of the name as yet + * unparsed is returned. Roughly speaking, + * 'get_name_s' = 'path_name' - 'string'. + * + * This routine follows the standard convention that /usr/ast, /usr//ast, + * //usr///ast and /usr/ast/ are all equivalent. + */ + size_t len; + char *cp, *ep; + + cp= path_name; + + /* Skip leading slashes */ + while (cp[0] == '/') + cp++; + + /* Find the end of the first component */ + ep= cp; + while(ep[0] != '\0' && ep[0] != '/') + ep++; + + len= ep-cp; + + /* Truncate the amount to be copied if it exceeds NAME_MAX */ + if (len > NAME_MAX) + len= NAME_MAX; + + /* Special case of the string at cp is empty */ + if (len == 0) + { + /* Return "." */ + strcpy(string, "."); + } + else + { + memcpy(string, cp, len); + string[len]= '\0'; + } + + return ep; +} diff --git a/servers/iso9660fs/protect.c b/servers/iso9660fs/protect.c new file mode 100644 index 000000000..c3eb05bf1 --- /dev/null +++ b/servers/iso9660fs/protect.c @@ -0,0 +1,32 @@ +#include "inc.h" +#include +#include +#include "buf.h" + +#include + +/* This calling is used to access a particular file. */ +/*===========================================================================* + * fs_access * + *===========================================================================*/ +PUBLIC int fs_access() +{ + struct dir_record *rip; + int r = OK; + + /* Temporarily open the file whose access is to be checked. */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_dir_record(fs_m_in.REQ_INODE_NR)) == NULL) { + printf("I9660FS(%d) get_dir_record by fs_access() failed\n", SELF_E); + return(EINVAL); + } + + /* For now ISO9660 doesn't have permission control (read and execution to + * everybody by default. So the access is always granted. */ + + release_dir_record(rip); /* Release the dir record used */ + return(r); +} diff --git a/servers/iso9660fs/proto.h b/servers/iso9660fs/proto.h new file mode 100644 index 000000000..a4410180d --- /dev/null +++ b/servers/iso9660fs/proto.h @@ -0,0 +1,82 @@ +/* Function prototypes for iso9660 file system. */ + +struct dir_record; +struct ext_attr_rec; +struct iso9660_vd_pri; + +int fs_getnode(void); +int fs_putnode(void); +int fs_new_driver(void); +int fs_sync(void); +int lookup(void); +int fs_access(void); +int fs_getdents(void); + +/* main.c */ +_PROTOTYPE( int main, (void) ); +_PROTOTYPE( void reply, (int who, message *m_out) ); + +/* device.c */ +_PROTOTYPE( int block_dev_io, (int op, Dev_t dev, int proc, void *buf, + u64_t pos, int bytes, int flags)); +_PROTOTYPE( int dev_open, (endpoint_t driver_e, Dev_t dev, int proc, + int flags)); +_PROTOTYPE( void dev_close, (endpoint_t driver_e, Dev_t dev)); + +/* super.c */ +_PROTOTYPE(int release_v_pri,(struct iso9660_vd_pri *v_pri)); +_PROTOTYPE(int read_vds,(struct iso9660_vd_pri *v_pri, Dev_t dev)); +_PROTOTYPE(int create_v_pri,(struct iso9660_vd_pri *v_pri, char *buffer,unsigned long address)); + +/* inode.c */ +_PROTOTYPE(int release_dir_record,(struct dir_record *dir)); +_PROTOTYPE(struct dir_record *get_free_dir_record,(void)); +_PROTOTYPE(struct dir_record *get_dir_record,(ino_t id_dir)); +_PROTOTYPE(struct ext_attr_rec *get_free_ext_attr,(void)); +_PROTOTYPE(int create_ext_attr,(struct ext_attr_rec *ext, + char *buffer)); +_PROTOTYPE(int create_dir_record,(struct dir_record *dir, char *buffer, + u32_t address)); +_PROTOTYPE(struct dir_record *load_dir_record_from_disk,(u32_t address)); + +/* path.c */ +int fs_lookup_s(void); +_PROTOTYPE(struct dir_record *advance,(struct dir_record **dirp, + char string[NAME_MAX])); +_PROTOTYPE( int search_dir, (struct dir_record *ldir_ptr, + char string [NAME_MAX], ino_t *numb)); +_PROTOTYPE( struct dir_record *parse_path, (char *path, + char string[NAME_MAX], + int action)); + +/* read.c */ +int fs_read_s(void); +int fs_read(void); +int fs_bread(void); +int fs_bread_s(void); +_PROTOTYPE(int read_chunk,(struct dir_record *dir, u64_t position, + unsigned off, int chunk, char *buff, int seg, + int usr, int block_size, int *completed)); + +/* utility.c */ +_PROTOTYPE(int no_sys, (void)); +_PROTOTYPE(void panic, (char *who, char *mess, int num)); + +/* cache.c */ +_PROTOTYPE(struct buf *get_block,(block_t block)); +_PROTOTYPE(void put_block,(struct buf *bp)); + +/* ids.c */ +/* _PROTOTYPE(void hash_init, (void)); */ +/* _PROTOTYPE(int assign_id_to_dir_record, (struct dir_record *dir)); */ +/* _PROTOTYPE(struct dir_record *get_dir_record_by_id,(int id)); */ + +/* mount.c */ +int fs_readsuper(void); +int fs_readsuper_s(void); +int fs_mountpoint_s(void); +int fs_unmount(void); + +/* stadir.c */ +int fs_stat(void); +int fs_fstatfs(void); diff --git a/servers/iso9660fs/read.c b/servers/iso9660fs/read.c new file mode 100644 index 000000000..480bd27f8 --- /dev/null +++ b/servers/iso9660fs/read.c @@ -0,0 +1,464 @@ + +/* Functions to reads_file */ + +#include "inc.h" +#include +#include +#include +#include "buf.h" + +FORWARD _PROTOTYPE( int read_chunk_s, (struct dir_record *rip, off_t position, + unsigned off, int chunk, unsigned left,cp_grant_id_t gid, + unsigned buf_off, int block_size, int *completed)); + +/*===========================================================================* + * fs_read_s * + *===========================================================================*/ +PUBLIC int fs_read_s(void) { + + int r, chunk, block_size; + int nrbytes; + cp_grant_id_t gid; + off_t position, f_size, bytes_left; + unsigned int off, cum_io; + int completed; + struct dir_record *dir; + + r = OK; + + /* Try to get inode according to its index */ + dir = get_dir_record(fs_m_in.REQ_FD_INODE_NR); + if (dir == NULL) return EINVAL; /* No inode found */ + + + position = fs_m_in.REQ_FD_POS; /* start reading from this position */ + nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES; /* number of bytes to read */ + block_size = v_pri.logical_block_size_l; + gid = fs_m_in.REQ_FD_GID; + f_size = dir->d_file_size; + + rdwt_err = OK; /* set to EIO if disk error occurs */ + + cum_io = 0; + /* Split the transfer into chunks that don't span two blocks. */ + while (nrbytes != 0) { + off = (unsigned int) (position % block_size);/* offset in blk*/ + + chunk = MIN(nrbytes, block_size - off); + if (chunk < 0) chunk = block_size - off; + + bytes_left = f_size - position; + if (position >= f_size) break; /* we are beyond EOF */ + if (chunk > bytes_left) chunk = (int) bytes_left; + + /* Read or write 'chunk' bytes. */ + r = read_chunk_s(dir, position, off, chunk, (unsigned) nrbytes, + gid, cum_io, block_size, &completed); + + if (r != OK) break; /* EOF reached */ + if (rdwt_err < 0) break; + + /* Update counters and pointers. */ + nrbytes -= chunk; /* bytes yet to be read */ + cum_io += chunk; /* bytes read so far */ + position += chunk; /* position within the file */ + } + + fs_m_out.RES_FD_POS = position; /* It might change later and the VFS has + to know this value */ + + if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ + if (rdwt_err == END_OF_FILE) r = OK; + +/* rip->i_update |= ATIME; */ + + fs_m_out.RES_FD_CUM_IO = cum_io; + fs_m_out.RES_FD_SIZE = dir->d_file_size; + release_dir_record(dir); + + return(r); +} + +/* Function that is called with the request read. It performs the read and + * returns the answer. */ +/*===========================================================================* + * fs_read * + *===========================================================================*/ +PUBLIC int fs_read(void) { + struct dir_record *dir; + int r,nrbytes,block_size, chunk, completed, seg, usr; + char* user_addr; + off_t bytes_left, position; + unsigned int off, cum_io; + + r = OK; + + dir = get_dir_record(fs_m_in.REQ_FD_INODE_NR); + if (dir == NULL) return EINVAL; /* No inode found */ + + /* Get values for reading */ + position = fs_m_in.REQ_FD_POS; /* start reading from this position */ + nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES; /* number of bytes to read */ + user_addr = fs_m_in.REQ_FD_USER_ADDR; /* user addr buffer */ + usr = fs_m_in.REQ_FD_WHO_E; + seg = fs_m_in.REQ_FD_SEG; + block_size = v_pri.logical_block_size_l; + + cum_io = 0; + while (nrbytes != 0) { + off = (unsigned int) (position % block_size); /* offset in blk*/ + + chunk = MIN(nrbytes, block_size - off); + if (chunk < 0) chunk = block_size - off; + bytes_left = dir->d_file_size - position; + if (position >= dir->d_file_size) break; /* we are beyond EOF */ + if (chunk > bytes_left) chunk = (int) bytes_left; + + /* Read chunk of block. */ + r = read_chunk(dir, cvul64(position), off, chunk, + user_addr, seg, usr, block_size, &completed); + if (r != OK) + break; /* EOF reached */ + if (rdwt_err < 0) break; + + + user_addr += chunk; /* user buffer address */ + nrbytes -= chunk; /* bytes yet to be read */ + cum_io += chunk; /* bytes read so far */ + position += chunk; /* position within the file */ + } + + fs_m_out.RES_FD_POS = position; /* return the position now within the file */ + fs_m_out.RES_FD_CUM_IO = cum_io; + fs_m_out.RES_FD_SIZE = dir->data_length_l; /* returns the size of the file */ + + release_dir_record(dir); /* release the dir record. */ + return r; +} + +/*===========================================================================* + * fs_bread_s * + *===========================================================================*/ +PUBLIC int fs_bread_s(void) { + return fs_bread(); +} + +/*===========================================================================* + * fs_bread * + *===========================================================================*/ +PUBLIC int fs_bread(void) +{ + int r, usr, rw_flag, chunk, block_size, seg; + int nrbytes; + u64_t position; + unsigned int off, cum_io; + mode_t mode_word; + int completed, r2 = OK; + char *user_addr; + + /* This function is called when it is requested a raw reading without any + * conversion. It is similar to fs_read but here the data is returned + * without any preprocessing. */ + r = OK; + + /* Get the values from the request message */ + rw_flag = (fs_m_in.m_type == REQ_BREAD_S ? READING : WRITING); + usr = fs_m_in.REQ_XFD_WHO_E; + position = make64(fs_m_in.REQ_XFD_POS_LO, fs_m_in.REQ_XFD_POS_HI); + nrbytes = (unsigned) fs_m_in.REQ_XFD_NBYTES; + user_addr = fs_m_in.REQ_XFD_USER_ADDR; + seg = fs_m_in.REQ_FD_SEG; + + block_size = v_pri.logical_block_size_l; + + rdwt_err = OK; /* set to EIO if disk error occurs */ + + cum_io = 0; + /* Split the transfer into chunks that don't span two blocks. */ + while (nrbytes != 0) { + off = rem64u(position, block_size); /* offset in blk*/ + + chunk = MIN(nrbytes, block_size - off); + if (chunk < 0) chunk = block_size - off; + + /* Read or write 'chunk' bytes. */ + r = read_chunk(NULL, position, off, chunk, + user_addr, seg, usr, block_size, &completed); + + if (r != OK) break; /* EOF reached */ + if (rdwt_err < 0) break; + + /* Update counters and pointers. */ + user_addr += chunk; /* user buffer address */ + nrbytes -= chunk; /* bytes yet to be read */ + cum_io += chunk; /* bytes read so far */ + position= add64ul(position, chunk); /* position within the file */ + } + + fs_m_out.RES_XFD_POS_LO = ex64lo(position); + fs_m_out.RES_XFD_POS_HI = ex64hi(position); + + if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ + if (rdwt_err == END_OF_FILE) r = OK; + + fs_m_out.RES_XFD_CUM_IO = cum_io; + + return(r); +} + +#define GETDENTS_BUFSIZ 257 + +PRIVATE char getdents_buf[GETDENTS_BUFSIZ]; + +/* This function returns the content of a directory using the ``standard" + * data structure (that are non FS dependent). */ +/*===========================================================================* + * fs_getdents * + *===========================================================================*/ +PUBLIC int fs_getdents(void) { + struct dir_record *dir; + ino_t ino; + cp_grant_id_t gid; + size_t size_to_read, block_size; + off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off; + struct buf *bp; + struct dir_record *dir_tmp; + struct dirent *dirp; + int r,done,o,len,reclen; + char *cp; + char name[NAME_MAX + 1]; + char name_old[NAME_MAX + 1]; + + /* Initialize the tmp arrays */ + memset(name,'\0',NAME_MAX); + memset(name_old,'\0',NAME_MAX); + + /* Get input parameters */ + ino= fs_m_in.REQ_GDE_INODE; + gid= fs_m_in.REQ_GDE_GRANT; + size_to_read = fs_m_in.REQ_GDE_SIZE; + pos= fs_m_in.REQ_GDE_POS; + + block_size = v_pri.logical_block_size_l; + cur_pos = pos; /* The current position */ + tmpbuf_offset = 0; + userbuf_off = 0; + memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */ + + if ((dir = get_dir_record(ino)) == NULL) { + printf("I9660FS(%d) get_dir_record by fs_getdents() failed\n", SELF_E); + return(EINVAL); + } + + block = dir->loc_extent_l; /* First block of the directory */ + + block += pos / block_size; /* Shift to the block where start to read */ + done = FALSE; + + while (cur_posd_file_size) { + bp = get_block(block); /* Get physical block */ + + if (bp == NIL_BUF) { + release_dir_record(dir); + return EINVAL; + } + + block_pos = cur_pos % block_size; /* Position where to start read */ + + while (block_posb_data + block_pos, + block*block_size + block_pos); + + if (dir_tmp->length == 0) { /* EOF. I exit and return 0s */ + block_pos = block_size; + done = TRUE; + release_dir_record(dir_tmp); + } else { /* The dir record is valid. Copy data... */ + if (dir_tmp->file_id[0] == 0) strcpy(name,"."); + else if (dir_tmp->file_id[0] == 1) strcpy(name,".."); + else { + /* These next functions will extract the name from the field + * file_id */ + strncpy(name,dir_tmp->file_id,dir_tmp->length_file_id); + name[dir_tmp->length_file_id] = 0; + cp = memchr(name, ';', NAME_MAX); /* Remove the final part of the + * dir name. */ + if (cp != NULL) + name[cp - name] = 0; + + /* If there is no extension I remove the last '.' */ + if (name[strlen(name) - 1] == '.') + name[strlen(name) - 1] = '\0'; + + } + + if (strcmp(name_old,name) == 0) { + cur_pos += dir_tmp->length; + release_dir_record(dir_tmp); + continue; + } + strcpy(name_old,name); + + /* Compute the length of the name */ + cp= memchr(name, '\0', NAME_MAX); + if (cp == NULL) len= NAME_MAX; + else len= cp - name; + + /* Compute record length */ + reclen= offsetof(struct dirent, d_name) + len + 1; + o= (reclen % sizeof(long)); + if (o != 0) + reclen += sizeof(long)-o; + + /* If the new record does not fit I copy the buffer and I start + * from the beginning. */ + if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) { + r= sys_safecopyto(FS_PROC_NR, gid, userbuf_off, + (vir_bytes)getdents_buf, tmpbuf_offset, D); + + if (r != OK) + panic(__FILE__,"fs_getdents: sys_safecopyto failed\n",r); + + userbuf_off += tmpbuf_offset; + tmpbuf_offset= 0; + } + + /* The standard data structure is created using the data in the + * buffer. */ + dirp = (struct dirent *)&getdents_buf[tmpbuf_offset]; + dirp->d_ino = (ino_t)(bp->b_data + block_pos); + dirp->d_off= cur_pos; + dirp->d_reclen= reclen; + memcpy(dirp->d_name, name, len); + dirp->d_name[len]= '\0'; + tmpbuf_offset += reclen; + + cur_pos += dir_tmp->length; + release_dir_record(dir_tmp); + } + + block_pos += dir_tmp->length; + } + + put_block(bp); /* release the block */ + if (done == TRUE) break; + + cur_pos += block_size - cur_pos; + + block++; /* read the next one */ + } + + if (tmpbuf_offset != 0) { + r= sys_safecopyto(FS_PROC_NR, gid, userbuf_off, + (vir_bytes)getdents_buf, tmpbuf_offset, D); + if (r != OK) + panic(__FILE__, "fs_getdents: sys_safecopyto failed\n", r); + + userbuf_off += tmpbuf_offset; + } + + r= ENOSYS; + fs_m_out.RES_GDE_POS_CHANGE= 0; /* No change in case of an error */ + + r= userbuf_off; + if (cur_pos >= pos) + fs_m_out.RES_GDE_POS_CHANGE= cur_pos-pos; + + release_dir_record(dir); /* release the inode */ + + return(r); +} + +/* Read a chunk of data that does not span in two blocks. */ +PUBLIC int read_chunk(dir, position, off, chunk, buff, seg, usr, block_size, + completed) + struct dir_record *dir; /* file to read */ + u64_t position; /* position within file to read or write */ + unsigned off; /* off within the current block */ + int chunk; /* number of bytes to read or write */ + char *buff; /* virtual address of the user buffer */ + int seg; /* T or D segment in user space */ + int usr; /* which user process */ + int block_size; /* block size of FS operating on */ + int *completed; /* number of bytes copied */ +{ + register struct buf *bp; + register int r = OK; + block_t b; + + b = dir->loc_extent_l + div64u(position, block_size); /* Physical position + * to read. */ + + bp = get_block(b); /* Get physical block */ + if (bp == NIL_BUF) + return EINVAL; + + r = sys_vircopy(SELF_E, D, (phys_bytes) (bp->b_data+off), + usr, seg, (phys_bytes) buff, + (phys_bytes) chunk); + + if (r != OK) + panic(__FILE__,"fs_getdents: sys_vircopy failed\n",r); + + put_block(bp); /* Return the block */ + return OK; +} + +/* Read a chunk of data that does not span in two blocks. */ +/*===========================================================================* + * read_chunk_s * + *===========================================================================*/ +PRIVATE int read_chunk_s(dir, position, off, chunk, left, gid, buf_off, block_size, completed) +register struct dir_record *dir;/* pointer to inode for file to be rd/wr */ +off_t position; /* position within file to read or write */ +unsigned off; /* off within the current block */ +int chunk; /* number of bytes to read or write */ +unsigned left; /* max number of bytes wanted after position */ +cp_grant_id_t gid; /* grant */ +unsigned buf_off; /* offset in grant */ +int block_size; /* block size of FS operating on */ +int *completed; /* number of bytes copied */ +{ +/* Read or write (part of) a block. */ + + register struct buf *bp; + register int r = OK; + int n; + block_t b; + dev_t dev; + int file_unit, rel_block, offset; + + *completed = 0; + + if ((position <= dir->d_file_size) && (position > dir->data_length_l)) { + while ((dir->d_next != NULL) && (position > dir->data_length_l)) { + position -= dir->data_length_l; + dir = dir->d_next; + } + } + + if (dir->inter_gap_size != 0) { + rel_block = position / block_size; + file_unit = rel_block / dir->data_length_l; + offset = rel_block % dir->file_unit_size; + b = dir->loc_extent_l + (dir->file_unit_size + dir->inter_gap_size) * file_unit + offset; + } else { + b = dir->loc_extent_l + position / block_size; /* Physical position + * to read. */ + } + + bp = get_block(b); + + /* In all cases, bp now points to a valid buffer. */ + if (bp == NIL_BUF) { + panic(__FILE__,"bp not valid in rw_chunk, this can't happen", NO_NUM); + } + + r = sys_safecopyto(FS_PROC_NR, gid, buf_off, + (vir_bytes) (bp->b_data+off), (phys_bytes) chunk, D); + + put_block(bp); + + return(r); +} diff --git a/servers/iso9660fs/stadir.c b/servers/iso9660fs/stadir.c new file mode 100644 index 000000000..5511c67ac --- /dev/null +++ b/servers/iso9660fs/stadir.c @@ -0,0 +1,104 @@ +#include "inc.h" +#include +#include +#include +#include +#include + +#include + + +FORWARD _PROTOTYPE(int stat_dir_record, (struct dir_record *dir, int pipe_pos, + int who_e, cp_grant_id_t gid)); + +/* This function returns all the info about a particular inode. It's missing + * the recording date because of a bug in the standard functions stdtime. + * Once the bug is fixed the function can be called inside this function to + * return the date. */ +/*===========================================================================* + * stat_dir_record * + *===========================================================================*/ +PRIVATE int stat_dir_record(dir, pipe_pos, who_e, gid) +register struct dir_record *dir; /* pointer to dir record to stat */ +int pipe_pos; /* position in a pipe, supplied by fstat() */ +int who_e; /* Caller endpoint */ +cp_grant_id_t gid; /* grant for the stat buf */ +{ + +/* Common code for stat and fstat system calls. */ + struct stat statbuf; + mode_t mo; + int r, s; + struct tm ltime; + time_t time1; + + statbuf.st_dev = fs_dev; /* the device of the file */ + statbuf.st_ino = ID_DIR_RECORD(dir); /* the id of the dir record */ + statbuf.st_mode = dir->d_mode; /* flags of the file */ + statbuf.st_nlink = dir->d_count; /* times this file is used */ + statbuf.st_uid = 0; /* user root */ + statbuf.st_gid = 0; /* group operator */ + statbuf.st_rdev = NO_DEV; + statbuf.st_size = dir->d_file_size; /* size of the file */ + + ltime.tm_year = dir->rec_date[0]; + ltime.tm_mon = dir->rec_date[1] - 1; + ltime.tm_mday = dir->rec_date[2]; + ltime.tm_hour = dir->rec_date[3]; + ltime.tm_min = dir->rec_date[4]; + ltime.tm_sec = dir->rec_date[5]; + ltime.tm_isdst = 0; + + if (dir->rec_date[6] != 0) + ltime.tm_hour += dir->rec_date[6] / 4; + + time1 = mktime(<ime); + + statbuf.st_atime = time1; + statbuf.st_mtime = time1; + statbuf.st_ctime = time1; + + /* Copy the struct to user space. */ + r = sys_safecopyto(who_e, gid, 0, (vir_bytes) &statbuf, + (phys_bytes) sizeof(statbuf), D); + + return(r); +} + +/* This function is a wrapper to the function above. It is called with the + * request. */ +/*===========================================================================* + * fs_stat * + *===========================================================================*/ +PUBLIC int fs_stat() +{ + register int r; /* return value */ + struct dir_record *dir; + r = EINVAL; + + if ((dir = get_dir_record(fs_m_in.REQ_INODE_NR)) != NULL) { + r = stat_dir_record(dir, 0, fs_m_in.m_source, fs_m_in.REQ_GRANT); + release_dir_record(dir); + } else + printf("I9660FS(%d) fs_stat() failed\n", SELF_E); + + return r; +} + +/*===========================================================================* + * fs_fstatfs * + *===========================================================================*/ +PUBLIC int fs_fstatfs() +{ + struct statfs st; + int r; + + st.f_bsize = v_pri.logical_block_size_l; + + /* Copy the struct to user space. */ + r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, 0, + (vir_bytes) &st, (phys_bytes) sizeof(st), D); + + return(r); +} + diff --git a/servers/iso9660fs/super.c b/servers/iso9660fs/super.c new file mode 100644 index 000000000..7e56a26be --- /dev/null +++ b/servers/iso9660fs/super.c @@ -0,0 +1,116 @@ +/* Functions to manage the superblock of the filesystem. These functions are + * are called at the beginning and at the end of the server. */ + +#include "inc.h" +#include +#include +#include + +/* This function is called when the filesystem is umounted. It releases the + * super block. */ +PUBLIC int release_v_pri(v_pri) + register struct iso9660_vd_pri *v_pri; +{ + /* Release the root dir record */ + release_dir_record(v_pri->dir_rec_root); + v_pri->count = 0; + return OK; +} + +/* This function fullfill the super block data structure using the information + * contained in the stream buf. Such stream is physically read from the device + * . */ +PUBLIC int create_v_pri(v_pri,buf,address) + register struct iso9660_vd_pri *v_pri; + register char* buf; + register unsigned long address; +{ + struct dir_record *dir; + + v_pri->vd_type = buf[0]; + memcpy(v_pri->standard_id,buf + 1,sizeof(v_pri->standard_id)); + v_pri->vd_version = buf[6]; + memcpy(v_pri->system_id,buf + 8,sizeof(v_pri->system_id)); + memcpy(v_pri->volume_id,buf + 40,sizeof(v_pri->volume_id)); + memcpy(&v_pri->volume_space_size_l,buf + 80, + sizeof(v_pri->volume_space_size_l)); + memcpy(&v_pri->volume_space_size_m,buf + 84, + sizeof(v_pri->volume_space_size_m)); + memcpy(&v_pri->volume_set_size,buf + 120,sizeof(v_pri->volume_set_size)); + memcpy(&v_pri->volume_sequence_number,buf + 124, + sizeof(v_pri->volume_sequence_number)); + memcpy(&v_pri->logical_block_size_l,buf + 128, + sizeof(v_pri->logical_block_size_l)); + memcpy(&v_pri->logical_block_size_m,buf + 130, + sizeof(v_pri->logical_block_size_m)); + memcpy(&v_pri->path_table_size_l,buf + 132, + sizeof(v_pri->path_table_size_l)); + memcpy(&v_pri->path_table_size_m,buf + 136, + sizeof(v_pri->path_table_size_m)); + memcpy(&v_pri->loc_l_occ_path_table,buf + 140, + sizeof(v_pri->loc_l_occ_path_table)); + memcpy(&v_pri->loc_opt_l_occ_path_table,buf + 144, + sizeof(v_pri->loc_opt_l_occ_path_table)); + memcpy(&v_pri->loc_m_occ_path_table, buf + 148, + sizeof(v_pri->loc_m_occ_path_table)); + memcpy(&v_pri->loc_opt_m_occ_path_table,buf + 152, + sizeof(v_pri->loc_opt_m_occ_path_table)); + + dir = get_free_dir_record(); + if (dir == NULL) return EINVAL; + create_dir_record(dir,buf + 156,(u32_t)(address + 156)); + v_pri->dir_rec_root = dir; + dir->d_ino_nr = ROOT_INO_NR; + + memcpy(v_pri->volume_set_id,buf + 190,sizeof(v_pri->volume_set_id)); + memcpy(v_pri->publisher_id,buf + 318,sizeof(v_pri->publisher_id)); + memcpy(v_pri->data_preparer_id,buf + 446,sizeof(v_pri->data_preparer_id)); + memcpy(v_pri->application_id,buf + 574,sizeof(v_pri->application_id)); + memcpy(v_pri->copyright_file_id,buf + 702,sizeof(v_pri->copyright_file_id)); + memcpy(v_pri->abstract_file_id,buf + 739,sizeof(v_pri->abstract_file_id)); + memcpy(v_pri->bibl_file_id,buf + 776,sizeof(v_pri->bibl_file_id)); + memcpy(v_pri->volume_cre_date,buf + 813,sizeof(v_pri->volume_cre_date)); + memcpy(v_pri->volume_mod_date,buf + 830,sizeof(v_pri->volume_mod_date)); + memcpy(v_pri->volume_exp_date,buf + 847,sizeof(v_pri->volume_exp_date)); + memcpy(v_pri->volume_eff_date,buf + 864,sizeof(v_pri->volume_eff_date)); + v_pri->file_struct_ver = buf[881]; + return OK; +} + +/* This function reads from a ISO9660 filesystem (in the device dev) the + * super block and saves it in v_pri. */ +PUBLIC int read_vds(v_pri,dev) + register struct iso9660_vd_pri *v_pri; + register dev_t dev; +{ + u64_t offset; + int vol_ok = FALSE; + int r; + static char sbbuf[ISO9660_MIN_BLOCK_SIZE]; + int i = 0; + + offset = cvul64(ISO9660_SUPER_BLOCK_POSITION); + while (!vol_ok && i++ +#include +#include +#include +#include + +static int panicking; + +/*===========================================================================* + * no_sys * + *===========================================================================*/ +PUBLIC int no_sys() +{ +/* Somebody has used an illegal system call number */ + return(EINVAL); +} + +/*===========================================================================* + * panic * + *===========================================================================*/ +PUBLIC void panic(who, mess, num) +char *who; /* who caused the panic */ +char *mess; /* panic message string */ +int num; /* number to go with it */ +{ +/* Something awful has happened. Panics are caused when an internal + * inconsistency is detected, e.g., a programming error or illegal value of a + * defined constant. + */ + if (panicking) return; /* do not panic during a sync */ + panicking = TRUE; /* prevent another panic during the sync */ + + printf("FS panic (%s): %s ", who, mess); + if (num != NO_NUM) printf("%d",num); + sys_exit(SELF); +}