]> Zhao Yanbai Git Server - minix.git/commitdiff
Initial import of ISOFS by Jacopo Urbani
authorThomas Veerman <thomas@minix3.org>
Thu, 1 Oct 2009 14:00:27 +0000 (14:00 +0000)
committerThomas Veerman <thomas@minix3.org>
Thu, 1 Oct 2009 14:00:27 +0000 (14:00 +0000)
22 files changed:
servers/iso9660fs/Makefile [new file with mode: 0644]
servers/iso9660fs/buf.h [new file with mode: 0644]
servers/iso9660fs/cache.c [new file with mode: 0644]
servers/iso9660fs/const.h [new file with mode: 0644]
servers/iso9660fs/device.c [new file with mode: 0644]
servers/iso9660fs/drivers.h [new file with mode: 0644]
servers/iso9660fs/glo.h [new file with mode: 0644]
servers/iso9660fs/inc.h [new file with mode: 0644]
servers/iso9660fs/inode.c [new file with mode: 0644]
servers/iso9660fs/inode.h [new file with mode: 0644]
servers/iso9660fs/main.c [new file with mode: 0644]
servers/iso9660fs/misc.c [new file with mode: 0644]
servers/iso9660fs/mount.c [new file with mode: 0644]
servers/iso9660fs/path.c [new file with mode: 0644]
servers/iso9660fs/protect.c [new file with mode: 0644]
servers/iso9660fs/proto.h [new file with mode: 0644]
servers/iso9660fs/read.c [new file with mode: 0644]
servers/iso9660fs/stadir.c [new file with mode: 0644]
servers/iso9660fs/super.c [new file with mode: 0644]
servers/iso9660fs/super.h [new file with mode: 0644]
servers/iso9660fs/table.c [new file with mode: 0644]
servers/iso9660fs/utility.c [new file with mode: 0644]

diff --git a/servers/iso9660fs/Makefile b/servers/iso9660fs/Makefile
new file mode 100644 (file)
index 0000000..1b82eeb
--- /dev/null
@@ -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 (file)
index 0000000..f61880f
--- /dev/null
@@ -0,0 +1,23 @@
+#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 */
diff --git a/servers/iso9660fs/cache.c b/servers/iso9660fs/cache.c
new file mode 100644 (file)
index 0000000..b393f7e
--- /dev/null
@@ -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 <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;
+}
diff --git a/servers/iso9660fs/const.h b/servers/iso9660fs/const.h
new file mode 100644 (file)
index 0000000..43e2a69
--- /dev/null
@@ -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 (file)
index 0000000..1ffa70e
--- /dev/null
@@ -0,0 +1,344 @@
+
+/* 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);
+}
diff --git a/servers/iso9660fs/drivers.h b/servers/iso9660fs/drivers.h
new file mode 100644 (file)
index 0000000..2878aca
--- /dev/null
@@ -0,0 +1,9 @@
+#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];
+
diff --git a/servers/iso9660fs/glo.h b/servers/iso9660fs/glo.h
new file mode 100644 (file)
index 0000000..5c93a59
--- /dev/null
@@ -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 (file)
index 0000000..683ab65
--- /dev/null
@@ -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 <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"
diff --git a/servers/iso9660fs/inode.c b/servers/iso9660fs/inode.c
new file mode 100644 (file)
index 0000000..2289aad
--- /dev/null
@@ -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 <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;
+}
diff --git a/servers/iso9660fs/inode.h b/servers/iso9660fs/inode.h
new file mode 100644 (file)
index 0000000..da1a8da
--- /dev/null
@@ -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 (file)
index 0000000..b41b79e
--- /dev/null
@@ -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 <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);
+}
diff --git a/servers/iso9660fs/misc.c b/servers/iso9660fs/misc.c
new file mode 100644 (file)
index 0000000..457bf3f
--- /dev/null
@@ -0,0 +1,14 @@
+/* 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 */
+}
diff --git a/servers/iso9660fs/mount.c b/servers/iso9660fs/mount.c
new file mode 100644 (file)
index 0000000..b470624
--- /dev/null
@@ -0,0 +1,151 @@
+#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;
+}
diff --git a/servers/iso9660fs/path.c b/servers/iso9660fs/path.c
new file mode 100644 (file)
index 0000000..4c79d60
--- /dev/null
@@ -0,0 +1,667 @@
+#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;
+}
diff --git a/servers/iso9660fs/protect.c b/servers/iso9660fs/protect.c
new file mode 100644 (file)
index 0000000..c3eb05b
--- /dev/null
@@ -0,0 +1,32 @@
+#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);
+}
diff --git a/servers/iso9660fs/proto.h b/servers/iso9660fs/proto.h
new file mode 100644 (file)
index 0000000..a441018
--- /dev/null
@@ -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 (file)
index 0000000..480bd27
--- /dev/null
@@ -0,0 +1,464 @@
+
+/* 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);
+}
diff --git a/servers/iso9660fs/stadir.c b/servers/iso9660fs/stadir.c
new file mode 100644 (file)
index 0000000..5511c67
--- /dev/null
@@ -0,0 +1,104 @@
+#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(&ltime);
+
+  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 (file)
index 0000000..7e56a26
--- /dev/null
@@ -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 <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. */
+}
diff --git a/servers/iso9660fs/super.h b/servers/iso9660fs/super.h
new file mode 100644 (file)
index 0000000..488b6db
--- /dev/null
@@ -0,0 +1,48 @@
+/* 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;
diff --git a/servers/iso9660fs/table.c b/servers/iso9660fs/table.c
new file mode 100644 (file)
index 0000000..86d84c3
--- /dev/null
@@ -0,0 +1,64 @@
+
+/* 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 */
+};
diff --git a/servers/iso9660fs/utility.c b/servers/iso9660fs/utility.c
new file mode 100644 (file)
index 0000000..6f4a676
--- /dev/null
@@ -0,0 +1,37 @@
+#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);
+}