From d34477d549a892634b7870a2963711479e8ec36f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Sat, 4 Apr 2015 01:58:46 +0200 Subject: [PATCH] isofs: add support for Rock Ridge deep directories --- minix/fs/isofs/inode.c | 14 +++++++-- minix/fs/isofs/inode.h | 3 ++ minix/fs/isofs/proto.h | 3 ++ minix/fs/isofs/susp_rock_ridge.c | 54 +++++++++++++++++++++++++++++--- 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/minix/fs/isofs/inode.c b/minix/fs/isofs/inode.c index 20b4f09a6..973554d17 100644 --- a/minix/fs/isofs/inode.c +++ b/minix/fs/isofs/inode.c @@ -16,9 +16,6 @@ struct inode_cache { struct inode_cache *icache = NULL; -struct inode* inode_cache_get(ino_t ino_nr); -void inode_cache_add(ino_t ino_nr, struct inode *i_node); - void read_inode_iso9660(struct inode_dir_entry *i, const struct iso9660_dir_record *dir_rec, struct dir_extent *extent, size_t offset, int name_only); @@ -117,6 +114,7 @@ int read_directory(struct inode *dir) { if (cur_entry >= MAX_DIRECTORY_LENGTH) break; +read_next_inode: memset(&entries[cur_entry], 0, sizeof(struct inode_dir_entry)); status = read_inode(&entries[cur_entry], dir->extent, &pos); if (status != OK) @@ -363,6 +361,7 @@ void read_inode_susp(struct inode_dir_entry *i, rrii_data.rdev = NO_DEV; rrii_data.file_id_rrip[0] = '\0'; rrii_data.slink_rrip[0] = '\0'; + rrii_data.reparented_inode = NULL; parse_susp_buffer(&rrii_data, b_data(bp)+offset+susp_offset, susp_size); @@ -379,6 +378,15 @@ void read_inode_susp(struct inode_dir_entry *i, memcpy(i->i_node->s_name, rrii_data.slink_rrip, name_length); } + if (rrii_data.reparented_inode) { + i->i_node = rrii_data.reparented_inode; + return; + } + + /* XXX: not the correct way to detect reparented directory holder... */ + if (strcmp(rrii_data.file_id_rrip, ".rr_moved") == 0) + i->i_node->skip = 1; + if (name_only == TRUE) return; diff --git a/minix/fs/isofs/inode.h b/minix/fs/isofs/inode.h index 61dd68cb8..b136bc7f4 100644 --- a/minix/fs/isofs/inode.h +++ b/minix/fs/isofs/inode.h @@ -36,6 +36,8 @@ struct rrii_dir_record { char file_id_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* file name */ char slink_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* symbolic link */ + + struct inode *reparented_inode; } ; struct dir_extent { @@ -63,6 +65,7 @@ struct inode { struct inode_dir_entry *dir_contents; /* contents of directory */ size_t dir_size; /* number of inodes in this directory */ char *s_name; /* Rock Ridge symbolic link */ + int skip; /* skip inode because of reparenting */ } ; struct opt { diff --git a/minix/fs/isofs/proto.h b/minix/fs/isofs/proto.h index 667e32f09..24dbb32d5 100644 --- a/minix/fs/isofs/proto.h +++ b/minix/fs/isofs/proto.h @@ -21,6 +21,9 @@ int read_directory(struct inode *dir); int read_inode(struct inode_dir_entry *dir_entry, struct dir_extent *extent, size_t *offset); +struct inode* inode_cache_get(ino_t ino_nr); +void inode_cache_add(ino_t ino_nr, struct inode *i_node); + int check_inodes(void); /* link.c */ diff --git a/minix/fs/isofs/susp_rock_ridge.c b/minix/fs/isofs/susp_rock_ridge.c index 38f66688b..0ab8a8d12 100644 --- a/minix/fs/isofs/susp_rock_ridge.c +++ b/minix/fs/isofs/susp_rock_ridge.c @@ -8,6 +8,42 @@ #ifdef ISO9660_OPTION_ROCKRIDGE +void parse_susp_rock_ridge_plcl(struct rrii_dir_record *dir, u32_t block) { + struct inode *rep_inode; + struct buf *bp; + struct iso9660_dir_record *dir_rec; + struct dir_extent extent; + struct inode_dir_entry dummy_dir_entry; + size_t dummy_offset = 0; + + /* Check if inode wasn't already parsed. */ + rep_inode = inode_cache_get(block); + if (rep_inode != NULL) { + rep_inode->i_refcount++; + dir->reparented_inode = rep_inode; + return; + } + + /* Peek ahead to build extent for read_inode. */ + bp = lmfs_get_block(fs_dev, block, NORMAL); + if (!bp) + return; + + dir_rec = (struct iso9660_dir_record*)b_data(bp); + + extent.location = block; + 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) + extent.length++; + extent.next = NULL; + lmfs_put_block(bp, FULL_DATA_BLOCK); + + memset(&dummy_dir_entry, 0, sizeof(struct inode_dir_entry)); + read_inode(&dummy_dir_entry, &extent, &dummy_offset); + free(dummy_dir_entry.r_name); + dir->reparented_inode = dummy_dir_entry.i_node; +} + void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length) { /* Parse a Rock Ridge SUSP symbolic link entry (SL). */ @@ -108,6 +144,7 @@ int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer) u32_t rrii_pn_rdev_major; u32_t rrii_pn_rdev_minor; mode_t rrii_px_posix_mode; + u32_t rrii_pcl_block; susp_signature[0] = buffer[0]; susp_signature[1] = buffer[1]; @@ -166,16 +203,25 @@ int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer) return OK; } - else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L')) { - /* Ignored, skip. */ + else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L') && + (susp_length >= 12) && (susp_version >= 1)) { + /* Reparenting ".." directory entry. */ + rrii_pcl_block = *((u32_t*)(buffer + 4)); + parse_susp_rock_ridge_plcl(dir, rrii_pcl_block); + return OK; } - else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L')) { - /* Ignored, skip. */ + else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L') && + (susp_length >= 12) && (susp_version >= 1)) { + /* Reorganize deep directory entry. */ + rrii_pcl_block = *((u32_t*)(buffer + 4)); + parse_susp_rock_ridge_plcl(dir, rrii_pcl_block); + 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') &&