From 77d319267f869d0d9eb9ac5a831164add8a5aa8d Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 29 May 2020 12:21:56 +0100 Subject: [PATCH] [iso] add Rock Ridge deep directory support * Closes #1526 --- src/iso.c | 4 + src/libcdio/cdio/rock.h | 36 +++- src/libcdio/driver/cdio_private.h | 20 ++- src/libcdio/iso9660/iso9660_fs.c | 116 ++++++++++--- src/libcdio/iso9660/rock.c | 274 +++++++----------------------- src/rufus.c | 1 + src/rufus.h | 1 + src/rufus.rc | 10 +- 8 files changed, 216 insertions(+), 246 deletions(-) diff --git a/src/iso.c b/src/iso.c index 0cb93a91..c6e1413a 100644 --- a/src/iso.c +++ b/src/iso.c @@ -654,6 +654,10 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) _CDIO_LIST_FOREACH(p_entnode, p_entlist) { if (FormatStatus) goto out; p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode); + if ((p_statbuf->rr.b3_rock == yep) && enable_rockridge) { + if (p_statbuf->rr.u_su_fields & ISO_ROCK_SUF_PL) + img_report.has_deep_directories = TRUE; + } // Eliminate . and .. entries if ( (strcmp(p_statbuf->filename, ".") == 0) || (strcmp(p_statbuf->filename, "..") == 0) ) diff --git a/src/libcdio/cdio/rock.h b/src/libcdio/cdio/rock.h index 8ae66807..33774c7a 100644 --- a/src/libcdio/cdio/rock.h +++ b/src/libcdio/cdio/rock.h @@ -190,12 +190,12 @@ typedef struct iso_rock_nm_s { /*! Child link. See Section 4.1.5.1 */ typedef struct iso_rock_cl_s { - char location[1]; + iso733_t location; } GNUC_PACKED iso_rock_cl_t ; /*! Parent link. See Section 4.1.5.2 */ typedef struct iso_rock_pl_s { - char location[1]; + iso733_t location; } GNUC_PACKED iso_rock_pl_t ; /*! These are the bits and their meanings for flags in the TF structure. */ @@ -264,9 +264,29 @@ typedef struct iso_extension_record_s { iso_rock_cl_t CL; /**< Rock Ridge child link */ iso_rock_pl_t PL; /**< Rock Ridge parent link */ iso_rock_tf_t TF; /**< Rock Ridge timestamp(s) for a file */ + iso_rock_sf_t SF; /**< Rock Ridge sparse file */ } u; } GNUC_PACKED iso_extension_record_t; +/* Bits for the u_su_fields of iso_rock_statbuf_t */ +#define ISO_ROCK_SUF_SP 0x00000001 +#define ISO_ROCK_SUF_ER 0x00000002 +#define ISO_ROCK_SUF_CE 0x00000004 +#define ISO_ROCK_SUF_PX 0x00000008 +#define ISO_ROCK_SUF_PN 0x00000010 +#define ISO_ROCK_SUF_SL 0x00000020 +#define ISO_ROCK_SUF_NM 0x00000040 +#define ISO_ROCK_SUF_TF 0x00000080 +#define ISO_ROCK_SUF_CL 0x00000100 +#define ISO_ROCK_SUF_PL 0x00000200 +#define ISO_ROCK_SUF_RE 0x00000400 +#define ISO_ROCK_SUF_SF 0x00000800 + +#define ISO_ROCK_SUF_FORMAL (ISO_ROCK_SUF_ER | ISO_ROCK_SUF_PX | ISO_ROCK_SUF_PN | \ + ISO_ROCK_SUF_SL | ISO_ROCK_SUF_NM | ISO_ROCK_SUF_CL | \ + ISO_ROCK_SUF_PL | ISO_ROCK_SUF_RE | ISO_ROCK_SUF_TF | \ + ISO_ROCK_SUF_SF) + typedef struct iso_rock_time_s { bool b_used; /**< If true, field has been set and is valid. Otherwise remaning fields are meaningless. */ @@ -306,19 +326,23 @@ typedef struct iso_rock_statbuf_s { 9660:9.5.6. */ iso_rock_time_t effective; /**< Effective time; See ISO 9660:9.5.7. */ - uint32_t i_rdev; /**< the upper 16-bits is major device + uint32_t i_rdev; /**< the upper 16-bits is major device number, the lower 16-bits is the minor device number */ + uint32_t u_su_fields; /**< System Use field attributes */ } iso_rock_statbuf_t; - + PRAGMA_END_PACKED /*! return length of name field; 0: not found, -1: to be ignored */ -int get_rock_ridge_filename(iso9660_dir_t * de, /*out*/ char * retname, +int get_rock_ridge_filename(iso9660_dir_t * de, + /*in*/ void * p_iso, + /*out*/ char * retname, /*out*/ iso9660_stat_t *p_stat); - int parse_rock_ridge_stat(iso9660_dir_t *de, /*out*/ iso9660_stat_t *p_stat); +int parse_rock_ridge_stat(iso9660_dir_t *de, + /*out*/ iso9660_stat_t *p_stat); /*! Returns POSIX mode bitstring for a given file. diff --git a/src/libcdio/driver/cdio_private.h b/src/libcdio/driver/cdio_private.h index 0480c316..5664a989 100644 --- a/src/libcdio/driver/cdio_private.h +++ b/src/libcdio/driver/cdio_private.h @@ -55,7 +55,7 @@ static inline char *libcdio_strndup(const char *s, size_t n) if (!result) return 0; result[len] = '\0'; - return (char *) strncpy (result, s, len); + return (char *) memcpy (result, s, len); } #endif /*HAVE_STRNDUP*/ @@ -467,13 +467,23 @@ extern "C" { } cdio_funcs_t; + typedef struct { + uint16_t u_type; + uint16_t u_flags; + } cdio_header_t; + +#define CDIO_HEADER_TYPE_CDIO 0x0000 +#define CDIO_HEADER_TYPE_ISO 0x0001 + +#define CDIO_HEADER_FLAGS_DISABLE_RR_DD 0x0001 /*! Implementation of CdIo type */ struct _CdIo { - driver_id_t driver_id; /**< Particular driver opened. */ - cdio_funcs_t op; /**< driver-specific routines handling - implementation*/ - void *env; /**< environment. Passed to routine above. */ + cdio_header_t header; /**< Internal header - MUST come first. */ + driver_id_t driver_id; /**< Particular driver opened. */ + cdio_funcs_t op; /**< driver-specific routines handling + implementation. */ + void* env; /**< environment. Passed to routine above. */ }; /* This is used in drivers that must keep their own internal diff --git a/src/libcdio/iso9660/iso9660_fs.c b/src/libcdio/iso9660/iso9660_fs.c index 0e8994b1..08023707 100644 --- a/src/libcdio/iso9660/iso9660_fs.c +++ b/src/libcdio/iso9660/iso9660_fs.c @@ -61,6 +61,7 @@ /** Implementation of iso9660_t type */ struct _iso9660_s { + cdio_header_t header; /**< Internal header - MUST come first. */ CdioDataSource_t *stream; /**< Stream pointer */ bool_3way_t b_xa; /**< true if has XA attributes. */ bool_3way_t b_mode2; /**< true if has mode 2, false for mode 1. */ @@ -92,8 +93,7 @@ struct _iso9660_s { filesystem inside that it may be different. */ - bool b_have_superblock; /**< Superblock has been read in? */ - + bool b_have_superblock; /**< Superblock has been read in? */ }; static long int iso9660_seek_read_framesize (const iso9660_t *p_iso, @@ -174,8 +174,10 @@ iso9660_open_ext_private (const char *psz_path, { iso9660_t *p_iso = (iso9660_t *) calloc(1, sizeof(iso9660_t)) ; - if (!p_iso) return NULL; + if (!p_iso) + return NULL; + p_iso->header.u_type = CDIO_HEADER_TYPE_ISO; p_iso->stream = cdio_stdio_new( psz_path ); if (NULL == p_iso->stream) goto error; @@ -778,19 +780,34 @@ iso9660_check_dir_block_end(iso9660_dir_t *p_iso9660_dir, unsigned *offset) return false; } +static inline bool +_iso9660_is_rock_ridge_enabled(void* p_image) +{ + cdio_header_t* p_header = (cdio_header_t*)p_image; + if (!p_header) + return false; + if (p_header->u_type == CDIO_HEADER_TYPE_ISO) { + iso9660_t* p_iso = (iso9660_t*)p_image; + return (p_iso->iso_extension_mask & ISO_EXTENSION_ROCK_RIDGE); + } + /* Rock Ridge is always enabled for other types */ + return true; +} static iso9660_stat_t * _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, iso9660_stat_t *last_p_stat, - bool_3way_t b_xa, uint8_t u_joliet_level) + void* p_image, + bool_3way_t b_xa, + uint8_t u_joliet_level) { uint8_t dir_len= iso9660_get_dir_len(p_iso9660_dir); iso711_t i_fname; unsigned int stat_len; iso9660_stat_t *p_stat = last_p_stat; char rr_fname[256] = ""; - int i_rr_fname; + int i_rr_fname = 0; lsn_t extent_lsn; bool first_extent; @@ -814,6 +831,9 @@ _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, } p_stat->type = (p_iso9660_dir->file_flags & ISO_DIRECTORY) ? _STAT_DIR : _STAT_FILE; + /* Ignore Rock Ridge Deep Directory RE entries */ + if (p_stat->rr.u_su_fields & ISO_ROCK_SUF_RE) + goto fail; /* Test for gaps between extents. Important: Use previous .total_size */ extent_lsn = from_733 (p_iso9660_dir->extent); @@ -831,8 +851,11 @@ _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, /* Only now update .total_size */ p_stat->total_size += from_733(p_iso9660_dir->size); - p_stat->rr.b3_rock = dunno; /*FIXME should do based on mask */ - p_stat->b_xa = false; +#ifdef HAVE_ROCK + if (_iso9660_is_rock_ridge_enabled(p_image)) + p_stat->rr.b3_rock = dunno; +#endif + p_stat->b_xa = false; #ifndef DO_NOT_WANT_COMPATIBILITY if (first_extent) { @@ -842,8 +865,7 @@ _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, #endif /* DO_NOT_WANT_COMPATIBILITY */ /* Only resolve the full filename when we're not dealing with extent */ - if ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0) - { + if ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0) { /* Check if this is the last part of a multiextent file */ if (!first_extent) { if (strlen(p_stat->filename) != i_fname || @@ -853,11 +875,9 @@ _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, goto fail; } } - i_rr_fname = + #ifdef HAVE_ROCK - get_rock_ridge_filename(p_iso9660_dir, rr_fname, p_stat); -#else - 0; + i_rr_fname = get_rock_ridge_filename(p_iso9660_dir, p_image, rr_fname, p_stat); #endif if (i_rr_fname > 0) { @@ -1024,7 +1044,7 @@ _fs_stat_root (CdIo_t *p_cdio) p_iso9660_dir = &(p_env->pvd.root_directory_record) ; #endif - p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL, + p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL, p_cdio, b_xa, p_env->u_joliet_level); return p_stat; } @@ -1046,7 +1066,7 @@ _ifs_stat_root (iso9660_t *p_iso) #endif p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL, - p_iso->b_xa, + p_iso, p_iso->b_xa, p_iso->u_joliet_level); return p_stat; } @@ -1105,8 +1125,8 @@ _fs_stat_traverse (const CdIo_t *p_cdio, const iso9660_stat_t *_root, /* Do not register remaining extents of ill file */ p_iso9660_stat = NULL; } else { - p_iso9660_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, - p_iso9660_stat, dunno, p_env->u_joliet_level); + p_iso9660_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso9660_stat, + (CdIo_t*)p_cdio, dunno, p_env->u_joliet_level); if (NULL == p_iso9660_stat) skip_following_extents = true; /* Start ill file mode */ } @@ -1213,7 +1233,7 @@ _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root, if (iso9660_check_dir_block_end(p_iso9660_dir, &offset)) continue; - p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_stat, + p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_stat, p_iso, p_iso->b_xa, p_iso->u_joliet_level); if (!p_stat) { @@ -1476,8 +1496,8 @@ iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[]) p_iso9660_stat = NULL; } else { p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, - p_iso9660_stat, dunno, - p_env->u_joliet_level); + p_iso9660_stat, p_cdio, + dunno, p_env->u_joliet_level); if (NULL == p_iso9660_stat) skip_following_extents = true; /* Start ill file mode */ } @@ -1570,10 +1590,13 @@ iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[]) } else { p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, p_iso9660_stat, + p_iso, p_iso->b_xa, p_iso->u_joliet_level); if (NULL == p_iso9660_stat) skip_following_extents = true; /* Start ill file mode */ + else if (p_iso9660_stat->rr.u_su_fields & ISO_ROCK_SUF_RE) + continue; /* Ignore RE entries */ } if ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0) skip_following_extents = false; /* Ill or not: The file ends now */ @@ -1752,6 +1775,55 @@ iso9660_ifs_find_lsn(iso9660_t *p_iso, lsn_t i_lsn) return ret; } +#ifdef HAVE_ROCK +/* Some compilers complain if the prototype is not defined */ +iso9660_stat_t * +_iso9660_dd_find_lsn(void* p_image, lsn_t i_lsn); + +/* Same as above for Rock Ridge deep directory traversing. */ +iso9660_stat_t * +_iso9660_dd_find_lsn(void* p_image, lsn_t i_lsn) +{ + cdio_header_t* p_header = (cdio_header_t*)p_image; + char* psz_full_filename = NULL; + void* p_image_dd; + iso9660_readdir_t* f_readdir; + iso9660_stat_t* ret; + size_t size; + + switch(p_header->u_type) { + case CDIO_HEADER_TYPE_ISO: + size = sizeof(iso9660_t); + f_readdir = (iso9660_readdir_t*)iso9660_ifs_readdir; + break; + case CDIO_HEADER_TYPE_CDIO: + size = sizeof(CdIo_t); + f_readdir = (iso9660_readdir_t*)iso9660_fs_readdir; + break; + default: + cdio_assert(false); + return NULL; + } + + /* Work with a duplicate to allow concurrency. */ + p_image_dd = calloc(1, size); + if (!p_image_dd) { + cdio_warn("Memory duplication error"); + return NULL; + } + memcpy(p_image_dd, p_image, size); + + /* Disable the deep directory flag so we can process all entries */ + p_header = (cdio_header_t*)p_image_dd; + p_header->u_flags |= CDIO_HEADER_FLAGS_DISABLE_RR_DD; + ret = find_lsn_recurse(p_image_dd, f_readdir, "/", i_lsn, &psz_full_filename); + if (psz_full_filename != NULL) + free(psz_full_filename); + free(p_image_dd); + return ret; +} +#endif /* HAVE ROCK */ + /*! Given a directory pointer, find the filesystem entry that contains lsn and return information about it. @@ -1860,8 +1932,8 @@ iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root, if (iso9660_check_dir_block_end(p_iso9660_dir, &offset)) continue; - p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL, p_iso->b_xa, - p_iso->u_joliet_level); + p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL, p_iso, + p_iso->b_xa, p_iso->u_joliet_level); have_rr = p_stat->rr.b3_rock; if ( have_rr != yep) { if (strlen(splitpath[0]) == 0) diff --git a/src/libcdio/iso9660/rock.c b/src/libcdio/iso9660/rock.c index b3a12d05..a957d785 100644 --- a/src/libcdio/iso9660/rock.c +++ b/src/libcdio/iso9660/rock.c @@ -1,4 +1,5 @@ /* + Copyright (C) 2020 Pete Batard Copyright (C) 2005, 2008, 2010-2011, 2014, 2017 Rocky Bernstein @@ -40,6 +41,7 @@ #include #include #include "filemode.h" +#include "cdio_private.h" #define CDIO_MKDEV(ma,mi) ((ma)<<16 | (mi)) @@ -48,6 +50,10 @@ iso_rock_nm_flag_t iso_rock_nm_flag; iso_rock_sl_flag_t iso_rock_sl_flag; iso_rock_tf_flag_t iso_rock_tf_flag; +/* Used by get_rock_ridge_filename() */ +extern iso9660_stat_t* +_iso9660_dd_find_lsn(void* p_image, lsn_t i_lsn); + /* Our own realloc routine tailored for the iso9660_stat_t symlink field. I can't figure out how to make realloc() work without valgrind complaint. @@ -142,12 +148,22 @@ realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow) } \ } +/* Indicates if we should process deep directory entries */ +static inline bool +is_rr_dd_enabled(void * p_image) { + cdio_header_t* p_header = (cdio_header_t*)p_image; + if (!p_header) + return false; + return !(p_header->u_flags & CDIO_HEADER_FLAGS_DISABLE_RR_DD); +} + /*! Get @return length of name field; 0: not found, -1: to be ignored */ int get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, + /*in*/ void * p_image, /*out*/ char * psz_name, /*in/out*/ iso9660_stat_t *p_stat) { @@ -158,7 +174,8 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, int i_namelen = 0; int truncate=0; - if (!p_stat || nope == p_stat->rr.b3_rock) return 0; + if (!p_stat || nope == p_stat->rr.b3_rock) + return 0; *psz_name = 0; SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len); @@ -172,19 +189,21 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, rr = (iso_extension_record_t *) chr; sig = *chr+(*(chr+1) << 8); - /* We used to check for some vaid values of SIG, specifically + /* We used to check for some valid values of SIG, specifically SP, CE, ER, RR, PX, PN, SL, NM, CL, PL, TF, and ZF. However there are various extensions to this set. So we skip checking now. */ - if (rr->len == 0) goto out; /* Something got screwed up here */ + if (rr->len == 0) + goto out; /* Something got screwed up here */ chr += rr->len; len -= rr->len; - switch(sig){ + switch(sig) { case SIG('S','P'): CHECK_SP(goto out); + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_SP; break; case SIG('C','E'): { @@ -195,19 +214,21 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, break; } CHECK_CE; + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_CE; break; case SIG('E','R'): - p_stat->rr.b3_rock = yep; cdio_debug("ISO 9660 Extensions: "); { int p; - for(p=0;pu.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]); + for (p=0; p < rr->u.ER.len_id; p++) + cdio_debug("%c", rr->u.ER.data[p]); } break; case SIG('N','M'): /* Alternate name */ - p_stat->rr.b3_rock = yep; - if (truncate) break; + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_NM; + if (truncate) + break; if (rr->u.NM.flags & ISO_ROCK_NM_PARENT) { i_namelen = sizeof(".."); strncat(psz_name, "..", i_namelen); @@ -235,7 +256,7 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks); p_stat->rr.st_uid = from_733(rr->u.PX.st_uid); p_stat->rr.st_gid = from_733(rr->u.PX.st_gid); - p_stat->rr.b3_rock = yep; + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_PX; break; case SIG('S','L'): { @@ -246,6 +267,7 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, slen = rr->len - 5; p_sl = &rr->u.SL.link; p_stat->rr.i_symlink = symlink_len; + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_SL; while (slen > 1){ rootflag = 0; switch(p_sl->flags &~1){ @@ -294,9 +316,6 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, realloc_symlink(p_stat, 1); p_stat->rr.psz_symlink[symlink_len]='\0'; break; - case SIG('R','E'): - free(buffer); - return -1; case SIG('T','F'): /* Time stamp(s) for a file */ { @@ -308,217 +327,56 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, add_time(ISO_ROCK_TF_BACKUP, backup); add_time(ISO_ROCK_TF_EXPIRATION, expiration); add_time(ISO_ROCK_TF_EFFECTIVE, effective); - p_stat->rr.b3_rock = yep; + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_TF; break; } - default: - break; - } - } - } - free(buffer); - return i_namelen; /* If 0, this file did not have a NM field */ - out: - free(buffer); - return 0; -} - -static int -parse_rock_ridge_stat_internal(iso9660_dir_t *p_iso9660_dir, - iso9660_stat_t *p_stat, int regard_xa) -{ - int len; - unsigned char * chr; - int symlink_len = 0; - CONTINUE_DECLS; - - if (nope == p_stat->rr.b3_rock) return 0; - - SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len); - if (regard_xa) - { - chr+=14; - len-=14; - if (len<0) len=0; - } - - /* repeat:*/ - { - int sig; - iso_extension_record_t * rr; - int rootflag; - - while (len > 1){ /* There may be one byte for padding somewhere */ - rr = (iso_extension_record_t *) chr; - if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = from_721(*chr); - chr += rr->len; - len -= rr->len; - - switch(sig){ - case SIG('S','P'): - CHECK_SP(goto out); - break; - case SIG('C','E'): - CHECK_CE; - break; - case SIG('E','R'): - p_stat->rr.b3_rock = yep; - cdio_debug("ISO 9660 Extensions: "); - { int p; - for(p=0;pu.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]); - } - break; - case SIG('P','X'): - p_stat->rr.st_mode = from_733(rr->u.PX.st_mode); - p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks); - p_stat->rr.st_uid = from_733(rr->u.PX.st_uid); - p_stat->rr.st_gid = from_733(rr->u.PX.st_gid); - break; - case SIG('P','N'): - /* Device major,minor number */ - { int32_t high, low; - high = from_733(rr->u.PN.dev_high); - low = from_733(rr->u.PN.dev_low); - /* - * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4, - * then the high field is unused, and the device number is completely - * stored in the low field. Some writers may ignore this subtlety, - * and as a result we test to see if the entire device number is - * stored in the low field, and use that. - */ - if((low & ~0xff) && high == 0) { - p_stat->rr.i_rdev = CDIO_MKDEV(low >> 8, low & 0xff); - } else { - p_stat->rr.i_rdev = CDIO_MKDEV(high, low); - } - } - break; - case SIG('T','F'): - /* Time stamp(s) for a file */ - { - int cnt = 0; - add_time(ISO_ROCK_TF_CREATE, create); - add_time(ISO_ROCK_TF_MODIFY, modify); - add_time(ISO_ROCK_TF_ACCESS, access); - add_time(ISO_ROCK_TF_ATTRIBUTES, attributes); - add_time(ISO_ROCK_TF_BACKUP, backup); - add_time(ISO_ROCK_TF_EXPIRATION, expiration); - add_time(ISO_ROCK_TF_EFFECTIVE, effective); - p_stat->rr.b3_rock = yep; - break; - } - case SIG('S','L'): - { - /* Symbolic link */ - uint8_t slen; - iso_rock_sl_part_t * p_sl; - iso_rock_sl_part_t * p_oldsl; - slen = rr->len - 5; - p_sl = &rr->u.SL.link; - p_stat->rr.i_symlink = symlink_len; - while (slen > 1){ - rootflag = 0; - switch(p_sl->flags &~1){ - case 0: - realloc_symlink(p_stat, p_sl->len); - if (p_sl->len) - memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]), - p_sl->text, p_sl->len); - p_stat->rr.i_symlink += p_sl->len; - break; - case 4: - realloc_symlink(p_stat, 1); - p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.'; - /* continue into next case. */ - case 2: - realloc_symlink(p_stat, 1); - p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.'; - break; - case 8: - rootflag = 1; - realloc_symlink(p_stat, 1); - p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/'; - p_stat->rr.i_symlink++; - break; - default: - cdio_warn("Symlink component flag not implemented"); - } - slen -= p_sl->len + 2; - p_oldsl = p_sl; - p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2); - - if (slen < 2) { - if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0)) - p_stat->rr.i_symlink += 1; - break; - } - - /* - * If this component record isn't continued, then append a '/'. - */ - if (!rootflag && (p_oldsl->flags & 1) == 0) { - realloc_symlink(p_stat, 1); - p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/'; - } - } - } - symlink_len = p_stat->rr.i_symlink; - realloc_symlink(p_stat, 1); - p_stat->rr.psz_symlink[symlink_len]='\0'; - break; - case SIG('R','E'): - cdio_warn("Attempt to read p_stat for relocated directory"); - goto out; -#ifdef FINISHED case SIG('C','L'): + /* Child Link for a deep directory */ + if (!is_rr_dd_enabled(p_image)) + break; { - iso9660_stat_t * reloc; - ISOFS_I(p_stat)->i_first_extent = from_733(rr->u.CL.location); - reloc = isofs_iget(p_stat->rr.i_sb, p_stat->rr.i_first_extent, 0); - if (!reloc) - goto out; - p_stat->rr.st_mode = reloc->st_mode; - p_stat->rr.st_nlinks = reloc->st_nlinks; - p_stat->rr.st_uid = reloc->st_uid; - p_stat->rr.st_gid = reloc->st_gid; - p_stat->rr.i_rdev = reloc->i_rdev; - p_stat->rr.i_symlink = reloc->i_symlink; - p_stat->rr.i_blocks = reloc->i_blocks; - p_stat->rr.i_atime = reloc->i_atime; - p_stat->rr.i_ctime = reloc->i_ctime; - p_stat->rr.i_mtime = reloc->i_mtime; - iput(reloc); + iso9660_stat_t* target = NULL; + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_CL; + target = _iso9660_dd_find_lsn(p_image, from_733(rr->u.PL.location)); + if (!target) { + cdio_warn("Could not get Rock Ridge deep directory child"); + break; + } + memcpy(p_stat, target, sizeof(iso9660_stat_t)); + /* Prevent the symlink from being freed on the duplicated struct */ + target->rr.psz_symlink = NULL; + iso9660_stat_free(target); } break; -#endif + case SIG('P','L'): + /* Parent link of a deep directory */ + if (is_rr_dd_enabled(p_image)) + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_PL; + break; + case SIG('R','E'): + /* Relocated entry for a deep directory */ + if (is_rr_dd_enabled(p_image)) + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_RE; + break; + case SIG('S','F'): + /* Sparse File */ + p_stat->rr.u_su_fields |= ISO_ROCK_SUF_SF; + cdio_warn("Rock Ridge Sparse File detected"); + break; default: break; } } } - out: + free(buffer); + if (p_stat->rr.u_su_fields & ISO_ROCK_SUF_FORMAL) + p_stat->rr.b3_rock = yep; + return i_namelen; /* If 0, this file did not have a NM field */ +out: free(buffer); return 0; } -int -parse_rock_ridge_stat(iso9660_dir_t *p_iso9660_dir, - /*out*/ iso9660_stat_t *p_stat) -{ - int result; - - if (!p_stat) return 0; - - result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 0); - /* if Rock-Ridge flag was reset and we didn't look for attributes - * behind eventual XA attributes, have a look there */ - if (0xFF == p_stat->rr.s_rock_offset && nope != p_stat->rr.b3_rock) { - result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 14); - } - return result; -} - #define BUF_COUNT 16 #define BUF_SIZE sizeof("drwxrwxrwx") diff --git a/src/rufus.c b/src/rufus.c index 8e68649a..ec19b742 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -1052,6 +1052,7 @@ static void DisplayISOProps(void) PRINT_ISO_PROP(img_report.has_4GB_file, " Has a >4GB file"); PRINT_ISO_PROP(img_report.has_long_filename, " Has a >64 chars filename"); + PRINT_ISO_PROP(img_report.has_deep_directories, " Has a Rock Ridge deep directory"); PRINT_ISO_PROP(HAS_SYSLINUX(img_report), " Uses: Syslinux/Isolinux v%s", img_report.sl_version_str); if (HAS_SYSLINUX(img_report) && (SL_MAJOR(img_report.sl_version) < 5)) { for (i = 0; i