~ubuntu-branches/ubuntu/edgy/libcdio/edgy-updates

« back to all changes in this revision

Viewing changes to lib/iso9660.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2005-11-15 16:53:23 UTC
  • mfrom: (3.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20051115165323-peroku75syl2j36u
Tags: 0.76-1ubuntu1
* Sync to new Debian version, manually apply Ubuntu patches:
  - debian/control: Remove dpkg-awk build dependency.
  - debian/rules: hardcode $LIBCDEV. This keeps the diff small (compared to
    the original patch of changing every ${libcdev} occurence).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    $Id: iso9660.c,v 1.24 2004/10/30 02:55:17 rocky Exp $
3
 
 
4
 
    Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
5
 
    Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
6
 
 
7
 
    This program is free software; you can redistribute it and/or modify
8
 
    it under the terms of the GNU General Public License as published by
9
 
    the Free Software Foundation; either version 2 of the License, or
10
 
    (at your option) any later version.
11
 
 
12
 
    This program is distributed in the hope that it will be useful,
13
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
    GNU General Public License for more details.
16
 
 
17
 
    You should have received a copy of the GNU General Public License
18
 
    along with this program; if not, write to the Free Software
19
 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 
*/
21
 
 
22
 
/* Private headers */
23
 
#include "iso9660_private.h"
24
 
#include "cdio_assert.h"
25
 
 
26
 
/* Public headers */
27
 
#include <cdio/bytesex.h>
28
 
#include <cdio/iso9660.h>
29
 
#include <cdio/util.h>
30
 
 
31
 
#include <time.h>
32
 
#include <ctype.h>
33
 
#ifdef HAVE_STRING_H
34
 
#include <string.h>
35
 
#endif
36
 
#ifdef HAVE_STDIO_H
37
 
#include <stdio.h>
38
 
#endif
39
 
 
40
 
static const char _rcsid[] = "$Id: iso9660.c,v 1.24 2004/10/30 02:55:17 rocky Exp $";
41
 
 
42
 
/* some parameters... */
43
 
#define SYSTEM_ID         "CD-RTOS CD-BRIDGE"
44
 
#define VOLUME_SET_ID     ""
45
 
 
46
 
/*!
47
 
   Change trailing blanks in str to nulls.  Str has a maximum size of
48
 
   n characters.
49
 
*/
50
 
static char *
51
 
strip_trail (const char str[], size_t n)
52
 
{
53
 
  static char buf[1024];
54
 
  int j;
55
 
 
56
 
  cdio_assert (n < 1024);
57
 
 
58
 
  strncpy (buf, str, n);
59
 
  buf[n] = '\0';
60
 
 
61
 
  for (j = strlen (buf) - 1; j >= 0; j--)
62
 
    {
63
 
      if (buf[j] != ' ')
64
 
        break;
65
 
 
66
 
      buf[j] = '\0';
67
 
    }
68
 
 
69
 
  return buf;
70
 
}
71
 
 
72
 
static void
73
 
pathtable_get_size_and_entries(const void *pt, unsigned int *size, 
74
 
                               unsigned int *entries);
75
 
 
76
 
/*!
77
 
  Get time structure from structure in an ISO 9660 directory index 
78
 
  record. Even though tm_wday and tm_yday fields are not explicitly in
79
 
  idr_date, the are calculated from the other fields.
80
 
 
81
 
  If tm is to reflect the localtime set b_localtime true, otherwise
82
 
  tm will reported in GMT.
83
 
*/
84
 
void
85
 
iso9660_get_dtime (const iso9660_dtime_t *idr_date, bool b_localtime,
86
 
                   /*out*/ struct tm *p_tm)
87
 
{
88
 
  time_t t;
89
 
  struct tm *p_temp_tm;
90
 
  
91
 
  if (!idr_date) return;
92
 
 
93
 
  memset(p_tm, 0, sizeof(struct tm));
94
 
  p_tm->tm_year   = idr_date->dt_year;
95
 
  p_tm->tm_mon    = idr_date->dt_month - 1;
96
 
  p_tm->tm_mday   = idr_date->dt_day;
97
 
  p_tm->tm_hour   = idr_date->dt_hour;
98
 
  p_tm->tm_min    = idr_date->dt_minute;
99
 
  p_tm->tm_sec    = idr_date->dt_second;
100
 
 
101
 
#if defined(HAVE_TM_GMTOFF) && defined(HAVE_TZSET)
102
 
  if (b_localtime) {
103
 
    tzset();
104
 
#if defined(HAVE_TZNAME)
105
 
    p_tm->tm_zone   = (char *) tzname;
106
 
#endif
107
 
#if defined(HAVE_DAYLIGHT)
108
 
    p_tm->tm_isdst  = daylight;
109
 
    p_tm->tm_gmtoff = timezone;
110
 
#endif
111
 
  }
112
 
#endif
113
 
 
114
 
  /* Recompute tm_wday and tm_yday via mktime. */
115
 
  t = mktime(p_tm);
116
 
 
117
 
  if (b_localtime)
118
 
    p_temp_tm = localtime(&t);
119
 
  else
120
 
    p_temp_tm = gmtime(&t);
121
 
 
122
 
  memcpy(p_tm, p_temp_tm, sizeof(struct tm));
123
 
}
124
 
 
125
 
/*!
126
 
  Set time in format used in ISO 9660 directory index record
127
 
  from a Unix time structure. */
128
 
void
129
 
iso9660_set_dtime (const struct tm *p_tm, /*out*/ iso9660_dtime_t *p_idr_date)
130
 
{
131
 
  memset (p_idr_date, 0, 7);
132
 
 
133
 
  if (!p_tm) return;
134
 
 
135
 
  p_idr_date->dt_year   = p_tm->tm_year;
136
 
  p_idr_date->dt_month  = p_tm->tm_mon + 1;
137
 
  p_idr_date->dt_day    = p_tm->tm_mday;
138
 
  p_idr_date->dt_hour   = p_tm->tm_hour;
139
 
  p_idr_date->dt_minute = p_tm->tm_min;
140
 
  p_idr_date->dt_second = p_tm->tm_sec;
141
 
 
142
 
#ifdef HAVE_TM_GMTOFF
143
 
  /* The ISO 9660 timezone is in the range -48..+52 and each unit
144
 
     represents a 15-minute interval. */
145
 
  p_idr_date->dt_gmtoff = p_tm->tm_gmtoff / (15 * 60);
146
 
 
147
 
  if (p_tm->tm_isdst) p_idr_date->dt_gmtoff -= 4;
148
 
 
149
 
  if (p_idr_date->dt_gmtoff < -48 ) {
150
 
    
151
 
    cdio_warn ("Converted ISO 9660 timezone %d is less than -48. Adjusted", 
152
 
               p_idr_date->dt_gmtoff);
153
 
    p_idr_date->dt_gmtoff = -48;
154
 
  } else if (p_idr_date->dt_gmtoff > 52) {
155
 
    cdio_warn ("Converted ISO 9660 timezone %d is over 52. Adjusted", 
156
 
               p_idr_date->dt_gmtoff);
157
 
    p_idr_date->dt_gmtoff = 52;
158
 
  }
159
 
#else 
160
 
  p_idr_date->dt_gmtoff = 0;
161
 
#endif
162
 
}
163
 
 
164
 
/*!
165
 
  Set "long" time in format used in ISO 9660 primary volume descriptor
166
 
  from a Unix time structure. */
167
 
void
168
 
iso9660_set_ltime (const struct tm *_tm, /*out*/ iso9660_ltime_t *pvd_date)
169
 
{
170
 
  char *_pvd_date = (char *) pvd_date; 
171
 
 
172
 
  memset (_pvd_date, '0', 16);
173
 
  _pvd_date[16] = (int8_t) 0; /* tz */
174
 
 
175
 
  if (!_tm) return;
176
 
 
177
 
  snprintf(_pvd_date, 17, 
178
 
           "%4.4d%2.2d%2.2d" "%2.2d%2.2d%2.2d" "%2.2d",
179
 
           _tm->tm_year + 1900, _tm->tm_mon + 1, _tm->tm_mday,
180
 
           _tm->tm_hour, _tm->tm_min, _tm->tm_sec,
181
 
           0 /* 1/100 secs */ );
182
 
  
183
 
  _pvd_date[16] = (int8_t) 0; /* tz */
184
 
}
185
 
 
186
 
/*!
187
 
   Convert ISO-9660 file name that stored in a directory entry into 
188
 
   what's usually listed as the file name in a listing.
189
 
   Lowercase name, and remove trailing ;1's or .;1's and
190
 
   turn the other ;'s into version numbers.
191
 
 
192
 
   The length of the translated string is returned.
193
 
*/
194
 
int 
195
 
iso9660_name_translate(const char *old, char *new)
196
 
{
197
 
  return iso9660_name_translate_ext(old, new, 0);
198
 
}
199
 
 
200
 
/*!
201
 
   Convert ISO-9660 file name that stored in a directory entry into
202
 
   what's usually listed as the file name in a listing.  Lowercase
203
 
   name if not using Joliet extension. Remove trailing ;1's or .;1's and
204
 
   turn the other ;'s into version numbers.
205
 
 
206
 
   The length of the translated string is returned.
207
 
*/
208
 
int 
209
 
iso9660_name_translate_ext(const char *old, char *new, uint8_t i_joliet_level)
210
 
{
211
 
  int len = strlen(old);
212
 
  int i;
213
 
  
214
 
  for (i = 0; i < len; i++) {
215
 
    unsigned char c = old[i];
216
 
    if (!c)
217
 
      break;
218
 
    
219
 
    /* Lower case, unless we have Joliet extensions.  */
220
 
    if (!i_joliet_level && isupper(c)) c = tolower(c);
221
 
    
222
 
    /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
223
 
    if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
224
 
      break;
225
 
    
226
 
    /* Drop trailing ';1' */
227
 
    if (c == ';' && i == len - 2 && old[i + 1] == '1')
228
 
      break;
229
 
    
230
 
    /* Convert remaining ';' to '.' */
231
 
    if (c == ';')
232
 
      c = '.';
233
 
    
234
 
    new[i] = c;
235
 
  }
236
 
  new[i] = '\0';
237
 
  return i;
238
 
}
239
 
 
240
 
/*!  
241
 
  Pad string src with spaces to size len and copy this to dst. If
242
 
  len is less than the length of src, dst will be truncated to the
243
 
  first len characters of src.
244
 
 
245
 
  src can also be scanned to see if it contains only ACHARs, DCHARs, 
246
 
  7-bit ASCII chars depending on the enumeration _check.
247
 
 
248
 
  In addition to getting changed, dst is the return value.
249
 
  Note: this string might not be NULL terminated.
250
 
 */
251
 
char *
252
 
iso9660_strncpy_pad(char dst[], const char src[], size_t len,
253
 
                    enum strncpy_pad_check _check)
254
 
{
255
 
  size_t rlen;
256
 
 
257
 
  cdio_assert (dst != NULL);
258
 
  cdio_assert (src != NULL);
259
 
  cdio_assert (len > 0);
260
 
 
261
 
  switch (_check)
262
 
    {
263
 
      int idx;
264
 
    case ISO9660_NOCHECK:
265
 
      break;
266
 
 
267
 
    case ISO9660_7BIT:
268
 
      for (idx = 0; src[idx]; idx++)
269
 
        if ((int8_t) src[idx] < 0)
270
 
          {
271
 
            cdio_warn ("string '%s' fails 7bit constraint (pos = %d)", 
272
 
                      src, idx);
273
 
            break;
274
 
          }
275
 
      break;
276
 
 
277
 
    case ISO9660_ACHARS:
278
 
      for (idx = 0; src[idx]; idx++)
279
 
        if (!iso9660_isachar (src[idx]))
280
 
          {
281
 
            cdio_warn ("string '%s' fails a-character constraint (pos = %d)",
282
 
                      src, idx);
283
 
            break;
284
 
          }
285
 
      break;
286
 
 
287
 
    case ISO9660_DCHARS:
288
 
      for (idx = 0; src[idx]; idx++)
289
 
        if (!iso9660_isdchar (src[idx]))
290
 
          {
291
 
            cdio_warn ("string '%s' fails d-character constraint (pos = %d)",
292
 
                      src, idx);
293
 
            break;
294
 
          }
295
 
      break;
296
 
 
297
 
    default:
298
 
      cdio_assert_not_reached ();
299
 
      break;
300
 
    }
301
 
 
302
 
  rlen = strlen (src);
303
 
 
304
 
  if (rlen > len)
305
 
    cdio_warn ("string '%s' is getting truncated to %d characters",  
306
 
              src, (unsigned int) len);
307
 
 
308
 
  strncpy (dst, src, len);
309
 
  if (rlen < len)
310
 
    memset(dst+rlen, ' ', len-rlen);
311
 
  return dst;
312
 
}
313
 
 
314
 
/*!
315
 
   Return true if c is a DCHAR - a valid ISO-9660 level 1 character.
316
 
   These are the ASCSII capital letters A-Z, the digits 0-9 and an
317
 
   underscore.
318
 
*/
319
 
bool
320
 
iso9660_isdchar (int c)
321
 
{
322
 
  if (!IN (c, 0x30, 0x5f)
323
 
      || IN (c, 0x3a, 0x40)
324
 
      || IN (c, 0x5b, 0x5e))
325
 
    return false;
326
 
 
327
 
  return true;
328
 
}
329
 
 
330
 
 
331
 
/*!
332
 
   Return true if c is an ACHAR - 
333
 
   These are the DCHAR's plus some ASCII symbols including the space 
334
 
   symbol.   
335
 
*/
336
 
bool
337
 
iso9660_isachar (int c)
338
 
{
339
 
  if (!IN (c, 0x20, 0x5f)
340
 
      || IN (c, 0x23, 0x24)
341
 
      || c == 0x40
342
 
      || IN (c, 0x5b, 0x5e))
343
 
    return false;
344
 
 
345
 
  return true;
346
 
}
347
 
 
348
 
void 
349
 
iso9660_set_evd(void *pd)
350
 
{
351
 
  struct iso_volume_descriptor ied;
352
 
 
353
 
  cdio_assert (sizeof(struct iso_volume_descriptor) == ISO_BLOCKSIZE);
354
 
 
355
 
  cdio_assert (pd != NULL);
356
 
  
357
 
  memset(&ied, 0, sizeof(ied));
358
 
 
359
 
  ied.type = to_711(ISO_VD_END);
360
 
  iso9660_strncpy_pad (ied.id, ISO_STANDARD_ID, sizeof(ied.id), ISO9660_DCHARS);
361
 
  ied.version = to_711(ISO_VERSION);
362
 
 
363
 
  memcpy(pd, &ied, sizeof(ied));
364
 
}
365
 
 
366
 
void
367
 
iso9660_set_pvd(void *pd,
368
 
                const char volume_id[],
369
 
                const char publisher_id[],
370
 
                const char preparer_id[],
371
 
                const char application_id[],
372
 
                uint32_t iso_size,
373
 
                const void *root_dir,
374
 
                uint32_t path_table_l_extent,
375
 
                uint32_t path_table_m_extent,
376
 
                uint32_t path_table_size,
377
 
                const time_t *pvd_time
378
 
                )
379
 
{
380
 
  iso9660_pvd_t ipd;
381
 
 
382
 
  cdio_assert (sizeof(iso9660_pvd_t) == ISO_BLOCKSIZE);
383
 
 
384
 
  cdio_assert (pd != NULL);
385
 
  cdio_assert (volume_id != NULL);
386
 
  cdio_assert (application_id != NULL);
387
 
 
388
 
  memset(&ipd,0,sizeof(ipd)); /* paranoia? */
389
 
 
390
 
  /* magic stuff ... thatis CD XA marker... */
391
 
  strcpy(((char*)&ipd)+ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING);
392
 
 
393
 
  ipd.type = to_711(ISO_VD_PRIMARY);
394
 
  iso9660_strncpy_pad (ipd.id, ISO_STANDARD_ID, 5, ISO9660_DCHARS);
395
 
  ipd.version = to_711(ISO_VERSION);
396
 
 
397
 
  iso9660_strncpy_pad (ipd.system_id, SYSTEM_ID, 32, ISO9660_ACHARS);
398
 
  iso9660_strncpy_pad (ipd.volume_id, volume_id, 32, ISO9660_DCHARS);
399
 
 
400
 
  ipd.volume_space_size = to_733(iso_size);
401
 
 
402
 
  ipd.volume_set_size = to_723(1);
403
 
  ipd.volume_sequence_number = to_723(1);
404
 
  ipd.logical_block_size = to_723(ISO_BLOCKSIZE);
405
 
 
406
 
  ipd.path_table_size = to_733(path_table_size);
407
 
  ipd.type_l_path_table = to_731(path_table_l_extent); 
408
 
  ipd.type_m_path_table = to_732(path_table_m_extent); 
409
 
  
410
 
  /* root_directory_record doesn't contain the 1-byte filename,
411
 
     so we add one for that. */
412
 
  cdio_assert (sizeof(ipd.root_directory_record) == 33);
413
 
  memcpy(&(ipd.root_directory_record), root_dir, 
414
 
         sizeof(ipd.root_directory_record));
415
 
  ipd.root_directory_filename='\0';
416
 
  ipd.root_directory_record.length = 33+1;
417
 
  iso9660_strncpy_pad (ipd.volume_set_id, VOLUME_SET_ID, 128, ISO9660_DCHARS);
418
 
 
419
 
  iso9660_strncpy_pad (ipd.publisher_id, publisher_id, 128, ISO9660_ACHARS);
420
 
  iso9660_strncpy_pad (ipd.preparer_id, preparer_id, 128, ISO9660_ACHARS);
421
 
  iso9660_strncpy_pad (ipd.application_id, application_id, 128, ISO9660_ACHARS); 
422
 
 
423
 
  iso9660_strncpy_pad (ipd.copyright_file_id    , "", 37, ISO9660_DCHARS);
424
 
  iso9660_strncpy_pad (ipd.abstract_file_id     , "", 37, ISO9660_DCHARS);
425
 
  iso9660_strncpy_pad (ipd.bibliographic_file_id, "", 37, ISO9660_DCHARS);
426
 
 
427
 
  iso9660_set_ltime (gmtime (pvd_time), &(ipd.creation_date));
428
 
  iso9660_set_ltime (gmtime (pvd_time), &(ipd.modification_date));
429
 
  iso9660_set_ltime (NULL,              &(ipd.expiration_date));
430
 
  iso9660_set_ltime (NULL,              &(ipd.effective_date));
431
 
 
432
 
  ipd.file_structure_version = to_711(1);
433
 
 
434
 
  /* we leave ipd.application_data = 0 */
435
 
 
436
 
  memcpy(pd, &ipd, sizeof(ipd)); /* copy stuff to arg ptr */
437
 
}
438
 
 
439
 
unsigned int
440
 
iso9660_dir_calc_record_size(unsigned int namelen, unsigned int su_len)
441
 
{
442
 
  unsigned int length;
443
 
 
444
 
  length = sizeof(iso9660_dir_t);
445
 
  length += namelen;
446
 
  if (length % 2) /* pad to word boundary */
447
 
    length++;
448
 
  length += su_len;
449
 
  if (length % 2) /* pad to word boundary again */
450
 
    length++;
451
 
 
452
 
  return length;
453
 
}
454
 
 
455
 
void
456
 
iso9660_dir_add_entry_su(void *dir,
457
 
                         const char filename[], 
458
 
                         uint32_t extent,
459
 
                         uint32_t size,
460
 
                         uint8_t file_flags,
461
 
                         const void *su_data,
462
 
                         unsigned int su_size,
463
 
                         const time_t *entry_time)
464
 
{
465
 
  iso9660_dir_t *idr = dir;
466
 
  uint8_t *dir8 = dir;
467
 
  unsigned int offset = 0;
468
 
  uint32_t dsize = from_733(idr->size);
469
 
  int length, su_offset;
470
 
  cdio_assert (sizeof(iso9660_dir_t) == 33);
471
 
 
472
 
  if (!dsize && !idr->length)
473
 
    dsize = ISO_BLOCKSIZE; /* for when dir lacks '.' entry */
474
 
  
475
 
  cdio_assert (dsize > 0 && !(dsize % ISO_BLOCKSIZE));
476
 
  cdio_assert (dir != NULL);
477
 
  cdio_assert (extent > 17);
478
 
  cdio_assert (filename != NULL);
479
 
  cdio_assert (strlen(filename) <= MAX_ISOPATHNAME);
480
 
 
481
 
  length = sizeof(iso9660_dir_t);
482
 
  length += strlen(filename);
483
 
  length = _cdio_ceil2block (length, 2); /* pad to word boundary */
484
 
  su_offset = length;
485
 
  length += su_size;
486
 
  length = _cdio_ceil2block (length, 2); /* pad to word boundary again */
487
 
 
488
 
  /* find the last entry's end */
489
 
  {
490
 
    unsigned int ofs_last_rec = 0;
491
 
 
492
 
    offset = 0;
493
 
    while (offset < dsize)
494
 
      {
495
 
        if (!dir8[offset])
496
 
          {
497
 
            offset++;
498
 
            continue;
499
 
          }
500
 
 
501
 
        offset += dir8[offset];
502
 
        ofs_last_rec = offset;
503
 
      }
504
 
 
505
 
    cdio_assert (offset == dsize);
506
 
 
507
 
    offset = ofs_last_rec;
508
 
  }
509
 
 
510
 
  /* be sure we don't cross sectors boundaries */
511
 
  offset = _cdio_ofs_add (offset, length, ISO_BLOCKSIZE);
512
 
  offset -= length;
513
 
 
514
 
  cdio_assert (offset + length <= dsize);
515
 
 
516
 
  idr = (iso9660_dir_t *) &dir8[offset];
517
 
  
518
 
  cdio_assert (offset+length < dsize); 
519
 
  
520
 
  memset(idr, 0, length);
521
 
 
522
 
  idr->length = to_711(length);
523
 
  idr->extent = to_733(extent);
524
 
  idr->size = to_733(size);
525
 
  
526
 
  iso9660_set_dtime (gmtime(entry_time), &(idr->recording_time));
527
 
  
528
 
  idr->file_flags = to_711(file_flags);
529
 
 
530
 
  idr->volume_sequence_number = to_723(1);
531
 
 
532
 
  idr->filename_len = to_711(strlen(filename) 
533
 
                             ? strlen(filename) : 1); /* working hack! */
534
 
 
535
 
  memcpy(idr->filename, filename, from_711(idr->filename_len));
536
 
  memcpy(&dir8[offset] + su_offset, su_data, su_size);
537
 
}
538
 
 
539
 
void
540
 
iso9660_dir_init_new (void *dir,
541
 
                      uint32_t self,
542
 
                      uint32_t ssize,
543
 
                      uint32_t parent,
544
 
                      uint32_t psize,
545
 
                      const time_t *dir_time)
546
 
{
547
 
  iso9660_dir_init_new_su (dir, self, ssize, NULL, 0, parent, psize, NULL, 
548
 
                           0, dir_time);
549
 
}
550
 
 
551
 
void 
552
 
iso9660_dir_init_new_su (void *dir,
553
 
                         uint32_t self,
554
 
                         uint32_t ssize,
555
 
                         const void *ssu_data,
556
 
                         unsigned int ssu_size,
557
 
                         uint32_t parent,
558
 
                         uint32_t psize,
559
 
                         const void *psu_data,
560
 
                         unsigned int psu_size,
561
 
                         const time_t *dir_time)
562
 
{
563
 
  cdio_assert (ssize > 0 && !(ssize % ISO_BLOCKSIZE));
564
 
  cdio_assert (psize > 0 && !(psize % ISO_BLOCKSIZE));
565
 
  cdio_assert (dir != NULL);
566
 
 
567
 
  memset (dir, 0, ssize);
568
 
 
569
 
  /* "\0" -- working hack due to padding  */
570
 
  iso9660_dir_add_entry_su (dir, "\0", self, ssize, ISO_DIRECTORY, ssu_data, 
571
 
                            ssu_size, dir_time); 
572
 
 
573
 
  iso9660_dir_add_entry_su (dir, "\1", parent, psize, ISO_DIRECTORY, psu_data, 
574
 
                            psu_size, dir_time);
575
 
}
576
 
 
577
 
/* Zero's out pathable. Do this first.  */
578
 
void 
579
 
iso9660_pathtable_init (void *pt)
580
 
{
581
 
  cdio_assert (sizeof (struct iso_path_table) == 8);
582
 
 
583
 
  cdio_assert (pt != NULL);
584
 
  
585
 
  memset (pt, 0, ISO_BLOCKSIZE); /* fixme */
586
 
}
587
 
 
588
 
static const struct iso_path_table*
589
 
pathtable_get_entry (const void *pt, unsigned int entrynum)
590
 
{
591
 
  const uint8_t *tmp = pt;
592
 
  unsigned int offset = 0;
593
 
  unsigned int count = 0;
594
 
 
595
 
  cdio_assert (pt != NULL);
596
 
 
597
 
  while (from_711 (*tmp)) 
598
 
    {
599
 
      if (count == entrynum)
600
 
        break;
601
 
 
602
 
      cdio_assert (count < entrynum);
603
 
 
604
 
      offset += sizeof (struct iso_path_table);
605
 
      offset += from_711 (*tmp);
606
 
      if (offset % 2)
607
 
        offset++;
608
 
      tmp = (uint8_t *)pt + offset;
609
 
      count++;
610
 
    }
611
 
 
612
 
  if (!from_711 (*tmp))
613
 
    return NULL;
614
 
 
615
 
  return (const void *) tmp;
616
 
}
617
 
 
618
 
void
619
 
pathtable_get_size_and_entries (const void *pt, 
620
 
                                unsigned int *size,
621
 
                                unsigned int *entries)
622
 
{
623
 
  const uint8_t *tmp = pt;
624
 
  unsigned int offset = 0;
625
 
  unsigned int count = 0;
626
 
 
627
 
  cdio_assert (pt != NULL);
628
 
 
629
 
  while (from_711 (*tmp)) 
630
 
    {
631
 
      offset += sizeof (struct iso_path_table);
632
 
      offset += from_711 (*tmp);
633
 
      if (offset % 2)
634
 
        offset++;
635
 
      tmp = (uint8_t *)pt + offset;
636
 
      count++;
637
 
    }
638
 
 
639
 
  if (size)
640
 
    *size = offset;
641
 
 
642
 
  if (entries)
643
 
    *entries = count;
644
 
}
645
 
 
646
 
unsigned int
647
 
iso9660_pathtable_get_size (const void *pt)
648
 
{
649
 
  unsigned int size = 0;
650
 
  pathtable_get_size_and_entries (pt, &size, NULL);
651
 
  return size;
652
 
}
653
 
 
654
 
uint16_t 
655
 
iso9660_pathtable_l_add_entry (void *pt, 
656
 
                               const char name[], 
657
 
                               uint32_t extent, 
658
 
                               uint16_t parent)
659
 
{
660
 
  struct iso_path_table *ipt = 
661
 
    (struct iso_path_table*)((char *)pt + iso9660_pathtable_get_size (pt));
662
 
  size_t name_len = strlen (name) ? strlen (name) : 1;
663
 
  unsigned int entrynum = 0;
664
 
 
665
 
  cdio_assert (iso9660_pathtable_get_size (pt) < ISO_BLOCKSIZE); /*fixme */
666
 
 
667
 
  memset (ipt, 0, sizeof (struct iso_path_table) + name_len); /* paranoia */
668
 
 
669
 
  ipt->name_len = to_711 (name_len);
670
 
  ipt->extent = to_731 (extent);
671
 
  ipt->parent = to_721 (parent);
672
 
  memcpy (ipt->name, name, name_len);
673
 
 
674
 
  pathtable_get_size_and_entries (pt, NULL, &entrynum);
675
 
 
676
 
  if (entrynum > 1)
677
 
    {
678
 
      const struct iso_path_table *ipt2 
679
 
        = pathtable_get_entry (pt, entrynum - 2);
680
 
 
681
 
      cdio_assert (ipt2 != NULL);
682
 
 
683
 
      cdio_assert (from_721 (ipt2->parent) <= parent);
684
 
    }
685
 
  
686
 
  return entrynum;
687
 
}
688
 
 
689
 
uint16_t 
690
 
iso9660_pathtable_m_add_entry (void *pt, 
691
 
                               const char name[], 
692
 
                               uint32_t extent, 
693
 
                               uint16_t parent)
694
 
{
695
 
  struct iso_path_table *ipt =
696
 
    (struct iso_path_table*)((char *)pt + iso9660_pathtable_get_size (pt));
697
 
  size_t name_len = strlen (name) ? strlen (name) : 1;
698
 
  unsigned int entrynum = 0;
699
 
 
700
 
  cdio_assert (iso9660_pathtable_get_size(pt) < ISO_BLOCKSIZE); /* fixme */
701
 
 
702
 
  memset(ipt, 0, sizeof (struct iso_path_table) + name_len); /* paranoia */
703
 
 
704
 
  ipt->name_len = to_711 (name_len);
705
 
  ipt->extent = to_732 (extent);
706
 
  ipt->parent = to_722 (parent);
707
 
  memcpy (ipt->name, name, name_len);
708
 
 
709
 
  pathtable_get_size_and_entries (pt, NULL, &entrynum);
710
 
 
711
 
  if (entrynum > 1)
712
 
    {
713
 
      const struct iso_path_table *ipt2 
714
 
        = pathtable_get_entry (pt, entrynum - 2);
715
 
 
716
 
      cdio_assert (ipt2 != NULL);
717
 
 
718
 
      cdio_assert (from_722 (ipt2->parent) <= parent);
719
 
    }
720
 
 
721
 
  return entrynum;
722
 
}
723
 
 
724
 
/*!
725
 
  Check that pathname is a valid ISO-9660 directory name.
726
 
 
727
 
  A valid directory name should not start out with a slash (/), 
728
 
  dot (.) or null byte, should be less than 37 characters long, 
729
 
  have no more than 8 characters in a directory component 
730
 
  which is separated by a /, and consist of only DCHARs. 
731
 
 */
732
 
bool
733
 
iso9660_dirname_valid_p (const char pathname[])
734
 
{
735
 
  const char *p = pathname;
736
 
  int len;
737
 
 
738
 
  cdio_assert (pathname != NULL);
739
 
 
740
 
  if (*p == '/' || *p == '.' || *p == '\0')
741
 
    return false;
742
 
 
743
 
  if (strlen (pathname) > MAX_ISOPATHNAME)
744
 
    return false;
745
 
  
746
 
  len = 0;
747
 
  for (; *p; p++)
748
 
    if (iso9660_isdchar (*p))
749
 
      {
750
 
        len++;
751
 
        if (len > 8)
752
 
          return false;
753
 
      }
754
 
    else if (*p == '/')
755
 
      {
756
 
        if (!len)
757
 
          return false;
758
 
        len = 0;
759
 
      }
760
 
    else
761
 
      return false; /* unexpected char */
762
 
 
763
 
  if (!len)
764
 
    return false; /* last char may not be '/' */
765
 
 
766
 
  return true;
767
 
}
768
 
 
769
 
/*!
770
 
  Check that pathname is a valid ISO-9660 pathname.  
771
 
 
772
 
  A valid pathname contains a valid directory name, if one appears and
773
 
  the filename portion should be no more than 8 characters for the
774
 
  file prefix and 3 characters in the extension (or portion after a
775
 
  dot). There should be exactly one dot somewhere in the filename
776
 
  portion and the filename should be composed of only DCHARs.
777
 
  
778
 
  True is returned if pathname is valid.
779
 
 */
780
 
bool
781
 
iso9660_pathname_valid_p (const char pathname[])
782
 
{
783
 
  const char *p = NULL;
784
 
 
785
 
  cdio_assert (pathname != NULL);
786
 
 
787
 
  if ((p = strrchr (pathname, '/')))
788
 
    {
789
 
      bool rc;
790
 
      char *_tmp = strdup (pathname);
791
 
      
792
 
      *strrchr (_tmp, '/') = '\0';
793
 
 
794
 
      rc = iso9660_dirname_valid_p (_tmp);
795
 
 
796
 
      free (_tmp);
797
 
 
798
 
      if (!rc)
799
 
        return false;
800
 
 
801
 
      p++;
802
 
    }
803
 
  else
804
 
    p = pathname;
805
 
 
806
 
  if (strlen (pathname) > (MAX_ISOPATHNAME - 6))
807
 
    return false;
808
 
 
809
 
  {
810
 
    int len = 0;
811
 
    int dots = 0;
812
 
 
813
 
    for (; *p; p++)
814
 
      if (iso9660_isdchar (*p))
815
 
        {
816
 
          len++;
817
 
          if (dots == 0 ? len > 8 : len > 3)
818
 
            return false;
819
 
        }
820
 
      else if (*p == '.')
821
 
        {
822
 
          dots++;
823
 
          if (dots > 1)
824
 
            return false;
825
 
          if (!len)
826
 
            return false;
827
 
          len = 0;
828
 
        }
829
 
      else
830
 
        return false;
831
 
 
832
 
    if (dots != 1)
833
 
      return false;
834
 
  }
835
 
 
836
 
  return true;
837
 
}
838
 
 
839
 
/*!  
840
 
  Take pathname and a version number and turn that into a ISO-9660
841
 
  pathname.  (That's just the pathname followd by ";" and the version
842
 
  number. For example, mydir/file.ext -> mydir/file.ext;1 for version
843
 
  1. The resulting ISO-9660 pathname is returned.
844
 
*/
845
 
char *
846
 
iso9660_pathname_isofy (const char pathname[], uint16_t version)
847
 
{
848
 
  char tmpbuf[1024] = { 0, };
849
 
    
850
 
  cdio_assert (strlen (pathname) < (sizeof (tmpbuf) - sizeof (";65535")));
851
 
 
852
 
  snprintf (tmpbuf, sizeof(tmpbuf), "%s;%d", pathname, version);
853
 
 
854
 
  return strdup (tmpbuf);
855
 
}
856
 
 
857
 
/*!
858
 
  Return the PVD's application ID.
859
 
  NULL is returned if there is some problem in getting this. 
860
 
*/
861
 
char * 
862
 
iso9660_get_application_id(iso9660_pvd_t *p_pvd)
863
 
{
864
 
  if (NULL==p_pvd) return NULL;
865
 
  return strdup(strip_trail(p_pvd->application_id, ISO_MAX_APPLICATION_ID));
866
 
}
867
 
 
868
 
#if FIXME
869
 
lsn_t
870
 
iso9660_get_dir_extent(const iso9660_dir_t *idr) 
871
 
{
872
 
  if (NULL == idr) return 0;
873
 
  return from_733(idr->extent);
874
 
}
875
 
#endif
876
 
 
877
 
uint8_t
878
 
iso9660_get_dir_len(const iso9660_dir_t *idr) 
879
 
{
880
 
  if (NULL == idr) return 0;
881
 
  return idr->length;
882
 
}
883
 
 
884
 
#if FIXME
885
 
uint8_t
886
 
iso9660_get_dir_size(const iso9660_dir_t *idr) 
887
 
{
888
 
  if (NULL == idr) return 0;
889
 
  return from_733(idr->size);
890
 
}
891
 
#endif
892
 
 
893
 
uint8_t
894
 
iso9660_get_pvd_type(const iso9660_pvd_t *pvd) 
895
 
{
896
 
  if (NULL == pvd) return 255;
897
 
  return(pvd->type);
898
 
}
899
 
 
900
 
const char *
901
 
iso9660_get_pvd_id(const iso9660_pvd_t *pvd) 
902
 
{
903
 
  if (NULL == pvd) return "ERR";
904
 
  return(pvd->id);
905
 
}
906
 
 
907
 
int
908
 
iso9660_get_pvd_space_size(const iso9660_pvd_t *pvd) 
909
 
{
910
 
  if (NULL == pvd) return 0;
911
 
  return from_733(pvd->volume_space_size);
912
 
}
913
 
 
914
 
int
915
 
iso9660_get_pvd_block_size(const iso9660_pvd_t *pvd) 
916
 
{
917
 
  if (NULL == pvd) return 0;
918
 
  return from_723(pvd->logical_block_size);
919
 
}
920
 
 
921
 
/*! Return the primary volume id version number (of pvd).
922
 
    If there is an error 0 is returned. 
923
 
 */
924
 
int
925
 
iso9660_get_pvd_version(const iso9660_pvd_t *pvd) 
926
 
{
927
 
  if (NULL == pvd) return 0;
928
 
  return pvd->version;
929
 
}
930
 
 
931
 
/*! Return the LSN of the root directory for pvd.
932
 
    If there is an error CDIO_INVALID_LSN is returned. 
933
 
 */
934
 
lsn_t
935
 
iso9660_get_root_lsn(const iso9660_pvd_t *pvd) 
936
 
{
937
 
  if (NULL == pvd) 
938
 
    return CDIO_INVALID_LSN;
939
 
  else {
940
 
    const iso9660_dir_t *idr = &(pvd->root_directory_record);
941
 
    if (NULL == idr) return CDIO_INVALID_LSN;
942
 
    return(from_733 (idr->extent));
943
 
  }
944
 
}
945
 
 
946
 
/*!
947
 
   Return a string containing the preparer id with trailing
948
 
   blanks removed.
949
 
*/
950
 
char *
951
 
iso9660_get_preparer_id(const iso9660_pvd_t *pvd)
952
 
{
953
 
  if (NULL==pvd) return NULL;
954
 
  return strdup(strip_trail(pvd->preparer_id, ISO_MAX_PREPARER_ID));
955
 
}
956
 
 
957
 
/*!
958
 
   Return a string containing the publisher id with trailing
959
 
   blanks removed.
960
 
*/
961
 
char *
962
 
iso9660_get_publisher_id(const iso9660_pvd_t *pvd)
963
 
{
964
 
  if (NULL==pvd) return NULL;
965
 
  return strdup(strip_trail(pvd->publisher_id, ISO_MAX_PUBLISHER_ID));
966
 
}
967
 
 
968
 
/*!
969
 
   Return a string containing the PVD's system id with trailing
970
 
   blanks removed.
971
 
*/
972
 
char *
973
 
iso9660_get_system_id(const iso9660_pvd_t *pvd)
974
 
{
975
 
  if (NULL==pvd) return NULL;
976
 
  return strdup(strip_trail(pvd->system_id, ISO_MAX_SYSTEM_ID));
977
 
}
978
 
 
979
 
/*!
980
 
  Return the PVD's volume ID.
981
 
*/
982
 
char *
983
 
iso9660_get_volume_id(const iso9660_pvd_t *pvd) 
984
 
{
985
 
  if (NULL == pvd) return NULL;
986
 
  return strdup(strip_trail(pvd->volume_id, ISO_MAX_VOLUME_ID));
987
 
}
988
 
 
989
 
/*!
990
 
  Return the PVD's volumeset ID.
991
 
  NULL is returned if there is some problem in getting this. 
992
 
*/
993
 
char *
994
 
iso9660_get_volumeset_id(const iso9660_pvd_t *pvd)
995
 
{
996
 
  if ( NULL == pvd ) return NULL;
997
 
  return strdup(strip_trail(pvd->volume_set_id, ISO_MAX_VOLUMESET_ID));
998
 
}
999
 
 
1000
 
 
1001
 
/* 
1002
 
 * Local variables:
1003
 
 *  c-file-style: "gnu"
1004
 
 *  tab-width: 8
1005
 
 *  indent-tabs-mode: nil
1006
 
 * End:
1007
 
 */