iso9660fs: rewrite ISO 9660 file system server
iso9660fs has been cleaned up and debugged. It now supports: * ISO 9660 Level 3, * System Use Sharing Protocol (SUSP), * Rock Ridge Interchange Protocol (RRIP). The following Rock Ridge features are supported: * POSIX file attributes (PX), * POSIX device number (PN), * Symbolic links (SL), * Alternate file name (NM), * Timestamps in 7-byte format (TF). Change-Id: Ib227411bdda5bc10a957b27ad05fafdc95eca35f
This commit is contained in:
parent
1858c65d72
commit
3e08d38e8e
21 changed files with 1975 additions and 1465 deletions
|
@ -1,11 +1,11 @@
|
|||
# Makefile for ISO9660 fs
|
||||
PROG= isofs
|
||||
SRCS= main.c table.c mount.c super.c inode.c \
|
||||
utility.c misc.c path.c read.c stadir.c
|
||||
link.c utility.c misc.c path.c read.c susp.c susp_rock_ridge.c stadir.c
|
||||
|
||||
DPADD+= ${LIBBDEV} ${LIBSYS}
|
||||
LDADD+= -lbdev -lsys -lc -lminixfs
|
||||
|
||||
CPPFLAGS+= -DNR_BUFS=100
|
||||
CPPFLAGS+= -DNR_BUFS=100 -Wall
|
||||
|
||||
.include <minix.service.mk>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#include <sys/dirent.h>
|
||||
|
||||
#define b_data(bp) ((char *) (bp->data))
|
||||
|
||||
/* A block is free if b_dev == NO_DEV. */
|
||||
|
||||
#define INODE_BLOCK 0 /* inode block */
|
||||
#define DIRECTORY_BLOCK 1 /* directory block */
|
|
@ -1,17 +1,10 @@
|
|||
|
||||
#define GETDENTS_BUFSIZ 261
|
||||
#define GETDENTS_BUFSIZ 1024
|
||||
|
||||
#define ISO9660_STANDARD_ID "CD001" /* Standard code for ISO9660 file systems */
|
||||
|
||||
#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 filesystem can
|
||||
* handle */
|
||||
#define NR_INODE_RECORDS 64
|
||||
#define NR_DIR_EXTENT_RECORDS NR_INODE_RECORDS * 16
|
||||
|
||||
#define NO_ADDRESS (-1) /* Error constants */
|
||||
#define NO_FREE_INODES (-1)
|
||||
|
@ -19,12 +12,8 @@
|
|||
#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_SUPER_BLOCK_POSITION 32768
|
||||
#define ISO9660_MIN_BLOCK_SIZE 2048
|
||||
|
||||
/* SIZES FIELDS ISO9660 STRUCTURES */
|
||||
|
@ -42,10 +31,8 @@
|
|||
#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_DATE17 17
|
||||
#define ISO9660_SIZE_DATE7 7
|
||||
|
||||
#define ISO9660_SIZE_ESCAPE_SQC 32
|
||||
#define ISO9660_SIZE_PART_ID 32
|
||||
|
@ -54,9 +41,11 @@
|
|||
|
||||
/* maximum size of length of name file used in dir records */
|
||||
#define ISO9660_MAX_FILE_ID_LEN 32
|
||||
#define ISO9660_RRIP_MAX_FILE_ID_LEN 256
|
||||
|
||||
#define END_OF_FILE (-104) /* eof detected */
|
||||
|
||||
/* Miscellaneous constants */
|
||||
#define SYS_UID ((uid_t) 0) /* uid_t for processes PM and INIT */
|
||||
#define SYS_GID ((gid_t) 0) /* gid_t for processes PM and INIT */
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#define EXTERN
|
||||
#endif
|
||||
|
||||
#include <minix/optset.h>
|
||||
|
||||
/* The following variables are used for returning results to the caller. */
|
||||
|
||||
EXTERN int err_code; /* temporary storage for error number */
|
||||
|
@ -12,8 +14,7 @@ EXTERN int rdwt_err; /* status of last disk i/o request */
|
|||
EXTERN int(*fs_call_vec[]) (void);
|
||||
|
||||
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 message fs_m_out; /* contains the output message of the request */
|
||||
EXTERN int FS_STATE;
|
||||
|
||||
EXTERN uid_t caller_uid;
|
||||
|
@ -31,3 +32,4 @@ EXTERN int unmountdone;
|
|||
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 struct opt opt; /* global mount options */
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <minix/callnr.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/log.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <minix/bitmap.h>
|
||||
|
@ -24,8 +26,15 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslimits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/dirent.h>
|
||||
|
||||
#define b_data(bp) ((char *) (bp->data))
|
||||
|
||||
#include "proto.h"
|
||||
#include "super.h"
|
||||
#include "glo.h"
|
||||
|
||||
|
|
|
@ -1,296 +1,384 @@
|
|||
|
||||
/* This file contains all the function that handle the dir records
|
||||
* (inodes) for the ISO9660 filesystem.*/
|
||||
/*
|
||||
* 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>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static struct inode inodes[NR_INODE_RECORDS];
|
||||
static struct buf* fetch_inode(struct dir_extent *extent, size_t *offset);
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_putnode *
|
||||
*===========================================================================*/
|
||||
int fs_putnode()
|
||||
{
|
||||
/* Find the inode specified by the request message and decrease its counter. */
|
||||
int count;
|
||||
struct dir_record *dir = NULL;
|
||||
/*
|
||||
* Find the inode specified by the request message and decrease its
|
||||
* counter.
|
||||
*/
|
||||
int count = fs_m_in.m_vfs_fs_putnode.count;
|
||||
struct inode *i_node = find_inode(fs_m_in.m_vfs_fs_putnode.inode);
|
||||
|
||||
dir = get_dir_record(fs_m_in.m_vfs_fs_putnode.inode);
|
||||
release_dir_record(dir);
|
||||
|
||||
count = fs_m_in.m_vfs_fs_putnode.count;
|
||||
|
||||
if (count <= 0) return(EINVAL);
|
||||
|
||||
if (count > dir->d_count) {
|
||||
printf("put_inode: count too high: %d > %d\n", count, dir->d_count);
|
||||
return(EINVAL);
|
||||
if (i_node == NULL) {
|
||||
printf("put_inode: trying to free unused inode\n");
|
||||
panic("fs_putnode failed");
|
||||
}
|
||||
if (count <= 0) {
|
||||
printf("put_inode: bad value for count: %d\n", count);
|
||||
panic("fs_putnode failed");
|
||||
}
|
||||
if (count > i_node->i_count) {
|
||||
printf("put_inode: count too high: %d > %d\n", count, i_node->i_count);
|
||||
panic("fs_putnode failed");
|
||||
}
|
||||
|
||||
if (dir->d_count > 1)
|
||||
dir->d_count = dir->d_count - count + 1;/*Keep at least one reference*/
|
||||
|
||||
release_dir_record(dir); /* Actual inode release, might be last reference */
|
||||
|
||||
return(OK);
|
||||
i_node->i_count -= count - 1;
|
||||
put_inode(i_node);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* release_dir_record *
|
||||
*===========================================================================*/
|
||||
int release_dir_record(dir)
|
||||
struct dir_record *dir;
|
||||
struct inode* alloc_inode()
|
||||
{
|
||||
/* Release a dir record (decrement the counter) */
|
||||
if (dir == NULL)
|
||||
return(EINVAL);
|
||||
/*
|
||||
* Return a free inode from the pool.
|
||||
*/
|
||||
static int i;
|
||||
int end = i;
|
||||
struct inode *i_node;
|
||||
|
||||
if (--dir->d_count == 0) {
|
||||
if (dir->ext_attr != NULL)
|
||||
dir->ext_attr->count = 0;
|
||||
dir->ext_attr = NULL;
|
||||
dir->d_mountpoint = FALSE;
|
||||
i = (i + 1) % NR_INODE_RECORDS;
|
||||
do {
|
||||
i_node = &inodes[i];
|
||||
|
||||
dir->d_prior = NULL;
|
||||
if (dir->d_next != NULL)
|
||||
release_dir_record(dir);
|
||||
dir->d_next = NULL;
|
||||
}
|
||||
return(OK);
|
||||
if (i_node->i_count == 0) {
|
||||
free_extent(i_node->extent);
|
||||
|
||||
memset(i_node, 0, sizeof(*i_node));
|
||||
i_node->i_count = 1;
|
||||
|
||||
return i_node;
|
||||
}
|
||||
|
||||
i = (i + 1) % NR_INODE_RECORDS;
|
||||
}
|
||||
while(i != end);
|
||||
|
||||
/*===========================================================================*
|
||||
* get_free_dir_record *
|
||||
*===========================================================================*/
|
||||
struct dir_record *get_free_dir_record(void)
|
||||
panic("No free inodes in cache");
|
||||
}
|
||||
|
||||
struct inode* find_inode(ino_t i)
|
||||
{
|
||||
/* Get a free dir record */
|
||||
struct dir_record *dir;
|
||||
/* Get inode from cache. */
|
||||
int cpt;
|
||||
struct inode *i_node;
|
||||
|
||||
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);
|
||||
}
|
||||
if (i == 0)
|
||||
return NULL;
|
||||
|
||||
for (cpt = 0; cpt < NR_INODE_RECORDS; cpt++) {
|
||||
i_node = &inodes[cpt];
|
||||
|
||||
if ((i_node->i_stat.st_ino == i) && (i_node->i_count > 0))
|
||||
return i_node;
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* get_dir_record *
|
||||
*===========================================================================*/
|
||||
struct dir_record *get_dir_record(id_dir_record)
|
||||
ino_t id_dir_record;
|
||||
struct inode* get_inode(ino_t i)
|
||||
{
|
||||
struct dir_record *dir = NULL;
|
||||
u32_t address;
|
||||
int i;
|
||||
struct inode *i_node;
|
||||
struct dir_extent *extent;
|
||||
|
||||
/* 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 (i == 0)
|
||||
return NULL;
|
||||
|
||||
/* Try to get inode from cache. */
|
||||
i_node = find_inode(i);
|
||||
if (i_node != NULL) {
|
||||
dup_inode(i_node);
|
||||
return i_node;
|
||||
}
|
||||
|
||||
if (dir == NULL) {
|
||||
address = (u32_t)id_dir_record;
|
||||
dir = load_dir_record_from_disk(address);
|
||||
/*
|
||||
* Inode wasn't in cache, try to load it.
|
||||
* FIXME: a fake extent of one logical block is created for
|
||||
* read_inode(). Reading a inode this way could be problematic if
|
||||
* additional extents are stored behind the block boundary.
|
||||
*/
|
||||
i_node = alloc_inode();
|
||||
extent = alloc_extent();
|
||||
extent->location = i / v_pri.logical_block_size_l;
|
||||
extent->length = 1;
|
||||
|
||||
if (read_inode(i_node, extent, i % v_pri.logical_block_size_l, NULL) != OK) {
|
||||
free_extent(extent);
|
||||
put_inode(i_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dir == NULL) return(NULL);
|
||||
|
||||
return(dir);
|
||||
free_extent(extent);
|
||||
return i_node;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* get_free_ext_attr *
|
||||
*===========================================================================*/
|
||||
struct ext_attr_rec *get_free_ext_attr(void) {
|
||||
/* Get a free extended attribute structure */
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_ext_attr *
|
||||
*===========================================================================*/
|
||||
int create_ext_attr(struct ext_attr_rec *ext,char *buffer)
|
||||
void put_inode(struct inode *i_node)
|
||||
{
|
||||
/* Fill an extent structure from the data read on the device */
|
||||
if (ext == NULL) return(EINVAL);
|
||||
if (i_node == NULL)
|
||||
return;
|
||||
|
||||
/* In input we have a stream of bytes that are physically read from the
|
||||
* device. This stream of data is copied to 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));
|
||||
if (i_node->i_count <= 0)
|
||||
panic("put_inode: i_count already below 1: %d", i_node->i_count);
|
||||
|
||||
return(OK);
|
||||
i_node->i_count--;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_ext_attr *
|
||||
*===========================================================================*/
|
||||
int create_dir_record(dir,buffer,address)
|
||||
struct dir_record *dir;
|
||||
char *buffer;
|
||||
u32_t address;
|
||||
void dup_inode(struct inode *i_node)
|
||||
{
|
||||
/* 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. */
|
||||
short size;
|
||||
if (i_node == NULL)
|
||||
panic("dup_inode: trying to duplicate NULL inode");
|
||||
|
||||
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;
|
||||
|
||||
/* Set permission to read only. Equal for all 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 = address;
|
||||
|
||||
return(OK);
|
||||
i_node->i_count++;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* load_dir_record_from_disk *
|
||||
*===========================================================================*/
|
||||
struct dir_record *load_dir_record_from_disk(address)
|
||||
u32_t address;
|
||||
static struct buf* fetch_inode(struct dir_extent *extent, size_t *offset)
|
||||
{
|
||||
/* This function load a particular dir record from a specific address
|
||||
* on the device */
|
||||
|
||||
int block_nr, offset, block_size, new_pos;
|
||||
struct iso9660_dir_record *dir_rec;
|
||||
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 */
|
||||
/*
|
||||
* Directory entries aren't allowed to cross a logical block boundary in
|
||||
* ISO 9660, so we keep searching until we find something or reach the
|
||||
* end of the extent.
|
||||
*/
|
||||
bp = read_extent_block(extent, *offset / v_pri.logical_block_size_l);
|
||||
while (bp != NULL) {
|
||||
dir_rec = (struct iso9660_dir_record*)(b_data(bp) + *offset %
|
||||
v_pri.logical_block_size_l);
|
||||
if (dir_rec->length == 0) {
|
||||
*offset -= *offset % v_pri.logical_block_size_l;
|
||||
*offset += v_pri.logical_block_size_l;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
bp = get_block(block_nr); /* Read the block from the device */
|
||||
put_block(bp);
|
||||
bp = read_extent_block(extent, *offset / v_pri.logical_block_size_l);
|
||||
}
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
int read_inode(struct inode *i_node, struct dir_extent *extent, size_t offset,
|
||||
size_t *new_offset)
|
||||
{
|
||||
struct iso9660_dir_record *dir_rec;
|
||||
struct buf *bp;
|
||||
|
||||
/* Find inode. */
|
||||
bp = fetch_inode(extent, &offset);
|
||||
if (bp == NULL)
|
||||
return(NULL);
|
||||
return EOF;
|
||||
|
||||
dir = get_free_dir_record(); /* Get a free record */
|
||||
if (dir == NULL)
|
||||
return(NULL);
|
||||
dir_rec = (struct iso9660_dir_record*)(b_data(bp) + offset %
|
||||
v_pri.logical_block_size_l);
|
||||
|
||||
/* Fill the dir record with the data read from the device */
|
||||
create_dir_record(dir,b_data(bp) + offset, address);
|
||||
|
||||
/* In case the file is composed of more file sections, load also the
|
||||
* next section into 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, b_data(bp) + 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;
|
||||
/* Parse basic ISO 9660 specs. */
|
||||
if (check_dir_record(dir_rec, offset % v_pri.logical_block_size_l) != OK) {
|
||||
put_block(bp);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
memset(&i_node->i_stat, 0, sizeof(struct stat));
|
||||
|
||||
i_node->i_stat.st_ino = get_extent_absolute_block_id(extent,
|
||||
offset / v_pri.logical_block_size_l) * v_pri.logical_block_size_l +
|
||||
offset % v_pri.logical_block_size_l;
|
||||
|
||||
read_inode_iso9660(i_node, dir_rec);
|
||||
|
||||
/* Parse extensions. */
|
||||
read_inode_susp(i_node, dir_rec, bp, offset % v_pri.logical_block_size_l);
|
||||
|
||||
offset += dir_rec->length;
|
||||
read_inode_extents(i_node, dir_rec, extent, &offset);
|
||||
|
||||
put_block(bp);
|
||||
if (new_offset != NULL)
|
||||
*new_offset = offset;
|
||||
return OK;
|
||||
}
|
||||
} else { /* record not valid */
|
||||
release_dir_record(dir_next);
|
||||
new_pos = block_size; /* Exit from the while */
|
||||
|
||||
void read_inode_iso9660(struct inode *i, const struct iso9660_dir_record *dir_rec)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
/* Parse first extent. */
|
||||
if (dir_rec->data_length_l > 0) {
|
||||
i->extent = alloc_extent();
|
||||
i->extent->location = dir_rec->loc_extent_l +
|
||||
dir_rec->ext_attr_rec_length;
|
||||
i->extent->length = dir_rec->data_length_l /
|
||||
v_pri.logical_block_size_l;
|
||||
if (dir_rec->data_length_l % v_pri.logical_block_size_l)
|
||||
i->extent->length++;
|
||||
|
||||
i->i_stat.st_size = dir_rec->data_length_l;
|
||||
}
|
||||
|
||||
/* Parse timestamps (record date). */
|
||||
i->i_stat.st_atime = i->i_stat.st_mtime = i->i_stat.st_ctime =
|
||||
i->i_stat.st_birthtime = date7_to_time_t(dir_rec->rec_date);
|
||||
|
||||
if ((dir_rec->file_flags & D_TYPE) == D_DIRECTORY) {
|
||||
i->i_stat.st_mode = S_IFDIR;
|
||||
i->i_stat.st_ino = i->extent->location * v_pri.logical_block_size_l;
|
||||
}
|
||||
else
|
||||
i->i_stat.st_mode = S_IFREG;
|
||||
i->i_stat.st_mode |= 0555;
|
||||
|
||||
/* Parse file name. */
|
||||
if (dir_rec->file_id[0] == 0)
|
||||
strcpy(i->i_name, ".");
|
||||
else if (dir_rec->file_id[0] == 1)
|
||||
strcpy(i->i_name, "..");
|
||||
else {
|
||||
memcpy(i->i_name, dir_rec->file_id, dir_rec->length_file_id);
|
||||
|
||||
/* Truncate/ignore file version suffix. */
|
||||
cp = strchr(i->i_name, ';');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
/* Truncate dot if file has no extension. */
|
||||
if (strchr(i->i_name, '.') + 1 == cp)
|
||||
*(cp-1) = '\0';
|
||||
}
|
||||
|
||||
/* Initialize stat. */
|
||||
i->i_stat.st_dev = fs_dev;
|
||||
i->i_stat.st_blksize = v_pri.logical_block_size_l;
|
||||
i->i_stat.st_blocks = dir_rec->data_length_l / v_pri.logical_block_size_l;
|
||||
i->i_stat.st_nlink = 1;
|
||||
}
|
||||
|
||||
void read_inode_extents(struct inode *i, const struct iso9660_dir_record *dir_rec,
|
||||
struct dir_extent *extent, size_t *offset)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct iso9660_dir_record *extent_rec;
|
||||
struct dir_extent *cur_extent = i->extent;
|
||||
int done = FALSE;
|
||||
|
||||
/*
|
||||
* No need to search extents if file is empty or has final directory
|
||||
* record flag set.
|
||||
*/
|
||||
if (cur_extent == NULL || ((dir_rec->file_flags & D_NOT_LAST_EXTENT) == 0))
|
||||
return;
|
||||
|
||||
while (!done) {
|
||||
bp = fetch_inode(extent, offset);
|
||||
if (bp == NULL)
|
||||
return;
|
||||
|
||||
bp = read_extent_block(extent, *offset / v_pri.logical_block_size_l);
|
||||
extent_rec = (struct iso9660_dir_record*)(b_data(bp) + *offset %
|
||||
v_pri.logical_block_size_l);
|
||||
|
||||
if (check_dir_record(dir_rec, *offset % v_pri.logical_block_size_l) != OK) {
|
||||
put_block(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extent entries should share the same name. */
|
||||
if ((dir_rec->length_file_id == extent_rec->length_file_id) &&
|
||||
(memcmp(dir_rec->file_id, extent_rec->file_id, dir_rec->length_file_id) == 0)) {
|
||||
/* Add the extent at the end of the linked list. */
|
||||
cur_extent->next = alloc_extent();
|
||||
cur_extent->next->location = dir_rec->loc_extent_l +
|
||||
dir_rec->ext_attr_rec_length;
|
||||
cur_extent->next->length = dir_rec->data_length_l /
|
||||
v_pri.logical_block_size_l;
|
||||
if (dir_rec->data_length_l % v_pri.logical_block_size_l)
|
||||
cur_extent->next->length++;
|
||||
|
||||
i->i_stat.st_size += dir_rec->data_length_l;
|
||||
i->i_stat.st_blocks += cur_extent->next->length;
|
||||
|
||||
cur_extent = cur_extent->next;
|
||||
*offset += extent_rec->length;
|
||||
}
|
||||
else
|
||||
done = TRUE;
|
||||
|
||||
/* Check if not last extent bit is not set. */
|
||||
if ((dir_rec->file_flags & D_NOT_LAST_EXTENT) == 0)
|
||||
done = TRUE;
|
||||
|
||||
put_block(bp);
|
||||
}
|
||||
}
|
||||
|
||||
put_block(bp); /* Release the block read. */
|
||||
return(dir);
|
||||
void read_inode_susp(struct inode *i, const struct iso9660_dir_record *dir_rec,
|
||||
struct buf *bp, size_t offset)
|
||||
{
|
||||
int susp_offset, susp_size;
|
||||
struct rrii_dir_record rrii_data;
|
||||
|
||||
susp_offset = 33 + dir_rec->length_file_id;
|
||||
/* Get rid of padding byte. */
|
||||
if(dir_rec->length_file_id % 2 == 0) {
|
||||
susp_offset++;
|
||||
}
|
||||
|
||||
if(dir_rec->length - susp_offset >= 4) {
|
||||
susp_size = dir_rec->length - susp_offset;
|
||||
|
||||
/* Initialize rrii_dir_record structure with known, sane data. */
|
||||
memcpy(rrii_data.mtime, dir_rec->rec_date, ISO9660_SIZE_DATE7);
|
||||
memcpy(rrii_data.atime, dir_rec->rec_date, ISO9660_SIZE_DATE7);
|
||||
memcpy(rrii_data.ctime, dir_rec->rec_date, ISO9660_SIZE_DATE7);
|
||||
memcpy(rrii_data.birthtime, dir_rec->rec_date, ISO9660_SIZE_DATE7);
|
||||
|
||||
rrii_data.d_mode = i->i_stat.st_mode;
|
||||
rrii_data.uid = 0;
|
||||
rrii_data.gid = 0;
|
||||
rrii_data.rdev = NO_DEV;
|
||||
rrii_data.file_id_rrip[0] = '\0';
|
||||
rrii_data.slink_rrip[0] = '\0';
|
||||
|
||||
parse_susp_buffer(&rrii_data, b_data(bp)+offset+susp_offset, susp_size);
|
||||
|
||||
/* Copy back data from rrii_dir_record structure. */
|
||||
i->i_stat.st_atime = date7_to_time_t(rrii_data.atime);
|
||||
i->i_stat.st_ctime = date7_to_time_t(rrii_data.ctime);
|
||||
i->i_stat.st_mtime = date7_to_time_t(rrii_data.mtime);
|
||||
i->i_stat.st_birthtime = date7_to_time_t(rrii_data.birthtime);
|
||||
|
||||
i->i_stat.st_mode = rrii_data.d_mode;
|
||||
i->i_stat.st_uid = rrii_data.uid;
|
||||
i->i_stat.st_gid = rrii_data.gid;
|
||||
i->i_stat.st_rdev = rrii_data.rdev;
|
||||
|
||||
if (rrii_data.file_id_rrip[0] != '\0')
|
||||
strlcpy(i->i_name, rrii_data.file_id_rrip, ISO9660_RRIP_MAX_FILE_ID_LEN);
|
||||
if (rrii_data.slink_rrip[0] != '\0')
|
||||
strlcpy(i->s_link, rrii_data.slink_rrip, ISO9660_RRIP_MAX_FILE_ID_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
int check_dir_record(const struct iso9660_dir_record *d, size_t offset)
|
||||
{
|
||||
/* Run some consistency check on a directory entry. */
|
||||
if ((d->length < 33) || (d->length_file_id < 1))
|
||||
return EINVAL;
|
||||
if (d->length_file_id + 32 > d->length)
|
||||
return EINVAL;
|
||||
if (offset + d->length > v_pri.logical_block_size_l)
|
||||
return EINVAL;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "const.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
struct dir_record {
|
||||
struct iso9660_dir_record {
|
||||
/*
|
||||
* ISO standard directory 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 */
|
||||
|
@ -14,54 +18,54 @@ struct dir_record {
|
|||
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;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 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 */
|
||||
struct rrii_dir_record {
|
||||
/*
|
||||
* Rock Ridge directory record extensions.
|
||||
*/
|
||||
u8_t mtime[7]; /* stat.st_mtime */
|
||||
u8_t atime[7]; /* stat.st_atime */
|
||||
u8_t ctime[7]; /* stat.st_ctime */
|
||||
u8_t birthtime[7]; /* stat.st_birthtime */
|
||||
|
||||
} dir_records[NR_DIR_RECORDS];
|
||||
mode_t d_mode; /* file mode */
|
||||
uid_t uid; /* user ID of the file's owner */
|
||||
gid_t gid; /* group ID of the file's group */
|
||||
dev_t rdev; /* device ID */
|
||||
|
||||
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;
|
||||
char file_id_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* file name */
|
||||
char slink_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* symbolic link */
|
||||
} ;
|
||||
|
||||
int count;
|
||||
} ext_attr_recs[NR_ATTR_RECS];
|
||||
struct dir_extent {
|
||||
/*
|
||||
* Extent (contiguous array of logical sectors).
|
||||
*/
|
||||
char in_use;
|
||||
u32_t location;
|
||||
u32_t length;
|
||||
struct dir_extent *next;
|
||||
} ;
|
||||
|
||||
struct inode {
|
||||
int i_count; /* usage counter of this inode */
|
||||
int i_mountpoint; /* flag for inode being used as a mount point */
|
||||
int ea_length; /* total size of extended attributes in bytes */
|
||||
struct stat i_stat; /* inode properties */
|
||||
struct dir_extent *extent; /* first extent of file */
|
||||
char i_name[NAME_MAX]; /* inode name */
|
||||
char s_link[NAME_MAX]; /* symbolic link target */
|
||||
} ;
|
||||
|
||||
struct opt {
|
||||
/*
|
||||
* Global mount options.
|
||||
*/
|
||||
int norock; /* Bool: dont use Rock Ridge */
|
||||
} ;
|
||||
|
||||
#define D_DIRECTORY 0x2
|
||||
#define D_NOT_LAST_EXTENT 0x80
|
||||
#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 */
|
||||
|
|
36
minix/fs/iso9660fs/link.c
Normal file
36
minix/fs/iso9660fs/link.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "inc.h"
|
||||
#include <minix/com.h>
|
||||
#include <minix/vfsif.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef __NBSD_LIBC
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
#include "proto.h"
|
||||
|
||||
int fs_rdlink()
|
||||
{
|
||||
struct inode *i_node; /* target inode */
|
||||
int r; /* return value */
|
||||
size_t copylen;
|
||||
|
||||
/* Try to get inode according to its index */
|
||||
i_node = find_inode(fs_m_in.m_vfs_fs_rdlink.inode);
|
||||
if (i_node == NULL)
|
||||
return EINVAL; /* no inode found */
|
||||
|
||||
if(!S_ISLNK(i_node->i_stat.st_mode))
|
||||
r = EACCES;
|
||||
else {
|
||||
/* Passed all checks */
|
||||
copylen = MIN( (size_t) fs_m_in.m_vfs_fs_rdlink.mem_size, NAME_MAX);
|
||||
|
||||
r = sys_safecopyto(VFS_PROC_NR,
|
||||
(cp_grant_id_t) fs_m_in.m_vfs_fs_rdlink.grant,
|
||||
(vir_bytes) 0,
|
||||
(vir_bytes) i_node->s_link,
|
||||
copylen);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
/* This file contains the main directory for the server. It waits for a
|
||||
* request and then send a response. */
|
||||
/*
|
||||
* This file contains the main function for the server. It waits for a request
|
||||
* and then send a response.
|
||||
*/
|
||||
|
||||
#include "inc.h"
|
||||
#include <minix/vfsif.h>
|
||||
|
@ -15,18 +17,20 @@ static void sef_local_startup(void);
|
|||
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
||||
static void sef_cb_signal_handler(int signo);
|
||||
|
||||
/*===========================================================================*
|
||||
* main *
|
||||
*===========================================================================*/
|
||||
int main(void) {
|
||||
static struct optset optset_table[] = {
|
||||
{ "norock", OPT_BOOL, &opt.norock, TRUE },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
endpoint_t who_e;
|
||||
int ind, error, transid;
|
||||
|
||||
/* SEF local startup. */
|
||||
env_setargs(argc, argv);
|
||||
sef_local_startup();
|
||||
|
||||
for (;;) {
|
||||
|
||||
while (TRUE) {
|
||||
/* Wait for request message. */
|
||||
get_work(&fs_m_in);
|
||||
|
||||
|
@ -36,7 +40,8 @@ int main(void) {
|
|||
assert(!IS_VFS_FS_TRANSID(transid));
|
||||
fs_m_in.m_type = transid; /* Backwards compat. */
|
||||
transid = 0;
|
||||
} else
|
||||
}
|
||||
else
|
||||
assert(IS_VFS_FS_TRANSID(transid));
|
||||
|
||||
error = OK;
|
||||
|
@ -60,9 +65,9 @@ int main(void) {
|
|||
|
||||
ind = req_nr - FS_BASE;
|
||||
|
||||
if (ind < 0 || ind >= NREQS) {
|
||||
if (ind < 0 || ind >= NREQS)
|
||||
error = EINVAL;
|
||||
} else
|
||||
else
|
||||
error = (*fs_call_vec[ind])(); /* Process the request calling
|
||||
* the appropriate function. */
|
||||
|
||||
|
@ -80,6 +85,17 @@ int main(void) {
|
|||
*===========================================================================*/
|
||||
static void sef_local_startup()
|
||||
{
|
||||
/* Initialize the Minix file server. */
|
||||
int i;
|
||||
|
||||
/* Defaults */
|
||||
opt.norock = FALSE;
|
||||
|
||||
/* If we have been given an options string, parse options here. */
|
||||
for (i = 1; i < env_argc - 1; i++)
|
||||
if (!strcmp(env_argv[i], "-o"))
|
||||
optset_parse(optset_table, env_argv[++i]);
|
||||
|
||||
/* Register init callbacks. */
|
||||
sef_setcb_init_fresh(sef_cb_init_fresh);
|
||||
sef_setcb_init_restart(sef_cb_init_fail);
|
||||
|
@ -95,22 +111,14 @@ static void sef_local_startup()
|
|||
lmfs_buf_pool(10);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_init_fresh *
|
||||
*===========================================================================*/
|
||||
static int sef_cb_init_fresh(int type, sef_init_info_t *info)
|
||||
{
|
||||
/* Initialize the iso9660fs server. */
|
||||
|
||||
/* hash_init(); */ /* Init the table with the ids */
|
||||
setenv("TZ","",1); /* Used to calculate the time */
|
||||
|
||||
return(OK);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_signal_handler *
|
||||
*===========================================================================*/
|
||||
static void sef_cb_signal_handler(int signo)
|
||||
{
|
||||
/* Only check for termination signal, ignore anything else. */
|
||||
|
@ -118,30 +126,23 @@ static void sef_cb_signal_handler(int signo)
|
|||
|
||||
/* No need to do a sync, as this is a read-only file system. */
|
||||
|
||||
/* If the file system has already been unmounted, exit immediately.
|
||||
/*
|
||||
* If the file system has already been unmounted, exit immediately.
|
||||
* We might not get another message.
|
||||
*/
|
||||
if (unmountdone) exit(0);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* get_work *
|
||||
*===========================================================================*/
|
||||
static void get_work(m_in)
|
||||
message *m_in; /* pointer to message */
|
||||
static void get_work(message *m_in)
|
||||
{
|
||||
int s; /* receive status */
|
||||
if (OK != (s = sef_receive(ANY, m_in))) /* wait for message */
|
||||
panic("sef_receive failed: %d", s);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* reply *
|
||||
*===========================================================================*/
|
||||
void reply(who, m_out)
|
||||
int who;
|
||||
message *m_out; /* report result */
|
||||
void reply(int who, message *m_out)
|
||||
{
|
||||
if (OK != ipc_send(who, m_out)) /* send the message */
|
||||
printf("ISOFS(%d) was unable to send reply\n", sef_self());
|
||||
}
|
||||
|
||||
|
|
|
@ -3,20 +3,12 @@
|
|||
#include <minix/vfsif.h>
|
||||
#include <minix/bdev.h>
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_sync *
|
||||
*===========================================================================*/
|
||||
int fs_sync()
|
||||
{
|
||||
/* Always mounted read only, so nothing to sync */
|
||||
return(OK); /* sync() can't fail */
|
||||
return OK; /* sync() can't fail */
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_new_driver *
|
||||
*===========================================================================*/
|
||||
int fs_new_driver(void)
|
||||
{
|
||||
/* Set a new driver endpoint for this device. */
|
||||
|
@ -31,17 +23,17 @@ int fs_new_driver(void)
|
|||
label_len = fs_m_in.m_vfs_fs_new_driver.path_len;
|
||||
|
||||
if (label_len > sizeof(label))
|
||||
return(EINVAL);
|
||||
return EINVAL;
|
||||
|
||||
r = sys_safecopyfrom(fs_m_in.m_source, label_gid, (vir_bytes) 0,
|
||||
(vir_bytes) label, label_len);
|
||||
|
||||
if (r != OK) {
|
||||
printf("ISOFS: fs_new_driver safecopyfrom failed (%d)\n", r);
|
||||
return(EINVAL);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
bdev_driver(dev, label);
|
||||
|
||||
return(OK);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,7 @@
|
|||
#include "const.h"
|
||||
#include "glo.h"
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_readsuper *
|
||||
*===========================================================================*/
|
||||
int fs_readsuper() {
|
||||
|
||||
cp_grant_id_t label_gid;
|
||||
size_t label_len;
|
||||
int r = OK;
|
||||
|
@ -19,13 +14,13 @@ int fs_readsuper() {
|
|||
label_len = fs_m_in.m_vfs_fs_readsuper.path_len;
|
||||
|
||||
if (label_len > sizeof(fs_dev_label))
|
||||
return(EINVAL);
|
||||
return EINVAL;
|
||||
|
||||
r = sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label,
|
||||
label_len);
|
||||
if (r != OK) {
|
||||
printf("ISOFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r);
|
||||
return(EINVAL);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Map the driver label for this major */
|
||||
|
@ -33,69 +28,62 @@ int fs_readsuper() {
|
|||
|
||||
/* Open the device the file system lives on in read only mode */
|
||||
if (bdev_open(fs_dev, BDEV_R_BIT) != OK) {
|
||||
return(EINVAL);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Read the superblock */
|
||||
r = read_vds(&v_pri, fs_dev);
|
||||
if (r != OK) {
|
||||
bdev_close(fs_dev);
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
lmfs_set_blocksize(v_pri.logical_block_size_l, major(fs_dev));
|
||||
|
||||
/* Return some root inode properties */
|
||||
fs_m_out.m_fs_vfs_readsuper.inode = ID_DIR_RECORD(v_pri.dir_rec_root);
|
||||
fs_m_out.m_fs_vfs_readsuper.mode = v_pri.dir_rec_root->d_mode;
|
||||
fs_m_out.m_fs_vfs_readsuper.file_size = v_pri.dir_rec_root->d_file_size;
|
||||
fs_m_out.m_fs_vfs_readsuper.inode = v_pri.inode_root->i_stat.st_ino;
|
||||
fs_m_out.m_fs_vfs_readsuper.mode = v_pri.inode_root->i_stat.st_mode;
|
||||
fs_m_out.m_fs_vfs_readsuper.file_size = v_pri.inode_root->i_stat.st_size;
|
||||
fs_m_out.m_fs_vfs_readsuper.uid = SYS_UID; /* Always root */
|
||||
fs_m_out.m_fs_vfs_readsuper.gid = SYS_GID; /* operator */
|
||||
fs_m_out.m_fs_vfs_readsuper.flags = RES_NOFLAGS;
|
||||
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_mountpoint *
|
||||
*===========================================================================*/
|
||||
int fs_mountpoint()
|
||||
{
|
||||
/* This function looks up the mount point, it checks the condition whether
|
||||
* the partition can be mounted on the inode or not.
|
||||
/*
|
||||
* 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;
|
||||
struct inode *rip;
|
||||
int r = OK;
|
||||
|
||||
/* Temporarily open the file. */
|
||||
if ((rip = get_dir_record(fs_m_in.m_vfs_fs_mountpoint.inode)) == NULL)
|
||||
return(EINVAL);
|
||||
if ((rip = find_inode(fs_m_in.m_vfs_fs_mountpoint.inode)) == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (rip->d_mountpoint)
|
||||
if (rip->i_mountpoint)
|
||||
r = EBUSY;
|
||||
|
||||
/* If the inode is not a dir returns error */
|
||||
if ((rip->d_mode & I_TYPE) != I_DIRECTORY)
|
||||
if ((rip->i_stat.st_mode & I_TYPE) != I_DIRECTORY)
|
||||
r = ENOTDIR;
|
||||
|
||||
release_dir_record(rip);
|
||||
put_inode(rip);
|
||||
|
||||
if (r == OK)
|
||||
rip->d_mountpoint = TRUE;
|
||||
rip->i_mountpoint = TRUE;
|
||||
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_unmount *
|
||||
*===========================================================================*/
|
||||
int fs_unmount(void) {
|
||||
release_v_pri(&v_pri); /* Release the super block */
|
||||
int fs_unmount(void)
|
||||
{
|
||||
release_vol_pri_desc(&v_pri); /* Release the super block */
|
||||
bdev_close(fs_dev);
|
||||
unmountdone = TRUE;
|
||||
return(OK);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
#include <string.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/vfsif.h>
|
||||
|
||||
#include "buf.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
static char *get_name(char *name, char string[NAME_MAX+1]);
|
||||
static int ltraverse(struct inode *rip, char *suffix);
|
||||
static int parse_path(ino_t dir_ino, ino_t root_ino, int flags, struct
|
||||
dir_record **res_inop, size_t *offsetp);
|
||||
inode **res_inop, size_t *offsetp, int *symlinkp);
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -15,10 +15,10 @@ static int parse_path(ino_t dir_ino, ino_t root_ino, int flags, struct
|
|||
*===========================================================================*/
|
||||
int fs_lookup() {
|
||||
cp_grant_id_t grant;
|
||||
int r, len, flags;
|
||||
size_t offset;
|
||||
int r, len, flags, symlinks = 0;
|
||||
size_t offset = 0;
|
||||
ino_t dir_ino, root_ino;
|
||||
struct dir_record *dir;
|
||||
struct inode *dir = 0;
|
||||
|
||||
grant = fs_m_in.m_vfs_fs_lookup.grant_path;
|
||||
len = fs_m_in.m_vfs_fs_lookup.path_len; /* including terminating nul */
|
||||
|
@ -29,8 +29,10 @@ int fs_lookup() {
|
|||
caller_gid = fs_m_in.m_vfs_fs_lookup.gid;
|
||||
|
||||
/* Check length. */
|
||||
if(len > sizeof(user_path)) return(E2BIG); /* too big for buffer */
|
||||
if(len < 1) return(EINVAL); /* too small */
|
||||
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(VFS_PROC_NR, grant, 0, (vir_bytes) user_path,
|
||||
|
@ -38,39 +40,40 @@ int fs_lookup() {
|
|||
if (r != OK) {
|
||||
printf("ISOFS %s:%d sys_safecopyfrom failed: %d\n",
|
||||
__FILE__, __LINE__, r);
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Verify this is a null-terminated path. */
|
||||
if(user_path[len-1] != '\0') return(EINVAL);
|
||||
if(user_path[len-1] != '\0')
|
||||
return EINVAL;
|
||||
|
||||
/* Lookup inode */
|
||||
dir = NULL;
|
||||
offset = 0;
|
||||
r = parse_path(dir_ino, root_ino, flags, &dir, &offset);
|
||||
r = parse_path(dir_ino, root_ino, flags, &dir, &offset, &symlinks);
|
||||
|
||||
if (r == ELEAVEMOUNT) {
|
||||
if(r == ELEAVEMOUNT || r == ESYMLINK) {
|
||||
/* Report offset and the error */
|
||||
fs_m_out.m_fs_vfs_lookup.offset = offset;
|
||||
fs_m_out.m_fs_vfs_lookup.symloop = 0;
|
||||
return(r);
|
||||
fs_m_out.m_fs_vfs_lookup.symloop = symlinks;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r != OK && r != EENTERMOUNT) return(r);
|
||||
if (r != OK && r != EENTERMOUNT)
|
||||
return r;
|
||||
|
||||
fs_m_out.m_fs_vfs_lookup.inode = ID_DIR_RECORD(dir);
|
||||
fs_m_out.m_fs_vfs_lookup.mode = dir->d_mode;
|
||||
fs_m_out.m_fs_vfs_lookup.file_size = dir->d_file_size;
|
||||
fs_m_out.m_fs_vfs_lookup.inode = dir->i_stat.st_ino;
|
||||
fs_m_out.m_fs_vfs_lookup.mode = dir->i_stat.st_mode;
|
||||
fs_m_out.m_fs_vfs_lookup.file_size = dir->i_stat.st_size;
|
||||
fs_m_out.m_fs_vfs_lookup.device = dir->i_stat.st_rdev;
|
||||
fs_m_out.m_fs_vfs_lookup.symloop = 0;
|
||||
fs_m_out.m_fs_vfs_lookup.uid = SYS_UID; /* root */
|
||||
fs_m_out.m_fs_vfs_lookup.gid = SYS_GID; /* operator */
|
||||
fs_m_out.m_fs_vfs_lookup.uid = dir->i_stat.st_uid;
|
||||
fs_m_out.m_fs_vfs_lookup.gid = dir->i_stat.st_gid;
|
||||
|
||||
if (r == EENTERMOUNT) {
|
||||
fs_m_out.m_fs_vfs_lookup.offset = offset;
|
||||
release_dir_record(dir);
|
||||
put_inode(dir);
|
||||
}
|
||||
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* The search dir actually performs the operation of searching for the
|
||||
|
@ -80,101 +83,78 @@ int fs_lookup() {
|
|||
* search_dir *
|
||||
*===========================================================================*/
|
||||
int search_dir(
|
||||
register struct dir_record *ldir_ptr, /* dir record parent */
|
||||
struct inode *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;
|
||||
int pos;
|
||||
char* comma_pos = NULL;
|
||||
char tmp_string[NAME_MAX];
|
||||
struct inode *dir_tmp;
|
||||
size_t pos = 0;
|
||||
int r;
|
||||
|
||||
/* This function search a particular element (in string) in a inode and
|
||||
* return its number */
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
if ((ldir_ptr->i_stat.st_mode & S_IFMT) != S_IFDIR)
|
||||
return ENOTDIR;
|
||||
|
||||
if (strcmp(string, ".") == 0) {
|
||||
*numb = ID_DIR_RECORD(ldir_ptr);
|
||||
*numb = ldir_ptr->i_stat.st_ino;
|
||||
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); */
|
||||
/*
|
||||
* Parent directories need special attention to make sure directory
|
||||
* inodes stay consistent.
|
||||
*/
|
||||
if (strcmp(string, "..") == 0) {
|
||||
if (ldir_ptr->i_stat.st_ino == v_pri.inode_root->i_stat.st_ino) {
|
||||
*numb = v_pri.inode_root->i_stat.st_ino;
|
||||
return OK;
|
||||
}
|
||||
else {
|
||||
dir_tmp = alloc_inode();
|
||||
r = read_inode(dir_tmp, ldir_ptr->extent, pos, &pos);
|
||||
if ((r != OK) || (pos >= ldir_ptr->i_stat.st_size)) {
|
||||
put_inode(dir_tmp);
|
||||
return EINVAL;
|
||||
}
|
||||
r = read_inode(dir_tmp, ldir_ptr->extent, pos, &pos);
|
||||
if ((r != OK) || (pos >= ldir_ptr->i_stat.st_size)) {
|
||||
put_inode(dir_tmp);
|
||||
return EINVAL;
|
||||
}
|
||||
*numb = dir_tmp->i_stat.st_ino;
|
||||
put_inode(dir_tmp);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the dir's content */
|
||||
pos = ldir_ptr->ext_attr_rec_length;
|
||||
bp = get_block(ldir_ptr->loc_extent_l);
|
||||
|
||||
if (bp == NULL)
|
||||
return EINVAL;
|
||||
|
||||
while (pos < v_pri.logical_block_size_l) {
|
||||
if ((dir_tmp = get_free_dir_record()) == NULL) {
|
||||
put_block(bp);
|
||||
while (TRUE) {
|
||||
dir_tmp = alloc_inode();
|
||||
r = read_inode(dir_tmp, ldir_ptr->extent, pos, &pos);
|
||||
if ((r != OK) || (pos >= ldir_ptr->i_stat.st_size)) {
|
||||
put_inode(dir_tmp);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (create_dir_record(dir_tmp,b_data(bp) + 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);
|
||||
if ((strcmp(dir_tmp->i_name, string) == 0) ||
|
||||
(strcmp(dir_tmp->i_name, "..") && strcmp(string, "..") == 0)) {
|
||||
if (dir_tmp->i_stat.st_ino == v_pri.inode_root->i_stat.st_ino) {
|
||||
*numb = v_pri.inode_root->i_stat.st_ino;
|
||||
put_inode(dir_tmp);
|
||||
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,b_data(bp));
|
||||
}
|
||||
|
||||
*numb = ID_DIR_RECORD(dir_tmp);
|
||||
release_dir_record(dir_tmp);
|
||||
put_block(bp);
|
||||
|
||||
*numb = dir_tmp->i_stat.st_ino;
|
||||
put_inode(dir_tmp);
|
||||
return OK;
|
||||
}
|
||||
|
||||
pos += dir_tmp->length;
|
||||
release_dir_record(dir_tmp);
|
||||
put_inode(dir_tmp);
|
||||
}
|
||||
|
||||
put_block(bp);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,21 +165,23 @@ static int parse_path(
|
|||
ino_t dir_ino,
|
||||
ino_t root_ino,
|
||||
int flags,
|
||||
struct dir_record **res_inop,
|
||||
size_t *offsetp
|
||||
struct inode **res_inop,
|
||||
size_t *offsetp,
|
||||
int *symlinkp
|
||||
) {
|
||||
int r;
|
||||
char string[NAME_MAX+1];
|
||||
char *cp, *ncp;
|
||||
struct dir_record *start_dir, *old_dir;
|
||||
struct inode *start_dir = 0, *old_dir = 0;
|
||||
|
||||
/* Find starting inode inode according to the request message */
|
||||
if ((start_dir = get_dir_record(dir_ino)) == NULL) {
|
||||
if ((start_dir = find_inode(dir_ino)) == NULL) {
|
||||
printf("ISOFS: couldn't find starting inode %llu\n", dir_ino);
|
||||
return(ENOENT);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
cp = user_path;
|
||||
dup_inode(start_dir);
|
||||
|
||||
/* Scan the path component by component. */
|
||||
while (TRUE) {
|
||||
|
@ -209,15 +191,16 @@ size_t *offsetp
|
|||
*offsetp += cp-user_path;
|
||||
|
||||
/* Return EENTERMOUNT if we are at a mount point */
|
||||
if (start_dir->d_mountpoint)
|
||||
if (start_dir->i_mountpoint)
|
||||
return EENTERMOUNT;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (cp[0] == '/') {
|
||||
/* Special case code. If the remaining path consists of just
|
||||
* slashes, we need to look up '.'
|
||||
/*
|
||||
* Special case code. If the remaining path consists of
|
||||
* just slashes, we need to look up '.'
|
||||
*/
|
||||
while(cp[0] == '/')
|
||||
cp++;
|
||||
|
@ -227,7 +210,8 @@ size_t *offsetp
|
|||
}
|
||||
else
|
||||
ncp = get_name(cp, string);
|
||||
} else
|
||||
}
|
||||
else
|
||||
/* Just get the first component */
|
||||
ncp = get_name(cp, string);
|
||||
|
||||
|
@ -238,23 +222,24 @@ size_t *offsetp
|
|||
if (strcmp(string, "..") == 0) {
|
||||
|
||||
/* This condition is not necessary since it will never be the root filesystem */
|
||||
/* if (start_dir == dir_records) { */
|
||||
/* if (start_dir == v_pri.inode_root) { */
|
||||
/* cp = ncp; */
|
||||
/* continue; /\* Just ignore the '..' at a process' */
|
||||
/* * root. */
|
||||
/* *\/ */
|
||||
/* } */
|
||||
|
||||
if (start_dir == dir_records) {
|
||||
/* Climbing up mountpoint */
|
||||
release_dir_record(start_dir);
|
||||
if (start_dir == v_pri.inode_root) {
|
||||
/* Climbing up mountpoint. */
|
||||
put_inode(start_dir);
|
||||
*res_inop = NULL;
|
||||
*offsetp += cp-user_path;
|
||||
return ELEAVEMOUNT;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
/* Only check for a mount point if we are not looking for '..'. */
|
||||
if (start_dir->d_mountpoint) {
|
||||
if (start_dir->i_mountpoint) {
|
||||
*res_inop = start_dir;
|
||||
*offsetp += cp-user_path;
|
||||
return EENTERMOUNT;
|
||||
|
@ -267,64 +252,161 @@ size_t *offsetp
|
|||
r = advance(old_dir, string, &start_dir);
|
||||
|
||||
if (r != OK) {
|
||||
release_dir_record(old_dir);
|
||||
put_inode(old_dir);
|
||||
return r;
|
||||
}
|
||||
|
||||
release_dir_record(old_dir);
|
||||
/* The call to advance() succeeded. Fetch next component. */
|
||||
if (S_ISLNK(start_dir->i_stat.st_mode)) {
|
||||
|
||||
if (ncp[0] == '\0' && (flags & PATH_RET_SYMLINK)) {
|
||||
put_inode(old_dir);
|
||||
*res_inop = start_dir;
|
||||
*offsetp += ncp - user_path;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Extract path name from the symlink file */
|
||||
r = ltraverse(start_dir, ncp);
|
||||
ncp = user_path;
|
||||
*offsetp = 0;
|
||||
|
||||
/* Symloop limit reached? */
|
||||
if (++(*symlinkp) > _POSIX_SYMLOOP_MAX)
|
||||
r = ELOOP;
|
||||
|
||||
if (r != OK) {
|
||||
put_inode(old_dir);
|
||||
put_inode(start_dir);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ncp[0] == '/') {
|
||||
put_inode(old_dir);
|
||||
put_inode(start_dir);
|
||||
return ESYMLINK;
|
||||
}
|
||||
|
||||
put_inode(start_dir);
|
||||
dup_inode(old_dir);
|
||||
start_dir = old_dir;
|
||||
}
|
||||
|
||||
put_inode(old_dir);
|
||||
cp = ncp;
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* ltraverse *
|
||||
*===========================================================================*/
|
||||
static int ltraverse(
|
||||
struct inode *rip, /* symbolic link */
|
||||
char *suffix) /* current remaining path. Has to point in the
|
||||
* user_path buffer
|
||||
*/
|
||||
{
|
||||
/* Traverse a symbolic link. Copy the link text from the inode and insert
|
||||
* the text into the path. Return error code or report success. Base
|
||||
* directory has to be determined according to the first character of the
|
||||
* new pathname.
|
||||
*/
|
||||
|
||||
size_t llen; /* length of link */
|
||||
size_t slen; /* length of suffix */
|
||||
char *sp; /* start of link text */
|
||||
|
||||
llen = strlen(rip->s_link);
|
||||
sp = rip->s_link;
|
||||
slen = strlen(suffix);
|
||||
|
||||
/* The path we're parsing looks like this:
|
||||
* /already/processed/path/<link> or
|
||||
* /already/processed/path/<link>/not/yet/processed/path
|
||||
* After expanding the <link>, the path will look like
|
||||
* <expandedlink> or
|
||||
* <expandedlink>/not/yet/processed
|
||||
* In both cases user_path must have enough room to hold <expandedlink>.
|
||||
* However, in the latter case we have to move /not/yet/processed to the
|
||||
* right place first, before we expand <link>. When strlen(<expandedlink>) is
|
||||
* smaller than strlen(/already/processes/path), we move the suffix to the
|
||||
* left. Is strlen(<expandedlink>) greater then we move it to the right. Else
|
||||
* we do nothing.
|
||||
*/
|
||||
|
||||
if (slen > 0) { /* Do we have path after the link? */
|
||||
/* For simplicity we require that suffix starts with a slash */
|
||||
if (suffix[0] != '/') {
|
||||
panic("ltraverse: suffix does not start with a slash");
|
||||
}
|
||||
|
||||
/* To be able to expand the <link>, we have to move the 'suffix'
|
||||
* to the right place.
|
||||
*/
|
||||
if (slen + llen + 1 > sizeof(user_path))
|
||||
return ENAMETOOLONG;/* <expandedlink>+suffix+\0 does not fit*/
|
||||
if ((unsigned) (suffix - user_path) != llen) {
|
||||
/* Move suffix left or right */
|
||||
memmove(&user_path[llen], suffix, slen+1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (llen + 1 > sizeof(user_path))
|
||||
return ENAMETOOLONG; /* <expandedlink> + \0 does not fix */
|
||||
|
||||
/* Set terminating nul */
|
||||
user_path[llen]= '\0';
|
||||
}
|
||||
|
||||
/* Everything is set, now copy the expanded link to user_path */
|
||||
memmove(user_path, sp, llen);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* advance *
|
||||
*===========================================================================*/
|
||||
int advance(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 */
|
||||
int advance(
|
||||
struct inode *dirp, /* inode for directory to be searched */
|
||||
char string[NAME_MAX], /* component name to look for */
|
||||
struct inode **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;
|
||||
struct inode *rip = NULL;
|
||||
int r;
|
||||
ino_t numb;
|
||||
|
||||
/* If 'string' is empty, yield same inode straight away. */
|
||||
if (string[0] == '\0') {
|
||||
if (string[0] == '\0')
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/* Check for NULL. */
|
||||
if (dirp == NULL) {
|
||||
if (dirp == NULL)
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* If 'string' is not present in the directory, signal error. */
|
||||
if ( (r = search_dir(dirp, string, &numb)) != OK) {
|
||||
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);
|
||||
}
|
||||
if ( (rip = get_inode((int) numb)) == NULL)
|
||||
return err_code;
|
||||
|
||||
*resp= rip;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* get_name *
|
||||
*===========================================================================*/
|
||||
static char *get_name(path_name, string)
|
||||
char *path_name; /* path name to parse */
|
||||
char string[NAME_MAX+1]; /* component extracted from 'old_name' */
|
||||
static char *get_name(
|
||||
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).
|
||||
|
@ -357,15 +439,13 @@ char string[NAME_MAX+1]; /* component extracted from 'old_name' */
|
|||
|
||||
/* Special case of the string at cp is empty */
|
||||
if (len == 0)
|
||||
{
|
||||
/* Return "." */
|
||||
strlcpy(string, ".", NAME_MAX + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
memcpy(string, cp, len);
|
||||
string[len]= '\0';
|
||||
}
|
||||
|
||||
return ep;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
/* Function prototypes for iso9660 file system. */
|
||||
|
||||
struct dir_record;
|
||||
struct ext_attr_rec;
|
||||
struct iso9660_vd_pri;
|
||||
struct dir_extent;
|
||||
struct rrii_dir_record;
|
||||
struct iso9660_dir_record;
|
||||
struct iso9660_vol_pri_desc;
|
||||
struct inode;
|
||||
|
||||
#include <minix/libminixfs.h>
|
||||
|
||||
|
@ -10,20 +13,30 @@ struct iso9660_vd_pri;
|
|||
#define put_block(n) lmfs_put_block(n, FULL_DATA_BLOCK)
|
||||
|
||||
/* main.c */
|
||||
int main(void);
|
||||
int main(int argc, char *argv[]);
|
||||
void reply(int who, message *m_out);
|
||||
|
||||
/* inode.c */
|
||||
int create_dir_record(struct dir_record *dir, char *buffer, u32_t
|
||||
address);
|
||||
int create_ext_attr(struct ext_attr_rec *ext, char *buffer);
|
||||
int fs_getnode(void);
|
||||
int fs_putnode(void);
|
||||
struct dir_record *get_dir_record(ino_t id_dir);
|
||||
struct dir_record *get_free_dir_record(void);
|
||||
struct ext_attr_rec *get_free_ext_attr(void);
|
||||
struct dir_record *load_dir_record_from_disk(u32_t address);
|
||||
int release_dir_record(struct dir_record *dir);
|
||||
|
||||
struct inode* alloc_inode();
|
||||
struct inode* find_inode(ino_t i);
|
||||
void put_inode(struct inode *i);
|
||||
void dup_inode(struct inode *i_node);
|
||||
struct inode* get_inode(ino_t i);
|
||||
|
||||
int read_inode(struct inode *i_node, struct dir_extent *extent, size_t offset,
|
||||
size_t *new_offset);
|
||||
void read_inode_iso9660(struct inode *i, const struct iso9660_dir_record *dir_rec);
|
||||
void read_inode_extents(struct inode *i, const struct iso9660_dir_record *dir_rec,
|
||||
struct dir_extent *extent, size_t *offset);
|
||||
void read_inode_susp(struct inode *i, const struct iso9660_dir_record *dir_rec,
|
||||
struct buf *bp, size_t offset);
|
||||
|
||||
int check_dir_record(const struct iso9660_dir_record *d, size_t offset);
|
||||
|
||||
/* link.c */
|
||||
int fs_rdlink(void);
|
||||
|
||||
/* misc.c */
|
||||
int fs_sync(void);
|
||||
|
@ -36,29 +49,44 @@ int fs_unmount(void);
|
|||
|
||||
/* path.c */
|
||||
int fs_lookup(void);
|
||||
int advance(struct dir_record *dirp, char string[NAME_MAX], struct
|
||||
dir_record **resp);
|
||||
int search_dir(struct dir_record *ldir_ptr, char string [NAME_MAX], ino_t *numb);
|
||||
int advance(struct inode *dirp, char string[NAME_MAX], struct
|
||||
inode **resp);
|
||||
int search_dir(struct inode *ldir_ptr, char string [NAME_MAX], ino_t *numb);
|
||||
|
||||
/* read.c */
|
||||
int fs_read(void);
|
||||
int fs_bread(void);
|
||||
int fs_getdents(void);
|
||||
int read_chunk(struct dir_record *rip, u64_t position, unsigned off, int
|
||||
int read_chunk(struct inode *rip, u64_t position, unsigned off, int
|
||||
chunk, unsigned left, cp_grant_id_t gid, unsigned buf_off, int
|
||||
block_size, int *completed, int rw);
|
||||
|
||||
|
||||
/* stadir.c */
|
||||
int fs_stat(void);
|
||||
int fs_statvfs(void);
|
||||
|
||||
/* super.c */
|
||||
int release_v_pri(struct iso9660_vd_pri *v_pri);
|
||||
int read_vds(struct iso9660_vd_pri *v_pri, dev_t dev);
|
||||
int create_v_pri(struct iso9660_vd_pri *v_pri, char *buffer, unsigned
|
||||
long address);
|
||||
int release_vol_pri_desc(struct iso9660_vol_pri_desc *v_pri);
|
||||
int create_vol_pri_desc(struct iso9660_vol_pri_desc *v_pri, char *buf,
|
||||
size_t address);
|
||||
int read_vds(struct iso9660_vol_pri_desc *v_pri, dev_t dev);
|
||||
|
||||
/* susp.c */
|
||||
int parse_susp(struct rrii_dir_record *dir, char *buffer);
|
||||
void parse_susp_buffer(struct rrii_dir_record *dir, char *buffer, u32_t size);
|
||||
|
||||
/* susp_rock_ridge.c */
|
||||
void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length);
|
||||
int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer);
|
||||
|
||||
/* utility.c */
|
||||
struct dir_extent* alloc_extent();
|
||||
void free_extent(struct dir_extent *extent);
|
||||
struct buf* read_extent_block(struct dir_extent *e, size_t block);
|
||||
size_t get_extent_absolute_block_id(struct dir_extent *e, size_t block);
|
||||
|
||||
time_t date7_to_time_t(const u8_t *date);
|
||||
int do_noop(void);
|
||||
int no_sys(void);
|
||||
|
||||
|
|
|
@ -4,23 +4,16 @@
|
|||
#include <minix/minlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include "buf.h"
|
||||
|
||||
static char getdents_buf[GETDENTS_BUFSIZ];
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_read *
|
||||
*===========================================================================*/
|
||||
int fs_read(void) {
|
||||
int r, chunk, block_size;
|
||||
size_t nrbytes;
|
||||
int fs_read(void)
|
||||
{
|
||||
int r = OK, chunk, block_size, completed, rw;
|
||||
size_t nrbytes, off, cum_io;
|
||||
cp_grant_id_t gid;
|
||||
off_t position, f_size, bytes_left;
|
||||
unsigned int off, cum_io;
|
||||
int completed;
|
||||
struct dir_record *dir;
|
||||
int rw;
|
||||
struct inode *i_node;
|
||||
|
||||
switch(fs_m_in.m_type) {
|
||||
case REQ_READ: rw = READING; break;
|
||||
|
@ -28,70 +21,67 @@ int fs_read(void) {
|
|||
default: panic("odd m_type");
|
||||
}
|
||||
|
||||
r = OK;
|
||||
|
||||
/* Try to get inode according to its index */
|
||||
dir = get_dir_record(fs_m_in.m_vfs_fs_readwrite.inode);
|
||||
if (dir == NULL) return(EINVAL); /* no inode found */
|
||||
/* Try to get inode according to its index. */
|
||||
i_node = find_inode(fs_m_in.m_vfs_fs_readwrite.inode);
|
||||
if (i_node == NULL)
|
||||
return EINVAL; /* No inode found. */
|
||||
|
||||
position = fs_m_in.m_vfs_fs_readwrite.seek_pos;
|
||||
nrbytes = fs_m_in.m_vfs_fs_readwrite.nbytes; /* number of bytes to read */
|
||||
nrbytes = fs_m_in.m_vfs_fs_readwrite.nbytes; /* Number of bytes to read. */
|
||||
block_size = v_pri.logical_block_size_l;
|
||||
gid = fs_m_in.m_vfs_fs_readwrite.grant;
|
||||
f_size = dir->d_file_size;
|
||||
|
||||
rdwt_err = OK; /* set to EIO if disk error occurs */
|
||||
|
||||
f_size = i_node->i_stat.st_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 = position % block_size;
|
||||
|
||||
chunk = MIN(nrbytes, block_size - off);
|
||||
if (chunk < 0) chunk = 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 = (int32_t) bytes_left;
|
||||
if (position >= f_size)
|
||||
break; /* We are beyond EOF. */
|
||||
if (chunk > bytes_left)
|
||||
chunk = (int32_t) bytes_left;
|
||||
|
||||
/* Read or write 'chunk' bytes. */
|
||||
r = read_chunk(dir, position, off, chunk,
|
||||
r = read_chunk(i_node, position, off, chunk,
|
||||
(uint32_t) nrbytes, gid, cum_io, block_size,
|
||||
&completed, rw);
|
||||
|
||||
if (r != OK) break; /* EOF reached */
|
||||
if (rdwt_err < 0) break;
|
||||
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 */
|
||||
nrbytes -= chunk; /* Bytes yet to be read. */
|
||||
cum_io += chunk; /* Bytes read so far. */
|
||||
position += chunk; /* Position within the file. */
|
||||
}
|
||||
|
||||
fs_m_out.m_fs_vfs_readwrite.seek_pos = position;
|
||||
|
||||
if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
|
||||
if (rdwt_err == END_OF_FILE) r = OK;
|
||||
if (rdwt_err != OK)
|
||||
r = rdwt_err; /* Check for disk error. */
|
||||
if (rdwt_err == END_OF_FILE)
|
||||
r = OK;
|
||||
|
||||
fs_m_out.m_fs_vfs_readwrite.nbytes = cum_io; /*dir->d_file_size;*/
|
||||
release_dir_record(dir);
|
||||
|
||||
return(r);
|
||||
fs_m_out.m_fs_vfs_readwrite.nbytes = cum_io;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_bread *
|
||||
*===========================================================================*/
|
||||
int fs_bread(void)
|
||||
{
|
||||
int r, rw_flag, chunk, block_size;
|
||||
int r = OK, rw_flag, chunk, block_size, completed;
|
||||
size_t nrbytes, off, cum_io;
|
||||
cp_grant_id_t gid;
|
||||
int nrbytes;
|
||||
u64_t position;
|
||||
unsigned int off, cum_io;
|
||||
int completed;
|
||||
struct dir_record *dir;
|
||||
off_t position;
|
||||
struct inode *i_node;
|
||||
|
||||
r = OK;
|
||||
|
||||
|
@ -100,9 +90,11 @@ int fs_bread(void)
|
|||
position = fs_m_in.m_vfs_fs_breadwrite.seek_pos;
|
||||
nrbytes = fs_m_in.m_vfs_fs_breadwrite.nbytes;
|
||||
block_size = v_pri.logical_block_size_l;
|
||||
dir = v_pri.dir_rec_root;
|
||||
i_node = v_pri.inode_root;
|
||||
|
||||
if(rw_flag == WRITING)
|
||||
return EIO; /* Not supported */
|
||||
|
||||
if(rw_flag == WRITING) return (EIO); /* Not supported */
|
||||
rdwt_err = OK; /* set to EIO if disk error occurs */
|
||||
|
||||
cum_io = 0;
|
||||
|
@ -111,14 +103,17 @@ int fs_bread(void)
|
|||
off = (unsigned int)(position % block_size); /* offset in blk*/
|
||||
|
||||
chunk = MIN(nrbytes, block_size - off);
|
||||
if (chunk < 0) chunk = block_size - off;
|
||||
if (chunk < 0)
|
||||
chunk = block_size - off;
|
||||
|
||||
/* Read 'chunk' bytes. */
|
||||
r = read_chunk(dir, position, off, chunk, (unsigned) nrbytes,
|
||||
r = read_chunk(i_node, position, off, chunk, (unsigned) nrbytes,
|
||||
gid, cum_io, block_size, &completed, READING);
|
||||
|
||||
if (r != OK) break; /* EOF reached */
|
||||
if (rdwt_err < 0) break;
|
||||
if (r != OK)
|
||||
break; /* EOF reached */
|
||||
if (rdwt_err < 0)
|
||||
break;
|
||||
|
||||
/* Update counters and pointers. */
|
||||
nrbytes -= chunk; /* bytes yet to be read */
|
||||
|
@ -128,220 +123,139 @@ int fs_bread(void)
|
|||
|
||||
fs_m_out.m_fs_vfs_breadwrite.seek_pos = position;
|
||||
|
||||
if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
|
||||
if (rdwt_err == END_OF_FILE) r = OK;
|
||||
if (rdwt_err != OK)
|
||||
r = rdwt_err; /* check for disk error */
|
||||
if (rdwt_err == END_OF_FILE)
|
||||
r = OK;
|
||||
|
||||
fs_m_out.m_fs_vfs_breadwrite.nbytes = cum_io;
|
||||
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_getdents *
|
||||
*===========================================================================*/
|
||||
int fs_getdents(void)
|
||||
{
|
||||
struct dir_record *dir;
|
||||
struct inode *i_node, *i_node_tmp;
|
||||
ino_t ino;
|
||||
cp_grant_id_t gid;
|
||||
size_t block_size;
|
||||
off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off;
|
||||
struct buf *bp;
|
||||
struct dir_record *dir_tmp;
|
||||
size_t old_pos = 0, cur_pos, new_pos, tmpbuf_off = 0, userbuf_off = 0, grant_size;
|
||||
struct dirent *dirp;
|
||||
int r,done,o,len,reclen;
|
||||
int r, 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.m_vfs_fs_getdents.inode;
|
||||
gid = fs_m_in.m_vfs_fs_getdents.grant;
|
||||
pos = fs_m_in.m_vfs_fs_getdents.seek_pos;
|
||||
cur_pos = fs_m_in.m_vfs_fs_getdents.seek_pos;
|
||||
grant_size = fs_m_in.m_vfs_fs_getdents.mem_size;
|
||||
|
||||
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 */
|
||||
//memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
|
||||
|
||||
if ((dir = get_dir_record(ino)) == NULL) return(EINVAL);
|
||||
if ((i_node = get_inode(ino)) == NULL)
|
||||
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 == NULL) {
|
||||
release_dir_record(dir);
|
||||
return(EINVAL);
|
||||
while (TRUE) {
|
||||
i_node_tmp = alloc_inode();
|
||||
r = read_inode(i_node_tmp, i_node->extent, cur_pos, &new_pos);
|
||||
if ((r != OK) || (new_pos >= i_node->i_stat.st_size)) {
|
||||
put_inode(i_node);
|
||||
put_inode(i_node_tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
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,b_data(bp) + 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)
|
||||
strlcpy(name, ".", NAME_MAX + 1);
|
||||
else if (dir_tmp->file_id[0] == 1)
|
||||
strlcpy(name, "..", NAME_MAX + 1);
|
||||
else {
|
||||
/* 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;
|
||||
|
||||
/* Tidy up file name */
|
||||
cp = memchr(name, ';', NAME_MAX);
|
||||
if (cp != NULL) name[cp - name] = 0;
|
||||
|
||||
/*If no file extension, then remove final '.'*/
|
||||
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;
|
||||
}
|
||||
|
||||
strlcpy(name_old, name, NAME_MAX + 1);
|
||||
cur_pos = new_pos;
|
||||
|
||||
/* Compute the length of the name */
|
||||
cp = memchr(name, '\0', NAME_MAX);
|
||||
cp = memchr(i_node_tmp->i_name, '\0', NAME_MAX);
|
||||
if (cp == NULL)
|
||||
len = NAME_MAX;
|
||||
else
|
||||
len= cp - name;
|
||||
len = cp - i_node_tmp->i_name;
|
||||
|
||||
/* Compute record length; also does alignment. */
|
||||
reclen = _DIRENT_RECLEN(dirp, len);
|
||||
|
||||
/* If the new record does not fit, then copy the buffer
|
||||
* and start from the beginning. */
|
||||
if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) {
|
||||
if (tmpbuf_off + reclen > GETDENTS_BUFSIZ ||
|
||||
userbuf_off + tmpbuf_off + reclen > grant_size) {
|
||||
r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
|
||||
(vir_bytes)getdents_buf, tmpbuf_offset);
|
||||
(vir_bytes)getdents_buf, tmpbuf_off);
|
||||
|
||||
if (r != OK)
|
||||
panic("fs_getdents: sys_safecopyto failed: %d", r);
|
||||
userbuf_off += tmpbuf_offset;
|
||||
tmpbuf_offset= 0;
|
||||
|
||||
/* Check if the user grant buffer is filled. */
|
||||
if (userbuf_off + tmpbuf_off + reclen > grant_size) {
|
||||
fs_m_out.m_fs_vfs_getdents.nbytes = userbuf_off + tmpbuf_off;
|
||||
fs_m_out.m_fs_vfs_getdents.seek_pos = old_pos;
|
||||
return OK;
|
||||
}
|
||||
|
||||
userbuf_off += tmpbuf_off;
|
||||
tmpbuf_off = 0;
|
||||
}
|
||||
|
||||
/* The standard data structure is created using the
|
||||
* data in the buffer. */
|
||||
dirp = (struct dirent *) &getdents_buf[tmpbuf_offset];
|
||||
dirp->d_fileno = (u32_t)(b_data(bp) + (size_t)block_pos);
|
||||
dirp = (struct dirent *) &getdents_buf[tmpbuf_off];
|
||||
dirp->d_fileno = i_node_tmp->i_stat.st_ino;
|
||||
dirp->d_reclen = reclen;
|
||||
dirp->d_type = fs_mode_to_type(dir_tmp->d_mode);
|
||||
dirp->d_type = fs_mode_to_type(i_node_tmp->i_stat.st_mode);
|
||||
dirp->d_namlen = len;
|
||||
memcpy(dirp->d_name, name, len);
|
||||
|
||||
memcpy(dirp->d_name, i_node_tmp->i_name, len);
|
||||
dirp->d_name[len]= '\0';
|
||||
tmpbuf_offset += reclen;
|
||||
|
||||
cur_pos += dir_tmp->length;
|
||||
release_dir_record(dir_tmp);
|
||||
tmpbuf_off += reclen;
|
||||
put_inode(i_node_tmp);
|
||||
|
||||
old_pos = cur_pos;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (tmpbuf_off != 0) {
|
||||
r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
|
||||
(vir_bytes) getdents_buf, tmpbuf_offset);
|
||||
(vir_bytes) getdents_buf, tmpbuf_off);
|
||||
|
||||
if (r != OK)
|
||||
panic("fs_getdents: sys_safecopyto failed: %d", r);
|
||||
|
||||
userbuf_off += tmpbuf_offset;
|
||||
userbuf_off += tmpbuf_off;
|
||||
}
|
||||
|
||||
fs_m_out.m_fs_vfs_getdents.nbytes = userbuf_off;
|
||||
fs_m_out.m_fs_vfs_getdents.seek_pos = cur_pos;
|
||||
|
||||
release_dir_record(dir); /* release the inode */
|
||||
return(OK);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* read_chunk *
|
||||
*===========================================================================*/
|
||||
int read_chunk(dir, position, off, chunk, left, gid, buf_off, block_size, completed, rw)
|
||||
register struct dir_record *dir;/* pointer to inode for file to be rd/wr */
|
||||
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 */
|
||||
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 */
|
||||
int rw; /* READING or PEEKING */
|
||||
int read_chunk(
|
||||
struct inode *i_node, /* pointer to inode for file to be rd/wr */
|
||||
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 */
|
||||
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 */
|
||||
int rw) /* READING or PEEKING */
|
||||
{
|
||||
|
||||
register struct buf *bp;
|
||||
register int r = OK;
|
||||
block_t b;
|
||||
int file_unit, rel_block, offset;
|
||||
struct buf *bp;
|
||||
int r = OK;
|
||||
|
||||
*completed = 0;
|
||||
|
||||
if ((ex64lo(position) <= dir->d_file_size) &&
|
||||
(ex64lo(position) > dir->data_length_l)) {
|
||||
while ((dir->d_next != NULL) && (ex64lo(position) > dir->data_length_l)) {
|
||||
position -= dir->data_length_l;
|
||||
dir = dir->d_next;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir->inter_gap_size != 0) {
|
||||
rel_block = (unsigned long)(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 + (unsigned long)(position / block_size);
|
||||
/* Physical position to read. */
|
||||
}
|
||||
|
||||
bp = get_block(b);
|
||||
|
||||
/* In all cases, bp now points to a valid buffer. */
|
||||
if (bp == NULL) {
|
||||
bp = read_extent_block(i_node->extent, position / block_size);
|
||||
if (bp == NULL)
|
||||
panic("bp not valid in rw_chunk; this can't happen");
|
||||
}
|
||||
|
||||
if(rw == READING) {
|
||||
r = sys_safecopyto(VFS_PROC_NR, gid, buf_off,
|
||||
(vir_bytes) (b_data(bp)+off), (phys_bytes) chunk);
|
||||
(vir_bytes) (b_data(bp)+off),
|
||||
(phys_bytes) chunk);
|
||||
}
|
||||
|
||||
put_block(bp);
|
||||
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,97 +8,25 @@
|
|||
|
||||
#include <minix/vfsif.h>
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* stat_dir_record *
|
||||
*===========================================================================*/
|
||||
static int stat_dir_record(
|
||||
register struct dir_record *dir, /* pointer to dir record to stat */
|
||||
int pipe_pos, /* position in a pipe, supplied by fstat() */
|
||||
endpoint_t who_e, /* Caller endpoint */
|
||||
cp_grant_id_t gid /* grant for the stat buf */
|
||||
)
|
||||
{
|
||||
/* 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. */
|
||||
|
||||
/* Common code for stat and fstat system calls. */
|
||||
struct stat statbuf;
|
||||
int r;
|
||||
struct tm ltime;
|
||||
time_t time1;
|
||||
u32_t blocks;
|
||||
|
||||
blocks = v_pri.volume_space_size_l;
|
||||
/* The unit of blocks should be 512 */
|
||||
assert(v_pri.logical_block_size_l >= 512);
|
||||
blocks = blocks * (v_pri.logical_block_size_l >> 9);
|
||||
|
||||
memset(&statbuf, 0, sizeof(struct stat));
|
||||
|
||||
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 */
|
||||
statbuf.st_blksize = v_pri.logical_block_size_l;
|
||||
statbuf.st_blocks = blocks;
|
||||
|
||||
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));
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_stat *
|
||||
*===========================================================================*/
|
||||
int fs_stat()
|
||||
{
|
||||
register int r; /* return value */
|
||||
struct dir_record *dir;
|
||||
r = EINVAL;
|
||||
int r = EINVAL; /* return value */
|
||||
struct inode *dir;
|
||||
|
||||
if ((dir = get_dir_record(fs_m_in.m_vfs_fs_stat.inode)) != NULL) {
|
||||
r = stat_dir_record(dir, 0, fs_m_in.m_source, fs_m_in.m_vfs_fs_stat.grant);
|
||||
release_dir_record(dir);
|
||||
if ((dir = get_inode(fs_m_in.m_vfs_fs_stat.inode)) != NULL) {
|
||||
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_stat.grant,
|
||||
0, (vir_bytes) &dir->i_stat,
|
||||
(phys_bytes) sizeof(dir->i_stat));
|
||||
put_inode(dir);
|
||||
}
|
||||
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* fs_statvfs *
|
||||
*===========================================================================*/
|
||||
int fs_statvfs()
|
||||
{
|
||||
struct statvfs st;
|
||||
int r;
|
||||
struct statvfs st;
|
||||
|
||||
memset(&st, 0, sizeof(st));
|
||||
|
||||
|
@ -112,12 +40,9 @@ int fs_statvfs()
|
|||
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_statvfs.grant, 0,
|
||||
(vir_bytes) &st, (phys_bytes) sizeof(st));
|
||||
|
||||
return(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* blockstats *
|
||||
*===========================================================================*/
|
||||
void fs_blockstats(u64_t *blocks, u64_t *free, u64_t *used)
|
||||
{
|
||||
*used = *blocks = v_pri.volume_space_size_l;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/* Functions to manage the superblock of the filesystem. These functions are
|
||||
* are called at the beginning and at the end of the server. */
|
||||
/*
|
||||
* 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>
|
||||
|
@ -7,112 +9,104 @@
|
|||
#include <minix/u64.h>
|
||||
#include <minix/bdev.h>
|
||||
|
||||
/* This function is called when the filesystem is umounted. It releases the
|
||||
* super block. */
|
||||
int release_v_pri(v_pri)
|
||||
register struct iso9660_vd_pri *v_pri;
|
||||
int release_vol_pri_desc(struct iso9660_vol_pri_desc *vol_pri)
|
||||
{
|
||||
/* Release the root dir record */
|
||||
release_dir_record(v_pri->dir_rec_root);
|
||||
v_pri->count = 0;
|
||||
/* Release the root dir root. */
|
||||
if (vol_pri->i_count > 0) {
|
||||
put_inode(vol_pri->inode_root);
|
||||
vol_pri->inode_root = NULL;
|
||||
vol_pri->i_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
|
||||
* . */
|
||||
int create_v_pri(v_pri,buf,address)
|
||||
register struct iso9660_vd_pri *v_pri;
|
||||
register char* buf;
|
||||
register unsigned long address;
|
||||
int create_vol_pri_desc(struct iso9660_vol_pri_desc *vol_pri, char *buf,
|
||||
size_t address)
|
||||
{
|
||||
struct dir_record *dir;
|
||||
/*
|
||||
* This function fullfill the super block data structure using the
|
||||
* information contained in the buffer.
|
||||
*/
|
||||
struct iso9660_dir_record *root_record;
|
||||
struct inode *root;
|
||||
struct dir_extent *extent;
|
||||
|
||||
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));
|
||||
if (vol_pri->i_count > 0)
|
||||
release_vol_pri_desc(vol_pri);
|
||||
|
||||
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(vol_pri, buf, 2048);
|
||||
|
||||
/* Check various fields for consistency. */
|
||||
if ((memcmp(vol_pri->standard_id, "CD001", ISO9660_SIZE_STANDARD_ID) != 0) ||
|
||||
(vol_pri->vd_version != 1) ||
|
||||
(vol_pri->logical_block_size_l < 2048) ||
|
||||
(vol_pri->file_struct_ver != 1))
|
||||
return EINVAL;
|
||||
|
||||
lmfs_set_blocksize(vol_pri->logical_block_size_l, major(fs_dev));
|
||||
|
||||
/* Read root directory record. */
|
||||
root_record = (struct iso9660_dir_record *)vol_pri->root_directory;
|
||||
root = alloc_inode();
|
||||
extent = alloc_extent();
|
||||
|
||||
extent->location = root_record->loc_extent_l + root_record->ext_attr_rec_length;
|
||||
extent->length = root_record->data_length_l / vol_pri->logical_block_size_l;
|
||||
if (root_record->data_length_l % vol_pri->logical_block_size_l)
|
||||
extent->length++;
|
||||
|
||||
if (read_inode(root, extent, 0, NULL) != OK) {
|
||||
free_extent(extent);
|
||||
put_inode(root);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
free_extent(extent);
|
||||
vol_pri->inode_root = root;
|
||||
vol_pri->i_count = 1;
|
||||
|
||||
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. */
|
||||
int read_vds(
|
||||
register struct iso9660_vd_pri *v_pri,
|
||||
register dev_t dev
|
||||
)
|
||||
int read_vds(struct iso9660_vol_pri_desc *vol_pri, dev_t dev)
|
||||
{
|
||||
u64_t offset;
|
||||
int vol_ok = FALSE;
|
||||
/*
|
||||
* This function reads from a ISO9660 filesystem (in the device dev) the
|
||||
* super block and saves it in vol_pri.
|
||||
*/
|
||||
size_t offset;
|
||||
int vol_ok = FALSE, vol_pri_flag = FALSE;
|
||||
int r;
|
||||
static char sbbuf[ISO9660_MIN_BLOCK_SIZE];
|
||||
int i = 0;
|
||||
|
||||
offset = ((u64_t)(ISO9660_SUPER_BLOCK_POSITION));
|
||||
while (!vol_ok && i++<MAX_ATTEMPTS) {
|
||||
|
||||
for(offset = ISO9660_SUPER_BLOCK_POSITION; !vol_ok && i++ < MAX_ATTEMPTS;
|
||||
offset += ISO9660_MIN_BLOCK_SIZE) {
|
||||
/* Read the sector of the super block. */
|
||||
r = bdev_read(dev, offset, sbbuf, ISO9660_MIN_BLOCK_SIZE, BDEV_NOFLAGS);
|
||||
|
||||
if (r != ISO9660_MIN_BLOCK_SIZE) /* Damaged sector or what? */
|
||||
continue;
|
||||
if (r != ISO9660_MIN_BLOCK_SIZE) {
|
||||
/* Damaged sector or what? */
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if ((sbbuf[0] & BYTE) == VD_PRIMARY) {
|
||||
create_v_pri(v_pri,sbbuf,offset); /* copy the buffer in the data structure. */
|
||||
/* Copy the buffer in the data structure. */
|
||||
if (create_vol_pri_desc(vol_pri, sbbuf, offset) == OK) {
|
||||
vol_pri_flag = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((sbbuf[0] & BYTE) == VD_SET_TERM)
|
||||
if ((sbbuf[0] & BYTE) == VD_SET_TERM) {
|
||||
/* I dont need to save anything about it */
|
||||
vol_ok = TRUE;
|
||||
|
||||
offset += ISO9660_MIN_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if (vol_ok == FALSE)
|
||||
if (vol_ok == FALSE || vol_pri_flag == FALSE)
|
||||
return EINVAL; /* If no superblock was found... */
|
||||
else
|
||||
return OK; /* otherwise. */
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* This file contains the definitions of a ISO9660 structures */
|
||||
/* This file contains the definitions of ISO9660 volume descriptors. */
|
||||
#include "inode.h"
|
||||
|
||||
#define VD_BOOT_RECORD 0
|
||||
|
@ -9,19 +9,27 @@
|
|||
|
||||
#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 */
|
||||
struct iso9660_vd_pri {
|
||||
/* Structure for the primary volume descriptor. */
|
||||
struct iso9660_vol_pri_desc {
|
||||
/*
|
||||
* On-disk structure format of the primary volume descriptor,
|
||||
* 2048 bytes long. See ISO specs for details.
|
||||
*/
|
||||
u8_t vd_type;
|
||||
char standard_id[ISO9660_SIZE_STANDARD_ID];
|
||||
u8_t vd_version;
|
||||
u8_t pad1;
|
||||
char system_id[ISO9660_SIZE_SYS_ID];
|
||||
char volume_id[ISO9660_SIZE_VOLUME_ID];
|
||||
u8_t pad2[8];
|
||||
u32_t volume_space_size_l;
|
||||
u32_t volume_space_size_m;
|
||||
u32_t volume_set_size;
|
||||
u32_t volume_sequence_number;
|
||||
u8_t pad3[32];
|
||||
u16_t volume_set_size_l;
|
||||
u16_t volume_set_size_m;
|
||||
u16_t volume_sequence_number_l;
|
||||
u16_t volume_sequence_number_m;
|
||||
u16_t logical_block_size_l;
|
||||
u16_t logical_block_size_m;
|
||||
u32_t path_table_size_l;
|
||||
|
@ -30,7 +38,7 @@ struct iso9660_vd_pri {
|
|||
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;
|
||||
u8_t root_directory[34];
|
||||
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];
|
||||
|
@ -38,11 +46,18 @@ struct iso9660_vd_pri {
|
|||
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];
|
||||
char volume_cre_date[ISO9660_SIZE_DATE17];
|
||||
char volume_mod_date[ISO9660_SIZE_DATE17];
|
||||
char volume_exp_date[ISO9660_SIZE_DATE17];
|
||||
char volume_eff_date[ISO9660_SIZE_DATE17];
|
||||
u8_t file_struct_ver;
|
||||
/* The rest is either not specified or reserved */
|
||||
u8_t count;
|
||||
} v_pri;
|
||||
u8_t reserved1;
|
||||
u8_t application_use[512];
|
||||
u8_t reserved2[652];
|
||||
|
||||
/* End of the on-disk structure format. */
|
||||
|
||||
struct inode *inode_root;
|
||||
int i_count;
|
||||
} __attribute__((packed)) v_pri;
|
||||
|
||||
|
|
130
minix/fs/iso9660fs/susp.c
Normal file
130
minix/fs/iso9660fs/susp.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* This file contains support for System Use Sharing Protocol (SUSP) extension
|
||||
* to ISO 9660.
|
||||
*/
|
||||
|
||||
#include "inc.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
int parse_susp(struct rrii_dir_record *dir, char *buffer)
|
||||
{
|
||||
/* Parse fundamental SUSP entries */
|
||||
char susp_signature[2];
|
||||
u8_t susp_length;
|
||||
u8_t susp_version;
|
||||
|
||||
u32_t ca_block_nr;
|
||||
u32_t ca_offset;
|
||||
u32_t ca_length;
|
||||
struct buf *ca_bp;
|
||||
|
||||
susp_signature[0] = buffer[0];
|
||||
susp_signature[1] = buffer[1];
|
||||
susp_length = *((u8_t*)buffer + 2);
|
||||
susp_version = *((u8_t*)buffer + 3);
|
||||
|
||||
if ((susp_signature[0] == 'C') && (susp_signature[1] == 'E') &&
|
||||
(susp_length >= 28) && (susp_version >= 1)) {
|
||||
/*
|
||||
* Continuation area, perform a recursion.
|
||||
*
|
||||
* FIXME: Currently we're parsing only first logical block of a
|
||||
* continuation area, and infinite recursion is not checked.
|
||||
*/
|
||||
|
||||
ca_block_nr = *((u32_t*)(buffer + 4));
|
||||
ca_offset = *((u32_t*)(buffer + 12));
|
||||
ca_length = *((u32_t*)(buffer + 20));
|
||||
|
||||
/* Truncate continuation area to fit one logical block. */
|
||||
if (ca_offset >= v_pri.logical_block_size_l) {
|
||||
return EINVAL;
|
||||
}
|
||||
if (ca_offset + ca_length > v_pri.logical_block_size_l) {
|
||||
ca_length = v_pri.logical_block_size_l - ca_offset;
|
||||
}
|
||||
|
||||
ca_bp = get_block(ca_block_nr);
|
||||
if (ca_bp == NULL) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
parse_susp_buffer(dir, b_data(ca_bp) + ca_offset, ca_length);
|
||||
put_block(ca_bp);
|
||||
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'D')) {
|
||||
/* Padding, skip. */
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'P')) {
|
||||
/* Ignored, skip. */
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'T')) {
|
||||
/* Terminator entry, stop processing. */
|
||||
return(ECANCELED);
|
||||
}
|
||||
else if ((susp_signature[0] == 'E') && (susp_signature[1] == 'R')) {
|
||||
/* Ignored, skip. */
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'E') && (susp_signature[1] == 'S')) {
|
||||
/* Ignored, skip. */
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Not a SUSP fundamental entry. */
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
void parse_susp_buffer(struct rrii_dir_record *dir, char *buffer, u32_t size)
|
||||
{
|
||||
/*
|
||||
* Parse a SUSP system use entry for the ISO 9660.
|
||||
* This is the main entry point for parsing SUSP data : SUSP entries are
|
||||
* routed from here to the relevant handling functions.
|
||||
*/
|
||||
char susp_signature[2];
|
||||
u8_t susp_length;
|
||||
|
||||
int parser_return;
|
||||
|
||||
while (TRUE) {
|
||||
/* A SUSP entry can't be smaller than 4 bytes. */
|
||||
if (size < 4)
|
||||
return;
|
||||
|
||||
susp_signature[0] = buffer[0];
|
||||
susp_signature[1] = buffer[1];
|
||||
susp_length = *((u8_t*)buffer + 2);
|
||||
|
||||
/* Check if SUSP entry is present. */
|
||||
if (((susp_signature[0] == 0) && (susp_signature[1] == 0)) ||
|
||||
(susp_length > size) || (susp_length < 4))
|
||||
return;
|
||||
|
||||
/* Check for SUSP fundamental entry. */
|
||||
parser_return = parse_susp(dir, buffer);
|
||||
if (parser_return == ECANCELED)
|
||||
return;
|
||||
else if (parser_return == OK)
|
||||
goto next_entry;
|
||||
|
||||
/* Check for Rock Ridge entry. */
|
||||
if (opt.norock == FALSE) {
|
||||
parser_return = parse_susp_rock_ridge(dir, buffer);
|
||||
if (parser_return == ECANCELED)
|
||||
return;
|
||||
else if (parser_return == OK)
|
||||
goto next_entry;
|
||||
}
|
||||
|
||||
/* Parse next SUSP entry. */
|
||||
next_entry:
|
||||
buffer += susp_length;
|
||||
size -= susp_length;
|
||||
}
|
||||
}
|
||||
|
248
minix/fs/iso9660fs/susp_rock_ridge.c
Normal file
248
minix/fs/iso9660fs/susp_rock_ridge.c
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* This file contains support for Rock Ridge Interchange Protocol (RRIP)
|
||||
* extension to ISO 9660.
|
||||
*/
|
||||
|
||||
#include "inc.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length)
|
||||
{
|
||||
/* Parse a Rock Ridge SUSP symbolic link entry (SL). */
|
||||
int offset = 0;
|
||||
int slink_size;
|
||||
u8_t flags, component_length;
|
||||
|
||||
while (offset + 2 <= length) {
|
||||
flags = *((u8_t*)(buffer + offset));
|
||||
component_length = *((u8_t*)(buffer + offset + 1));
|
||||
|
||||
/* Add directory separator if necessary. */
|
||||
if (dir->slink_rrip[0] != '\0') {
|
||||
slink_size = strlen(dir->slink_rrip);
|
||||
if (slink_size + 2 >= ISO9660_RRIP_MAX_FILE_ID_LEN)
|
||||
return;
|
||||
|
||||
dir->slink_rrip[slink_size] = '/';
|
||||
slink_size++;
|
||||
}
|
||||
else
|
||||
slink_size = strlen(dir->slink_rrip);
|
||||
|
||||
switch (flags & 0xF) {
|
||||
case 0:
|
||||
case 1: {
|
||||
/*
|
||||
* Directory path component.
|
||||
* Check if component fits within SL entry and
|
||||
* within symbolic link field.
|
||||
*/
|
||||
if ((component_length > length - offset) ||
|
||||
(slink_size + component_length + 1 >=
|
||||
ISO9660_RRIP_MAX_FILE_ID_LEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
strlcpy(dir->slink_rrip + slink_size,
|
||||
buffer + offset + 2, component_length+1);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
/* Current directory path component. */
|
||||
if (slink_size + 2 >=
|
||||
ISO9660_RRIP_MAX_FILE_ID_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcat(dir->slink_rrip + slink_size, ".");
|
||||
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
/* Parent directory path component. */
|
||||
if (slink_size + 3 >=
|
||||
ISO9660_RRIP_MAX_FILE_ID_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcat(dir->slink_rrip + slink_size, "..");
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
/* Root directory path component relative to
|
||||
the current process. */
|
||||
if (slink_size + 2 >=
|
||||
ISO9660_RRIP_MAX_FILE_ID_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcat(dir->slink_rrip + slink_size, "/");
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* Unsupported/invalid flags. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
offset += component_length + 2;
|
||||
}
|
||||
}
|
||||
|
||||
int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer)
|
||||
{
|
||||
/* Parse Rock Ridge SUSP entries for a directory entry. */
|
||||
char susp_signature[2];
|
||||
u8_t susp_length;
|
||||
u8_t susp_version;
|
||||
|
||||
int rrii_name_current_size;
|
||||
int rrii_name_append_size;
|
||||
int rrii_tf_flags;
|
||||
int rrii_tf_offset;
|
||||
u32_t rrii_pn_rdev_major;
|
||||
u32_t rrii_pn_rdev_minor;
|
||||
mode_t rrii_px_posix_mode;
|
||||
|
||||
susp_signature[0] = buffer[0];
|
||||
susp_signature[1] = buffer[1];
|
||||
susp_length = *((u8_t*)buffer + 2);
|
||||
susp_version = *((u8_t*)buffer + 3);
|
||||
|
||||
if ((susp_signature[0] == 'P') && (susp_signature[1] == 'X') &&
|
||||
(susp_length >= 36) && (susp_version >= 1)) {
|
||||
/* POSIX file mode, UID and GID. */
|
||||
rrii_px_posix_mode = *((u32_t*)(buffer + 4));
|
||||
|
||||
/* Check if file mode is supported by isofs. */
|
||||
switch (rrii_px_posix_mode & _S_IFMT) {
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
case S_IFREG:
|
||||
case S_IFDIR:
|
||||
case S_IFLNK: {
|
||||
dir->d_mode = rrii_px_posix_mode & _S_IFMT;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* Fall back to what ISO 9660 said. */
|
||||
dir->d_mode &= _S_IFMT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dir->d_mode |= rrii_px_posix_mode & 07777;
|
||||
dir->uid = *((u32_t*)(buffer + 20));
|
||||
dir->gid = *((u32_t*)(buffer + 28));
|
||||
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'N') &&
|
||||
(susp_length >= 20) && (susp_version >= 1)) {
|
||||
/* Device ID (for character or block special inode). */
|
||||
rrii_pn_rdev_major = *((u32_t*)(buffer + 4));
|
||||
rrii_pn_rdev_minor = *((u32_t*)(buffer + 12));
|
||||
|
||||
dir->rdev = makedev(rrii_pn_rdev_major, rrii_pn_rdev_minor);
|
||||
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'L') &&
|
||||
(susp_length > 5) && (susp_version >= 1)) {
|
||||
/* Symbolic link target. Multiple entries may be used to
|
||||
concatenate the complete path target. */
|
||||
parse_susp_rock_ridge_sl(dir, buffer + 5, susp_length - 5);
|
||||
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'N') && (susp_signature[1] == 'M') &&
|
||||
(susp_length > 5) && (susp_version >= 1)) {
|
||||
/* Alternate POSIX name. Multiple entries may be used to
|
||||
concatenate the complete filename. */
|
||||
rrii_name_current_size = strlen(dir->file_id_rrip);
|
||||
rrii_name_append_size = susp_length - 5;
|
||||
|
||||
/* Concatenate only if name component fits. */
|
||||
if (rrii_name_current_size + rrii_name_append_size + 1 <
|
||||
ISO9660_RRIP_MAX_FILE_ID_LEN) {
|
||||
strlcpy(dir->file_id_rrip + rrii_name_current_size,
|
||||
buffer + 5, rrii_name_append_size+1);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L')) {
|
||||
/* Ignored, skip. */
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L')) {
|
||||
/* Ignored, skip. */
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'R') && (susp_signature[1] == 'E')) {
|
||||
/* Ignored, skip. */
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'T') && (susp_signature[1] == 'F') &&
|
||||
(susp_length >= 5) && (susp_version >= 1)) {
|
||||
/* POSIX timestamp. */
|
||||
rrii_tf_flags = buffer[5];
|
||||
rrii_tf_offset = 5;
|
||||
|
||||
/*
|
||||
* ISO 9660 17-byte time format.
|
||||
* FIXME: 17-byte time format not supported in TF entry.
|
||||
*/
|
||||
if (rrii_tf_flags & (1 << 7)) { }
|
||||
|
||||
/* ISO 9660 7-byte time format. */
|
||||
else {
|
||||
/* Creation time */
|
||||
if ((rrii_tf_flags & (1 << 0)) &&
|
||||
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
|
||||
memcpy(dir->birthtime, buffer+rrii_tf_offset,
|
||||
ISO9660_SIZE_DATE7);
|
||||
rrii_tf_offset += ISO9660_SIZE_DATE7;
|
||||
}
|
||||
|
||||
/* Modification time */
|
||||
if ((rrii_tf_flags & (1 << 1)) &&
|
||||
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
|
||||
memcpy(dir->mtime, buffer+rrii_tf_offset,
|
||||
ISO9660_SIZE_DATE7);
|
||||
rrii_tf_offset += ISO9660_SIZE_DATE7;
|
||||
}
|
||||
|
||||
/* Last access time. */
|
||||
if ((rrii_tf_flags & (1 << 2)) &&
|
||||
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
|
||||
memcpy(dir->atime, buffer+rrii_tf_offset,
|
||||
ISO9660_SIZE_DATE7);
|
||||
rrii_tf_offset += ISO9660_SIZE_DATE7;
|
||||
}
|
||||
|
||||
/* Last attribute change time. */
|
||||
if ((rrii_tf_flags & (1 << 3)) &&
|
||||
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
|
||||
memcpy(dir->ctime, buffer+rrii_tf_offset,
|
||||
ISO9660_SIZE_DATE7);
|
||||
rrii_tf_offset += ISO9660_SIZE_DATE7;
|
||||
}
|
||||
|
||||
/* The rest is ignored. */
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'F')) {
|
||||
/* Ignored, skip. */
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Not a Rock Ridge entry. */
|
||||
return EINVAL;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
/* This file contains the table used to map system call numbers onto the
|
||||
/*
|
||||
* This file contains the table used to map system call numbers onto the
|
||||
* routines that perform them.
|
||||
*/
|
||||
|
||||
|
@ -38,13 +39,9 @@ int (*fs_call_vec[])(void) = {
|
|||
fs_mountpoint, /* 27 */
|
||||
fs_readsuper, /* 28 */
|
||||
no_sys, /* 29: not used */
|
||||
no_sys, /* 30: not used */
|
||||
fs_rdlink, /* 30 */
|
||||
fs_getdents, /* 31 */
|
||||
#if 0
|
||||
fs_read, /* 32 */
|
||||
no_sys, /* 33 */
|
||||
#else
|
||||
no_sys, /* 32 */
|
||||
no_sys, /* 33 */
|
||||
#endif
|
||||
} ;
|
||||
|
||||
|
|
|
@ -5,21 +5,99 @@
|
|||
#include <minix/callnr.h>
|
||||
#include <minix/vfsif.h>
|
||||
|
||||
/*===========================================================================*
|
||||
* do_noop *
|
||||
*===========================================================================*/
|
||||
static struct dir_extent dir_extents[NR_DIR_EXTENT_RECORDS];
|
||||
|
||||
struct dir_extent* alloc_extent()
|
||||
{
|
||||
/* Return a free extent from the pool. */
|
||||
int i;
|
||||
struct dir_extent *extent;
|
||||
|
||||
for (i = 0; i < NR_DIR_EXTENT_RECORDS; i++) {
|
||||
extent = &dir_extents[i];
|
||||
|
||||
if (extent->in_use == 0) {
|
||||
memset(extent, 0, sizeof(*extent));
|
||||
extent->in_use = 1;
|
||||
|
||||
return extent;
|
||||
}
|
||||
}
|
||||
|
||||
panic("No free extents in cache");
|
||||
}
|
||||
|
||||
void free_extent(struct dir_extent *e)
|
||||
{
|
||||
if (e == NULL)
|
||||
return;
|
||||
|
||||
if (e->in_use == 0)
|
||||
panic("Trying to free unused extent");
|
||||
|
||||
free_extent(e->next);
|
||||
e->in_use = 0;
|
||||
}
|
||||
|
||||
struct buf* read_extent_block(struct dir_extent *e, size_t block)
|
||||
{
|
||||
size_t block_id = get_extent_absolute_block_id(e, block);
|
||||
|
||||
if (block_id == 0 || block_id >= v_pri.volume_space_size_l)
|
||||
return NULL;
|
||||
|
||||
return get_block(block_id);
|
||||
}
|
||||
|
||||
size_t get_extent_absolute_block_id(struct dir_extent *e, size_t block)
|
||||
{
|
||||
size_t extent_offset = 0;
|
||||
|
||||
if (e == NULL)
|
||||
return 0;
|
||||
|
||||
/* Retrieve the extent on which the block lies. */
|
||||
while(block > extent_offset + e->length) {
|
||||
if (e->next == NULL)
|
||||
return 0;
|
||||
|
||||
extent_offset += e->length;
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
return e->location + block - extent_offset;
|
||||
}
|
||||
|
||||
time_t date7_to_time_t(const u8_t *date)
|
||||
{
|
||||
/* This function converts from the ISO 9660 7-byte time format to a time_t. */
|
||||
struct tm ltime;
|
||||
signed char time_zone = (signed char)date[6];
|
||||
|
||||
ltime.tm_year = date[0];
|
||||
ltime.tm_mon = date[1] - 1;
|
||||
ltime.tm_mday = date[2];
|
||||
ltime.tm_hour = date[3];
|
||||
ltime.tm_min = date[4];
|
||||
ltime.tm_sec = date[5];
|
||||
ltime.tm_isdst = 0;
|
||||
|
||||
/* Offset from Greenwich Mean Time */
|
||||
if (time_zone >= -52 && time_zone <= 52)
|
||||
ltime.tm_hour += time_zone;
|
||||
|
||||
return mktime(<ime);
|
||||
}
|
||||
|
||||
int do_noop(void)
|
||||
{
|
||||
/* Do not do anything. */
|
||||
return(OK);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* no_sys *
|
||||
*===========================================================================*/
|
||||
int no_sys(void)
|
||||
{
|
||||
/* Somebody has used an illegal system call number */
|
||||
return(EINVAL);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue