--- /dev/null
+# 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
--- /dev/null
+#include <sys/dir.h> /* need struct direct */
+#include <dirent.h>
+
+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 */
--- /dev/null
+/* 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 <minix/com.h>
+#include <minix/u64.h>
+#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;
+}
--- /dev/null
+/* 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))
--- /dev/null
+
+/* This file handles the direct communication to the device */
+#include "inc.h"
+#include <minix/vfsif.h>
+
+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);
+}
--- /dev/null
+#include <minix/dmap.h>
+
+/* 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];
+
--- /dev/null
+/* 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 */
--- /dev/null
+
+#define _SYSTEM 1 /* get OK and negative error codes */
+#define _MINIX 1 /* tell headers to include MINIX stuff */
+
+#define VERBOSE 0 /* display diagnostics */
+
+#include <ansi.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <minix/callnr.h>
+#include <minix/config.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/com.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <minix/keymap.h>
+#include <minix/bitmap.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "proto.h"
+#include "super.h"
+#include "glo.h"
+#include "drivers.h"
--- /dev/null
+
+/* This file contains all the function that handle the dir records
+ * (inodes) for the ISO9660 filesystem.*/
+
+#include "inc.h"
+#include "buf.h"
+#include <minix/vfsif.h>
+
+/*===========================================================================*
+ * 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;
+}
--- /dev/null
+#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 */
--- /dev/null
+
+
+/* This file contains the main directory for the server. It waits for a
+ * request and then send a response. */
+
+#include "inc.h"
+#include <minix/vfsif.h>
+#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);
+}
--- /dev/null
+/* Some misc functions */
+
+#include "inc.h"
+#include <fcntl.h>
+#include <minix/vfsif.h>
+
+/*===========================================================================*
+ * fs_sync *
+ *===========================================================================*/
+PUBLIC int fs_sync() /* Calling of syncing the filesystem. No action
+ * is taken */
+{
+ return(OK); /* sync() can't fail */
+}
--- /dev/null
+#include "inc.h"
+#include <string.h>
+#include <minix/com.h>
+#include <minix/vfsif.h>
+#include <minix/ds.h>
+
+#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;
+}
--- /dev/null
+#include "inc.h"
+#include <string.h>
+#include <minix/com.h>
+#include <minix/vfsif.h>
+
+#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;
+}
--- /dev/null
+#include "inc.h"
+#include <unistd.h>
+#include <minix/callnr.h>
+#include "buf.h"
+
+#include <minix/vfsif.h>
+
+/* 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);
+}
--- /dev/null
+/* 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);
--- /dev/null
+
+/* Functions to reads_file */
+
+#include "inc.h"
+#include <minix/com.h>
+#include <minix/vfsif.h>
+#include <fcntl.h>
+#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_pos<dir->d_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_pos<block_size) {
+ dir_tmp = get_free_dir_record();
+ create_dir_record(dir_tmp,bp->b_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);
+}
--- /dev/null
+#include "inc.h"
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <minix/com.h>
+#include <string.h>
+#include <time.h>
+
+#include <minix/vfsif.h>
+
+
+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);
+}
+
--- /dev/null
+/* 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 <string.h>
+#include <minix/com.h>
+#include <minix/u64.h>
+
+/* 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++<MAX_ATTEMPTS) {
+
+ /* Read the sector of the super block. */
+ r = block_dev_io(MFS_DEV_READ, dev, SELF_E, sbbuf, offset, ISO9660_MIN_BLOCK_SIZE, 0);
+
+ if (r != ISO9660_MIN_BLOCK_SIZE) /* Damaged sector or what? */
+ continue;
+
+ if ((sbbuf[0] & BYTE) == VD_PRIMARY) {
+ create_v_pri(v_pri,sbbuf,cv64ul(offset)); /* copy the buffer in the data structure. */
+ }
+
+ if ((sbbuf[0] & BYTE) == VD_SET_TERM)
+ /* I dont need to save anything about it */
+ vol_ok = TRUE;
+
+ offset = add64u(offset,ISO9660_MIN_BLOCK_SIZE);
+ }
+
+ if (vol_ok == FALSE)
+ return EINVAL; /* If no superblock was found... */
+ else
+ return OK; /* otherwise. */
+}
--- /dev/null
+/* This file contains the definitions of a ISO9660 structures */
+#include "inode.h"
+
+#define VD_BOOT_RECORD 0
+#define VD_PRIMARY 1
+#define VD_SUPPL 2
+#define VD_PART 3
+#define VD_SET_TERM 255
+
+#define MAX_ATTEMPTS 20 /* # attempts to read the volume descriptors.
+ * After it gives up */
+#define ROOT_INO_NR 1
+
+/* Structure for the primary volume descriptor */
+PUBLIC struct iso9660_vd_pri {
+ u8_t vd_type;
+ char standard_id[ISO9660_SIZE_STANDARD_ID];
+ u8_t vd_version;
+ char system_id[ISO9660_SIZE_SYS_ID];
+ char volume_id[ISO9660_SIZE_VOLUME_ID];
+ u32_t volume_space_size_l;
+ u32_t volume_space_size_m;
+ u32_t volume_set_size;
+ u32_t volume_sequence_number;
+ u16_t logical_block_size_l;
+ u16_t logical_block_size_m;
+ u32_t path_table_size_l;
+ u32_t path_table_size_m;
+ u32_t loc_l_occ_path_table;
+ u32_t loc_opt_l_occ_path_table;
+ u32_t loc_m_occ_path_table;
+ u32_t loc_opt_m_occ_path_table;
+ struct dir_record *dir_rec_root;
+ char volume_set_id[ISO9660_SIZE_VOLUME_SET_ID];
+ char publisher_id[ISO9660_SIZE_PUBLISHER_ID];
+ char data_preparer_id[ISO9660_SIZE_DATA_PREP_ID];
+ char application_id[ISO9660_SIZE_APPL_ID];
+ char copyright_file_id[ISO9660_SIZE_COPYRIGHT_FILE_ID];
+ char abstract_file_id[ISO9660_SIZE_ABSTRACT_FILE_ID];
+ char bibl_file_id[ISO9660_SIZE_BIBL_FILE_ID];
+ char volume_cre_date[ISO9660_SIZE_VOL_CRE_DATE];
+ char volume_mod_date[ISO9660_SIZE_VOL_MOD_DATE];
+ char volume_exp_date[ISO9660_SIZE_VOL_EXP_DATE];
+ char volume_eff_date[ISO9660_SIZE_VOL_EFF_DATE];
+ u8_t file_struct_ver;
+ /* The rest is either not specified or reserved */
+ u8_t count;
+} v_pri;
--- /dev/null
+
+/* This file contains the table used to map system call numbers onto the
+ * routines that perform them.
+ */
+
+#define _TABLE
+
+#include "inc.h"
+
+PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = {
+ no_sys, /* 0: not used */
+ fs_getnode, /* 1 */
+ fs_putnode, /* 2 */
+ no_sys, /* 3: not used */
+ no_sys, /* 4: not used */
+ fs_read, /* 5 */
+ no_sys, /* 6: not used */
+ no_sys, /* 7: not used */
+ no_sys, /* 8: not used */
+ no_sys, /* 9: not used */
+ no_sys, /* 10: not used */
+ fs_access, /* 11 */
+ no_sys, /* 12: not used */
+ no_sys, /* 13: not used */
+ no_sys, /* 14: not used */
+ fs_stat, /* 15 */
+ no_sys, /* 16: not used */
+ no_sys, /* 17: not used */
+ no_sys, /* 18: not used */
+ no_sys, /* 19: not used */
+ no_sys, /* 20: not used */
+ fs_fstatfs, /* 21 */
+ fs_bread_s, /* 22 */
+ no_sys, /* 23: not used */
+ no_sys, /* 24: not used */
+ no_sys, /* 25: not used */
+ no_sys, /* 26: not used */
+ no_sys, /* 27: not used */
+ no_sys, /* 28: not used */
+ no_sys, /* 29: not used */
+ no_sys, /* 30: not used */
+ fs_readsuper, /* 31 */
+ fs_unmount, /* 32 */
+ no_sys, /* 33: not used */
+ fs_sync, /* 34 */
+ lookup, /* 35 */
+ no_sys, /* 36: not used */
+ fs_new_driver, /* 37 */
+ fs_bread, /* 38 */
+ no_sys, /* 39 */
+ fs_getdents, /* 40 */
+ no_sys, /* 41: not_used */
+ fs_read_s, /* 42 */
+ no_sys, /* 43: not used */
+ no_sys, /* 44: not used */
+ no_sys, /* 45: not used */
+ no_sys, /* 46: not used */
+ no_sys, /* 47: not used */
+ no_sys, /* 48: not used */
+ fs_lookup_s, /* 49 */
+ fs_mountpoint_s, /* 50 */
+ fs_readsuper_s, /* 51 */
+ no_sys, /* 52: not used */
+};
--- /dev/null
+#include "inc.h"
+#include <sys/stat.h>
+#include <string.h>
+#include <minix/com.h>
+#include <minix/callnr.h>
+#include <minix/vfsif.h>
+
+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);
+}