Initial import of ISOFS by Jacopo Urbani
This commit is contained in:
parent
cee82da892
commit
471ad9384f
22 changed files with 2948 additions and 0 deletions
38
servers/iso9660fs/Makefile
Normal file
38
servers/iso9660fs/Makefile
Normal 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
23
servers/iso9660fs/buf.h
Normal 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
115
servers/iso9660fs/cache.c
Normal 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
66
servers/iso9660fs/const.h
Normal 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
344
servers/iso9660fs/device.c
Normal 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);
|
||||
}
|
9
servers/iso9660fs/drivers.h
Normal file
9
servers/iso9660fs/drivers.h
Normal 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
34
servers/iso9660fs/glo.h
Normal 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
33
servers/iso9660fs/inc.h
Normal 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
318
servers/iso9660fs/inode.c
Normal 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
67
servers/iso9660fs/inode.h
Normal 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
122
servers/iso9660fs/main.c
Normal 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
14
servers/iso9660fs/misc.c
Normal 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
151
servers/iso9660fs/mount.c
Normal 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
667
servers/iso9660fs/path.c
Normal 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;
|
||||
}
|
32
servers/iso9660fs/protect.c
Normal file
32
servers/iso9660fs/protect.c
Normal 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
82
servers/iso9660fs/proto.h
Normal 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
464
servers/iso9660fs/read.c
Normal 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
104
servers/iso9660fs/stadir.c
Normal 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(<ime);
|
||||
|
||||
statbuf.st_atime = time1;
|
||||
statbuf.st_mtime = time1;
|
||||
statbuf.st_ctime = time1;
|
||||
|
||||
/* Copy the struct to user space. */
|
||||
r = sys_safecopyto(who_e, gid, 0, (vir_bytes) &statbuf,
|
||||
(phys_bytes) sizeof(statbuf), D);
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
/* This function is a wrapper to the function above. It is called with the
|
||||
* request. */
|
||||
/*===========================================================================*
|
||||
* fs_stat *
|
||||
*===========================================================================*/
|
||||
PUBLIC int fs_stat()
|
||||
{
|
||||
register int r; /* return value */
|
||||
struct dir_record *dir;
|
||||
r = EINVAL;
|
||||
|
||||
if ((dir = get_dir_record(fs_m_in.REQ_INODE_NR)) != NULL) {
|
||||
r = stat_dir_record(dir, 0, fs_m_in.m_source, fs_m_in.REQ_GRANT);
|
||||
release_dir_record(dir);
|
||||
} else
|
||||
printf("I9660FS(%d) fs_stat() failed\n", SELF_E);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_fstatfs *
|
||||
*===========================================================================*/
|
||||
PUBLIC int fs_fstatfs()
|
||||
{
|
||||
struct statfs st;
|
||||
int r;
|
||||
|
||||
st.f_bsize = v_pri.logical_block_size_l;
|
||||
|
||||
/* Copy the struct to user space. */
|
||||
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, 0,
|
||||
(vir_bytes) &st, (phys_bytes) sizeof(st), D);
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
116
servers/iso9660fs/super.c
Normal file
116
servers/iso9660fs/super.c
Normal 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
48
servers/iso9660fs/super.h
Normal 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
64
servers/iso9660fs/table.c
Normal 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 */
|
||||
};
|
37
servers/iso9660fs/utility.c
Normal file
37
servers/iso9660fs/utility.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue