From a2fccc90c4616979d978e3c21ceccb10eac3e91e Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 22 Feb 2005 02:02:46 +0000 Subject: [PATCH] Add routine for extracing ISO 9660 long time format and probably correct the short-time format a little. Handle Rock-Ridge time and be able to display it. This pretty much completes the bulk of handling Rock-Ridge extensions. --- include/cdio/iso9660.h | 31 ++++++++++----- lib/iso9660/iso9660.c | 89 ++++++++++++++++++++++++++++++------------ lib/iso9660/rock.c | 83 +++++++++++++++++++-------------------- src/cd-info.c | 4 +- src/util.c | 81 ++++++++++++++++++++++++++------------ 5 files changed, 183 insertions(+), 105 deletions(-) diff --git a/include/cdio/iso9660.h b/include/cdio/iso9660.h index 668e25be..ca49551d 100644 --- a/include/cdio/iso9660.h +++ b/include/cdio/iso9660.h @@ -1,5 +1,5 @@ /* - $Id: iso9660.h,v 1.71 2005/02/21 09:00:53 rocky Exp $ + $Id: iso9660.h,v 1.72 2005/02/22 02:02:46 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003, 2004, 2005 Rocky Bernstein @@ -49,6 +49,7 @@ specification. */ typedef uint8_t iso711_t; /*! See section 7.1.1 */ +typedef int8_t iso712_t; /*! See section 7.1.2 */ typedef uint16_t iso721_t; /*! See section 7.2.1 */ typedef uint16_t iso722_t; /*! See section 7.2.2 */ typedef uint32_t iso723_t; /*! See section 7.2.3 */ @@ -232,7 +233,9 @@ typedef struct iso9660_dtime_s iso9660_dtime_t; /*! \brief ISO-9660 longer-format time structure. - Section 8.4.26.1 of ECMA 119 + Section 8.4.26.1 of ECMA 119. All values are encoded as character + arrays, eg. '1', '9', '5', '5' for the year 1955 (no null terminated + byte). @see iso9660_ltime */ @@ -244,14 +247,17 @@ struct iso9660_ltime_s { 1..12. Note starts at 1, not 0 like a tm struct. */ - char lt_day [_delta( 7, 8)]; - char lt_hour [_delta( 9, 10)]; - char lt_minute [_delta( 11, 12)]; - char lt_second [_delta( 13, 14)]; - char lt_hsecond [_delta( 15, 16)]; /** Copyright (C) 2003, 2004, 2005 Rocky Bernstein @@ -44,7 +44,11 @@ const char ISO_STANDARD_ID[] = {'C', 'D', '0', '0', '1'}; #include #endif -static const char _rcsid[] = "$Id: iso9660.c,v 1.5 2005/02/20 17:47:01 rocky Exp $"; +#ifdef HAVE_ERRNO_H +#include +#endif + +static const char _rcsid[] = "$Id: iso9660.c,v 1.6 2005/02/22 02:02:46 rocky Exp $"; /* Variables to hold debugger-helping enumerations */ enum iso_enums1 iso_enums1; @@ -93,14 +97,11 @@ pathtable_get_size_and_entries(const void *pt, unsigned int *size, If tm is to reflect the localtime set b_localtime true, otherwise tm will reported in GMT. */ -void +bool iso9660_get_dtime (const iso9660_dtime_t *idr_date, bool b_localtime, /*out*/ struct tm *p_tm) { - time_t t; - struct tm *p_temp_tm; - - if (!idr_date) return; + if (!idr_date) return false; memset(p_tm, 0, sizeof(struct tm)); p_tm->tm_year = idr_date->dt_year; @@ -109,31 +110,69 @@ iso9660_get_dtime (const iso9660_dtime_t *idr_date, bool b_localtime, p_tm->tm_hour = idr_date->dt_hour; p_tm->tm_min = idr_date->dt_minute; p_tm->tm_sec = idr_date->dt_second; + p_tm->tm_gmtoff = - timezone * 15; + p_tm->tm_isdst = -1; /* information not available */ -#if defined(HAVE_TM_GMTOFF) && defined(HAVE_TZSET) - if (b_localtime) { - tzset(); -#if defined(HAVE_TZNAME) - p_tm->tm_zone = (char *) tzname; -#endif -#if defined(HAVE_DAYLIGHT) - p_tm->tm_isdst = daylight; - p_tm->tm_gmtoff = timezone; -#endif + + { + + time_t t; + struct tm *p_temp_tm; + + /* Recompute tm_wday and tm_yday via mktime. */ + t = mktime(p_tm); + + if (b_localtime) + p_temp_tm = localtime(&t); + else + p_temp_tm = gmtime(&t); + + memcpy(p_tm, p_temp_tm, sizeof(struct tm)); } -#endif + return true; +} + +#define set_ltime_field(TM_FIELD, LT_FIELD, ADD_CONSTANT) \ + { \ + p_tm->TM_FIELD = strtol(p_ldate->LT_FIELD, \ + (char **)NULL, 10)+ADD_CONSTANT; \ + if (0 != errno) return false; \ + } + +/*! + Get "long" time in format used in ISO 9660 primary volume descriptor + from a Unix time structure. +*/ +bool +iso9660_get_ltime (const iso9660_ltime_t *p_ldate, + /*out*/ struct tm *p_tm) +{ + if (!p_tm) return false; + memset(p_tm, 0, sizeof(struct tm)); + set_ltime_field(tm_year, lt_year, 0); + set_ltime_field(tm_mon, lt_month, -1); + set_ltime_field(tm_mday, lt_day, 0); + set_ltime_field(tm_hour, lt_hour, 0); + set_ltime_field(tm_min, lt_minute, 0); + set_ltime_field(tm_sec, lt_second, 0); + p_tm->tm_isdst= -1; /* information not available */ + p_tm->tm_gmtoff = - timezone * 15; /* Recompute tm_wday and tm_yday via mktime. */ - t = mktime(p_tm); - - if (b_localtime) - p_temp_tm = localtime(&t); - else + { + time_t t; + struct tm *p_temp_tm; + + t = mktime(p_tm); p_temp_tm = gmtime(&t); - - memcpy(p_tm, p_temp_tm, sizeof(struct tm)); + + p_tm->tm_wday = p_temp_tm->tm_wday; + p_tm->tm_yday = p_temp_tm->tm_yday; + } + return true; } + /*! Set time in format used in ISO 9660 directory index record from a Unix time structure. */ diff --git a/lib/iso9660/rock.c b/lib/iso9660/rock.c index 2dec2b90..9957ff65 100644 --- a/lib/iso9660/rock.c +++ b/lib/iso9660/rock.c @@ -1,5 +1,5 @@ /* - $Id: rock.c,v 1.9 2005/02/21 09:00:53 rocky Exp $ + $Id: rock.c,v 1.10 2005/02/22 02:02:46 rocky Exp $ Copyright (C) 2005 Rocky Bernstein Adapted from GNU/Linux fs/isofs/rock.c (C) 1992, 1993 Eric Youngdale @@ -117,6 +117,7 @@ realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow) */ #define add_time(FLAG, TIME_FIELD) \ if (rr->u.TF.flags & FLAG) { \ + p_stat->rr.TIME_FIELD.b_used = true; \ p_stat->rr.TIME_FIELD.b_longdate = \ (0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM)); \ if (p_stat->rr.TIME_FIELD.b_longdate) { \ @@ -262,9 +263,9 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, 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; + if (slen < 2) { + if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0)) + p_stat->rr.i_symlink += 1; break; } @@ -383,39 +384,26 @@ parse_rock_ridge_stat_internal(iso9660_dir_t *p_iso9660_dir, } break; #endif -#ifdef TIME_FIXED case SIG('T','F'): + /* Time stamp(s) for a file */ { - int cnt = 0; /* Rock ridge never appears on a High Sierra disk */ - /* Some RRIP writers incorrectly place ctime in the - ISO_ROCK_TF_CREATE field. Try to handle this correctly for - either case. */ - /*** FIXME: - Test on long format or not and use - iso9660_get_dtime or iso9660_get_ltime - which needs to be - written. - */ - if (rr->u.TF.flags & ISO_ROCK_TF_CREATE) { - p_stat->rr.st_ctime = rr->u.TF.times[cnt++].time; - } - if(rr->u.TF.flags & ISO_ROCK_TF_MODIFY) { - p_stat->rr.st_mtime = rr->u.TF.times[cnt++].time; - } - if(rr->u.TF.flags & ISO_ROCK_TF_ACCESS) { - p_stat->rr.st_atime = rr->u.TF.times[cnt++].time; - } - if(rr->u.TF.flags & ISO_ROCK_TF_ATTRIBUTES) { - p_stat->rr.st_ctime = rr->u.TF.times[cnt++].time; - } + 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; } -#endif case SIG('S','L'): - /* Symbolic link. */ { - int slen; - iso_rock_sl_part_t *p_sl; - iso_rock_sl_part_t *p_oldsl; + /* 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; @@ -423,45 +411,54 @@ parse_rock_ridge_stat_internal(iso9660_dir_t *p_iso9660_dir, rootflag = 0; switch(p_sl->flags &~1){ case 0: + realloc_symlink(p_stat, 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; - /*memcpy(psz_rsymlink, p_sl->text, p_sl->len); - psz_rsymlink+=p_sl->len;*/ break; case 4: - /**psz_rsymlink++='.';*/ + realloc_symlink(p_stat, 1); + p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.'; p_stat->rr.i_symlink++; /* continue into next case. */ break; case 2: - /**psz_rsymlink++='.';*/ + realloc_symlink(p_stat, 1); + p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.'; p_stat->rr.i_symlink++; break; case 8: rootflag = 1; - /**rootflag = 1;*/ - p_stat->rr.i_symlink += 1; + realloc_symlink(p_stat, 1); + p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/'; + p_stat->rr.i_symlink++; break; default: - cdio_info("Symlink component flag not implemented"); + 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; + 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) - p_stat->rr.i_symlink += 1; + if (!rootflag && (p_oldsl->flags & 1) == 0) { + realloc_symlink(p_stat, 1); + p_stat->rr.psz_symlink[p_stat->rr.i_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"); diff --git a/src/cd-info.c b/src/cd-info.c index 2f16d2ae..5b513a87 100644 --- a/src/cd-info.c +++ b/src/cd-info.c @@ -1,5 +1,5 @@ /* - $Id: cd-info.c,v 1.119 2005/02/21 09:00:53 rocky Exp $ + $Id: cd-info.c,v 1.120 2005/02/22 02:02:46 rocky Exp $ Copyright (C) 2003, 2004, 2005 Rocky Bernstein Copyright (C) 1996, 1997, 1998 Gerd Knorr @@ -857,7 +857,7 @@ int main(int argc, const char *argv[]) { - CdIo_t *p_cdio=NULL; + CdIo_t *p_cdio=NULL; cdio_fs_anal_t fs=CDIO_FS_AUDIO; int i; lsn_t start_track_lsn; /* lsn of first track */ diff --git a/src/util.c b/src/util.c index ae5c5c21..0e0633b4 100644 --- a/src/util.c +++ b/src/util.c @@ -1,5 +1,5 @@ /* - $Id: util.c,v 1.42 2005/02/21 09:00:53 rocky Exp $ + $Id: util.c,v 1.43 2005/02/22 02:02:46 rocky Exp $ Copyright (C) 2003, 2004, 2005 Rocky Bernstein @@ -464,44 +464,73 @@ print_fs_attrs(iso9660_stat_t *p_statbuf, bool b_rock, bool b_xa, char date_str[30]; if (yep == p_statbuf->rr.b3_rock && b_rock) { - report (stdout, " %s %d %d %d [LSN %6lu] %9u", - iso9660_get_rock_attr_str (p_statbuf->rr.st_mode), - p_statbuf->rr.st_nlinks, - p_statbuf->rr.st_uid, - p_statbuf->rr.st_gid, - (long unsigned int) p_statbuf->lsn, - (unsigned int) p_statbuf->size); + report ( stdout, " %s %3d %d %d [LSN %6lu] %9u", + iso9660_get_rock_attr_str (p_statbuf->rr.st_mode), + p_statbuf->rr.st_nlinks, + p_statbuf->rr.st_uid, + p_statbuf->rr.st_gid, + (long unsigned int) p_statbuf->lsn, + S_ISLNK(p_statbuf->rr.st_mode) + ? strlen(p_statbuf->rr.psz_symlink) + : (unsigned int) p_statbuf->size ); } else if (b_xa) { - report (stdout, " %s %d %d [fn %.2d] [LSN %6lu] ", + report ( stdout, " %s %d %d [fn %.2d] [LSN %6lu] ", iso9660_get_xa_attr_str (p_statbuf->xa.attributes), uint16_from_be (p_statbuf->xa.user_id), uint16_from_be (p_statbuf->xa.group_id), p_statbuf->xa.filenum, - (long unsigned int) p_statbuf->lsn); + (long unsigned int) p_statbuf->lsn ); if (uint16_from_be(p_statbuf->xa.attributes) & XA_ATTR_MODE2FORM2) { - report (stdout, "%9u (%9u)", - (unsigned int) p_statbuf->secsize * M2F2_SECTOR_SIZE, - (unsigned int) p_statbuf->size); + report ( stdout, "%9u (%9u)", + (unsigned int) p_statbuf->secsize * M2F2_SECTOR_SIZE, + (unsigned int) p_statbuf->size ); } else report (stdout, "%9u", (unsigned int) p_statbuf->size); } else { - report (stdout," %c [LSN %6lu] %9u", - (p_statbuf->type == _STAT_DIR) ? 'd' : '-', - (long unsigned int) p_statbuf->lsn, - (unsigned int) p_statbuf->size); + report ( stdout," %c [LSN %6lu] %9u", + (p_statbuf->type == _STAT_DIR) ? 'd' : '-', + (long unsigned int) p_statbuf->lsn, + (unsigned int) p_statbuf->size ); } - strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M ", &p_statbuf->tm); - report (stdout," %s %s", date_str, - yep == p_statbuf->rr.b3_rock && b_rock - ? psz_name_untranslated : psz_name_translated); - if (yep == p_statbuf->rr.b3_rock && b_rock - && S_ISLNK(p_statbuf->rr.st_mode)) { - report(stdout, " -> %s", p_statbuf->rr.psz_symlink); + if (yep == p_statbuf->rr.b3_rock && b_rock) { + struct tm tm; + + strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M ", &p_statbuf->tm); + + /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. + Try to handle this correctly for either case. */ + if (p_statbuf->rr.create.b_used) { + if (p_statbuf->rr.create.b_longdate) { + iso9660_get_ltime(&p_statbuf->rr.create.t.ltime, &tm); + } else { + iso9660_get_dtime(&p_statbuf->rr.create.t.dtime, true, &tm); + } + strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M ", &p_statbuf->tm); + } + + /* Now try the proper field for ctime: attributes */ + if (p_statbuf->rr.attributes.b_used) { + if (p_statbuf->rr.create.b_longdate) { + iso9660_get_ltime(&p_statbuf->rr.attributes.t.ltime, &tm); + } else { + iso9660_get_dtime(&p_statbuf->rr.attributes.t.dtime, true, &tm); + } + strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M ", &tm); + } + + report (stdout," %s %s", date_str, psz_name_untranslated ); + + if (S_ISLNK(p_statbuf->rr.st_mode)) { + report(stdout, " -> %s", p_statbuf->rr.psz_symlink); + } + + } else { + strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M ", &p_statbuf->tm); + report (stdout," %s %s", date_str, psz_name_translated); } - + report(stdout, "\n"); - }