Initial import of ISOFS by Jacopo Urbani

This commit is contained in:
Thomas Veerman 2009-10-01 14:00:27 +00:00
parent cee82da892
commit 471ad9384f
22 changed files with 2948 additions and 0 deletions

View file

@ -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

23
servers/iso9660fs/buf.h Normal file
View file

@ -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 */

115
servers/iso9660fs/cache.c Normal file
View file

@ -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;
}

66
servers/iso9660fs/const.h Normal file
View file

@ -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))

344
servers/iso9660fs/device.c Normal file
View file

@ -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);
}

View file

@ -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];

34
servers/iso9660fs/glo.h Normal file
View file

@ -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 */

33
servers/iso9660fs/inc.h Normal file
View file

@ -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"

318
servers/iso9660fs/inode.c Normal file
View file

@ -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;
}

67
servers/iso9660fs/inode.h Normal file
View file

@ -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 */

122
servers/iso9660fs/main.c Normal file
View file

@ -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);
}

14
servers/iso9660fs/misc.c Normal file
View file

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

151
servers/iso9660fs/mount.c Normal file
View file

@ -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;
}

667
servers/iso9660fs/path.c Normal file
View file

@ -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;
}

View file

@ -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);
}

82
servers/iso9660fs/proto.h Normal file
View file

@ -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);

464
servers/iso9660fs/read.c Normal file
View file

@ -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);
}

104
servers/iso9660fs/stadir.c Normal file
View file

@ -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);
}

116
servers/iso9660fs/super.c Normal file
View file

@ -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. */
}

48
servers/iso9660fs/super.h Normal file
View file

@ -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;

64
servers/iso9660fs/table.c Normal file
View file

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

View file

@ -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);
}