From: Jean-Baptiste Boric Date: Sun, 3 Aug 2014 17:24:51 +0000 (+0200) Subject: iso9660fs: rewrite ISO 9660 file system server X-Git-Url: http://zhaoyanbai.com/repos/%22http:/static/doc/zpipe.c?a=commitdiff_plain;h=refs%2Fchanges%2F33%2F2833%2F2;p=minix.git 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 --- diff --git a/minix/fs/iso9660fs/Makefile b/minix/fs/iso9660fs/Makefile index d95cfd17a..69f05c7d5 100644 --- a/minix/fs/iso9660fs/Makefile +++ b/minix/fs/iso9660fs/Makefile @@ -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 diff --git a/minix/fs/iso9660fs/buf.h b/minix/fs/iso9660fs/buf.h deleted file mode 100644 index 39a19ce43..000000000 --- a/minix/fs/iso9660fs/buf.h +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#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 */ diff --git a/minix/fs/iso9660fs/const.h b/minix/fs/iso9660fs/const.h index 3174947f1..4443afd68 100644 --- a/minix/fs/iso9660fs/const.h +++ b/minix/fs/iso9660fs/const.h @@ -1,62 +1,51 @@ -#define GETDENTS_BUFSIZ 261 +#define GETDENTS_BUFSIZ 1024 -#define ISO9660_STANDARD_ID "CD001" /* Standard code for ISO9660 filesystems */ +#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_ADDRESS (-1) /* Error constants */ #define NO_FREE_INODES (-1) -#define PATH_PENULTIMATE 001 /* parse_path stops at last but one name */ -#define PATH_NONSYMBOLIC 004 /* parse_path scans final name if symbolic */ - -#define DIR_ENTRY_SIZE sizeof (struct direct) -#define NR_DIR_ENTRIES(b) ((b)/DIR_ENTRY_SIZE) +#define PATH_PENULTIMATE 001 /* parse_path stops at last but one name */ +#define PATH_NONSYMBOLIC 004 /* parse_path scans final name if symbolic */ /* Below there are constant of the ISO9660 fs */ - -#define ISO9660_SUPER_BLOCK_POSITION (32768) -#define ISO9660_MIN_BLOCK_SIZE 2048 +#define ISO9660_SUPER_BLOCK_POSITION 32768 +#define ISO9660_MIN_BLOCK_SIZE 2048 /* SIZES FIELDS ISO9660 STRUCTURES */ -#define ISO9660_SIZE_STANDARD_ID 5 -#define ISO9660_SIZE_BOOT_SYS_ID 32 -#define ISO9660_SIZE_BOOT_ID 32 - -#define ISO9660_SIZE_SYS_ID 32 -#define ISO9660_SIZE_VOLUME_ID 32 -#define ISO9660_SIZE_VOLUME_SET_ID 128 -#define ISO9660_SIZE_PUBLISHER_ID 128 -#define ISO9660_SIZE_DATA_PREP_ID 128 -#define ISO9660_SIZE_APPL_ID 128 -#define ISO9660_SIZE_COPYRIGHT_FILE_ID 37 -#define ISO9660_SIZE_ABSTRACT_FILE_ID 37 -#define ISO9660_SIZE_BIBL_FILE_ID 37 - -#define ISO9660_SIZE_VOL_CRE_DATE 17 -#define ISO9660_SIZE_VOL_MOD_DATE 17 -#define ISO9660_SIZE_VOL_EXP_DATE 17 -#define ISO9660_SIZE_VOL_EFF_DATE 17 - -#define ISO9660_SIZE_ESCAPE_SQC 32 -#define ISO9660_SIZE_PART_ID 32 - -#define ISO9660_SIZE_SYSTEM_USE 64 +#define ISO9660_SIZE_STANDARD_ID 5 +#define ISO9660_SIZE_BOOT_SYS_ID 32 +#define ISO9660_SIZE_BOOT_ID 32 + +#define ISO9660_SIZE_SYS_ID 32 +#define ISO9660_SIZE_VOLUME_ID 32 +#define ISO9660_SIZE_VOLUME_SET_ID 128 +#define ISO9660_SIZE_PUBLISHER_ID 128 +#define ISO9660_SIZE_DATA_PREP_ID 128 +#define ISO9660_SIZE_APPL_ID 128 +#define ISO9660_SIZE_COPYRIGHT_FILE_ID 37 +#define ISO9660_SIZE_ABSTRACT_FILE_ID 37 +#define ISO9660_SIZE_BIBL_FILE_ID 37 + +#define ISO9660_SIZE_DATE17 17 +#define ISO9660_SIZE_DATE7 7 + +#define ISO9660_SIZE_ESCAPE_SQC 32 +#define ISO9660_SIZE_PART_ID 32 + +#define ISO9660_SIZE_SYSTEM_USE 64 /* maximum size of length of name file used in dir records */ -#define ISO9660_MAX_FILE_ID_LEN 32 +#define ISO9660_MAX_FILE_ID_LEN 32 +#define ISO9660_RRIP_MAX_FILE_ID_LEN 256 -#define END_OF_FILE (-104) /* eof detected */ +#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 */ +#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 */ + diff --git a/minix/fs/iso9660fs/glo.h b/minix/fs/iso9660fs/glo.h index 46b0cd905..877e9e70a 100644 --- a/minix/fs/iso9660fs/glo.h +++ b/minix/fs/iso9660fs/glo.h @@ -4,30 +4,32 @@ #define EXTERN #endif +#include + /* The following variables are used for returning results to the caller. */ -EXTERN int err_code; /* temporary storage for error number */ -EXTERN int rdwt_err; /* status of last disk i/o request */ +EXTERN int err_code; /* temporary storage for error number */ +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_in; /* contains the input message of the request */ +EXTERN message fs_m_out; /* contains the output message of the request */ EXTERN int FS_STATE; EXTERN uid_t caller_uid; EXTERN gid_t caller_gid; -EXTERN int req_nr; /* request number to the server */ +EXTERN int req_nr; /* request number to the server */ -EXTERN short path_processed; /* number of characters processed */ +EXTERN short path_processed; /* number of characters processed */ EXTERN char user_path[PATH_MAX+1]; /* pathname to be processed */ EXTERN char *vfs_slink_storage; EXTERN int symloop; EXTERN 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 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 */ diff --git a/minix/fs/iso9660fs/inc.h b/minix/fs/iso9660fs/inc.h index 764236477..8bc447cc9 100644 --- a/minix/fs/iso9660fs/inc.h +++ b/minix/fs/iso9660fs/inc.h @@ -1,7 +1,7 @@ -#define _SYSTEM 1 /* get OK and negative error codes */ +#define _SYSTEM 1 /* get OK and negative error codes */ -#define VERBOSE 0 /* display diagnostics */ +#define VERBOSE 0 /* display diagnostics */ #include #include @@ -10,11 +10,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -24,8 +26,15 @@ #include #include #include +#include #include +#include +#include +#include + +#define b_data(bp) ((char *) (bp->data)) #include "proto.h" #include "super.h" #include "glo.h" + diff --git a/minix/fs/iso9660fs/inode.c b/minix/fs/iso9660fs/inode.c index e3e122fed..331772046 100644 --- a/minix/fs/iso9660fs/inode.c +++ b/minix/fs/iso9660fs/inode.c @@ -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 +#include +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); + + 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"); + } - 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; + i_node->i_count -= count - 1; + put_inode(i_node); + return OK; +} - 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); - } +struct inode* alloc_inode() +{ + /* + * Return a free inode from the pool. + */ + static int i; + int end = i; + struct inode *i_node; - if (dir->d_count > 1) - dir->d_count = dir->d_count - count + 1;/*Keep at least one reference*/ + i = (i + 1) % NR_INODE_RECORDS; + do { + i_node = &inodes[i]; - release_dir_record(dir); /* Actual inode release, might be last reference */ + if (i_node->i_count == 0) { + free_extent(i_node->extent); - return(OK); -} + memset(i_node, 0, sizeof(*i_node)); + i_node->i_count = 1; + return i_node; + } -/*===========================================================================* - * release_dir_record * - *===========================================================================*/ -int release_dir_record(dir) -struct dir_record *dir; -{ -/* Release a dir record (decrement the counter) */ - if (dir == NULL) - return(EINVAL); - - if (--dir->d_count == 0) { - if (dir->ext_attr != NULL) - dir->ext_attr->count = 0; - dir->ext_attr = NULL; - dir->d_mountpoint = FALSE; - - dir->d_prior = NULL; - if (dir->d_next != NULL) - release_dir_record(dir); - dir->d_next = NULL; - } - return(OK); -} + i = (i + 1) % NR_INODE_RECORDS; + } + while(i != end); + panic("No free inodes in cache"); +} -/*===========================================================================* - * get_free_dir_record * - *===========================================================================*/ -struct dir_record *get_free_dir_record(void) +struct inode* find_inode(ino_t i) { -/* Get a free dir record */ - struct dir_record *dir; - - for(dir = dir_records; dir < &dir_records[NR_ATTR_RECS]; dir++) { - if (dir->d_count == 0) { /* The record is free */ - dir->d_count = 1; /* Set count to 1 */ - dir->ext_attr = NULL; - return(dir); + /* Get inode from cache. */ + int cpt; + struct inode *i_node; + + 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; - - /* 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++; + struct inode *i_node; + struct dir_extent *extent; + + 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; } +void put_inode(struct inode *i_node) +{ + if (i_node == NULL) + return; -/*===========================================================================* - * 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); + if (i_node->i_count <= 0) + panic("put_inode: i_count already below 1: %d", i_node->i_count); + + i_node->i_count--; } +void dup_inode(struct inode *i_node) +{ + if (i_node == NULL) + panic("dup_inode: trying to duplicate NULL inode"); + + i_node->i_count++; +} -/*===========================================================================* - * create_ext_attr * - *===========================================================================*/ -int create_ext_attr(struct ext_attr_rec *ext,char *buffer) +static struct buf* fetch_inode(struct dir_extent *extent, size_t *offset) { -/* Fill an extent structure from the data read on the device */ - if (ext == NULL) return(EINVAL); - - /* In input we have a stream of bytes that are physically read from the - * device. This stream of data is copied 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)); - - return(OK); + struct iso9660_dir_record *dir_rec; + struct buf *bp; + + /* + * 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; + } + + 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; -/*===========================================================================* - * create_ext_attr * - *===========================================================================*/ -int create_dir_record(dir,buffer,address) -struct dir_record *dir; -char *buffer; -u32_t address; + /* Find inode. */ + bp = fetch_inode(extent, &offset); + if (bp == NULL) + return EOF; + + dir_rec = (struct iso9660_dir_record*)(b_data(bp) + offset % + v_pri.logical_block_size_l); + + /* Parse basic ISO 9660 specs. */ + if (check_dir_record(dir_rec, offset % v_pri.logical_block_size_l) != OK) { + put_block(bp); + return EINVAL; + } + + 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; +} + +void read_inode_iso9660(struct inode *i, const struct iso9660_dir_record *dir_rec) { -/* 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; - - 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); + 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); + } +} -/*===========================================================================* - * load_dir_record_from_disk * - *===========================================================================*/ -struct dir_record *load_dir_record_from_disk(address) -u32_t address; +void read_inode_susp(struct inode *i, const struct iso9660_dir_record *dir_rec, + struct buf *bp, 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 buf *bp; - struct dir_record *dir, *dir_next, *dir_parent, *dir_tmp; - char name[NAME_MAX + 1]; - char old_name[NAME_MAX + 1]; - u32_t new_address, size; - - block_size = v_pri.logical_block_size_l; /* Block size */ - block_nr = address / block_size; /* Block number from the address */ - offset = address % block_size; /* Offset starting from the block */ - - bp = get_block(block_nr); /* Read the block from the device */ - if (bp == NULL) - return(NULL); - - dir = get_free_dir_record(); /* Get a free record */ - if (dir == NULL) - return(NULL); - - /* 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; - } - - new_pos += dir_parent->length; - new_address += dir_next->length; - dir_parent = dir_next; - } else { /* This is another inode. */ - release_dir_record(dir_next); - new_pos = block_size; - } - } else { /* record not valid */ - release_dir_record(dir_next); - new_pos = block_size; /* Exit from the while */ + 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); } - } +} - put_block(bp); /* Release the block read. */ - return(dir); +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; } diff --git a/minix/fs/iso9660fs/inode.h b/minix/fs/iso9660fs/inode.h index d0e7bddcf..19ce1953e 100644 --- a/minix/fs/iso9660fs/inode.h +++ b/minix/fs/iso9660fs/inode.h @@ -1,67 +1,71 @@ #include "const.h" +#include -struct dir_record { - u8_t length; /* The length of the record */ - u8_t ext_attr_rec_length; - u32_t loc_extent_l; /* The same data (in this case loc_extent)is */ - u32_t loc_extent_m; /* saved in two ways. The first puts the le- */ - u32_t data_length_l; /* ast significant byte first, the second */ - u32_t data_length_m; /* does the opposite */ - u8_t rec_date[7]; /* => recording date */ - u8_t file_flags; /* => flags of the file */ - u8_t file_unit_size; /* set of blocks in interleave mode */ - u8_t inter_gap_size; /* gap between file units in interleave mode */ - u32_t vol_seq_number; /* volume sequence number: not used */ - u8_t length_file_id; /* Length name file */ - char file_id[ISO9660_MAX_FILE_ID_LEN]; /* file name */ - struct ext_attr_rec *ext_attr; +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 */ + u32_t loc_extent_m; /* saved in two ways. The first puts the le- */ + u32_t data_length_l; /* ast significant byte first, the second */ + u32_t data_length_m; /* does the opposite */ + u8_t rec_date[7]; /* => recording date */ + u8_t file_flags; /* => flags of the file */ + u8_t file_unit_size; /* set of blocks in interleave mode */ + u8_t inter_gap_size; /* gap between file units in interleave mode */ + u32_t vol_seq_number; /* volume sequence number: not used */ + u8_t length_file_id; /* Length name file */ + char file_id[ISO9660_MAX_FILE_ID_LEN]; /* file name */ +} __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; +} ; -#define D_DIRECTORY 0x2 -#define D_TYPE 0x8E - -/* Vector with all the ids of the dir records */ -/* PUBLIC struct hash_idi_entry { */ -/* u32_t h_phy_addr; */ -/* struct dir_record *h_dir_record; */ -/* } hash_idi[NR_ID_INODES]; */ +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 */ +} ; -/* PUBLIC int size_hash_idi; */ +struct opt { + /* + * Global mount options. + */ + int norock; /* Bool: dont use Rock Ridge */ +} ; -/* #define ID_DIR_RECORD(id) id - hash_idi + 1 */ -#define ID_DIR_RECORD(dir) dir->d_ino_nr +#define D_DIRECTORY 0x2 +#define D_NOT_LAST_EXTENT 0x80 +#define D_TYPE 0x8E -/* #define ASSIGN_ID 1 */ -/* #define NOT_ASSIGN_ID 0 */ diff --git a/minix/fs/iso9660fs/link.c b/minix/fs/iso9660fs/link.c new file mode 100644 index 000000000..7e7d2a7d4 --- /dev/null +++ b/minix/fs/iso9660fs/link.c @@ -0,0 +1,36 @@ +#include "inc.h" +#include +#include +#include +#ifdef __NBSD_LIBC +#include +#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; +} + diff --git a/minix/fs/iso9660fs/main.c b/minix/fs/iso9660fs/main.c index 0836c6a69..d0b53ebe4 100644 --- a/minix/fs/iso9660fs/main.c +++ b/minix/fs/iso9660fs/main.c @@ -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 @@ -15,64 +17,67 @@ 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) { - endpoint_t who_e; - int ind, error, transid; +static struct optset optset_table[] = { + { "norock", OPT_BOOL, &opt.norock, TRUE }, + { NULL, 0, NULL, 0 } +}; - /* SEF local startup. */ - sef_local_startup(); +int main(int argc, char *argv[]) { + endpoint_t who_e; + int ind, error, transid; - for (;;) { + /* SEF local startup. */ + env_setargs(argc, argv); + sef_local_startup(); - /* Wait for request message. */ - get_work(&fs_m_in); + while (TRUE) { + /* Wait for request message. */ + get_work(&fs_m_in); - transid = TRNS_GET_ID(fs_m_in.m_type); - fs_m_in.m_type = TRNS_DEL_ID(fs_m_in.m_type); - if (fs_m_in.m_type == 0) { - assert(!IS_VFS_FS_TRANSID(transid)); - fs_m_in.m_type = transid; /* Backwards compat. */ - transid = 0; - } else - assert(IS_VFS_FS_TRANSID(transid)); + transid = TRNS_GET_ID(fs_m_in.m_type); + fs_m_in.m_type = TRNS_DEL_ID(fs_m_in.m_type); + if (fs_m_in.m_type == 0) { + assert(!IS_VFS_FS_TRANSID(transid)); + fs_m_in.m_type = transid; /* Backwards compat. */ + transid = 0; + } + else + assert(IS_VFS_FS_TRANSID(transid)); - error = OK; + error = OK; - caller_uid = -1; /* To trap errors */ - caller_gid = -1; + caller_uid = -1; /* To trap errors */ + caller_gid = -1; - who_e = fs_m_in.m_source; /* source of the request */ + who_e = fs_m_in.m_source; /* source of the request */ - if (who_e != VFS_PROC_NR) { /* If the message is not for us just - * continue */ - continue; - } + if (who_e != VFS_PROC_NR) { /* If the message is not for us just + * continue */ + continue; + } - req_nr = fs_m_in.m_type; - - if (req_nr < FS_BASE) { - fs_m_in.m_type += FS_BASE; req_nr = fs_m_in.m_type; - } - ind = req_nr-FS_BASE; - - if (ind < 0 || ind >= NREQS) { - error = EINVAL; - } else - error = (*fs_call_vec[ind])(); /* Process the request calling - * the appropriate function. */ - - fs_m_out.m_type = error; - if (IS_VFS_FS_TRANSID(transid)) { - /* If a transaction ID was set, reset it */ - fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, transid); + if (req_nr < FS_BASE) { + fs_m_in.m_type += FS_BASE; + req_nr = fs_m_in.m_type; + } + + ind = req_nr - FS_BASE; + + if (ind < 0 || ind >= NREQS) + error = EINVAL; + else + error = (*fs_call_vec[ind])(); /* Process the request calling + * the appropriate function. */ + + fs_m_out.m_type = error; + if (IS_VFS_FS_TRANSID(transid)) { + /* If a transaction ID was set, reset it */ + fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, transid); + } + reply(who_e, &fs_m_out); /* returns the response to VFS */ } - reply(who_e, &fs_m_out); /* returns the response to VFS */ - } } /*===========================================================================* @@ -80,68 +85,64 @@ int main(void) { *===========================================================================*/ static void sef_local_startup() { - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); + /* 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); - /* No live update support for now. */ + /* No live update support for now. */ - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); + /* Register signal callbacks. */ + sef_setcb_signal_handler(sef_cb_signal_handler); - /* Let SEF perform startup. */ - sef_startup(); + /* Let SEF perform startup. */ + sef_startup(); - lmfs_buf_pool(10); + 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 */ + /* Initialize the iso9660fs server. */ + 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. */ - if (signo != SIGTERM) return; + /* Only check for termination signal, ignore anything else. */ + if (signo != SIGTERM) return; - /* No need to do a sync, as this is a read-only file system. */ + /* No need to do a sync, as this is a read-only file system. */ - /* If the file system has already been unmounted, exit immediately. - * We might not get another message. - */ - if (unmountdone) exit(0); + /* + * 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); + 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()); + if (OK != ipc_send(who, m_out)) /* send the message */ + printf("ISOFS(%d) was unable to send reply\n", sef_self()); } + diff --git a/minix/fs/iso9660fs/misc.c b/minix/fs/iso9660fs/misc.c index 6749affe5..d0ded206d 100644 --- a/minix/fs/iso9660fs/misc.c +++ b/minix/fs/iso9660fs/misc.c @@ -3,45 +3,37 @@ #include #include - -/*===========================================================================* - * fs_sync * - *===========================================================================*/ int fs_sync() { - /* Always mounted read only, so nothing to sync */ - return(OK); /* sync() can't fail */ + /* Always mounted read only, so nothing to sync */ + return OK; /* sync() can't fail */ } - -/*===========================================================================* - * fs_new_driver * - *===========================================================================*/ int fs_new_driver(void) { -/* Set a new driver endpoint for this device. */ - dev_t dev; - cp_grant_id_t label_gid; - size_t label_len; - char label[sizeof(fs_dev_label)]; - int r; - - dev = fs_m_in.m_vfs_fs_new_driver.device; - label_gid = fs_m_in.m_vfs_fs_new_driver.grant; - label_len = fs_m_in.m_vfs_fs_new_driver.path_len; - - if (label_len > sizeof(label)) - 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); - } - - bdev_driver(dev, label); - - return(OK); + /* Set a new driver endpoint for this device. */ + dev_t dev; + cp_grant_id_t label_gid; + size_t label_len; + char label[sizeof(fs_dev_label)]; + int r; + + dev = fs_m_in.m_vfs_fs_new_driver.device; + label_gid = fs_m_in.m_vfs_fs_new_driver.grant; + label_len = fs_m_in.m_vfs_fs_new_driver.path_len; + + if (label_len > sizeof(label)) + 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; + } + + bdev_driver(dev, label); + return OK; } + diff --git a/minix/fs/iso9660fs/mount.c b/minix/fs/iso9660fs/mount.c index b852ec9b9..423644d32 100644 --- a/minix/fs/iso9660fs/mount.c +++ b/minix/fs/iso9660fs/mount.c @@ -4,98 +4,86 @@ #include "const.h" #include "glo.h" - -/*===========================================================================* - * fs_readsuper * - *===========================================================================*/ int fs_readsuper() { + cp_grant_id_t label_gid; + size_t label_len; + int r = OK; - cp_grant_id_t label_gid; - size_t label_len; - int r = OK; - - fs_dev = fs_m_in.m_vfs_fs_readsuper.device; - label_gid = fs_m_in.m_vfs_fs_readsuper.grant; - label_len = fs_m_in.m_vfs_fs_readsuper.path_len; + fs_dev = fs_m_in.m_vfs_fs_readsuper.device; + label_gid = fs_m_in.m_vfs_fs_readsuper.grant; + label_len = fs_m_in.m_vfs_fs_readsuper.path_len; - if (label_len > sizeof(fs_dev_label)) - return(EINVAL); + if (label_len > sizeof(fs_dev_label)) + return EINVAL; - r = sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label, + 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); - } - - /* Map the driver label for this major */ - bdev_driver(fs_dev, fs_dev_label); - - /* Open the device the file system lives on in read only mode */ - if (bdev_open(fs_dev, BDEV_R_BIT) != OK) { - return(EINVAL); - } - - /* Read the superblock */ - r = read_vds(&v_pri, fs_dev); - if (r != OK) { - bdev_close(fs_dev); - return(r); - } + if (r != OK) { + printf("ISOFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r); + return EINVAL; + } + + /* Map the driver label for this major */ + bdev_driver(fs_dev, fs_dev_label); + + /* Open the device the file system lives on in read only mode */ + if (bdev_open(fs_dev, BDEV_R_BIT) != OK) { + return EINVAL; + } + + /* Read the superblock */ + r = read_vds(&v_pri, fs_dev); + if (r != OK) { + bdev_close(fs_dev); + return r; + } + + /* Return some root inode properties */ + 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; +} - lmfs_set_blocksize(v_pri.logical_block_size_l, major(fs_dev)); +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. + */ - /* 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.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; + struct inode *rip; + int r = OK; - return(r); -} + /* Temporarily open the file. */ + if ((rip = find_inode(fs_m_in.m_vfs_fs_mountpoint.inode)) == NULL) + return EINVAL; + if (rip->i_mountpoint) + r = EBUSY; -/*===========================================================================* - * 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. - */ - - register struct dir_record *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->d_mountpoint) - r = EBUSY; - - /* If the inode is not a dir returns error */ - if ((rip->d_mode & I_TYPE) != I_DIRECTORY) - r = ENOTDIR; - - release_dir_record(rip); - - if (r == OK) - rip->d_mountpoint = TRUE; - - return(r); + /* If the inode is not a dir returns error */ + if ((rip->i_stat.st_mode & I_TYPE) != I_DIRECTORY) + r = ENOTDIR; + + put_inode(rip); + + if (r == OK) + rip->i_mountpoint = TRUE; + + return r; } +int fs_unmount(void) +{ + release_vol_pri_desc(&v_pri); /* Release the super block */ + bdev_close(fs_dev); + unmountdone = TRUE; -/*===========================================================================* - * fs_unmount * - *===========================================================================*/ -int fs_unmount(void) { - release_v_pri(&v_pri); /* Release the super block */ - bdev_close(fs_dev); - unmountdone = TRUE; - return(OK); + return OK; } diff --git a/minix/fs/iso9660fs/path.c b/minix/fs/iso9660fs/path.c index 73c55a2fb..30ab4af7c 100644 --- a/minix/fs/iso9660fs/path.c +++ b/minix/fs/iso9660fs/path.c @@ -2,75 +2,78 @@ #include #include #include - -#include "buf.h" +#include 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); /*===========================================================================* * fs_lookup * *===========================================================================*/ int fs_lookup() { - cp_grant_id_t grant; - int r, len, flags; - size_t offset; - ino_t dir_ino, root_ino; - struct dir_record *dir; - - grant = fs_m_in.m_vfs_fs_lookup.grant_path; - len = fs_m_in.m_vfs_fs_lookup.path_len; /* including terminating nul */ - dir_ino = fs_m_in.m_vfs_fs_lookup.dir_ino; - root_ino = fs_m_in.m_vfs_fs_lookup.root_ino; - flags = fs_m_in.m_vfs_fs_lookup.flags; - caller_uid = fs_m_in.m_vfs_fs_lookup.uid; - 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 */ - - /* Copy the pathname and set up caller's user and group id */ - r = sys_safecopyfrom(VFS_PROC_NR, grant, 0, (vir_bytes) user_path, - (phys_bytes) len); - if (r != OK) { - printf("ISOFS %s:%d sys_safecopyfrom failed: %d\n", - __FILE__, __LINE__, r); - return(r); - } - - /* Verify this is a null-terminated path. */ - if(user_path[len-1] != '\0') return(EINVAL); - - /* Lookup inode */ - dir = NULL; - offset = 0; - r = parse_path(dir_ino, root_ino, flags, &dir, &offset); - - if (r == ELEAVEMOUNT) { - /* 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); - } - - 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.symloop = 0; - fs_m_out.m_fs_vfs_lookup.uid = SYS_UID; /* root */ - fs_m_out.m_fs_vfs_lookup.gid = SYS_GID; /* operator */ - - if (r == EENTERMOUNT) { - fs_m_out.m_fs_vfs_lookup.offset = offset; - release_dir_record(dir); - } - - return(r); + cp_grant_id_t grant; + int r, len, flags, symlinks = 0; + size_t offset = 0; + ino_t dir_ino, root_ino; + 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 */ + dir_ino = fs_m_in.m_vfs_fs_lookup.dir_ino; + root_ino = fs_m_in.m_vfs_fs_lookup.root_ino; + flags = fs_m_in.m_vfs_fs_lookup.flags; + caller_uid = fs_m_in.m_vfs_fs_lookup.uid; + 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 */ + + /* Copy the pathname and set up caller's user and group id */ + r = sys_safecopyfrom(VFS_PROC_NR, grant, 0, (vir_bytes) user_path, + (phys_bytes) len); + if (r != OK) { + printf("ISOFS %s:%d sys_safecopyfrom failed: %d\n", + __FILE__, __LINE__, r); + return r; + } + + /* Verify this is a null-terminated path. */ + if(user_path[len-1] != '\0') + return EINVAL; + + /* Lookup inode */ + r = parse_path(dir_ino, root_ino, flags, &dir, &offset, &symlinks); + + 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 = symlinks; + return r; + } + + if (r != OK && r != EENTERMOUNT) + return r; + + 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 = 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; + put_inode(dir); + } + + 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]; - - /* 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 (strcmp(string,".") == 0) { - *numb = ID_DIR_RECORD(ldir_ptr); - return OK; - } - - if (strcmp(string,"..") == 0 && ldir_ptr->loc_extent_l == v_pri.dir_rec_root->loc_extent_l) { - *numb = ROOT_INO_NR; -/* *numb = ID_DIR_RECORD(ldir_ptr); */ - return OK; - } - - /* Read the dir's content */ - pos = ldir_ptr->ext_attr_rec_length; - bp = get_block(ldir_ptr->loc_extent_l); - - if (bp == NULL) - return EINVAL; - - while (pos < v_pri.logical_block_size_l) { - if ((dir_tmp = get_free_dir_record()) == NULL) { - put_block(bp); - return EINVAL; - } - - if (create_dir_record(dir_tmp,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); - 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); - - return OK; - } - - pos += dir_tmp->length; - release_dir_record(dir_tmp); - } - - put_block(bp); - return EINVAL; + 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. + */ + + if ((ldir_ptr->i_stat.st_mode & S_IFMT) != S_IFDIR) + return ENOTDIR; + + if (strcmp(string, ".") == 0) { + *numb = ldir_ptr->i_stat.st_ino; + return OK; + } + + /* + * 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 */ + 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 ((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; + } + + *numb = dir_tmp->i_stat.st_ino; + put_inode(dir_tmp); + return OK; + } + + put_inode(dir_tmp); + } } @@ -185,187 +165,287 @@ 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; - - /* Find starting inode inode according to the request message */ - if ((start_dir = get_dir_record(dir_ino)) == NULL) { - printf("ISOFS: couldn't find starting inode %llu\n", dir_ino); - return(ENOENT); - } - - cp = user_path; - - /* Scan the path component by component. */ - while (TRUE) { - if (cp[0] == '\0') { - /* Empty path */ - *res_inop= start_dir; - *offsetp += cp-user_path; - - /* Return EENTERMOUNT if we are at a mount point */ - if (start_dir->d_mountpoint) - return EENTERMOUNT; - - return OK; - } - - if (cp[0] == '/') { - /* Special case code. If the remaining path consists of just - * slashes, we need to look up '.' - */ - while(cp[0] == '/') - cp++; - if (cp[0] == '\0') { - strlcpy(string, ".", NAME_MAX + 1); - ncp = cp; - } - else - ncp = get_name(cp, string); - } else - /* Just get the first component */ - ncp = get_name(cp, string); - - /* Special code for '..'. A process is not allowed to leave a chrooted - * environment. A lookup of '..' at the root of a mounted filesystem - * has to return ELEAVEMOUNT. - */ - if (strcmp(string, "..") == 0) { - - /* This condition is not necessary since it will never be the root filesystem */ - /* if (start_dir == dir_records) { */ - /* cp = ncp; */ - /* continue; /\* Just ignore the '..' at a process' */ - /* * root. */ - /* *\/ */ - /* } */ - - if (start_dir == dir_records) { - /* Climbing up mountpoint */ - release_dir_record(start_dir); - *res_inop = NULL; - *offsetp += cp-user_path; - return ELEAVEMOUNT; - } - } else { - /* Only check for a mount point if we are not looking for '..'. */ - if (start_dir->d_mountpoint) { - *res_inop= start_dir; - *offsetp += cp-user_path; - return EENTERMOUNT; - } - } - - /* There is more path. Keep parsing. */ - old_dir = start_dir; - - r = advance(old_dir, string, &start_dir); - - if (r != OK) { - release_dir_record(old_dir); - return r; - } - - release_dir_record(old_dir); - cp = ncp; - } + int r; + char string[NAME_MAX+1]; + char *cp, *ncp; + struct inode *start_dir = 0, *old_dir = 0; + + /* Find starting inode inode according to the request message */ + if ((start_dir = find_inode(dir_ino)) == NULL) { + printf("ISOFS: couldn't find starting inode %llu\n", dir_ino); + return ENOENT; + } + + cp = user_path; + dup_inode(start_dir); + + /* Scan the path component by component. */ + while (TRUE) { + if (cp[0] == '\0') { + /* Empty path */ + *res_inop = start_dir; + *offsetp += cp-user_path; + + /* Return EENTERMOUNT if we are at a mount point */ + if (start_dir->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 '.' + */ + while(cp[0] == '/') + cp++; + if (cp[0] == '\0') { + strlcpy(string, ".", NAME_MAX + 1); + ncp = cp; + } + else + ncp = get_name(cp, string); + } + else + /* Just get the first component */ + ncp = get_name(cp, string); + + /* Special code for '..'. A process is not allowed to leave a chrooted + * environment. A lookup of '..' at the root of a mounted filesystem + * has to return ELEAVEMOUNT. + */ + if (strcmp(string, "..") == 0) { + + /* This condition is not necessary since it will never be the root filesystem */ + /* if (start_dir == v_pri.inode_root) { */ + /* cp = ncp; */ + /* continue; /\* Just ignore the '..' at a process' */ + /* * root. */ + /* *\/ */ + /* } */ + + if (start_dir == v_pri.inode_root) { + /* Climbing up mountpoint. */ + put_inode(start_dir); + *res_inop = NULL; + *offsetp += cp-user_path; + return ELEAVEMOUNT; + } + } + else { + /* Only check for a mount point if we are not looking for '..'. */ + if (start_dir->i_mountpoint) { + *res_inop = start_dir; + *offsetp += cp-user_path; + return EENTERMOUNT; + } + } + + /* There is more path. Keep parsing. */ + old_dir = start_dir; + + r = advance(old_dir, string, &start_dir); + + if (r != OK) { + put_inode(old_dir); + return r; + } + + /* 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/ or + * /already/processed/path//not/yet/processed/path + * After expanding the , the path will look like + * or + * /not/yet/processed + * In both cases user_path must have enough room to hold . + * However, in the latter case we have to move /not/yet/processed to the + * right place first, before we expand . When strlen() is + * smaller than strlen(/already/processes/path), we move the suffix to the + * left. Is strlen() 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 , we have to move the 'suffix' + * to the right place. + */ + if (slen + llen + 1 > sizeof(user_path)) + return ENAMETOOLONG;/* +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; /* + \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; - int r; - ino_t numb; - - /* If 'string' is empty, yield same inode straight away. */ - if (string[0] == '\0') { - return ENOENT; - } - - /* Check for NULL. */ - if (dirp == NULL) { - return EINVAL; - } - - /* If 'string' is not present in the directory, signal error. */ - if ( (r = search_dir(dirp, string, &numb)) != OK) { - return r; - } - - /* The component has been found in the directory. Get inode. */ - if ( (rip = get_dir_record((int) numb)) == NULL) { - return(err_code); - } - - *resp= rip; - return OK; -} + /* 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. + */ + struct inode *rip = NULL; + int r; + ino_t numb; + + /* If 'string' is empty, yield same inode straight away. */ + if (string[0] == '\0') + return ENOENT; + + /* Check for NULL. */ + if (dirp == NULL) + return EINVAL; + + /* If 'string' is not present in the directory, signal error. */ + if ( (r = search_dir(dirp, string, &numb)) != OK) + return r; + + /* The component has been found in the directory. Get inode. */ + if ( (rip = get_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). - * A pointer to the string after the first component of the name as yet - * unparsed is returned. Roughly speaking, - * 'get_name' = 'path_name' - 'string'. - * - * This routine follows the standard convention that /usr/ast, /usr//ast, - * //usr///ast and /usr/ast/ are all equivalent. - */ - size_t len; - char *cp, *ep; - - cp= path_name; - - /* Skip leading slashes */ - while (cp[0] == '/') - cp++; - - /* Find the end of the first component */ - ep= cp; - while(ep[0] != '\0' && ep[0] != '/') - ep++; - - len= ep-cp; - - /* Truncate the amount to be copied if it exceeds NAME_MAX */ - if (len > NAME_MAX) - len= NAME_MAX; - - /* Special case of the string at cp is empty */ - if (len == 0) - { - /* Return "." */ - strlcpy(string, ".", NAME_MAX + 1); - } - else - { - memcpy(string, cp, len); - string[len]= '\0'; - } - - return ep; + /* Given a pointer to a path name in fs space, 'path_name', copy the first + * component to 'string' (truncated if necessary, always nul terminated). + * A pointer to the string after the first component of the name as yet + * unparsed is returned. Roughly speaking, + * 'get_name' = 'path_name' - 'string'. + * + * This routine follows the standard convention that /usr/ast, /usr//ast, + * //usr///ast and /usr/ast/ are all equivalent. + */ + size_t len; + char *cp, *ep; + + cp = path_name; + + /* Skip leading slashes */ + while (cp[0] == '/') + cp++; + + /* Find the end of the first component */ + ep = cp; + while(ep[0] != '\0' && ep[0] != '/') + ep++; + + len = ep-cp; + + /* Truncate the amount to be copied if it exceeds NAME_MAX */ + if (len > NAME_MAX) + len = NAME_MAX; + + /* Special case of the string at cp is empty */ + if (len == 0) + /* Return "." */ + strlcpy(string, ".", NAME_MAX + 1); + else { + memcpy(string, cp, len); + string[len]= '\0'; + } + + return ep; } + diff --git a/minix/fs/iso9660fs/proto.h b/minix/fs/iso9660fs/proto.h index faa39aaac..fbcc7055b 100644 --- a/minix/fs/iso9660fs/proto.h +++ b/minix/fs/iso9660fs/proto.h @@ -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 @@ -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); diff --git a/minix/fs/iso9660fs/read.c b/minix/fs/iso9660fs/read.c index ff5738a3b..d0e3b6406 100644 --- a/minix/fs/iso9660fs/read.c +++ b/minix/fs/iso9660fs/read.c @@ -4,344 +4,258 @@ #include #include #include -#include "buf.h" static char getdents_buf[GETDENTS_BUFSIZ]; +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; + struct inode *i_node; + + switch(fs_m_in.m_type) { + case REQ_READ: rw = READING; break; + case REQ_PEEK: rw = PEEKING; break; + default: panic("odd m_type"); + } -/*===========================================================================* - * fs_read * - *===========================================================================*/ -int fs_read(void) { - int r, chunk, block_size; - size_t nrbytes; - 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; - - switch(fs_m_in.m_type) { - case REQ_READ: rw = READING; break; - case REQ_PEEK: rw = PEEKING; break; - 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 */ - - position = fs_m_in.m_vfs_fs_readwrite.seek_pos; - 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 */ - - 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; - - bytes_left = f_size - position; - 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, - (uint32_t) nrbytes, gid, cum_io, block_size, - &completed, rw); - - if (r != OK) break; /* EOF reached */ - if (rdwt_err < 0) break; - - /* Update counters and pointers. */ - nrbytes -= chunk; /* bytes yet to be read */ - cum_io += chunk; /* bytes read so far */ - position += chunk; /* position within the file */ - } - - fs_m_out.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; - - fs_m_out.m_fs_vfs_readwrite.nbytes = cum_io; /*dir->d_file_size;*/ - release_dir_record(dir); - - return(r); -} + /* 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. */ + block_size = v_pri.logical_block_size_l; + gid = fs_m_in.m_vfs_fs_readwrite.grant; + 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; + + bytes_left = f_size - position; + 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(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; + + /* Update counters and pointers. */ + nrbytes -= chunk; /* Bytes yet to be read. */ + cum_io += chunk; /* Bytes read so far. */ + position += chunk; /* Position within the file. */ + } + fs_m_out.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; + + 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; - cp_grant_id_t gid; - int nrbytes; - u64_t position; - unsigned int off, cum_io; - int completed; - struct dir_record *dir; - - r = OK; - - rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING); - gid = fs_m_in.m_vfs_fs_breadwrite.grant; - 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; - - if(rw_flag == WRITING) return (EIO); /* Not supported */ - rdwt_err = OK; /* set to EIO if disk error occurs */ - - cum_io = 0; - /* Split the transfer into chunks that don't span two blocks. */ - while (nrbytes != 0) { - off = (unsigned int)(position % block_size); /* offset in blk*/ - - chunk = MIN(nrbytes, block_size - off); - if (chunk < 0) chunk = block_size - off; - - /* Read 'chunk' bytes. */ - r = read_chunk(dir, position, off, chunk, (unsigned) nrbytes, - gid, cum_io, block_size, &completed, READING); - - if (r != OK) break; /* EOF reached */ - if (rdwt_err < 0) break; - - /* Update counters and pointers. */ - nrbytes -= chunk; /* bytes yet to be read */ - cum_io += chunk; /* bytes read so far */ - position += chunk; /* position within the file */ - } - - fs_m_out.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; - - fs_m_out.m_fs_vfs_breadwrite.nbytes = cum_io; - - return(r); -} + int r = OK, rw_flag, chunk, block_size, completed; + size_t nrbytes, off, cum_io; + cp_grant_id_t gid; + off_t position; + struct inode *i_node; + + r = OK; + + rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING); + gid = fs_m_in.m_vfs_fs_breadwrite.grant; + 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; + i_node = v_pri.inode_root; + + if(rw_flag == WRITING) + return EIO; /* Not supported */ + + rdwt_err = OK; /* set to EIO if disk error occurs */ + + cum_io = 0; + /* Split the transfer into chunks that don't span two blocks. */ + while (nrbytes != 0) { + off = (unsigned int)(position % block_size); /* offset in blk*/ + + chunk = MIN(nrbytes, block_size - off); + if (chunk < 0) + chunk = block_size - off; + + /* Read 'chunk' bytes. */ + 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; + + /* Update counters and pointers. */ + nrbytes -= chunk; /* bytes yet to be read */ + cum_io += chunk; /* bytes read so far */ + position += chunk; /* position within the file */ + } + + fs_m_out.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; + + fs_m_out.m_fs_vfs_breadwrite.nbytes = cum_io; + + return r; +} -/*===========================================================================* - * fs_getdents * - *===========================================================================*/ int fs_getdents(void) { - struct dir_record *dir; - 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; - struct dirent *dirp; - int r,done,o,len,reclen; - char *cp; - char name[NAME_MAX + 1]; - char name_old[NAME_MAX + 1]; - - /* Initialize the tmp arrays */ - memset(name,'\0',NAME_MAX); - memset(name_old,'\0',NAME_MAX); - - /* Get input parameters */ - ino = fs_m_in.m_vfs_fs_getdents.inode; - gid = fs_m_in.m_vfs_fs_getdents.grant; - pos = fs_m_in.m_vfs_fs_getdents.seek_pos; - - block_size = v_pri.logical_block_size_l; - cur_pos = pos; /* The current position */ - tmpbuf_offset = 0; - userbuf_off = 0; - memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */ - - if ((dir = get_dir_record(ino)) == NULL) 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_posd_file_size) { - bp = get_block(block); /* Get physical block */ - - if (bp == NULL) { - release_dir_record(dir); - return(EINVAL); - } - - block_pos = cur_pos % block_size; /* Position where to start read */ - - while (block_pos < block_size) { - dir_tmp = get_free_dir_record(); - create_dir_record(dir_tmp,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'; + struct inode *i_node, *i_node_tmp; + ino_t ino; + cp_grant_id_t gid; + size_t old_pos = 0, cur_pos, new_pos, tmpbuf_off = 0, userbuf_off = 0, grant_size; + struct dirent *dirp; + int r, len, reclen; + char *cp; + + /* Get input parameters */ + ino = fs_m_in.m_vfs_fs_getdents.inode; + gid = fs_m_in.m_vfs_fs_getdents.grant; + cur_pos = fs_m_in.m_vfs_fs_getdents.seek_pos; + grant_size = fs_m_in.m_vfs_fs_getdents.mem_size; + + //memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */ + + if ((i_node = get_inode(ino)) == NULL) + 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; + } + cur_pos = new_pos; + + /* Compute the length of the name */ + cp = memchr(i_node_tmp->i_name, '\0', NAME_MAX); + if (cp == NULL) + len = NAME_MAX; + else + 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_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_off); + + if (r != OK) + panic("fs_getdents: sys_safecopyto failed: %d", r); + + /* 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; } - if (strcmp(name_old, name) == 0) { - cur_pos += dir_tmp->length; - release_dir_record(dir_tmp); - continue; - } + userbuf_off += tmpbuf_off; + tmpbuf_off = 0; + } - strlcpy(name_old, name, NAME_MAX + 1); + /* The standard data structure is created using the + * data in the buffer. */ + 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(i_node_tmp->i_stat.st_mode); + dirp->d_namlen = len; - /* Compute the length of the name */ - cp = memchr(name, '\0', NAME_MAX); - if (cp == NULL) - len = NAME_MAX; - else - len= cp - name; + memcpy(dirp->d_name, i_node_tmp->i_name, len); + dirp->d_name[len]= '\0'; - /* Compute record length; also does alignment. */ - reclen = _DIRENT_RECLEN(dirp, len); + tmpbuf_off += reclen; + put_inode(i_node_tmp); - /* If the new record does not fit, then copy the buffer - * and start from the beginning. */ - if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) { - r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off, - (vir_bytes)getdents_buf, tmpbuf_offset); + old_pos = cur_pos; + } - if (r != OK) - panic("fs_getdents: sys_safecopyto failed: %d", r); - userbuf_off += tmpbuf_offset; - tmpbuf_offset= 0; - } - - /* The standard data structure is created using the - * data in the buffer. */ - dirp = (struct dirent *) &getdents_buf[tmpbuf_offset]; - dirp->d_fileno = (u32_t)(b_data(bp) + (size_t)block_pos); - dirp->d_reclen= reclen; - dirp->d_type = fs_mode_to_type(dir_tmp->d_mode); - dirp->d_namlen = len; - memcpy(dirp->d_name, name, len); - dirp->d_name[len]= '\0'; - tmpbuf_offset += reclen; - - cur_pos += dir_tmp->length; - release_dir_record(dir_tmp); - } + if (tmpbuf_off != 0) { + r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off, + (vir_bytes) getdents_buf, tmpbuf_off); - block_pos += dir_tmp->length; - } - - put_block(bp); /* release the block */ - if (done == TRUE) break; - - cur_pos += block_size - cur_pos; - block++; /* read the next one */ - } - - if (tmpbuf_offset != 0) { - r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off, - (vir_bytes) getdents_buf, tmpbuf_offset); - if (r != OK) - panic("fs_getdents: sys_safecopyto failed: %d", r); - - userbuf_off += tmpbuf_offset; - } - - 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); -} + if (r != OK) + panic("fs_getdents: sys_safecopyto failed: %d", r); + + 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; + 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 */ { + struct buf *bp; + int r = OK; + + *completed = 0; + + 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); + } - register struct buf *bp; - register int r = OK; - block_t b; - int file_unit, rel_block, offset; - - *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) { - 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); - } - - put_block(bp); - - return(r); + put_block(bp); + return r; } diff --git a/minix/fs/iso9660fs/stadir.c b/minix/fs/iso9660fs/stadir.c index 9f0d9d607..5ea10463d 100644 --- a/minix/fs/iso9660fs/stadir.c +++ b/minix/fs/iso9660fs/stadir.c @@ -8,119 +8,44 @@ #include - -/*===========================================================================* - * 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; + int r; + struct statvfs st; + + memset(&st, 0, sizeof(st)); - memset(&st, 0, sizeof(st)); + st.f_bsize = v_pri.logical_block_size_l; + st.f_frsize = st.f_bsize; + st.f_iosize = st.f_bsize; + st.f_blocks = v_pri.volume_space_size_l; + st.f_namemax = NAME_MAX; - st.f_bsize = v_pri.logical_block_size_l; - st.f_frsize = st.f_bsize; - st.f_iosize = st.f_bsize; - st.f_blocks = v_pri.volume_space_size_l; - st.f_namemax = NAME_MAX; + /* Copy the struct to user space. */ + r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_statvfs.grant, 0, + (vir_bytes) &st, (phys_bytes) sizeof(st)); - /* Copy the struct to user space. */ - 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; - *free = 0; + *used = *blocks = v_pri.volume_space_size_l; + *free = 0; } diff --git a/minix/fs/iso9660fs/super.c b/minix/fs/iso9660fs/super.c index 3f9bcfab8..df5a37353 100644 --- a/minix/fs/iso9660fs/super.c +++ b/minix/fs/iso9660fs/super.c @@ -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 @@ -7,112 +9,104 @@ #include #include -/* 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; - return OK; -} + /* 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; + } -/* 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; -{ - struct dir_record *dir; - - v_pri->vd_type = buf[0]; - memcpy(v_pri->standard_id,buf + 1,sizeof(v_pri->standard_id)); - v_pri->vd_version = buf[6]; - memcpy(v_pri->system_id,buf + 8,sizeof(v_pri->system_id)); - memcpy(v_pri->volume_id,buf + 40,sizeof(v_pri->volume_id)); - memcpy(&v_pri->volume_space_size_l,buf + 80, - sizeof(v_pri->volume_space_size_l)); - memcpy(&v_pri->volume_space_size_m,buf + 84, - sizeof(v_pri->volume_space_size_m)); - memcpy(&v_pri->volume_set_size,buf + 120,sizeof(v_pri->volume_set_size)); - memcpy(&v_pri->volume_sequence_number,buf + 124, - sizeof(v_pri->volume_sequence_number)); - memcpy(&v_pri->logical_block_size_l,buf + 128, - sizeof(v_pri->logical_block_size_l)); - memcpy(&v_pri->logical_block_size_m,buf + 130, - sizeof(v_pri->logical_block_size_m)); - memcpy(&v_pri->path_table_size_l,buf + 132, - sizeof(v_pri->path_table_size_l)); - memcpy(&v_pri->path_table_size_m,buf + 136, - sizeof(v_pri->path_table_size_m)); - memcpy(&v_pri->loc_l_occ_path_table,buf + 140, - sizeof(v_pri->loc_l_occ_path_table)); - memcpy(&v_pri->loc_opt_l_occ_path_table,buf + 144, - sizeof(v_pri->loc_opt_l_occ_path_table)); - memcpy(&v_pri->loc_m_occ_path_table, buf + 148, - sizeof(v_pri->loc_m_occ_path_table)); - memcpy(&v_pri->loc_opt_m_occ_path_table,buf + 152, - sizeof(v_pri->loc_opt_m_occ_path_table)); - - dir = get_free_dir_record(); - if (dir == NULL) return EINVAL; - create_dir_record(dir,buf + 156,(u32_t)(address + 156)); - v_pri->dir_rec_root = dir; - dir->d_ino_nr = ROOT_INO_NR; - - memcpy(v_pri->volume_set_id,buf + 190,sizeof(v_pri->volume_set_id)); - memcpy(v_pri->publisher_id,buf + 318,sizeof(v_pri->publisher_id)); - memcpy(v_pri->data_preparer_id,buf + 446,sizeof(v_pri->data_preparer_id)); - memcpy(v_pri->application_id,buf + 574,sizeof(v_pri->application_id)); - memcpy(v_pri->copyright_file_id,buf + 702,sizeof(v_pri->copyright_file_id)); - memcpy(v_pri->abstract_file_id,buf + 739,sizeof(v_pri->abstract_file_id)); - memcpy(v_pri->bibl_file_id,buf + 776,sizeof(v_pri->bibl_file_id)); - memcpy(v_pri->volume_cre_date,buf + 813,sizeof(v_pri->volume_cre_date)); - memcpy(v_pri->volume_mod_date,buf + 830,sizeof(v_pri->volume_mod_date)); - memcpy(v_pri->volume_exp_date,buf + 847,sizeof(v_pri->volume_exp_date)); - memcpy(v_pri->volume_eff_date,buf + 864,sizeof(v_pri->volume_eff_date)); - v_pri->file_struct_ver = buf[881]; - return OK; + 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 create_vol_pri_desc(struct iso9660_vol_pri_desc *vol_pri, char *buf, + size_t address) { - u64_t offset; - int vol_ok = FALSE; - int r; - static char sbbuf[ISO9660_MIN_BLOCK_SIZE]; - int i = 0; + /* + * 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; + + if (vol_pri->i_count > 0) + release_vol_pri_desc(vol_pri); + + memcpy(vol_pri, buf, 2048); - offset = ((u64_t)(ISO9660_SUPER_BLOCK_POSITION)); - while (!vol_ok && i++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; - /* Read the sector of the super block. */ - r = bdev_read(dev, offset, sbbuf, ISO9660_MIN_BLOCK_SIZE, BDEV_NOFLAGS); + lmfs_set_blocksize(vol_pri->logical_block_size_l, major(fs_dev)); - if (r != ISO9660_MIN_BLOCK_SIZE) /* Damaged sector or what? */ - continue; + /* Read root directory record. */ + root_record = (struct iso9660_dir_record *)vol_pri->root_directory; + root = alloc_inode(); + extent = alloc_extent(); - if ((sbbuf[0] & BYTE) == VD_PRIMARY) { - create_v_pri(v_pri,sbbuf,offset); /* copy the buffer in the data structure. */ - } + 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 ((sbbuf[0] & BYTE) == VD_SET_TERM) - /* I dont need to save anything about it */ - vol_ok = TRUE; + if (read_inode(root, extent, 0, NULL) != OK) { + free_extent(extent); + put_inode(root); + return EINVAL; + } - offset += ISO9660_MIN_BLOCK_SIZE; - } + free_extent(extent); + vol_pri->inode_root = root; + vol_pri->i_count = 1; - if (vol_ok == FALSE) - return EINVAL; /* If no superblock was found... */ - else - return OK; /* otherwise. */ + return OK; } + +int read_vds(struct iso9660_vol_pri_desc *vol_pri, dev_t dev) +{ + /* + * 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; + + 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? */ + return EINVAL; + } + + if ((sbbuf[0] & BYTE) == VD_PRIMARY) { + /* 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) { + /* I dont need to save anything about it */ + vol_ok = TRUE; + } + } + + if (vol_ok == FALSE || vol_pri_flag == FALSE) + return EINVAL; /* If no superblock was found... */ + else + return OK; /* otherwise. */ +} + diff --git a/minix/fs/iso9660fs/super.h b/minix/fs/iso9660fs/super.h index 363fe350b..9ace51aa2 100644 --- a/minix/fs/iso9660fs/super.h +++ b/minix/fs/iso9660fs/super.h @@ -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 @@ -7,42 +7,57 @@ #define VD_PART 3 #define VD_SET_TERM 255 -#define MAX_ATTEMPTS 20 /* # attempts to read the volume descriptors. - * After it gives up */ -#define ROOT_INO_NR 1 +#define MAX_ATTEMPTS 20 /* # attempts to read the volume descriptors. + * After it gives up */ + +/* 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; + 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; + u32_t path_table_size_m; + u32_t loc_l_occ_path_table; + u32_t loc_opt_l_occ_path_table; + u32_t loc_m_occ_path_table; + u32_t loc_opt_m_occ_path_table; + 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]; + char application_id[ISO9660_SIZE_APPL_ID]; + char copyright_file_id[ISO9660_SIZE_COPYRIGHT_FILE_ID]; + char abstract_file_id[ISO9660_SIZE_ABSTRACT_FILE_ID]; + char bibl_file_id[ISO9660_SIZE_BIBL_FILE_ID]; + char volume_cre_date[ISO9660_SIZE_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; + 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; -/* Structure for the primary volume descriptor */ -struct iso9660_vd_pri { - u8_t vd_type; - char standard_id[ISO9660_SIZE_STANDARD_ID]; - u8_t vd_version; - char system_id[ISO9660_SIZE_SYS_ID]; - char volume_id[ISO9660_SIZE_VOLUME_ID]; - u32_t volume_space_size_l; - u32_t volume_space_size_m; - u32_t volume_set_size; - u32_t volume_sequence_number; - u16_t logical_block_size_l; - u16_t logical_block_size_m; - u32_t path_table_size_l; - u32_t path_table_size_m; - u32_t loc_l_occ_path_table; - u32_t loc_opt_l_occ_path_table; - u32_t loc_m_occ_path_table; - u32_t loc_opt_m_occ_path_table; - struct dir_record *dir_rec_root; - char volume_set_id[ISO9660_SIZE_VOLUME_SET_ID]; - char publisher_id[ISO9660_SIZE_PUBLISHER_ID]; - char data_preparer_id[ISO9660_SIZE_DATA_PREP_ID]; - char application_id[ISO9660_SIZE_APPL_ID]; - char copyright_file_id[ISO9660_SIZE_COPYRIGHT_FILE_ID]; - char abstract_file_id[ISO9660_SIZE_ABSTRACT_FILE_ID]; - char bibl_file_id[ISO9660_SIZE_BIBL_FILE_ID]; - char volume_cre_date[ISO9660_SIZE_VOL_CRE_DATE]; - char volume_mod_date[ISO9660_SIZE_VOL_MOD_DATE]; - char volume_exp_date[ISO9660_SIZE_VOL_EXP_DATE]; - char volume_eff_date[ISO9660_SIZE_VOL_EFF_DATE]; - u8_t file_struct_ver; - /* The rest is either not specified or reserved */ - u8_t count; -} v_pri; diff --git a/minix/fs/iso9660fs/susp.c b/minix/fs/iso9660fs/susp.c new file mode 100644 index 000000000..034f9d5ad --- /dev/null +++ b/minix/fs/iso9660fs/susp.c @@ -0,0 +1,130 @@ +/* + * This file contains support for System Use Sharing Protocol (SUSP) extension + * to ISO 9660. + */ + +#include "inc.h" +#include + +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; + } +} + diff --git a/minix/fs/iso9660fs/susp_rock_ridge.c b/minix/fs/iso9660fs/susp_rock_ridge.c new file mode 100644 index 000000000..d68bb94c1 --- /dev/null +++ b/minix/fs/iso9660fs/susp_rock_ridge.c @@ -0,0 +1,248 @@ +/* + * This file contains support for Rock Ridge Interchange Protocol (RRIP) + * extension to ISO 9660. + */ + +#include "inc.h" +#include + +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; +} + diff --git a/minix/fs/iso9660fs/table.c b/minix/fs/iso9660fs/table.c index 6f9297c51..5a5cf1ba3 100644 --- a/minix/fs/iso9660fs/table.c +++ b/minix/fs/iso9660fs/table.c @@ -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. */ @@ -8,43 +9,39 @@ #include "inc.h" int (*fs_call_vec[])(void) = { - no_sys, /* 0: not used */ - no_sys, /* 1: not used */ - fs_putnode, /* 2 */ - no_sys, /* 3: not used */ - no_sys, /* 4: not used */ - no_sys, /* 5: not used */ - no_sys, /* 6: not used */ - do_noop, /* 7 */ - fs_stat, /* 8 */ - no_sys, /* 9: not used */ - fs_statvfs, /* 10 */ - fs_bread, /* 11 */ - no_sys, /* 12: not used */ - no_sys, /* 13: not used */ - no_sys, /* 14: not used */ - fs_unmount, /* 15 */ - fs_sync, /* 16 */ - fs_new_driver, /* 17 */ - no_sys, /* 18: not_used */ - fs_read, /* 19 */ - no_sys, /* 20: not used */ - no_sys, /* 21: not used */ - no_sys, /* 22: not used */ - no_sys, /* 23: not used */ - no_sys, /* 24: not used */ - no_sys, /* 25: not used */ - fs_lookup, /* 26 */ - fs_mountpoint, /* 27 */ - fs_readsuper, /* 28 */ - no_sys, /* 29: not used */ - no_sys, /* 30: not used */ - fs_getdents, /* 31 */ -#if 0 - fs_read, /* 32 */ - no_sys, /* 33 */ -#else - no_sys, /* 32 */ - no_sys, /* 33 */ -#endif -}; + no_sys, /* 0: not used */ + no_sys, /* 1: not used */ + fs_putnode, /* 2 */ + no_sys, /* 3: not used */ + no_sys, /* 4: not used */ + no_sys, /* 5: not used */ + no_sys, /* 6: not used */ + do_noop, /* 7 */ + fs_stat, /* 8 */ + no_sys, /* 9: not used */ + fs_statvfs, /* 10 */ + fs_bread, /* 11 */ + no_sys, /* 12: not used */ + no_sys, /* 13: not used */ + no_sys, /* 14: not used */ + fs_unmount, /* 15 */ + fs_sync, /* 16 */ + fs_new_driver, /* 17 */ + no_sys, /* 18: not_used */ + fs_read, /* 19 */ + no_sys, /* 20: not used */ + no_sys, /* 21: not used */ + no_sys, /* 22: not used */ + no_sys, /* 23: not used */ + no_sys, /* 24: not used */ + no_sys, /* 25: not used */ + fs_lookup, /* 26 */ + fs_mountpoint, /* 27 */ + fs_readsuper, /* 28 */ + no_sys, /* 29: not used */ + fs_rdlink, /* 30 */ + fs_getdents, /* 31 */ + no_sys, /* 32 */ + no_sys, /* 33 */ +} ; + diff --git a/minix/fs/iso9660fs/utility.c b/minix/fs/iso9660fs/utility.c index d62b75eb7..5a7e02407 100644 --- a/minix/fs/iso9660fs/utility.c +++ b/minix/fs/iso9660fs/utility.c @@ -5,21 +5,99 @@ #include #include -/*===========================================================================* - * 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); + /* Do not do anything. */ + return OK; } -/*===========================================================================* - * no_sys * - *===========================================================================*/ int no_sys(void) { -/* Somebody has used an illegal system call number */ - return(EINVAL); + /* Somebody has used an illegal system call number */ + return EINVAL; }