~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to util/mkisofs/write.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Program write.c - dump memory  structures to  file for iso9660 filesystem.
3
 
 
4
 
   Written by Eric Youngdale (1993).
5
 
 
6
 
   Copyright 1993 Yggdrasil Computing, Incorporated
7
 
 
8
 
   Copyright (C) 2009  Free Software Foundation, Inc.
9
 
 
10
 
   This program is free software; you can redistribute it and/or modify
11
 
   it under the terms of the GNU General Public License as published by
12
 
   the Free Software Foundation; either version 3, or (at your option)
13
 
   any later version.
14
 
 
15
 
   This program is distributed in the hope that it will be useful,
16
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
   GNU General Public License for more details.
19
 
 
20
 
   You should have received a copy of the GNU General Public License
21
 
   along with this program; if not, see <http://www.gnu.org/licenses/>.
22
 
 */
23
 
 
24
 
#include "config.h"
25
 
 
26
 
#include <string.h>
27
 
#include <stdlib.h>
28
 
#include <time.h>
29
 
#include <errno.h>
30
 
 
31
 
#include <sys/types.h>
32
 
#include <sys/stat.h>
33
 
#include <fcntl.h>
34
 
#include <assert.h>
35
 
 
36
 
#ifdef HAVE_UNISTD_H
37
 
#include <unistd.h>
38
 
#endif
39
 
 
40
 
#include "mkisofs.h"
41
 
#include "iso9660.h"
42
 
#include "msdos_partition.h"
43
 
 
44
 
#ifdef __SVR4
45
 
extern char * strdup(const char *);
46
 
#endif
47
 
 
48
 
#ifdef VMS
49
 
extern char * strdup(const char *);
50
 
#endif
51
 
 
52
 
 
53
 
/* Max number of sectors we will write at  one time */
54
 
#define NSECT 16
55
 
 
56
 
/* Counters for statistics */
57
 
 
58
 
static int table_size       = 0;
59
 
static int total_dir_size   = 0;
60
 
static int rockridge_size   = 0;
61
 
static struct directory ** pathlist;
62
 
static int next_path_index  = 1;
63
 
static int sort_goof;
64
 
 
65
 
struct output_fragment * out_tail;
66
 
struct output_fragment * out_list;
67
 
 
68
 
struct iso_primary_descriptor vol_desc;
69
 
 
70
 
static int root_gen     __PR((void));
71
 
static int generate_path_tables __PR((void));
72
 
static int file_gen     __PR((void));
73
 
static int dirtree_dump __PR((void));
74
 
 
75
 
/* Routines to actually write the disc.  We write sequentially so that
76
 
   we could write a tape, or write the disc directly */
77
 
 
78
 
 
79
 
#define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof(vol_desc.X))
80
 
 
81
 
void FDECL2(set_721, char *, pnt, unsigned int, i)
82
 
{
83
 
     pnt[0] = i & 0xff;
84
 
     pnt[1] = (i >> 8) &  0xff;
85
 
}
86
 
 
87
 
void FDECL2(set_722, char *, pnt, unsigned int, i)
88
 
{
89
 
     pnt[0] = (i >> 8) &  0xff;
90
 
     pnt[1] = i & 0xff;
91
 
}
92
 
 
93
 
void FDECL2(set_723, char *, pnt, unsigned int, i)
94
 
{
95
 
     pnt[3] = pnt[0] = i & 0xff;
96
 
     pnt[2] = pnt[1] = (i >> 8) &  0xff;
97
 
}
98
 
 
99
 
void FDECL2(set_731, char *, pnt, unsigned int, i)
100
 
{
101
 
     pnt[0] = i & 0xff;
102
 
     pnt[1] = (i >> 8) &  0xff;
103
 
     pnt[2] = (i >> 16) &  0xff;
104
 
     pnt[3] = (i >> 24) &  0xff;
105
 
}
106
 
 
107
 
void FDECL2(set_732, char *, pnt, unsigned int, i)
108
 
{
109
 
     pnt[3] = i & 0xff;
110
 
     pnt[2] = (i >> 8) &  0xff;
111
 
     pnt[1] = (i >> 16) &  0xff;
112
 
     pnt[0] = (i >> 24) &  0xff;
113
 
}
114
 
 
115
 
int FDECL1(get_731, char *, p)
116
 
{
117
 
  return ((p[0] & 0xff)
118
 
          | ((p[1] & 0xff) << 8)
119
 
          | ((p[2] & 0xff) << 16)
120
 
          | ((p[3] & 0xff) << 24));
121
 
}
122
 
 
123
 
int FDECL1(get_733, char *, p)
124
 
{
125
 
     return ((p[0] & 0xff)
126
 
             | ((p[1] & 0xff) << 8)
127
 
             | ((p[2] & 0xff) << 16)
128
 
             | ((p[3] & 0xff) << 24));
129
 
}
130
 
 
131
 
void FDECL2(set_733, char *, pnt, unsigned int, i)
132
 
{
133
 
     pnt[7] = pnt[0] = i & 0xff;
134
 
     pnt[6] = pnt[1] = (i >> 8) &  0xff;
135
 
     pnt[5] = pnt[2] = (i >> 16) &  0xff;
136
 
     pnt[4] = pnt[3] = (i >> 24) &  0xff;
137
 
}
138
 
 
139
 
void FDECL4(xfwrite, void *, buffer, uint64_t, count, uint64_t, size, FILE *, file)
140
 
{
141
 
        /*
142
 
         * This is a hack that could be made better. XXXIs this the only place?
143
 
         * It is definitely needed on Operating Systems that do not
144
 
         * allow to write files that are > 2GB.
145
 
         * If the system is fast enough to be able to feed 1400 KB/s
146
 
         * writing speed of a DVD-R drive, use stdout.
147
 
         * If the system cannot do this reliable, you need to use this
148
 
         * hacky option.
149
 
         */
150
 
        static  int     idx = 0;
151
 
        if (split_output != 0 &&
152
 
            (idx == 0 || ftell(file) >= (1024 * 1024 * 1024) )) {
153
 
                        char    nbuf[512];
154
 
                extern  char    *outfile;
155
 
 
156
 
                if (idx == 0)
157
 
                        unlink(outfile);
158
 
                sprintf(nbuf, "%s_%02d", outfile, idx++);
159
 
                file = freopen(nbuf, "wb", file);
160
 
                if (file == NULL)
161
 
                  error (1, errno, _("Cannot open `%s'"), nbuf);
162
 
 
163
 
        }
164
 
     while(count)
165
 
     {
166
 
          size_t got = fwrite (buffer, size, count, file);
167
 
 
168
 
          if (got != count)
169
 
            error (1, errno, _("cannot fwrite %llu*%llu\n"), size, count);
170
 
          count-=got,*(char**)&buffer+=size*got;
171
 
     }
172
 
}
173
 
 
174
 
struct deferred_write
175
 
{
176
 
  struct deferred_write * next;
177
 
  char                  * table;
178
 
  uint64_t                extent;
179
 
  uint64_t                size;
180
 
  char                  * name;
181
 
};
182
 
 
183
 
static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
184
 
 
185
 
uint64_t last_extent_written = 0;
186
 
static unsigned int path_table_index;
187
 
static time_t begun;
188
 
 
189
 
/* We recursively walk through all of the directories and assign extent
190
 
   numbers to them.  We have already assigned extent numbers to everything that
191
 
   goes in front of them */
192
 
 
193
 
static int FDECL1(assign_directory_addresses, struct directory *, node)
194
 
{
195
 
     int                dir_size;
196
 
     struct directory * dpnt;
197
 
 
198
 
     dpnt = node;
199
 
    
200
 
     while (dpnt)
201
 
     {
202
 
          /* skip if it's hidden */
203
 
          if(dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
204
 
             dpnt = dpnt->next;
205
 
             continue;
206
 
          }
207
 
 
208
 
          /*
209
 
           * If we already have an extent for this (i.e. it came from
210
 
           * a multisession disc), then don't reassign a new extent.
211
 
           */
212
 
          dpnt->path_index = next_path_index++;
213
 
          if( dpnt->extent == 0 )
214
 
          {
215
 
               dpnt->extent = last_extent;
216
 
               dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
217
 
              
218
 
               last_extent += dir_size;
219
 
              
220
 
               /*
221
 
                * Leave room for the CE entries for this directory.  Keep them
222
 
                * close to the reference directory so that access will be
223
 
                * quick.
224
 
                */
225
 
               if(dpnt->ce_bytes)
226
 
               {
227
 
                    last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
228
 
               }
229
 
          }
230
 
 
231
 
          if(dpnt->subdir)
232
 
          {
233
 
               assign_directory_addresses(dpnt->subdir);
234
 
          }
235
 
 
236
 
          dpnt = dpnt->next;
237
 
     }
238
 
     return 0;
239
 
}
240
 
 
241
 
static void FDECL3(write_one_file, char *, filename,
242
 
                   uint64_t, size, FILE *, outfile)
243
 
{
244
 
     char                 buffer[SECTOR_SIZE * NSECT];
245
 
     FILE               * infile;
246
 
     int64_t              remain;
247
 
     size_t               use;
248
 
 
249
 
 
250
 
     if ((infile = fopen(filename, "rb")) == NULL)
251
 
       error (1, errno, _("cannot open %s\n"), filename);
252
 
     remain = size;
253
 
 
254
 
     while(remain > 0)
255
 
     {
256
 
          use =  (remain >  SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
257
 
          use = ROUND_UP(use); /* Round up to nearest sector boundary */
258
 
          memset(buffer, 0, use);
259
 
          if (fread(buffer, 1, use, infile) == 0)
260
 
            error (1, errno, _("cannot read %llu bytes from %s"), use, filename);
261
 
          xfwrite(buffer, 1, use, outfile);
262
 
          last_extent_written += use/SECTOR_SIZE;
263
 
#if 0
264
 
          if((last_extent_written % 1000) < use/SECTOR_SIZE)
265
 
          {
266
 
               fprintf(stderr,"%d..", last_extent_written);
267
 
          }
268
 
#else
269
 
          if((last_extent_written % 5000) < use/SECTOR_SIZE)
270
 
          {
271
 
               time_t now;
272
 
               time_t the_end;
273
 
               double frac;
274
 
              
275
 
               time(&now);
276
 
               frac = last_extent_written / (double)last_extent;
277
 
               the_end = begun + (now - begun) / frac;
278
 
               fprintf (stderr, _("%6.2f%% done, estimate finish %s"),
279
 
                        frac * 100., ctime(&the_end));
280
 
          }
281
 
#endif
282
 
          remain -= use;
283
 
     }
284
 
     fclose(infile);
285
 
} /* write_one_file(... */
286
 
 
287
 
static void FDECL1(write_files, FILE *, outfile)
288
 
{
289
 
     struct deferred_write * dwpnt, *dwnext;
290
 
     dwpnt = dw_head;
291
 
     while(dwpnt)
292
 
     {
293
 
          if(dwpnt->table)
294
 
          {
295
 
            write_one_file (dwpnt->table, dwpnt->size, outfile);
296
 
            table_size += dwpnt->size;
297
 
            free (dwpnt->table);
298
 
          }
299
 
          else
300
 
          {
301
 
 
302
 
#ifdef VMS
303
 
               vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
304
 
#else
305
 
               write_one_file(dwpnt->name, dwpnt->size, outfile);
306
 
#endif
307
 
               free(dwpnt->name);
308
 
          }
309
 
 
310
 
          dwnext = dwpnt;
311
 
          dwpnt = dwpnt->next;
312
 
          free(dwnext);
313
 
     }
314
 
} /* write_files(... */
315
 
 
316
 
#if 0
317
 
static void dump_filelist()
318
 
{
319
 
     struct deferred_write * dwpnt;
320
 
     dwpnt = dw_head;
321
 
     while(dwpnt)
322
 
     {
323
 
          fprintf(stderr, "File %s\n",dwpnt->name);
324
 
          dwpnt = dwpnt->next;
325
 
     }
326
 
     fprintf(stderr,"\n");
327
 
}
328
 
#endif
329
 
 
330
 
static int FDECL2(compare_dirs, const void *, rr, const void *, ll)
331
 
{
332
 
     char * rpnt, *lpnt;
333
 
     struct directory_entry ** r, **l;
334
 
    
335
 
     r = (struct directory_entry **) rr;
336
 
     l = (struct directory_entry **) ll;
337
 
     rpnt = (*r)->isorec.name;
338
 
     lpnt = (*l)->isorec.name;
339
 
 
340
 
     /*
341
 
      * If the entries are the same, this is an error.
342
 
      */
343
 
     if( strcmp(rpnt, lpnt) == 0 )
344
 
       {
345
 
         sort_goof++;
346
 
       }
347
 
    
348
 
     /*
349
 
      *  Put the '.' and '..' entries on the head of the sorted list.
350
 
      *  For normal ASCII, this always happens to be the case, but out of
351
 
      *  band characters cause this not to be the case sometimes.
352
 
      *
353
 
      * FIXME(eric) - these tests seem redundant, in taht the name is
354
 
      * never assigned these values.  It will instead be \000 or \001,
355
 
      * and thus should always be sorted correctly.   I need to figure
356
 
      * out why I thought I needed this in the first place.
357
 
      */
358
 
#if 0
359
 
     if( strcmp(rpnt, ".") == 0 ) return -1;
360
 
     if( strcmp(lpnt, ".") == 0 ) return  1;
361
 
 
362
 
     if( strcmp(rpnt, "..") == 0 ) return -1;
363
 
     if( strcmp(lpnt, "..") == 0 ) return  1;
364
 
#else
365
 
     /*
366
 
      * The code above is wrong (as explained in Eric's comment), leading to incorrect
367
 
      * sort order iff the -L option ("allow leading dots") is in effect and a directory
368
 
      * contains entries that start with a dot.
369
 
      *
370
 
      * (TF, Tue Dec 29 13:49:24 CET 1998)
371
 
      */
372
 
     if((*r)->isorec.name_len[0] == 1 && *rpnt == 0) return -1; /* '.' */
373
 
     if((*l)->isorec.name_len[0] == 1 && *lpnt == 0) return 1;
374
 
 
375
 
     if((*r)->isorec.name_len[0] == 1 && *rpnt == 1) return -1; /* '..' */
376
 
     if((*l)->isorec.name_len[0] == 1 && *lpnt == 1) return 1;
377
 
#endif
378
 
 
379
 
     while(*rpnt && *lpnt)
380
 
     {
381
 
          if(*rpnt == ';' && *lpnt != ';') return -1;
382
 
          if(*rpnt != ';' && *lpnt == ';') return 1;
383
 
         
384
 
          if(*rpnt == ';' && *lpnt == ';') return 0;
385
 
         
386
 
          if(*rpnt == '.' && *lpnt != '.') return -1;
387
 
          if(*rpnt != '.' && *lpnt == '.') return 1;
388
 
         
389
 
          if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1;
390
 
          if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1;
391
 
          rpnt++;  lpnt++;
392
 
     }
393
 
     if(*rpnt) return 1;
394
 
     if(*lpnt) return -1;
395
 
     return 0;
396
 
}
397
 
 
398
 
/*
399
 
 * Function:            sort_directory
400
 
 *
401
 
 * Purpose:             Sort the directory in the appropriate ISO9660
402
 
 *                      order.
403
 
 *
404
 
 * Notes:               Returns 0 if OK, returns > 0 if an error occurred.
405
 
 */
406
 
int FDECL1(sort_directory, struct directory_entry **, sort_dir)
407
 
{
408
 
     int dcount = 0;
409
 
     int xcount = 0;
410
 
     int j;
411
 
     int i, len;
412
 
     struct directory_entry * s_entry;
413
 
     struct directory_entry ** sortlist;
414
 
    
415
 
     /* need to keep a count of how many entries are hidden */
416
 
     s_entry = *sort_dir;
417
 
     while(s_entry)
418
 
     {
419
 
          if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
420
 
            xcount++;
421
 
          dcount++;
422
 
          s_entry = s_entry->next;
423
 
     }
424
 
 
425
 
     if( dcount == 0 )
426
 
     {
427
 
          return 0;
428
 
     }
429
 
 
430
 
     /*
431
 
      * OK, now we know how many there are.  Build a vector for sorting.
432
 
      */
433
 
     sortlist =   (struct directory_entry **)
434
 
          e_malloc(sizeof(struct directory_entry *) * dcount);
435
 
 
436
 
     j = dcount - 1;
437
 
     dcount = 0;
438
 
     s_entry = *sort_dir;
439
 
     while(s_entry)
440
 
     {
441
 
        if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
442
 
         {
443
 
          /* put any hidden entries at the end of the vector */
444
 
          sortlist[j--] = s_entry;
445
 
         }
446
 
        else
447
 
         {
448
 
          sortlist[dcount] = s_entry;
449
 
          dcount++;
450
 
         }
451
 
         len = s_entry->isorec.name_len[0];
452
 
         s_entry->isorec.name[len] = 0;
453
 
         s_entry = s_entry->next;
454
 
     }
455
 
 
456
 
     /*
457
 
      * Each directory is required to contain at least . and ..
458
 
      */
459
 
     if( dcount < 2 )
460
 
       {
461
 
         sort_goof = 1;
462
 
        
463
 
       }
464
 
     else
465
 
       {
466
 
         /* only sort the non-hidden entries */
467
 
         sort_goof = 0;
468
 
#ifdef __STDC__
469
 
         qsort(sortlist, dcount, sizeof(struct directory_entry *),
470
 
               (int (*)(const void *, const void *))compare_dirs);
471
 
#else
472
 
         qsort(sortlist, dcount, sizeof(struct directory_entry *),
473
 
               compare_dirs);
474
 
#endif
475
 
        
476
 
         /*
477
 
          * Now reassemble the linked list in the proper sorted order
478
 
          * We still need the hidden entries, as they may be used in the
479
 
          * Joliet tree.
480
 
          */
481
 
         for(i=0; i<dcount+xcount-1; i++)
482
 
           {
483
 
             sortlist[i]->next = sortlist[i+1];
484
 
           }
485
 
        
486
 
         sortlist[dcount+xcount-1]->next = NULL;
487
 
         *sort_dir = sortlist[0];
488
 
       }
489
 
 
490
 
     free(sortlist);
491
 
     return sort_goof;
492
 
}
493
 
 
494
 
static int root_gen()
495
 
{
496
 
     init_fstatbuf();
497
 
    
498
 
     root_record.length[0] = 1 + sizeof(struct iso_directory_record)
499
 
          - sizeof(root_record.name);
500
 
     root_record.ext_attr_length[0] = 0;
501
 
     set_733((char *) root_record.extent, root->extent);
502
 
     set_733((char *) root_record.size, ROUND_UP(root->size));
503
 
     iso9660_date(root_record.date, root_statbuf.st_mtime);
504
 
     root_record.flags[0] = 2;
505
 
     root_record.file_unit_size[0] = 0;
506
 
     root_record.interleave[0] = 0;
507
 
     set_723(root_record.volume_sequence_number, volume_sequence_number);
508
 
     root_record.name_len[0] = 1;
509
 
     return 0;
510
 
}
511
 
 
512
 
static void FDECL1(assign_file_addresses, struct directory *, dpnt)
513
 
{
514
 
     struct directory * finddir;
515
 
     struct directory_entry * s_entry;
516
 
     struct file_hash *s_hash;
517
 
     struct deferred_write * dwpnt;
518
 
     char whole_path[1024];
519
 
 
520
 
     while (dpnt)
521
 
     {
522
 
          s_entry = dpnt->contents;
523
 
          for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
524
 
          {
525
 
               /*
526
 
                * If we already have an  extent for this entry,
527
 
                * then don't assign a new one.  It must have come
528
 
                * from a previous session on the disc.  Note that
529
 
                * we don't end up scheduling the thing for writing
530
 
                * either.
531
 
                */
532
 
               if( isonum_733((unsigned char *) s_entry->isorec.extent) != 0 )
533
 
               {
534
 
                    continue;
535
 
               }
536
 
              
537
 
               /*
538
 
                * This saves some space if there are symlinks present
539
 
                */
540
 
               s_hash = find_hash(s_entry->dev, s_entry->inode);
541
 
               if(s_hash)
542
 
               {
543
 
                    if(verbose > 2)
544
 
                    {
545
 
                      fprintf (stderr, _("Cache hit for %s%s%s\n"), s_entry->filedir->de_name,
546
 
                               SPATH_SEPARATOR, s_entry->name);
547
 
                    }
548
 
                    set_733((char *) s_entry->isorec.extent, s_hash->starting_block);
549
 
                    set_733((char *) s_entry->isorec.size, s_hash->size);
550
 
                    continue;
551
 
               }
552
 
 
553
 
               /*
554
 
                * If this is for a directory that is not a . or a .. entry,
555
 
                * then look up the information for the entry.  We have already
556
 
                * assigned extents for directories, so we just need to
557
 
                * fill in the blanks here.
558
 
                */
559
 
               if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") &&
560
 
                   s_entry->isorec.flags[0] == 2)
561
 
               {
562
 
                    finddir = dpnt->subdir;
563
 
                    while(1==1)
564
 
                    {
565
 
                         if(finddir->self == s_entry) break;
566
 
                         finddir = finddir->next;
567
 
                         if (!finddir)
568
 
                           error (1, 0, _("Fatal goof\n"));
569
 
                    }
570
 
                    set_733((char *) s_entry->isorec.extent, finddir->extent);
571
 
                    s_entry->starting_block = finddir->extent;
572
 
                    s_entry->size = ROUND_UP(finddir->size);
573
 
                    total_dir_size += s_entry->size;
574
 
                    add_hash(s_entry);
575
 
                    set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size));
576
 
                    continue;
577
 
               }
578
 
 
579
 
 
580
 
               /*
581
 
                * If this is . or .., then look up the relevant info from the
582
 
                * tables.
583
 
                */
584
 
               if(strcmp(s_entry->name,".") == 0)
585
 
               {
586
 
                    set_733((char *) s_entry->isorec.extent, dpnt->extent);
587
 
                   
588
 
                    /*
589
 
                     * Set these so that the hash table has the
590
 
                     * correct information
591
 
                     */
592
 
                    s_entry->starting_block = dpnt->extent;
593
 
                    s_entry->size = ROUND_UP(dpnt->size);
594
 
                   
595
 
                    add_hash(s_entry);
596
 
                    s_entry->starting_block = dpnt->extent;
597
 
                    set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size));
598
 
                    continue;
599
 
               }
600
 
 
601
 
               if(strcmp(s_entry->name,"..") == 0)
602
 
               {
603
 
                    if(dpnt == root)
604
 
                    {
605
 
                         total_dir_size += root->size;
606
 
                    }
607
 
                    set_733((char *) s_entry->isorec.extent, dpnt->parent->extent);
608
 
                   
609
 
                    /*
610
 
                     * Set these so that the hash table has the
611
 
                     * correct information
612
 
                     */
613
 
                    s_entry->starting_block = dpnt->parent->extent;
614
 
                    s_entry->size = ROUND_UP(dpnt->parent->size);
615
 
                   
616
 
                    add_hash(s_entry);
617
 
                    s_entry->starting_block = dpnt->parent->extent;
618
 
                    set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
619
 
                    continue;
620
 
               }
621
 
 
622
 
               /*
623
 
                * Some ordinary non-directory file.  Just schedule the
624
 
                * file to be written.  This is all quite
625
 
                * straightforward, just make a list and assign extents
626
 
                * as we go.  Once we get through writing all of the
627
 
                * directories, we should be ready write out these
628
 
                * files
629
 
                */
630
 
               if(s_entry->size)
631
 
               {
632
 
                    dwpnt = (struct deferred_write *)
633
 
                         e_malloc(sizeof(struct deferred_write));
634
 
                    if(dw_tail)
635
 
                    {
636
 
                         dw_tail->next = dwpnt;
637
 
                         dw_tail = dwpnt;
638
 
                    }
639
 
                    else
640
 
                    {
641
 
                         dw_head = dwpnt;
642
 
                         dw_tail = dwpnt;
643
 
                    }
644
 
                    if(s_entry->inode  ==  TABLE_INODE)
645
 
                    {
646
 
                         dwpnt->table = s_entry->table;
647
 
                         dwpnt->name = NULL;
648
 
                         sprintf(whole_path,"%s%sTRANS.TBL",
649
 
                                 s_entry->filedir->whole_name, SPATH_SEPARATOR);
650
 
                    }
651
 
                    else
652
 
                    {
653
 
                         dwpnt->table = NULL;
654
 
                         strcpy(whole_path, s_entry->whole_name);
655
 
                         dwpnt->name = strdup(whole_path);
656
 
                    }
657
 
                    dwpnt->next = NULL;
658
 
                    dwpnt->size = s_entry->size;
659
 
                    dwpnt->extent = last_extent;
660
 
                    set_733((char *) s_entry->isorec.extent, last_extent);
661
 
                    s_entry->starting_block = last_extent;
662
 
                    add_hash(s_entry);
663
 
                    last_extent += ROUND_UP(s_entry->size) >> 11;
664
 
                    if(verbose > 2)
665
 
                    {
666
 
                         fprintf(stderr,"%llu %llu %s\n", s_entry->starting_block,
667
 
                                 last_extent-1, whole_path);
668
 
                    }
669
 
#ifdef DBG_ISO
670
 
                    if((ROUND_UP(s_entry->size) >> 11) > 500)
671
 
                    {
672
 
                         fprintf (stderr, "Warning: large file %s\n", whole_path);
673
 
                         fprintf (stderr, "Starting block is %d\n", s_entry->starting_block);
674
 
                         fprintf (stderr, "Reported file size is %d extents\n", s_entry->size);
675
 
                        
676
 
                    }
677
 
#endif
678
 
#ifdef  NOT_NEEDED      /* Never use this code if you like to create a DVD */
679
 
 
680
 
                    if(last_extent > (800000000 >> 11))
681
 
                    {
682
 
                         /*
683
 
                          * More than 800Mb? Punt
684
 
                          */
685
 
                         fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
686
 
                         fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
687
 
                         fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
688
 
                         exit(1);
689
 
                    }
690
 
#endif
691
 
                    continue;
692
 
               }
693
 
 
694
 
               /*
695
 
                * This is for zero-length files.  If we leave the extent 0,
696
 
                * then we get screwed, because many readers simply drop files
697
 
                * that have an extent of zero.  Thus we leave the size 0,
698
 
                * and just assign the extent number.
699
 
                */
700
 
               set_733((char *) s_entry->isorec.extent, last_extent);
701
 
          }
702
 
          if(dpnt->subdir)
703
 
          {
704
 
               assign_file_addresses(dpnt->subdir);
705
 
          }
706
 
          dpnt = dpnt->next;
707
 
     }
708
 
} /* assign_file_addresses(... */
709
 
 
710
 
static void FDECL1(free_one_directory, struct directory *, dpnt)
711
 
{
712
 
     struct directory_entry             * s_entry;
713
 
     struct directory_entry             * s_entry_d;
714
 
    
715
 
     s_entry = dpnt->contents;
716
 
     while(s_entry)
717
 
     {
718
 
         s_entry_d = s_entry;
719
 
         s_entry = s_entry->next;
720
 
        
721
 
         if( s_entry_d->name != NULL )
722
 
         {
723
 
             free (s_entry_d->name);
724
 
         }
725
 
         if( s_entry_d->whole_name != NULL )
726
 
         {
727
 
             free (s_entry_d->whole_name);
728
 
         }
729
 
         free (s_entry_d);
730
 
     }
731
 
     dpnt->contents = NULL;
732
 
} /* free_one_directory(... */
733
 
 
734
 
static void FDECL1(free_directories, struct directory *, dpnt)
735
 
{
736
 
  while (dpnt)
737
 
    {
738
 
      free_one_directory(dpnt);
739
 
      if(dpnt->subdir) free_directories(dpnt->subdir);
740
 
      dpnt = dpnt->next;
741
 
    }
742
 
}
743
 
 
744
 
void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)
745
 
{
746
 
     unsigned int                         ce_address = 0;
747
 
     char                               * ce_buffer;
748
 
     unsigned int                         ce_index = 0;
749
 
     unsigned int                         ce_size;
750
 
     unsigned int                         dir_index;
751
 
     char                               * directory_buffer;
752
 
     int                                  new_reclen;
753
 
     struct directory_entry             * s_entry;
754
 
     struct directory_entry             * s_entry_d;
755
 
     unsigned int                         total_size;
756
 
    
757
 
     total_size = (dpnt->size + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
758
 
     directory_buffer = (char *) e_malloc(total_size);
759
 
     memset(directory_buffer, 0, total_size);
760
 
     dir_index = 0;
761
 
    
762
 
     ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
763
 
     ce_buffer = NULL;
764
 
    
765
 
     if(ce_size)
766
 
     {
767
 
          ce_buffer = (char *) e_malloc(ce_size);
768
 
          memset(ce_buffer, 0, ce_size);
769
 
         
770
 
          ce_index = 0;
771
 
         
772
 
          /*
773
 
           * Absolute byte address of CE entries for this directory
774
 
           */
775
 
          ce_address = last_extent_written + (total_size >> 11);
776
 
          ce_address = ce_address << 11;
777
 
     }
778
 
    
779
 
     s_entry = dpnt->contents;
780
 
     while(s_entry)
781
 
     {
782
 
          /* skip if it's hidden */
783
 
          if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
784
 
            s_entry = s_entry->next;
785
 
            continue;
786
 
          }
787
 
 
788
 
          /*
789
 
           * We do not allow directory entries to cross sector boundaries. 
790
 
           * Simply pad, and then start the next entry at the next sector
791
 
           */
792
 
          new_reclen = s_entry->isorec.length[0];
793
 
          if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
794
 
          {
795
 
               dir_index = (dir_index + (SECTOR_SIZE - 1)) &
796
 
                    ~(SECTOR_SIZE - 1);
797
 
          }
798
 
 
799
 
          memcpy(directory_buffer + dir_index, &s_entry->isorec,
800
 
                 sizeof(struct iso_directory_record) -
801
 
                 sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]);
802
 
          dir_index += sizeof(struct iso_directory_record) -
803
 
               sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0];
804
 
 
805
 
          /*
806
 
           * Add the Rock Ridge attributes, if present
807
 
           */
808
 
          if(s_entry->rr_attr_size)
809
 
          {
810
 
               if(dir_index & 1)
811
 
               {
812
 
                    directory_buffer[dir_index++] = 0;
813
 
               }
814
 
 
815
 
               /*
816
 
                * If the RR attributes were too long, then write the
817
 
                * CE records, as required.
818
 
                */
819
 
               if(s_entry->rr_attr_size != s_entry->total_rr_attr_size)
820
 
               {
821
 
                    unsigned char * pnt;
822
 
                    int len, nbytes;
823
 
                   
824
 
                    /*
825
 
                     * Go through the entire record and fix up the CE entries
826
 
                     * so that the extent and offset are correct
827
 
                     */
828
 
                   
829
 
                    pnt = s_entry->rr_attributes;
830
 
                    len = s_entry->total_rr_attr_size;
831
 
                    while(len > 3)
832
 
                    {
833
 
#ifdef DEBUG
834
 
                         if (!ce_size)
835
 
                         {
836
 
                              fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n",
837
 
                                      ce_index, ce_address);
838
 
                         }
839
 
#endif
840
 
                        
841
 
                         if(pnt[0] == 'C' && pnt[1] == 'E')
842
 
                         {
843
 
                              nbytes = get_733( (char *) pnt+20);
844
 
                             
845
 
                              if((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
846
 
                                 SECTOR_SIZE)
847
 
                              {
848
 
                                   ce_index = ROUND_UP(ce_index);
849
 
                              }
850
 
                             
851
 
                              set_733( (char *) pnt+4,
852
 
                                       (ce_address + ce_index) >> 11);
853
 
                              set_733( (char *) pnt+12,
854
 
                                       (ce_address + ce_index) & (SECTOR_SIZE - 1));
855
 
                             
856
 
                             
857
 
                              /*
858
 
                               * Now store the block in the ce buffer
859
 
                               */
860
 
                              memcpy(ce_buffer + ce_index,
861
 
                                     pnt + pnt[2], nbytes);
862
 
                              ce_index += nbytes;
863
 
                              if(ce_index & 1)
864
 
                              {
865
 
                                   ce_index++;
866
 
                              }
867
 
                         }
868
 
                         len -= pnt[2];
869
 
                         pnt += pnt[2];
870
 
                    }
871
 
                   
872
 
               }
873
 
 
874
 
               rockridge_size += s_entry->total_rr_attr_size;
875
 
               memcpy(directory_buffer + dir_index, s_entry->rr_attributes,
876
 
                      s_entry->rr_attr_size);
877
 
               dir_index += s_entry->rr_attr_size;
878
 
          }
879
 
          if(dir_index & 1)
880
 
          {
881
 
               directory_buffer[dir_index++] = 0;
882
 
          }
883
 
         
884
 
          s_entry_d = s_entry;
885
 
          s_entry = s_entry->next;
886
 
         
887
 
          /*
888
 
           * Joliet doesn't use the Rock Ridge attributes, so we free it here.
889
 
           */
890
 
          if (s_entry_d->rr_attributes)
891
 
            {
892
 
              free(s_entry_d->rr_attributes);
893
 
              s_entry_d->rr_attributes = NULL;
894
 
            }
895
 
     }
896
 
 
897
 
     if(dpnt->size != dir_index)
898
 
     {
899
 
          fprintf (stderr, _("Unexpected directory length %d %d %s\n"), dpnt->size,
900
 
                   dir_index, dpnt->de_name);
901
 
     }
902
 
 
903
 
     xfwrite(directory_buffer, 1, total_size, outfile);
904
 
     last_extent_written += total_size >> 11;
905
 
     free(directory_buffer);
906
 
 
907
 
     if(ce_size)
908
 
     {
909
 
          if(ce_index != dpnt->ce_bytes)
910
 
          {
911
 
            fprintf (stderr, _("Continuation entry record length mismatch (%d %d).\n"),
912
 
                     ce_index, dpnt->ce_bytes);
913
 
          }
914
 
          xfwrite(ce_buffer, 1, ce_size, outfile);
915
 
          last_extent_written += ce_size >> 11;
916
 
          free(ce_buffer);
917
 
     }
918
 
    
919
 
} /* generate_one_directory(... */
920
 
 
921
 
static
922
 
void FDECL1(build_pathlist, struct directory *, node)
923
 
{
924
 
     struct directory * dpnt;
925
 
    
926
 
     dpnt = node;
927
 
    
928
 
     while (dpnt)
929
 
     {
930
 
        /* skip if it's hidden */
931
 
        if( (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0 )
932
 
          pathlist[dpnt->path_index] = dpnt;
933
 
 
934
 
        if(dpnt->subdir) build_pathlist(dpnt->subdir);
935
 
        dpnt = dpnt->next;
936
 
     }
937
 
} /* build_pathlist(... */
938
 
 
939
 
static int FDECL2(compare_paths, void const *, r, void const *, l)
940
 
{
941
 
  struct directory const *ll = *(struct directory * const *)l;
942
 
  struct directory const *rr = *(struct directory * const *)r;
943
 
 
944
 
  if (rr->parent->path_index < ll->parent->path_index)
945
 
  {
946
 
       return -1;
947
 
  }
948
 
 
949
 
  if (rr->parent->path_index > ll->parent->path_index)
950
 
  {
951
 
       return 1;
952
 
  }
953
 
 
954
 
  return strcmp(rr->self->isorec.name, ll->self->isorec.name);
955
 
 
956
 
} /* compare_paths(... */
957
 
 
958
 
static int generate_path_tables()
959
 
{
960
 
  struct directory_entry * de;
961
 
  struct directory       * dpnt;
962
 
  int                      fix;
963
 
  int                      i;
964
 
  int                      j;
965
 
  int                      namelen;
966
 
  char                   * npnt;
967
 
  char                   * npnt1;
968
 
  int                      tablesize;
969
 
 
970
 
  /*
971
 
   * First allocate memory for the tables and initialize the memory
972
 
   */
973
 
  tablesize = path_blocks << 11;
974
 
  path_table_m = (char *) e_malloc(tablesize);
975
 
  path_table_l = (char *) e_malloc(tablesize);
976
 
  memset(path_table_l, 0, tablesize);
977
 
  memset(path_table_m, 0, tablesize);
978
 
 
979
 
  /*
980
 
   * Now start filling in the path tables.  Start with root directory
981
 
   */
982
 
  if( next_path_index > 0xffff )
983
 
  {
984
 
    error (1, 0, _("Unable to generate sane path tables - too many directories (%d)\n"),
985
 
           next_path_index);
986
 
  }
987
 
 
988
 
  path_table_index = 0;
989
 
  pathlist = (struct directory **) e_malloc(sizeof(struct directory *)
990
 
                                            * next_path_index);
991
 
  memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
992
 
  build_pathlist(root);
993
 
 
994
 
  do
995
 
  {
996
 
       fix = 0;
997
 
#ifdef __STDC__
998
 
       qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *),
999
 
             (int (*)(const void *, const void *))compare_paths);
1000
 
#else
1001
 
       qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *),
1002
 
             compare_paths);
1003
 
#endif
1004
 
 
1005
 
       for(j=1; j<next_path_index; j++)
1006
 
       {
1007
 
            if(pathlist[j]->path_index != j)
1008
 
            {
1009
 
                 pathlist[j]->path_index = j;
1010
 
                 fix++;
1011
 
            }
1012
 
       }
1013
 
  } while(fix);
1014
 
 
1015
 
  for(j=1; j<next_path_index; j++)
1016
 
  {
1017
 
       dpnt = pathlist[j];
1018
 
       if(!dpnt)
1019
 
       {
1020
 
         error (1, 0, _("Entry %d not in path tables\n"), j);
1021
 
       }
1022
 
       npnt = dpnt->de_name;
1023
 
      
1024
 
       /*
1025
 
        * So the root comes out OK
1026
 
        */
1027
 
       if( (*npnt == 0) || (dpnt == root) )
1028
 
       {
1029
 
            npnt = "."; 
1030
 
       }
1031
 
       npnt1 = strrchr(npnt, PATH_SEPARATOR);
1032
 
       if(npnt1)
1033
 
       {
1034
 
            npnt = npnt1 + 1;
1035
 
       }
1036
 
      
1037
 
       de = dpnt->self;
1038
 
       if(!de)
1039
 
       {
1040
 
         error (1, 0, _("Fatal goof\n"));
1041
 
       }
1042
 
      
1043
 
      
1044
 
       namelen = de->isorec.name_len[0];
1045
 
      
1046
 
       path_table_l[path_table_index] = namelen;
1047
 
       path_table_m[path_table_index] = namelen;
1048
 
       path_table_index += 2;
1049
 
      
1050
 
       set_731(path_table_l + path_table_index, dpnt->extent);
1051
 
       set_732(path_table_m + path_table_index, dpnt->extent);
1052
 
       path_table_index += 4;
1053
 
      
1054
 
       set_721(path_table_l + path_table_index,
1055
 
               dpnt->parent->path_index);
1056
 
       set_722(path_table_m + path_table_index,
1057
 
               dpnt->parent->path_index);
1058
 
       path_table_index += 2;
1059
 
      
1060
 
       for(i =0; i<namelen; i++)
1061
 
       {
1062
 
            path_table_l[path_table_index] = de->isorec.name[i];
1063
 
            path_table_m[path_table_index] = de->isorec.name[i];
1064
 
            path_table_index++;
1065
 
       }
1066
 
       if(path_table_index & 1)
1067
 
       {
1068
 
            path_table_index++;  /* For odd lengths we pad */
1069
 
       }
1070
 
  }
1071
 
 
1072
 
  free(pathlist);
1073
 
  if(path_table_index != path_table_size)
1074
 
  {
1075
 
    fprintf (stderr, _("Path table lengths do not match %d %d\n"),
1076
 
             path_table_index,
1077
 
             path_table_size);
1078
 
  }
1079
 
  return 0;
1080
 
} /* generate_path_tables(... */
1081
 
 
1082
 
void
1083
 
FDECL3(memcpy_max, char *, to, char *, from, int, max)
1084
 
{
1085
 
  int n = strlen(from);
1086
 
  if (n > max)
1087
 
  {
1088
 
       n = max;
1089
 
  }
1090
 
  memcpy(to, from, n);
1091
 
 
1092
 
} /* memcpy_max(... */
1093
 
 
1094
 
void FDECL1(outputlist_insert, struct output_fragment *, frag)
1095
 
{
1096
 
  if( out_tail == NULL )
1097
 
    {
1098
 
      out_list = out_tail = frag;
1099
 
    }
1100
 
  else
1101
 
    {
1102
 
      out_tail->of_next = frag;
1103
 
      out_tail = frag;
1104
 
    }
1105
 
}
1106
 
 
1107
 
static int FDECL1(file_write, FILE *, outfile)
1108
 
{
1109
 
  int                           should_write;
1110
 
 
1111
 
  /*
1112
 
   * OK, all done with that crap.  Now write out the directories.
1113
 
   * This is where the fur starts to fly, because we need to keep track of
1114
 
   * each file as we find it and keep track of where we put it.
1115
 
   */
1116
 
 
1117
 
  should_write = last_extent - session_start;
1118
 
 
1119
 
  if( print_size > 0 )
1120
 
    {
1121
 
      fprintf (stderr, _("Total extents scheduled to be written = %llu\n"),
1122
 
               last_extent - session_start);
1123
 
      exit (0);
1124
 
    }
1125
 
  if( verbose > 2 )
1126
 
    {
1127
 
#ifdef DBG_ISO
1128
 
      fprintf(stderr,"Total directory extents being written = %llu\n", last_extent);
1129
 
#endif
1130
 
     
1131
 
      fprintf (stderr, _("Total extents scheduled to be written = %llu\n"),
1132
 
               last_extent - session_start);
1133
 
    }
1134
 
 
1135
 
  /*
1136
 
   * Now write all of the files that we need.
1137
 
   */
1138
 
  write_files(outfile);
1139
 
 
1140
 
  /*
1141
 
   * The rest is just fluff.
1142
 
   */
1143
 
  if( verbose == 0 )
1144
 
    {
1145
 
      return 0;
1146
 
    }
1147
 
 
1148
 
  fprintf (stderr, _("Total extents actually written = %llu\n"),
1149
 
           last_extent_written - session_start);
1150
 
 
1151
 
  /*
1152
 
   * Hard links throw us off here
1153
 
   */
1154
 
  assert (last_extent > session_start);
1155
 
  if(should_write + session_start != last_extent)
1156
 
    {
1157
 
      fprintf (stderr, _("Number of extents written different than what was predicted.  Please fix.\n"));
1158
 
      fprintf (stderr, _("Predicted = %d, written = %llu\n"), should_write, last_extent);
1159
 
    }
1160
 
 
1161
 
  fprintf (stderr, _("Total translation table size: %d\n"), table_size);
1162
 
  fprintf (stderr, _("Total rockridge attributes bytes: %d\n"), rockridge_size);
1163
 
  fprintf (stderr, _("Total directory bytes: %d\n"), total_dir_size);
1164
 
  fprintf (stderr, _("Path table size(bytes): %d\n"), path_table_size);
1165
 
 
1166
 
#ifdef DEBUG
1167
 
  fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
1168
 
          next_extent, last_extent, last_extent_written);
1169
 
#endif
1170
 
 
1171
 
  return 0;
1172
 
 
1173
 
} /* iso_write(... */
1174
 
 
1175
 
char *creation_date = NULL;
1176
 
char *modification_date = NULL;
1177
 
char *expiration_date = NULL;
1178
 
char *effective_date = NULL;
1179
 
 
1180
 
/*
1181
 
 * Function to write the PVD for the disc.
1182
 
 */
1183
 
static int FDECL1(pvd_write, FILE *, outfile)
1184
 
{
1185
 
  char                          iso_time[17];
1186
 
  int                           should_write;
1187
 
  struct tm                     local;
1188
 
  struct tm                     gmt;
1189
 
 
1190
 
 
1191
 
  time(&begun);
1192
 
 
1193
 
  local = *localtime(&begun);
1194
 
  gmt   = *gmtime(&begun);
1195
 
 
1196
 
  /*
1197
 
   * This will break  in the year  2000, I supose, but there is no good way
1198
 
   * to get the top two digits of the year.
1199
 
   */
1200
 
  sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local.tm_year,
1201
 
          local.tm_mon+1, local.tm_mday,
1202
 
          local.tm_hour, local.tm_min, local.tm_sec);
1203
 
 
1204
 
  local.tm_min -= gmt.tm_min;
1205
 
  local.tm_hour -= gmt.tm_hour;
1206
 
  local.tm_yday -= gmt.tm_yday;
1207
 
  iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15;
1208
 
 
1209
 
  /*
1210
 
   * Next we write out the primary descriptor for the disc
1211
 
   */
1212
 
  memset(&vol_desc, 0, sizeof(vol_desc));
1213
 
  vol_desc.type[0] = ISO_VD_PRIMARY;
1214
 
  memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
1215
 
  vol_desc.version[0] = 1;
1216
 
 
1217
 
  memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
1218
 
  memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
1219
 
 
1220
 
  memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
1221
 
  memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
1222
 
 
1223
 
  should_write = last_extent - session_start;
1224
 
  set_733((char *) vol_desc.volume_space_size, should_write);
1225
 
  set_723(vol_desc.volume_set_size, volume_set_size);
1226
 
  set_723(vol_desc.volume_sequence_number, volume_sequence_number);
1227
 
  set_723(vol_desc.logical_block_size, 2048);
1228
 
 
1229
 
  /*
1230
 
   * The path tables are used by DOS based machines to cache directory
1231
 
   * locations
1232
 
   */
1233
 
 
1234
 
  set_733((char *) vol_desc.path_table_size, path_table_size);
1235
 
  set_731(vol_desc.type_l_path_table, path_table[0]);
1236
 
  set_731(vol_desc.opt_type_l_path_table, path_table[1]);
1237
 
  set_732(vol_desc.type_m_path_table, path_table[2]);
1238
 
  set_732(vol_desc.opt_type_m_path_table, path_table[3]);
1239
 
 
1240
 
  /*
1241
 
   * Now we copy the actual root directory record
1242
 
   */
1243
 
  memcpy(vol_desc.root_directory_record, &root_record,
1244
 
         sizeof(struct iso_directory_record) + 1);
1245
 
 
1246
 
  /*
1247
 
   * The rest is just fluff.  It looks nice to fill in many of these fields,
1248
 
   * though.
1249
 
   */
1250
 
  FILL_SPACE(volume_set_id);
1251
 
  if(volset_id)  memcpy_max(vol_desc.volume_set_id,  volset_id, strlen(volset_id));
1252
 
 
1253
 
  FILL_SPACE(publisher_id);
1254
 
  if(publisher)  memcpy_max(vol_desc.publisher_id,  publisher, strlen(publisher));
1255
 
 
1256
 
  FILL_SPACE(preparer_id);
1257
 
  if(preparer)  memcpy_max(vol_desc.preparer_id,  preparer, strlen(preparer));
1258
 
 
1259
 
  FILL_SPACE(application_id);
1260
 
  if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid));
1261
 
 
1262
 
  FILL_SPACE(copyright_file_id);
1263
 
  if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright,
1264
 
                       strlen(copyright));
1265
 
 
1266
 
  FILL_SPACE(abstract_file_id);
1267
 
  if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract,
1268
 
                          strlen(abstract));
1269
 
 
1270
 
  FILL_SPACE(bibliographic_file_id);
1271
 
  if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio,
1272
 
                       strlen(biblio));
1273
 
 
1274
 
  FILL_SPACE(creation_date);
1275
 
  FILL_SPACE(modification_date);
1276
 
  FILL_SPACE(expiration_date);
1277
 
  FILL_SPACE(effective_date);
1278
 
  vol_desc.file_structure_version[0] = 1;
1279
 
  FILL_SPACE(application_data);
1280
 
 
1281
 
  memcpy(vol_desc.creation_date, creation_date ? creation_date : iso_time, 17);
1282
 
  memcpy(vol_desc.modification_date, modification_date ? modification_date : iso_time, 17);
1283
 
  memcpy(vol_desc.expiration_date, expiration_date ? expiration_date : "0000000000000000", 17);
1284
 
  memcpy(vol_desc.effective_date, effective_date ? effective_date : iso_time, 17);
1285
 
 
1286
 
  /*
1287
 
   * if not a bootable cd do it the old way
1288
 
   */
1289
 
  xfwrite(&vol_desc, 1, 2048, outfile);
1290
 
  last_extent_written++;
1291
 
  return 0;
1292
 
}
1293
 
 
1294
 
/*
1295
 
 * Function to write the EVD for the disc.
1296
 
 */
1297
 
static int FDECL1(evd_write, FILE *, outfile)
1298
 
{
1299
 
  struct iso_primary_descriptor evol_desc;
1300
 
 
1301
 
  /*
1302
 
   * Now write the end volume descriptor.  Much simpler than the other one
1303
 
   */
1304
 
  memset(&evol_desc, 0, sizeof(evol_desc));
1305
 
  evol_desc.type[0] = ISO_VD_END;
1306
 
  memcpy(evol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
1307
 
  evol_desc.version[0] = 1;
1308
 
  xfwrite(&evol_desc, 1, 2048, outfile);
1309
 
  last_extent_written += 1;
1310
 
  return 0;
1311
 
}
1312
 
 
1313
 
/*
1314
 
 * Function to write the EVD for the disc.
1315
 
 */
1316
 
static int FDECL1(pathtab_write, FILE *, outfile)
1317
 
{
1318
 
  /*
1319
 
   * Next we write the path tables
1320
 
   */
1321
 
  xfwrite(path_table_l, 1, path_blocks << 11, outfile);
1322
 
  xfwrite(path_table_m, 1, path_blocks << 11, outfile);
1323
 
  last_extent_written += 2*path_blocks;
1324
 
  free(path_table_l);
1325
 
  free(path_table_m);
1326
 
  path_table_l = NULL;
1327
 
  path_table_m = NULL;
1328
 
  return 0;
1329
 
}
1330
 
 
1331
 
static int FDECL1(exten_write, FILE *, outfile)
1332
 
{
1333
 
  xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
1334
 
  last_extent_written++;
1335
 
  return 0;
1336
 
}
1337
 
 
1338
 
/*
1339
 
 * Functions to describe padding block at the start of the disc.
1340
 
 */
1341
 
int FDECL1(oneblock_size, int, starting_extent)
1342
 
{
1343
 
  last_extent++;
1344
 
  return 0;
1345
 
}
1346
 
 
1347
 
/*
1348
 
 * Functions to describe padding block at the start of the disc.
1349
 
 */
1350
 
 
1351
 
#define PADBLOCK_SIZE   16
1352
 
 
1353
 
static int FDECL1(pathtab_size, int, starting_extent)
1354
 
{
1355
 
  path_table[0] = starting_extent;
1356
 
 
1357
 
  path_table[1] = 0;
1358
 
  path_table[2] = path_table[0] + path_blocks;
1359
 
  path_table[3] = 0;
1360
 
  last_extent += 2*path_blocks;
1361
 
  return 0;
1362
 
}
1363
 
 
1364
 
static int FDECL1(padblock_size, int, starting_extent)
1365
 
{
1366
 
  last_extent += PADBLOCK_SIZE;
1367
 
  return 0;
1368
 
}
1369
 
 
1370
 
static int file_gen()
1371
 
{
1372
 
  assign_file_addresses(root);
1373
 
  return 0;
1374
 
}
1375
 
 
1376
 
static int dirtree_dump()
1377
 
{
1378
 
  if (verbose > 2)
1379
 
  {
1380
 
      dump_tree(root);
1381
 
  }
1382
 
  return 0;
1383
 
}
1384
 
 
1385
 
static int FDECL1(dirtree_fixup, int, starting_extent)
1386
 
{
1387
 
  if (use_RockRidge && reloc_dir)
1388
 
          finish_cl_pl_entries();
1389
 
 
1390
 
  if (use_RockRidge )
1391
 
          update_nlink_field(root);
1392
 
  return 0;
1393
 
}
1394
 
 
1395
 
static int FDECL1(dirtree_size, int, starting_extent)
1396
 
{
1397
 
  assign_directory_addresses(root);
1398
 
  return 0;
1399
 
}
1400
 
 
1401
 
static int FDECL1(ext_size, int, starting_extent)
1402
 
{
1403
 
  extern int extension_record_size;
1404
 
  struct directory_entry * s_entry;
1405
 
  extension_record_extent = starting_extent;
1406
 
  s_entry = root->contents;
1407
 
  set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24,
1408
 
          extension_record_extent);
1409
 
  set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8,
1410
 
          extension_record_size);
1411
 
  last_extent++;
1412
 
  return 0;
1413
 
}
1414
 
 
1415
 
static int FDECL1(dirtree_write, FILE *, outfile)
1416
 
{
1417
 
  generate_iso9660_directories(root, outfile);
1418
 
  return 0;
1419
 
}
1420
 
 
1421
 
static int FDECL1(dirtree_cleanup, FILE *, outfile)
1422
 
{
1423
 
  free_directories(root);
1424
 
  return 0;
1425
 
}
1426
 
 
1427
 
static int FDECL1(padblock_write, FILE *, outfile)
1428
 
{
1429
 
  char *buffer;
1430
 
 
1431
 
  buffer = e_malloc (2048 * PADBLOCK_SIZE);
1432
 
  memset (buffer, 0, 2048 * PADBLOCK_SIZE);
1433
 
 
1434
 
  if (use_embedded_boot)
1435
 
    {
1436
 
      FILE *fp = fopen (boot_image_embed, "rb");
1437
 
      if (! fp)
1438
 
        error (1, errno, _("Unable to open %s"), boot_image_embed);
1439
 
 
1440
 
      if (fread (buffer, 1, 2048 * PADBLOCK_SIZE, fp) == 0)
1441
 
        error (1, errno, _("cannot read %d bytes from %s"),
1442
 
               2048 * PADBLOCK_SIZE, boot_image_embed);
1443
 
      if (fgetc (fp) != EOF)
1444
 
        error (1, 0, _("%s is too big for embed area"), boot_image_embed);
1445
 
    }
1446
 
 
1447
 
  if (use_protective_msdos_label)
1448
 
    {
1449
 
      struct msdos_partition_mbr *mbr = (void *) buffer;
1450
 
 
1451
 
      memset (mbr->entries, 0, sizeof(mbr->entries));
1452
 
 
1453
 
      /* Some idiotic BIOSes refuse to boot if they don't find at least
1454
 
         one partition with active bit set.  */
1455
 
      mbr->entries[0].flag = 0x80;
1456
 
 
1457
 
      /* Doesn't really matter, as long as it's non-zero.  It seems that
1458
 
         0xCD is used elsewhere, so we follow suit.  */
1459
 
      mbr->entries[0].type = 0xcd;
1460
 
 
1461
 
      /* Start immediately (sector 1).  */
1462
 
      mbr->entries[0].start = 1;
1463
 
 
1464
 
      /* We don't know yet.  Let's keep it safe.  */
1465
 
      mbr->entries[0].length = UINT32_MAX;
1466
 
 
1467
 
      mbr->signature = MSDOS_PARTITION_SIGNATURE;
1468
 
    }
1469
 
 
1470
 
  xfwrite (buffer, 1, 2048 * PADBLOCK_SIZE, outfile);
1471
 
  last_extent_written += PADBLOCK_SIZE;
1472
 
 
1473
 
  return 0;
1474
 
}
1475
 
 
1476
 
struct output_fragment padblock_desc  = {NULL, padblock_size, NULL,     padblock_write};
1477
 
struct output_fragment voldesc_desc   = {NULL, oneblock_size, root_gen, pvd_write};
1478
 
struct output_fragment end_vol        = {NULL, oneblock_size, NULL,     evd_write};
1479
 
struct output_fragment pathtable_desc = {NULL, pathtab_size,  generate_path_tables,     pathtab_write};
1480
 
struct output_fragment dirtree_desc   = {NULL, dirtree_size,  NULL,     dirtree_write};
1481
 
struct output_fragment dirtree_clean  = {NULL, dirtree_fixup, dirtree_dump,     dirtree_cleanup};
1482
 
struct output_fragment extension_desc = {NULL, ext_size,      NULL,     exten_write};
1483
 
struct output_fragment files_desc     = {NULL, NULL,          file_gen, file_write};