isofs: add support for Rock Ridge deep directories

This commit is contained in:
Jean-Baptiste Boric 2015-04-04 01:58:46 +02:00
parent e2b37bcf44
commit d34477d549
4 changed files with 67 additions and 7 deletions

View File

@ -16,9 +16,6 @@ struct inode_cache {
struct inode_cache *icache = NULL; 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, void read_inode_iso9660(struct inode_dir_entry *i,
const struct iso9660_dir_record *dir_rec, struct dir_extent *extent, const struct iso9660_dir_record *dir_rec, struct dir_extent *extent,
size_t offset, int name_only); size_t offset, int name_only);
@ -117,6 +114,7 @@ int read_directory(struct inode *dir) {
if (cur_entry >= MAX_DIRECTORY_LENGTH) if (cur_entry >= MAX_DIRECTORY_LENGTH)
break; break;
read_next_inode:
memset(&entries[cur_entry], 0, sizeof(struct inode_dir_entry)); memset(&entries[cur_entry], 0, sizeof(struct inode_dir_entry));
status = read_inode(&entries[cur_entry], dir->extent, &pos); status = read_inode(&entries[cur_entry], dir->extent, &pos);
if (status != OK) if (status != OK)
@ -363,6 +361,7 @@ void read_inode_susp(struct inode_dir_entry *i,
rrii_data.rdev = NO_DEV; rrii_data.rdev = NO_DEV;
rrii_data.file_id_rrip[0] = '\0'; rrii_data.file_id_rrip[0] = '\0';
rrii_data.slink_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); 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); 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) if (name_only == TRUE)
return; return;

View File

@ -36,6 +36,8 @@ struct rrii_dir_record {
char file_id_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* file name */ char file_id_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* file name */
char slink_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* symbolic link */ char slink_rrip[ISO9660_RRIP_MAX_FILE_ID_LEN]; /* symbolic link */
struct inode *reparented_inode;
} ; } ;
struct dir_extent { struct dir_extent {
@ -63,6 +65,7 @@ struct inode {
struct inode_dir_entry *dir_contents; /* contents of directory */ struct inode_dir_entry *dir_contents; /* contents of directory */
size_t dir_size; /* number of inodes in this directory */ size_t dir_size; /* number of inodes in this directory */
char *s_name; /* Rock Ridge symbolic link */ char *s_name; /* Rock Ridge symbolic link */
int skip; /* skip inode because of reparenting */
} ; } ;
struct opt { struct opt {

View File

@ -21,6 +21,9 @@ int read_directory(struct inode *dir);
int read_inode(struct inode_dir_entry *dir_entry, struct dir_extent *extent, int read_inode(struct inode_dir_entry *dir_entry, struct dir_extent *extent,
size_t *offset); 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); int check_inodes(void);
/* link.c */ /* link.c */

View File

@ -8,6 +8,42 @@
#ifdef ISO9660_OPTION_ROCKRIDGE #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) void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length)
{ {
/* Parse a Rock Ridge SUSP symbolic link entry (SL). */ /* 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_major;
u32_t rrii_pn_rdev_minor; u32_t rrii_pn_rdev_minor;
mode_t rrii_px_posix_mode; mode_t rrii_px_posix_mode;
u32_t rrii_pcl_block;
susp_signature[0] = buffer[0]; susp_signature[0] = buffer[0];
susp_signature[1] = buffer[1]; susp_signature[1] = buffer[1];
@ -166,16 +203,25 @@ int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer)
return OK; return OK;
} }
else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L')) { else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L') &&
/* Ignored, skip. */ (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; return OK;
} }
else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L')) { else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L') &&
/* Ignored, skip. */ (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; return OK;
} }
else if ((susp_signature[0] == 'R') && (susp_signature[1] == 'E')) { else if ((susp_signature[0] == 'R') && (susp_signature[1] == 'E')) {
/* Ignored, skip. */ /* Ignored, skip. */
return OK; return OK;
} }
else if ((susp_signature[0] == 'T') && (susp_signature[1] == 'F') && else if ((susp_signature[0] == 'T') && (susp_signature[1] == 'F') &&