Blame lib/iso9660/iso9660.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2003-2009, 2013-2014, 2016-2017 Rocky Bernstein
Packit dd8086
  <rocky@gnu.org>
Packit dd8086
  Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086

Packit dd8086
/*! String inside frame which identifies an ISO 9660 filesystem. This
Packit dd8086
    string is the "id" field of an iso9660_pvd_t or an iso9660_svd_t.
Packit dd8086
    Note should come *before* #include <cdio/iso9660.h> which does
Packit dd8086
    a #define of this name.
Packit dd8086
*/
Packit dd8086
const char ISO_STANDARD_ID[] = {'C', 'D', '0', '0', '1'};
Packit dd8086
Packit dd8086
/* Private headers */
Packit dd8086
#include "iso9660_private.h"
Packit dd8086
#include "cdio_assert.h"
Packit dd8086
Packit dd8086
/* Public headers */
Packit dd8086
#include <cdio/bytesex.h>
Packit dd8086
#include <cdio/iso9660.h>
Packit dd8086
#include <cdio/util.h>
Packit dd8086
Packit dd8086
#include <time.h>
Packit dd8086
#include <ctype.h>
Packit dd8086
#ifdef HAVE_STRING_H
Packit dd8086
# include <string.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_STDIO_H
Packit dd8086
# include <stdio.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_LIMITS_H
Packit dd8086
# include <limits.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_STDLIB_H
Packit dd8086
# include <stdlib.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_SYS_STAT_H
Packit dd8086
# include <sys/stat.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_ERRNO_H
Packit dd8086
#include <errno.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifndef HAVE_SETENV
Packit dd8086
static int
Packit dd8086
setenv(const char *envname, const char *envval, int overwrite)
Packit dd8086
{
Packit dd8086
  return -1;
Packit dd8086
}
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifndef HAVE_UNSETENV
Packit dd8086
static int
Packit dd8086
unsetenv(const char *envname)
Packit dd8086
{
Packit dd8086
  return -1;
Packit dd8086
}
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifndef HAVE_TIMEGM
Packit dd8086
static time_t
Packit dd8086
timegm(struct tm *tm)
Packit dd8086
{
Packit dd8086
  time_t ret;
Packit dd8086
  char *tz;
Packit dd8086
Packit dd8086
  tz = getenv("TZ");
Packit dd8086
  setenv("TZ", "UTC", 1);
Packit dd8086
  tzset();
Packit dd8086
  ret = mktime(tm);
Packit dd8086
  if (tz)
Packit dd8086
    setenv("TZ", tz, 1);
Packit dd8086
  else
Packit dd8086
    unsetenv("TZ");
Packit dd8086
  tzset();
Packit dd8086
  return ret;
Packit dd8086
}
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifndef HAVE_GMTIME_R
Packit dd8086
static struct tm *
Packit dd8086
gmtime_r(const time_t *timer, struct tm *result)
Packit dd8086
{
Packit dd8086
    struct tm *tmp = gmtime(timer);
Packit dd8086
Packit dd8086
    if (tmp) {
Packit dd8086
        *result = *tmp;
Packit dd8086
        return result;
Packit dd8086
    }
Packit dd8086
    return tmp;
Packit dd8086
}
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifndef HAVE_LOCALTIME_R
Packit dd8086
static struct tm *
Packit dd8086
localtime_r(const time_t *timer, struct tm *result)
Packit dd8086
{
Packit dd8086
    struct tm *tmp = localtime(timer);
Packit dd8086
Packit dd8086
    if (tmp) {
Packit dd8086
        *result = *tmp;
Packit dd8086
        return result;
Packit dd8086
    }
Packit dd8086
    return tmp;
Packit dd8086
}
Packit dd8086
#endif
Packit dd8086
Packit dd8086
/* Variables to hold debugger-helping enumerations */
Packit dd8086
enum iso_enum1_s     iso_enums1;
Packit dd8086
enum iso_flag_enum_s iso_flag_enums;
Packit dd8086
enum iso_vd_enum_s   iso_vd_enums;
Packit dd8086
enum iso_extension_enum_s iso_extension_enums;
Packit dd8086
Packit dd8086
/* some parameters... */
Packit dd8086
#define SYSTEM_ID         "CD-RTOS CD-BRIDGE"
Packit dd8086
#define VOLUME_SET_ID     ""
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Change trailing blanks in str to nulls.  Str has a maximum size of
Packit dd8086
   n characters.
Packit dd8086
*/
Packit dd8086
static char *
Packit dd8086
strip_trail (const char str[], size_t n)
Packit dd8086
{
Packit dd8086
  static char buf[1025];
Packit dd8086
  int j;
Packit dd8086
Packit dd8086
  cdio_assert (n < 1024);
Packit dd8086
Packit dd8086
  strncpy (buf, str, n);
Packit dd8086
  buf[n] = '\0';
Packit dd8086
Packit dd8086
  for (j = strlen (buf) - 1; j >= 0; j--)
Packit dd8086
    {
Packit dd8086
      if (buf[j] != ' ')
Packit dd8086
        break;
Packit dd8086
Packit dd8086
      buf[j] = '\0';
Packit dd8086
    }
Packit dd8086
Packit dd8086
  return buf;
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
pathtable_get_size_and_entries(const void *pt, unsigned int *size,
Packit dd8086
                               unsigned int *entries);
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Get time structure from structure in an ISO 9660 directory index
Packit dd8086
  record. Even though tm_wday and tm_yday fields are not explicitly in
Packit dd8086
  idr_date, the are calculated from the other fields.
Packit dd8086
Packit dd8086
  If tm is to reflect the localtime set b_localtime true, otherwise
Packit dd8086
  tm will reported in GMT.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_get_dtime (const iso9660_dtime_t *idr_date, bool b_localtime,
Packit dd8086
                   /*out*/ struct tm *p_tm)
Packit dd8086
{
Packit dd8086
  if (!idr_date) return false;
Packit dd8086
Packit dd8086
  /*
Packit dd8086
     Section 9.1.5 of ECMA 119 says:
Packit dd8086
     If all seven numbers are zero, it shall mean that the date and
Packit dd8086
     time are not specified.
Packit dd8086
Packit dd8086
     HACK: However we've seen it happen that everything except gmtoff
Packit dd8086
     is zero and the expected date is the beginning of the epoch. So
Packit dd8086
     we accept 6 numbers being zero. I'm also not sure if using the
Packit dd8086
     beginning of the Epoch is also the right thing to do either.
Packit dd8086
  */
Packit dd8086
Packit dd8086
  if ( 0 == idr_date->dt_year   && 0 == idr_date->dt_month &&
Packit dd8086
       0 == idr_date->dt_day    && 0 == idr_date->dt_hour  &&
Packit dd8086
       0 == idr_date->dt_minute && 0 == idr_date->dt_second ) {
Packit dd8086
    time_t t = 0;
Packit dd8086
    struct tm temp_tm;
Packit dd8086
    localtime_r(&t, &temp_tm);
Packit dd8086
Packit dd8086
    memcpy(p_tm, &temp_tm, sizeof(struct tm));
Packit dd8086
    return true;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  memset(p_tm, 0, sizeof(struct tm));
Packit dd8086
Packit dd8086
  p_tm->tm_year   = idr_date->dt_year;
Packit dd8086
  p_tm->tm_mon    = idr_date->dt_month - 1;
Packit dd8086
  p_tm->tm_mday   = idr_date->dt_day;
Packit dd8086
  p_tm->tm_hour   = idr_date->dt_hour;
Packit dd8086
  p_tm->tm_min    = idr_date->dt_minute;
Packit dd8086
  p_tm->tm_sec    = idr_date->dt_second - idr_date->dt_gmtoff * (15 * 60);
Packit dd8086
  p_tm->tm_isdst  = -1; /* information not available */
Packit dd8086
Packit dd8086
#ifdef HAVE_STRUCT_TM_TM_ZONE
Packit dd8086
  /* Initialize everything */
Packit dd8086
  p_tm->tm_zone   = 0;
Packit dd8086
#endif
Packit dd8086
Packit dd8086
  /* Recompute tm_wday and tm_yday via mktime. mktime will also renormalize
Packit dd8086
     date values to account for the timezone offset. */
Packit dd8086
  {
Packit dd8086
    time_t t = 0;
Packit dd8086
    struct tm temp_tm;
Packit dd8086
Packit dd8086
    t = timegm(p_tm);
Packit dd8086
Packit dd8086
    if (b_localtime)
Packit dd8086
      localtime_r(&t, &temp_tm);
Packit dd8086
    else
Packit dd8086
      gmtime_r(&t, &temp_tm);
Packit dd8086
Packit dd8086
    memcpy(p_tm, &temp_tm, sizeof(struct tm));
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*
Packit dd8086
   A note regarding the strange strtol() testing below as pointed out SMS.
Packit dd8086
   From man strtol:
Packit dd8086
Packit dd8086
     If an underflow occurs, strtol() returns LONG_MIN. If an overflow
Packit dd8086
     occurs, strtol() returns LONG_MAX.  In both cases, errno is set to
Packit dd8086
     ERANGE.
Packit dd8086
Packit dd8086
   This implies that one should only look at errno if the value is
Packit dd8086
   LONG_MIN or LONG_MAX.
Packit dd8086
*/
Packit dd8086
Packit dd8086
#define set_ltime_field(TM_FIELD, LT_FIELD, ADD_CONSTANT)               \
Packit dd8086
  {                                                                     \
Packit dd8086
    char num[10]; long tmp;                                             \
Packit dd8086
    memcpy(num, p_ldate->LT_FIELD, sizeof(p_ldate->LT_FIELD));          \
Packit dd8086
    num[sizeof(p_ldate->LT_FIELD)] = '\0';                              \
Packit dd8086
    errno = 0;                                                          \
Packit dd8086
    tmp = strtol(num,                                                   \
Packit dd8086
                 (char **)NULL, 10);                                    \
Packit dd8086
    if ( tmp < INT_MIN || tmp > INT_MAX ||                              \
Packit dd8086
         ((unsigned long)tmp + ADD_CONSTANT) > INT_MAX ||               \
Packit dd8086
         (tmp + ADD_CONSTANT) < INT_MIN )                               \
Packit dd8086
      return false;                                                     \
Packit dd8086
    p_tm->TM_FIELD = tmp + ADD_CONSTANT;                                \
Packit dd8086
  }
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Get "long" time in format used in ISO 9660 primary volume descriptor
Packit dd8086
  from a Unix time structure.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_get_ltime (const iso9660_ltime_t *p_ldate,
Packit dd8086
                   /*out*/ struct tm *p_tm)
Packit dd8086
{
Packit dd8086
  if (!p_tm) return false;
Packit dd8086
  memset(p_tm, 0, sizeof(struct tm));
Packit dd8086
  set_ltime_field(tm_year, lt_year,  -1900);
Packit dd8086
  set_ltime_field(tm_mon,  lt_month, -1);
Packit dd8086
  set_ltime_field(tm_mday, lt_day,    0);
Packit dd8086
  set_ltime_field(tm_hour, lt_hour,   0);
Packit dd8086
  set_ltime_field(tm_min,  lt_minute, 0);
Packit dd8086
  set_ltime_field(tm_sec,  lt_second, 0);
Packit dd8086
  p_tm->tm_isdst= -1; /* information not available */
Packit dd8086
#ifndef HAVE_TM_GMTOFF
Packit dd8086
  p_tm->tm_sec += p_ldate->lt_gmtoff * (15 * 60);
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_STRUCT_TM_TM_ZONE
Packit dd8086
  /* Initialize everything */
Packit dd8086
  p_tm->tm_zone = 0;
Packit dd8086
#endif
Packit dd8086
Packit dd8086
  /* Recompute tm_wday and tm_yday via mktime. mktime will also renormalize
Packit dd8086
     date values to account for the timezone offset. */
Packit dd8086
  {
Packit dd8086
    time_t t;
Packit dd8086
    struct tm temp_tm;
Packit dd8086
Packit dd8086
    t = mktime(p_tm);
Packit dd8086
Packit dd8086
    localtime_r(&t, &temp_tm);
Packit dd8086
Packit dd8086
    memcpy(p_tm, &temp_tm, sizeof(struct tm));
Packit dd8086
  }
Packit dd8086
  p_tm->tm_isdst= -1; /* information not available */
Packit dd8086
#ifdef HAVE_TM_GMTOFF
Packit dd8086
  p_tm->tm_gmtoff = -p_ldate->lt_gmtoff * (15 * 60);
Packit dd8086
#endif
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Set time in format used in ISO 9660 directory index record
Packit dd8086
  from a Unix time structure. timezone is given as an offset
Packit dd8086
  correction in minutes.
Packit dd8086
*/
Packit dd8086
void
Packit dd8086
iso9660_set_dtime_with_timezone (const struct tm *p_tm,
Packit dd8086
                                 int time_zone,
Packit dd8086
                                 /*out*/ iso9660_dtime_t *p_idr_date)
Packit dd8086
{
Packit dd8086
  memset (p_idr_date, 0, 7);
Packit dd8086
Packit dd8086
  if (!p_tm) return;
Packit dd8086
Packit dd8086
  p_idr_date->dt_year   = p_tm->tm_year;
Packit dd8086
  p_idr_date->dt_month  = p_tm->tm_mon + 1;
Packit dd8086
  p_idr_date->dt_day    = p_tm->tm_mday;
Packit dd8086
  p_idr_date->dt_hour   = p_tm->tm_hour;
Packit dd8086
  p_idr_date->dt_minute = p_tm->tm_min;
Packit dd8086
  p_idr_date->dt_second = p_tm->tm_sec;
Packit dd8086
Packit dd8086
  /* The ISO 9660 timezone is in the range -48..+52 and each unit
Packit dd8086
     represents a 15-minute interval. */
Packit dd8086
  p_idr_date->dt_gmtoff = time_zone / 15;
Packit dd8086
Packit dd8086
  if (p_idr_date->dt_gmtoff < -48 ) {
Packit dd8086
Packit dd8086
    cdio_warn ("Converted ISO 9660 timezone %d is less than -48. Adjusted",
Packit dd8086
               p_idr_date->dt_gmtoff);
Packit dd8086
    p_idr_date->dt_gmtoff = -48;
Packit dd8086
  } else if (p_idr_date->dt_gmtoff > 52) {
Packit dd8086
    cdio_warn ("Converted ISO 9660 timezone %d is over 52. Adjusted",
Packit dd8086
               p_idr_date->dt_gmtoff);
Packit dd8086
    p_idr_date->dt_gmtoff = 52;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Set time in format used in ISO 9660 directory index record
Packit dd8086
  from a Unix time structure. */
Packit dd8086
void
Packit dd8086
iso9660_set_dtime(const struct tm *p_tm, /*out*/ iso9660_dtime_t *p_idr_date)
Packit dd8086
{
Packit dd8086
  int time_zone = 0;
Packit dd8086
  if (p_tm) {
Packit dd8086
#ifdef HAVE_TM_GMTOFF
Packit dd8086
    /* Convert seconds to minutes */
Packit dd8086
    time_zone = p_tm->tm_gmtoff / 60;
Packit dd8086
#else
Packit dd8086
    time_zone = (p_tm->tm_isdst > 0) ? -60 : 0;
Packit dd8086
#endif
Packit dd8086
  }
Packit dd8086
  iso9660_set_dtime_with_timezone (p_tm, time_zone, p_idr_date);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Set "long" time in format used in ISO 9660 primary volume descriptor
Packit dd8086
  from a Unix time structure. timezone is given as an offset
Packit dd8086
  correction in minutes.
Packit dd8086
*/
Packit dd8086
void
Packit dd8086
iso9660_set_ltime_with_timezone(const struct tm *p_tm,
Packit dd8086
                                int time_zone,
Packit dd8086
                                /*out*/ iso9660_ltime_t *pvd_date)
Packit dd8086
{
Packit dd8086
  char *_pvd_date = (char *) pvd_date;
Packit dd8086
Packit dd8086
  memset (_pvd_date, (int) '0', 16);
Packit dd8086
  pvd_date->lt_gmtoff = (iso712_t) 0; /* Start out with time zone GMT. */
Packit dd8086
Packit dd8086
  if (!p_tm) return;
Packit dd8086
Packit dd8086
  snprintf(_pvd_date, 17,
Packit dd8086
           "%4.4d%2.2d%2.2d" "%2.2d%2.2d%2.2d" "%2.2d",
Packit dd8086
           p_tm->tm_year + 1900, p_tm->tm_mon + 1, p_tm->tm_mday,
Packit dd8086
           p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec,
Packit dd8086
           0 /* 1/100 secs */ );
Packit dd8086
Packit dd8086
  /* Set time zone in 15-minute interval encoding. */
Packit dd8086
  pvd_date->lt_gmtoff -= (time_zone / 15);
Packit dd8086
  if (pvd_date->lt_gmtoff < -48 ) {
Packit dd8086
Packit dd8086
    cdio_warn ("Converted ISO 9660 timezone %d is less than -48. Adjusted",
Packit dd8086
               (int) pvd_date->lt_gmtoff);
Packit dd8086
    pvd_date->lt_gmtoff = -48;
Packit dd8086
  } else if (pvd_date->lt_gmtoff > 52) {
Packit dd8086
    cdio_warn ("Converted ISO 9660 timezone %d is over 52. Adjusted",
Packit dd8086
               (int) pvd_date->lt_gmtoff);
Packit dd8086
    pvd_date->lt_gmtoff = 52;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Set "long" time in format used in ISO 9660 primary volume descriptor
Packit dd8086
  from a Unix time structure. */
Packit dd8086
void
Packit dd8086
iso9660_set_ltime(const struct tm *p_tm, /*out*/ iso9660_ltime_t *pvd_date)
Packit dd8086
{
Packit dd8086
  int time_zone = 0;
Packit dd8086
  if (p_tm) {
Packit dd8086
#ifdef HAVE_TM_GMTOFF
Packit dd8086
    /* Set time zone in 15-minute interval encoding. */
Packit dd8086
    time_zone = p_tm->tm_gmtoff / 60;
Packit dd8086
#else
Packit dd8086
    time_zone = (p_tm->tm_isdst > 0) ? -60 : 0;
Packit dd8086
#endif
Packit dd8086
  }
Packit dd8086
  iso9660_set_ltime_with_timezone (p_tm, time_zone, pvd_date);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Convert an ISO-9660 file name which is in the format usually stored
Packit dd8086
   in a ISO 9660 directory entry into what's usually listed as the
Packit dd8086
   file name in a listing.  Lowercase name, and remove trailing ;1's
Packit dd8086
   or .;1's and turn the other ;'s into version numbers.
Packit dd8086
Packit dd8086
   @param psz_oldname the ISO-9660 filename to be translated.
Packit dd8086
   @param psz_newname returned string. The caller allocates this and
Packit dd8086
   it should be at least the size of psz_oldname.
Packit dd8086
   @return length of the translated string is returned. It will be no greater
Packit dd8086
   than the length of psz_oldname.
Packit dd8086
*/
Packit dd8086
int
Packit dd8086
iso9660_name_translate(const char *psz_oldname, char *psz_newname)
Packit dd8086
{
Packit dd8086
  return iso9660_name_translate_ext(psz_oldname, psz_newname, 0);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Convert an ISO-9660 file name which is in the format usually stored
Packit dd8086
   in a ISO 9660 directory entry into what's usually listed as the
Packit dd8086
   file name in a listing.  Lowercase name if no Joliet Extension
Packit dd8086
   interpretation. Remove trailing ;1's or .;1's and turn the other
Packit dd8086
   ;'s into version numbers.
Packit dd8086
Packit dd8086
   @param psz_oldname the ISO-9660 filename to be translated.
Packit dd8086
   @param psz_newname returned string. The caller allocates this and
Packit dd8086
   it should be at least the size of psz_oldname.
Packit dd8086
   @param u_joliet_level 0 if not using Joliet Extension. Otherwise the
Packit dd8086
   Joliet level.
Packit dd8086
   @return length of the translated string is returned. It will be no greater
Packit dd8086
   than the length of psz_oldname.
Packit dd8086
*/
Packit dd8086
int
Packit dd8086
iso9660_name_translate_ext(const char *psz_oldname, char *psz_newname,
Packit dd8086
                           uint8_t u_joliet_level)
Packit dd8086
{
Packit dd8086
  int len = strlen(psz_oldname);
Packit dd8086
  int i;
Packit dd8086
Packit dd8086
  if (0 == len) return 0;
Packit dd8086
  for (i = 0; i < len; i++) {
Packit dd8086
    unsigned char c = psz_oldname[i];
Packit dd8086
    if (!c)
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    /* Lower case, unless we have Joliet extensions.  */
Packit dd8086
    if (!u_joliet_level && isupper(c)) c = tolower(c);
Packit dd8086
Packit dd8086
    /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
Packit dd8086
    if (c == '.' && i == len - 3
Packit dd8086
        && psz_oldname[i + 1] == ';' && psz_oldname[i + 2] == '1')
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    /* Drop trailing ';1' */
Packit dd8086
    if (c == ';' && i == len - 2 && psz_oldname[i + 1] == '1')
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    /* Convert remaining ';' to '.' */
Packit dd8086
    if (c == ';')
Packit dd8086
      c = '.';
Packit dd8086
Packit dd8086
    psz_newname[i] = c;
Packit dd8086
  }
Packit dd8086
  psz_newname[i] = '\0';
Packit dd8086
  return i;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Pad string src with spaces to size len and copy this to dst. If
Packit dd8086
  len is less than the length of src, dst will be truncated to the
Packit dd8086
  first len characters of src.
Packit dd8086
Packit dd8086
  src can also be scanned to see if it contains only ACHARs, DCHARs,
Packit dd8086
  7-bit ASCII chars depending on the enumeration _check.
Packit dd8086
Packit dd8086
  In addition to getting changed, dst is the return value.
Packit dd8086
  Note: this string might not be NULL terminated.
Packit dd8086
 */
Packit dd8086
char *
Packit dd8086
iso9660_strncpy_pad(char dst[], const char src[], size_t len,
Packit dd8086
                    enum strncpy_pad_check _check)
Packit dd8086
{
Packit dd8086
  size_t rlen;
Packit dd8086
Packit dd8086
  cdio_assert (dst != NULL);
Packit dd8086
  cdio_assert (src != NULL);
Packit dd8086
  cdio_assert (len > 0);
Packit dd8086
Packit dd8086
  switch (_check)
Packit dd8086
    {
Packit dd8086
      int idx;
Packit dd8086
    case ISO9660_NOCHECK:
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    case ISO9660_7BIT:
Packit dd8086
      for (idx = 0; src[idx]; idx++)
Packit dd8086
        if ((int8_t) src[idx] < 0)
Packit dd8086
          {
Packit dd8086
            cdio_warn ("string '%s' fails 7bit constraint (pos = %d)",
Packit dd8086
                      src, idx);
Packit dd8086
            break;
Packit dd8086
          }
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    case ISO9660_ACHARS:
Packit dd8086
      for (idx = 0; src[idx]; idx++)
Packit dd8086
        if (!iso9660_is_achar (src[idx]))
Packit dd8086
          {
Packit dd8086
            cdio_warn ("string '%s' fails a-character constraint (pos = %d)",
Packit dd8086
                      src, idx);
Packit dd8086
            break;
Packit dd8086
          }
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    case ISO9660_DCHARS:
Packit dd8086
      for (idx = 0; src[idx]; idx++)
Packit dd8086
        if (!iso9660_is_dchar (src[idx]))
Packit dd8086
          {
Packit dd8086
            cdio_warn ("string '%s' fails d-character constraint (pos = %d)",
Packit dd8086
                      src, idx);
Packit dd8086
            break;
Packit dd8086
          }
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    default:
Packit dd8086
      cdio_assert_not_reached ();
Packit dd8086
      break;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  rlen = strlen (src);
Packit dd8086
Packit dd8086
  if (rlen > len)
Packit dd8086
    cdio_warn ("string '%s' is getting truncated to %d characters",
Packit dd8086
              src, (unsigned int) len);
Packit dd8086
Packit dd8086
  strncpy (dst, src, len);
Packit dd8086
  if (rlen < len)
Packit dd8086
    memset(dst+rlen, ' ', len-rlen);
Packit dd8086
  return dst;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return true if c is a DCHAR - a valid ISO-9660 level 1 character.
Packit dd8086
   These are the ASCSII capital letters A-Z, the digits 0-9 and an
Packit dd8086
   underscore.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_is_dchar (int c)
Packit dd8086
{
Packit dd8086
  if (!IN (c, 0x30, 0x5f)
Packit dd8086
      || IN (c, 0x3a, 0x40)
Packit dd8086
      || IN (c, 0x5b, 0x5e))
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return true if c is an ACHAR -
Packit dd8086
   These are the DCHAR's plus some ASCII symbols including the space
Packit dd8086
   symbol.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_is_achar (int c)
Packit dd8086
{
Packit dd8086
  if (!IN (c, 0x20, 0x5f)
Packit dd8086
      || IN (c, 0x23, 0x24)
Packit dd8086
      || c == 0x40
Packit dd8086
      || IN (c, 0x5b, 0x5e))
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
void
Packit dd8086
iso9660_set_evd(void *pd)
Packit dd8086
{
Packit dd8086
  iso_volume_descriptor_t ied;
Packit dd8086
Packit dd8086
  cdio_assert (sizeof(iso_volume_descriptor_t) == ISO_BLOCKSIZE);
Packit dd8086
Packit dd8086
  cdio_assert (pd != NULL);
Packit dd8086
Packit dd8086
  memset(&ied, 0, sizeof(ied));
Packit dd8086
Packit dd8086
  ied.type = to_711(ISO_VD_END);
Packit dd8086
  iso9660_strncpy_pad (ied.id, ISO_STANDARD_ID, sizeof(ied.id),
Packit dd8086
                       ISO9660_DCHARS);
Packit dd8086
  ied.version = to_711(ISO_VERSION);
Packit dd8086
Packit dd8086
  memcpy(pd, &ied, sizeof(ied));
Packit dd8086
}
Packit dd8086
Packit dd8086
void
Packit dd8086
iso9660_set_pvd(void *pd,
Packit dd8086
                const char volume_id[],
Packit dd8086
                const char publisher_id[],
Packit dd8086
                const char preparer_id[],
Packit dd8086
                const char application_id[],
Packit dd8086
                uint32_t iso_size,
Packit dd8086
                const void *root_dir,
Packit dd8086
                uint32_t path_table_l_extent,
Packit dd8086
                uint32_t path_table_m_extent,
Packit dd8086
                uint32_t path_table_size,
Packit dd8086
                const time_t *pvd_time
Packit dd8086
                )
Packit dd8086
{
Packit dd8086
  iso9660_pvd_t ipd;
Packit dd8086
  struct tm temp_tm;
Packit dd8086
Packit dd8086
  cdio_assert (sizeof(iso9660_pvd_t) == ISO_BLOCKSIZE);
Packit dd8086
Packit dd8086
  cdio_assert (pd != NULL);
Packit dd8086
  cdio_assert (volume_id != NULL);
Packit dd8086
  cdio_assert (application_id != NULL);
Packit dd8086
Packit dd8086
  memset(&ipd,0,sizeof(ipd)); /* paranoia? */
Packit dd8086
Packit dd8086
  /* magic stuff ... thatis CD XA marker... */
Packit dd8086
  strncpy(((char*)&ipd)+ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING,
Packit dd8086
          sizeof(ISO_XA_MARKER_STRING));
Packit dd8086
Packit dd8086
  ipd.type = to_711(ISO_VD_PRIMARY);
Packit dd8086
  iso9660_strncpy_pad (ipd.id, ISO_STANDARD_ID, 5, ISO9660_DCHARS);
Packit dd8086
  ipd.version = to_711(ISO_VERSION);
Packit dd8086
Packit dd8086
  iso9660_strncpy_pad (ipd.system_id, SYSTEM_ID, 32, ISO9660_ACHARS);
Packit dd8086
  iso9660_strncpy_pad (ipd.volume_id, volume_id, 32, ISO9660_DCHARS);
Packit dd8086
Packit dd8086
  ipd.volume_space_size = to_733(iso_size);
Packit dd8086
Packit dd8086
  ipd.volume_set_size = to_723(1);
Packit dd8086
  ipd.volume_sequence_number = to_723(1);
Packit dd8086
  ipd.logical_block_size = to_723(ISO_BLOCKSIZE);
Packit dd8086
Packit dd8086
  ipd.path_table_size = to_733(path_table_size);
Packit dd8086
  ipd.type_l_path_table = to_731(path_table_l_extent);
Packit dd8086
  ipd.type_m_path_table = to_732(path_table_m_extent);
Packit dd8086
Packit dd8086
  /* root_directory_record doesn't contain the 1-byte filename,
Packit dd8086
     so we add one for that. */
Packit dd8086
  cdio_assert (sizeof(ipd.root_directory_record) == 33);
Packit dd8086
  memcpy(&(ipd.root_directory_record), root_dir,
Packit dd8086
         sizeof(ipd.root_directory_record));
Packit dd8086
  ipd.root_directory_filename='\0';
Packit dd8086
  ipd.root_directory_record.length = sizeof(ipd.root_directory_record)+1;
Packit dd8086
  iso9660_strncpy_pad (ipd.volume_set_id, VOLUME_SET_ID,
Packit dd8086
                       ISO_MAX_VOLUMESET_ID, ISO9660_DCHARS);
Packit dd8086
Packit dd8086
  iso9660_strncpy_pad (ipd.publisher_id, publisher_id, ISO_MAX_PUBLISHER_ID,
Packit dd8086
                       ISO9660_ACHARS);
Packit dd8086
  iso9660_strncpy_pad (ipd.preparer_id, preparer_id, ISO_MAX_PREPARER_ID,
Packit dd8086
                       ISO9660_ACHARS);
Packit dd8086
  iso9660_strncpy_pad (ipd.application_id, application_id,
Packit dd8086
                       ISO_MAX_APPLICATION_ID, ISO9660_ACHARS);
Packit dd8086
Packit dd8086
  iso9660_strncpy_pad (ipd.copyright_file_id    , "", 37, ISO9660_DCHARS);
Packit dd8086
  iso9660_strncpy_pad (ipd.abstract_file_id     , "", 37, ISO9660_DCHARS);
Packit dd8086
  iso9660_strncpy_pad (ipd.bibliographic_file_id, "", 37, ISO9660_DCHARS);
Packit dd8086
Packit dd8086
  gmtime_r(pvd_time, &temp_tm);
Packit dd8086
  iso9660_set_ltime (&temp_tm, &(ipd.creation_date));
Packit dd8086
  gmtime_r(pvd_time, &temp_tm);
Packit dd8086
  iso9660_set_ltime (&temp_tm, &(ipd.modification_date));
Packit dd8086
  iso9660_set_ltime (NULL,     &(ipd.expiration_date));
Packit dd8086
  iso9660_set_ltime (NULL,     &(ipd.effective_date));
Packit dd8086
Packit dd8086
  ipd.file_structure_version = to_711(1);
Packit dd8086
Packit dd8086
  /* we leave ipd.application_data = 0 */
Packit dd8086
Packit dd8086
  memcpy(pd, &ipd, sizeof(ipd)); /* copy stuff to arg ptr */
Packit dd8086
}
Packit dd8086
Packit dd8086
unsigned int
Packit dd8086
iso9660_dir_calc_record_size(unsigned int namelen, unsigned int su_len)
Packit dd8086
{
Packit dd8086
  unsigned int length;
Packit dd8086
Packit dd8086
  length = sizeof(iso9660_dir_t);
Packit dd8086
  length += namelen;
Packit dd8086
  if (length % 2) /* pad to word boundary */
Packit dd8086
    length++;
Packit dd8086
  length += su_len;
Packit dd8086
  if (length % 2) /* pad to word boundary again */
Packit dd8086
    length++;
Packit dd8086
Packit dd8086
  return length;
Packit dd8086
}
Packit dd8086
Packit dd8086
void
Packit dd8086
iso9660_dir_add_entry_su(void *dir,
Packit dd8086
                         const char filename[],
Packit dd8086
                         uint32_t extent,
Packit dd8086
                         uint32_t size,
Packit dd8086
                         uint8_t file_flags,
Packit dd8086
                         const void *su_data,
Packit dd8086
                         unsigned int su_size,
Packit dd8086
                         const time_t *entry_time)
Packit dd8086
{
Packit dd8086
  iso9660_dir_t *idr = dir;
Packit dd8086
  uint8_t *dir8 = dir;
Packit dd8086
  unsigned int offset = 0;
Packit dd8086
  uint32_t dsize = from_733(idr->size);
Packit dd8086
  int length, su_offset;
Packit dd8086
  struct tm temp_tm;
Packit dd8086
  cdio_assert (sizeof(iso9660_dir_t) == 33);
Packit dd8086
Packit dd8086
  if (!dsize && !idr->length)
Packit dd8086
    dsize = ISO_BLOCKSIZE; /* for when dir lacks '.' entry */
Packit dd8086
Packit dd8086
  cdio_assert (dsize > 0 && !(dsize % ISO_BLOCKSIZE));
Packit dd8086
  cdio_assert (dir != NULL);
Packit dd8086
  cdio_assert (extent > 17);
Packit dd8086
  cdio_assert (filename != NULL);
Packit dd8086
  cdio_assert (strlen(filename) <= MAX_ISOPATHNAME);
Packit dd8086
Packit dd8086
  length = sizeof(iso9660_dir_t);
Packit dd8086
  length += strlen(filename);
Packit dd8086
  length = _cdio_ceil2block (length, 2); /* pad to word boundary */
Packit dd8086
  su_offset = length;
Packit dd8086
  length += su_size;
Packit dd8086
  length = _cdio_ceil2block (length, 2); /* pad to word boundary again */
Packit dd8086
Packit dd8086
  /* find the last entry's end */
Packit dd8086
  {
Packit dd8086
    unsigned int ofs_last_rec = 0;
Packit dd8086
Packit dd8086
    offset = 0;
Packit dd8086
    while (offset < dsize)
Packit dd8086
      {
Packit dd8086
        if (!dir8[offset])
Packit dd8086
          {
Packit dd8086
            offset++;
Packit dd8086
            continue;
Packit dd8086
          }
Packit dd8086
Packit dd8086
        offset += dir8[offset];
Packit dd8086
        ofs_last_rec = offset;
Packit dd8086
      }
Packit dd8086
Packit dd8086
    cdio_assert (offset == dsize);
Packit dd8086
Packit dd8086
    offset = ofs_last_rec;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* be sure we don't cross sectors boundaries */
Packit dd8086
  offset = _cdio_ofs_add (offset, length, ISO_BLOCKSIZE);
Packit dd8086
  offset -= length;
Packit dd8086
Packit dd8086
  cdio_assert (offset + length <= dsize);
Packit dd8086
Packit dd8086
  idr = (iso9660_dir_t *) &dir8[offset];
Packit dd8086
Packit dd8086
  cdio_assert (offset+length < dsize);
Packit dd8086
Packit dd8086
  memset(idr, 0, length);
Packit dd8086
Packit dd8086
  idr->length = to_711(length);
Packit dd8086
  idr->extent = to_733(extent);
Packit dd8086
  idr->size = to_733(size);
Packit dd8086
Packit dd8086
  gmtime_r(entry_time, &temp_tm);
Packit dd8086
  iso9660_set_dtime (&temp_tm, &(idr->recording_time));
Packit dd8086
Packit dd8086
  idr->file_flags = to_711(file_flags);
Packit dd8086
Packit dd8086
  idr->volume_sequence_number = to_723(1);
Packit dd8086
Packit dd8086
  idr->filename.len = to_711(strlen(filename)
Packit dd8086
                             ? strlen(filename) : 1); /* working hack! */
Packit dd8086
Packit dd8086
  memcpy(&idr->filename.str[1], filename, from_711(idr->filename.len));
Packit dd8086
  if (su_size > 0 && su_data)
Packit dd8086
    memcpy(&dir8[offset] + su_offset, su_data, su_size);
Packit dd8086
}
Packit dd8086
Packit dd8086
void
Packit dd8086
iso9660_dir_init_new (void *dir,
Packit dd8086
                      uint32_t self,
Packit dd8086
                      uint32_t ssize,
Packit dd8086
                      uint32_t parent,
Packit dd8086
                      uint32_t psize,
Packit dd8086
                      const time_t *dir_time)
Packit dd8086
{
Packit dd8086
  iso9660_dir_init_new_su (dir, self, ssize, NULL, 0, parent, psize, NULL,
Packit dd8086
                           0, dir_time);
Packit dd8086
}
Packit dd8086
Packit dd8086
void
Packit dd8086
iso9660_dir_init_new_su (void *dir,
Packit dd8086
                         uint32_t self,
Packit dd8086
                         uint32_t ssize,
Packit dd8086
                         const void *ssu_data,
Packit dd8086
                         unsigned int ssu_size,
Packit dd8086
                         uint32_t parent,
Packit dd8086
                         uint32_t psize,
Packit dd8086
                         const void *psu_data,
Packit dd8086
                         unsigned int psu_size,
Packit dd8086
                         const time_t *dir_time)
Packit dd8086
{
Packit dd8086
  cdio_assert (ssize > 0 && !(ssize % ISO_BLOCKSIZE));
Packit dd8086
  cdio_assert (psize > 0 && !(psize % ISO_BLOCKSIZE));
Packit dd8086
  cdio_assert (dir != NULL);
Packit dd8086
Packit dd8086
  memset (dir, 0, ssize);
Packit dd8086
Packit dd8086
  /* "\0" -- working hack due to padding  */
Packit dd8086
  iso9660_dir_add_entry_su (dir, "\0", self, ssize, ISO_DIRECTORY, ssu_data,
Packit dd8086
                            ssu_size, dir_time);
Packit dd8086
Packit dd8086
  iso9660_dir_add_entry_su (dir, "\1", parent, psize, ISO_DIRECTORY, psu_data,
Packit dd8086
                            psu_size, dir_time);
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Zero's out pathable. Do this first.  */
Packit dd8086
void
Packit dd8086
iso9660_pathtable_init (void *pt)
Packit dd8086
{
Packit dd8086
  cdio_assert (sizeof (iso_path_table_t) == 8);
Packit dd8086
Packit dd8086
  cdio_assert (pt != NULL);
Packit dd8086
Packit dd8086
  memset (pt, 0, ISO_BLOCKSIZE); /* fixme */
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns POSIX mode bitstring for a given file.
Packit dd8086
*/
Packit dd8086
mode_t
Packit dd8086
iso9660_get_posix_filemode(const iso9660_stat_t *p_iso_dirent)
Packit dd8086
{
Packit dd8086
  mode_t mode = 0;
Packit dd8086
Packit dd8086
#ifdef HAVE_ROCK
Packit dd8086
  if (yep == p_iso_dirent->rr.b3_rock) {
Packit dd8086
      return iso9660_get_posix_filemode_from_rock(&p_iso_dirent->rr);
Packit dd8086
  } else
Packit dd8086
#endif
Packit dd8086
  if (p_iso_dirent->b_xa) {
Packit dd8086
    return iso9660_get_posix_filemode_from_xa(p_iso_dirent->xa.attributes);
Packit dd8086
  }
Packit dd8086
  return mode;
Packit dd8086
}
Packit dd8086
Packit dd8086
static const iso_path_table_t *
Packit dd8086
pathtable_get_entry (const void *pt, unsigned int entrynum)
Packit dd8086
{
Packit dd8086
  const uint8_t *tmp = pt;
Packit dd8086
  unsigned int offset = 0;
Packit dd8086
  unsigned int count = 0;
Packit dd8086
Packit dd8086
  cdio_assert (pt != NULL);
Packit dd8086
Packit dd8086
  while (from_711 (*tmp))
Packit dd8086
    {
Packit dd8086
      if (count == entrynum)
Packit dd8086
        break;
Packit dd8086
Packit dd8086
      cdio_assert (count < entrynum);
Packit dd8086
Packit dd8086
      offset += sizeof (iso_path_table_t);
Packit dd8086
      offset += from_711 (*tmp);
Packit dd8086
      if (offset % 2)
Packit dd8086
        offset++;
Packit dd8086
      tmp = (uint8_t *)pt + offset;
Packit dd8086
      count++;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  if (!from_711 (*tmp))
Packit dd8086
    return NULL;
Packit dd8086
Packit dd8086
  return (const void *) tmp;
Packit dd8086
}
Packit dd8086
Packit dd8086
void
Packit dd8086
pathtable_get_size_and_entries (const void *pt,
Packit dd8086
                                unsigned int *size,
Packit dd8086
                                unsigned int *entries)
Packit dd8086
{
Packit dd8086
  const uint8_t *tmp = pt;
Packit dd8086
  unsigned int offset = 0;
Packit dd8086
  unsigned int count = 0;
Packit dd8086
Packit dd8086
  cdio_assert (pt != NULL);
Packit dd8086
Packit dd8086
  while (from_711 (*tmp))
Packit dd8086
    {
Packit dd8086
      offset += sizeof (iso_path_table_t);
Packit dd8086
      offset += from_711 (*tmp);
Packit dd8086
      if (offset % 2)
Packit dd8086
        offset++;
Packit dd8086
      tmp = (uint8_t *)pt + offset;
Packit dd8086
      count++;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  if (size)
Packit dd8086
    *size = offset;
Packit dd8086
Packit dd8086
  if (entries)
Packit dd8086
    *entries = count;
Packit dd8086
}
Packit dd8086
Packit dd8086
unsigned int
Packit dd8086
iso9660_pathtable_get_size (const void *pt)
Packit dd8086
{
Packit dd8086
  unsigned int size = 0;
Packit dd8086
  pathtable_get_size_and_entries (pt, &size, NULL);
Packit dd8086
  return size;
Packit dd8086
}
Packit dd8086
Packit dd8086
uint16_t
Packit dd8086
iso9660_pathtable_l_add_entry (void *pt,
Packit dd8086
                               const char name[],
Packit dd8086
                               uint32_t extent,
Packit dd8086
                               uint16_t parent)
Packit dd8086
{
Packit dd8086
  iso_path_table_t *ipt =
Packit dd8086
    (iso_path_table_t *)((char *)pt + iso9660_pathtable_get_size (pt));
Packit dd8086
  size_t name_len = strlen (name) ? strlen (name) : 1;
Packit dd8086
  unsigned int entrynum = 0;
Packit dd8086
Packit dd8086
  cdio_assert (iso9660_pathtable_get_size (pt) < ISO_BLOCKSIZE); /*fixme */
Packit dd8086
Packit dd8086
  memset (ipt, 0, sizeof (iso_path_table_t) + name_len); /* paranoia */
Packit dd8086
Packit dd8086
  ipt->name_len = to_711 (name_len);
Packit dd8086
  ipt->extent = to_731 (extent);
Packit dd8086
  ipt->parent = to_721 (parent);
Packit dd8086
  memcpy (ipt->name, name, name_len);
Packit dd8086
Packit dd8086
  pathtable_get_size_and_entries (pt, NULL, &entrynum);
Packit dd8086
Packit dd8086
  if (entrynum > 1)
Packit dd8086
    {
Packit dd8086
      const iso_path_table_t *ipt2
Packit dd8086
        = pathtable_get_entry (pt, entrynum - 2);
Packit dd8086
Packit dd8086
      cdio_assert (ipt2 != NULL);
Packit dd8086
Packit dd8086
      cdio_assert (from_721 (ipt2->parent) <= parent);
Packit dd8086
    }
Packit dd8086
Packit dd8086
  return entrynum;
Packit dd8086
}
Packit dd8086
Packit dd8086
uint16_t
Packit dd8086
iso9660_pathtable_m_add_entry (void *pt,
Packit dd8086
                               const char name[],
Packit dd8086
                               uint32_t extent,
Packit dd8086
                               uint16_t parent)
Packit dd8086
{
Packit dd8086
  iso_path_table_t *ipt =
Packit dd8086
    (iso_path_table_t *)((char *)pt + iso9660_pathtable_get_size (pt));
Packit dd8086
  size_t name_len = strlen (name) ? strlen (name) : 1;
Packit dd8086
  unsigned int entrynum = 0;
Packit dd8086
Packit dd8086
  cdio_assert (iso9660_pathtable_get_size(pt) < ISO_BLOCKSIZE); /* fixme */
Packit dd8086
Packit dd8086
  memset(ipt, 0, sizeof (iso_path_table_t) + name_len); /* paranoia */
Packit dd8086
Packit dd8086
  ipt->name_len = to_711 (name_len);
Packit dd8086
  ipt->extent = to_732 (extent);
Packit dd8086
  ipt->parent = to_722 (parent);
Packit dd8086
  memcpy (ipt->name, name, name_len);
Packit dd8086
Packit dd8086
  pathtable_get_size_and_entries (pt, NULL, &entrynum);
Packit dd8086
Packit dd8086
  if (entrynum > 1)
Packit dd8086
    {
Packit dd8086
      const iso_path_table_t *ipt2
Packit dd8086
        = pathtable_get_entry (pt, entrynum - 2);
Packit dd8086
Packit dd8086
      cdio_assert (ipt2 != NULL);
Packit dd8086
Packit dd8086
      cdio_assert (from_722 (ipt2->parent) <= parent);
Packit dd8086
    }
Packit dd8086
Packit dd8086
  return entrynum;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Check that pathname is a valid ISO-9660 directory name.
Packit dd8086
Packit dd8086
  A valid directory name should not start out with a slash (/),
Packit dd8086
  dot (.) or null byte, should be less than 37 characters long,
Packit dd8086
  have no more than 8 characters in a directory component
Packit dd8086
  which is separated by a /, and consist of only DCHARs.
Packit dd8086
 */
Packit dd8086
bool
Packit dd8086
iso9660_dirname_valid_p (const char pathname[])
Packit dd8086
{
Packit dd8086
  const char *p = pathname;
Packit dd8086
  int len;
Packit dd8086
Packit dd8086
  cdio_assert (pathname != NULL);
Packit dd8086
Packit dd8086
  if (*p == '/' || *p == '.' || *p == '\0')
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  if (strlen (pathname) > MAX_ISOPATHNAME)
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  len = 0;
Packit dd8086
  for (; *p; p++)
Packit dd8086
    if (iso9660_is_dchar (*p))
Packit dd8086
      {
Packit dd8086
        len++;
Packit dd8086
        if (len > 8)
Packit dd8086
          return false;
Packit dd8086
      }
Packit dd8086
    else if (*p == '/')
Packit dd8086
      {
Packit dd8086
        if (!len)
Packit dd8086
          return false;
Packit dd8086
        len = 0;
Packit dd8086
      }
Packit dd8086
    else
Packit dd8086
      return false; /* unexpected char */
Packit dd8086
Packit dd8086
  if (!len)
Packit dd8086
    return false; /* last char may not be '/' */
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Check that pathname is a valid ISO-9660 pathname.
Packit dd8086
Packit dd8086
  A valid pathname contains a valid directory name, if one appears and
Packit dd8086
  the filename portion should be no more than 8 characters for the
Packit dd8086
  file prefix and 3 characters in the extension (or portion after a
Packit dd8086
  dot). There should be exactly one dot somewhere in the filename
Packit dd8086
  portion and the filename should be composed of only DCHARs.
Packit dd8086
Packit dd8086
  True is returned if pathname is valid.
Packit dd8086
 */
Packit dd8086
bool
Packit dd8086
iso9660_pathname_valid_p (const char pathname[])
Packit dd8086
{
Packit dd8086
  const char *p = NULL;
Packit dd8086
Packit dd8086
  cdio_assert (pathname != NULL);
Packit dd8086
Packit dd8086
  if ((p = strrchr (pathname, '/')))
Packit dd8086
    {
Packit dd8086
      bool rc;
Packit dd8086
      char *_tmp = strdup (pathname);
Packit dd8086
Packit dd8086
      *strrchr (_tmp, '/') = '\0';
Packit dd8086
Packit dd8086
      rc = iso9660_dirname_valid_p (_tmp);
Packit dd8086
Packit dd8086
      free (_tmp);
Packit dd8086
Packit dd8086
      if (!rc)
Packit dd8086
        return false;
Packit dd8086
Packit dd8086
      p++;
Packit dd8086
    }
Packit dd8086
  else
Packit dd8086
    p = pathname;
Packit dd8086
Packit dd8086
  if (strlen (pathname) > (MAX_ISOPATHNAME - 6))
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  {
Packit dd8086
    int len = 0;
Packit dd8086
    int dots = 0;
Packit dd8086
Packit dd8086
    for (; *p; p++)
Packit dd8086
      if (iso9660_is_dchar (*p))
Packit dd8086
        {
Packit dd8086
          len++;
Packit dd8086
          if (dots == 0 ? len > 8 : len > 3)
Packit dd8086
            return false;
Packit dd8086
        }
Packit dd8086
      else if (*p == '.')
Packit dd8086
        {
Packit dd8086
          dots++;
Packit dd8086
          if (dots > 1)
Packit dd8086
            return false;
Packit dd8086
          if (!len)
Packit dd8086
            return false;
Packit dd8086
          len = 0;
Packit dd8086
        }
Packit dd8086
      else
Packit dd8086
        return false;
Packit dd8086
Packit dd8086
    if (dots != 1)
Packit dd8086
      return false;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Take pathname and a version number and turn that into a ISO-9660
Packit dd8086
  pathname.  (That's just the pathname followd by ";" and the version
Packit dd8086
  number. For example, mydir/file.ext -> mydir/file.ext;1 for version
Packit dd8086
  1. The resulting ISO-9660 pathname is returned.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
iso9660_pathname_isofy (const char pathname[], uint16_t version)
Packit dd8086
{
Packit dd8086
  char tmpbuf[1024] = { 0, };
Packit dd8086
Packit dd8086
  cdio_assert (strlen (pathname) < (sizeof (tmpbuf) - sizeof (";65535")));
Packit dd8086
Packit dd8086
  snprintf (tmpbuf, sizeof(tmpbuf), "%s;%d", pathname, version);
Packit dd8086
Packit dd8086
  return strdup (tmpbuf);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the PVD's application ID.
Packit dd8086
  NULL is returned if there is some problem in getting this.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
iso9660_get_application_id(iso9660_pvd_t *p_pvd)
Packit dd8086
{
Packit dd8086
  if (NULL==p_pvd) return NULL;
Packit dd8086
  return strdup(strip_trail(p_pvd->application_id, ISO_MAX_APPLICATION_ID));
Packit dd8086
}
Packit dd8086
Packit dd8086
#ifdef FIXME
Packit dd8086
lsn_t
Packit dd8086
iso9660_get_dir_extent(const iso9660_dir_t *idr)
Packit dd8086
{
Packit dd8086
  if (NULL == idr) return 0;
Packit dd8086
  return from_733(idr->extent);
Packit dd8086
}
Packit dd8086
#endif
Packit dd8086
Packit dd8086
uint8_t
Packit dd8086
iso9660_get_dir_len(const iso9660_dir_t *idr)
Packit dd8086
{
Packit dd8086
  if (NULL == idr) return 0;
Packit dd8086
  return idr->length;
Packit dd8086
}
Packit dd8086
Packit dd8086
#ifdef FIXME
Packit dd8086
uint8_t
Packit dd8086
iso9660_get_dir_size(const iso9660_dir_t *idr)
Packit dd8086
{
Packit dd8086
  if (NULL == idr) return 0;
Packit dd8086
  return from_733(idr->size);
Packit dd8086
}
Packit dd8086
#endif
Packit dd8086
Packit dd8086
uint8_t
Packit dd8086
iso9660_get_pvd_type(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL == pvd) return 255;
Packit dd8086
  return(pvd->type);
Packit dd8086
}
Packit dd8086
Packit dd8086
const char *
Packit dd8086
iso9660_get_pvd_id(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL == pvd) return "ERR";
Packit dd8086
  return(pvd->id);
Packit dd8086
}
Packit dd8086
Packit dd8086
int
Packit dd8086
iso9660_get_pvd_space_size(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL == pvd) return 0;
Packit dd8086
  return from_733(pvd->volume_space_size);
Packit dd8086
}
Packit dd8086
Packit dd8086
int
Packit dd8086
iso9660_get_pvd_block_size(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL == pvd) return 0;
Packit dd8086
  return from_723(pvd->logical_block_size);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Return the primary volume id version number (of pvd).
Packit dd8086
    If there is an error 0 is returned.
Packit dd8086
 */
Packit dd8086
int
Packit dd8086
iso9660_get_pvd_version(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL == pvd) return 0;
Packit dd8086
  return pvd->version;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Return the LSN of the root directory for pvd.
Packit dd8086
    If there is an error CDIO_INVALID_LSN is returned.
Packit dd8086
 */
Packit dd8086
lsn_t
Packit dd8086
iso9660_get_root_lsn(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL == pvd)
Packit dd8086
    return CDIO_INVALID_LSN;
Packit dd8086
  else {
Packit dd8086
    const iso9660_dir_t *idr = &(pvd->root_directory_record);
Packit dd8086
    if (NULL == idr) return CDIO_INVALID_LSN;
Packit dd8086
    return(from_733 (idr->extent));
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the preparer id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
iso9660_get_preparer_id(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL==pvd) return NULL;
Packit dd8086
  return strdup(strip_trail(pvd->preparer_id, ISO_MAX_PREPARER_ID));
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the publisher id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
iso9660_get_publisher_id(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL==pvd) return NULL;
Packit dd8086
  return strdup(strip_trail(pvd->publisher_id, ISO_MAX_PUBLISHER_ID));
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the PVD's system id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
iso9660_get_system_id(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL==pvd) return NULL;
Packit dd8086
  return strdup(strip_trail(pvd->system_id, ISO_MAX_SYSTEM_ID));
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the PVD's volume ID.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
iso9660_get_volume_id(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if (NULL == pvd) return NULL;
Packit dd8086
  return strdup(strip_trail(pvd->volume_id, ISO_MAX_VOLUME_ID));
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the PVD's volumeset ID.
Packit dd8086
  NULL is returned if there is some problem in getting this.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
iso9660_get_volumeset_id(const iso9660_pvd_t *pvd)
Packit dd8086
{
Packit dd8086
  if ( NULL == pvd ) return NULL;
Packit dd8086
  return strdup(strip_trail(pvd->volume_set_id, ISO_MAX_VOLUMESET_ID));
Packit dd8086
}
Packit dd8086
Packit dd8086

Packit dd8086
/*
Packit dd8086
 * Local variables:
Packit dd8086
 *  c-file-style: "gnu"
Packit dd8086
 *  tab-width: 8
Packit dd8086
 *  indent-tabs-mode: nil
Packit dd8086
 * End:
Packit dd8086
 */