File: | src/gnu/usr.sbin/mkhybrid/mkhybrid/../src/write.c |
Warning: | line 927, column 10 Null pointer passed as 1st argument to memory copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | This program is free software; you can redistribute it and/or modify | |||
9 | it under the terms of the GNU General Public License as published by | |||
10 | the Free Software Foundation; either version 2, or (at your option) | |||
11 | any later version. | |||
12 | ||||
13 | This program is distributed in the hope that it will be useful, | |||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
16 | GNU General Public License for more details. | |||
17 | ||||
18 | You should have received a copy of the GNU General Public License | |||
19 | along with this program; if not, write to the Free Software | |||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
21 | ||||
22 | /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 16/3/1999 */ | |||
23 | #include <string.h> | |||
24 | #include <stdlib.h> | |||
25 | #include <err.h> | |||
26 | #include "config.h" | |||
27 | #include "mkisofs.h" | |||
28 | #include "iso9660.h" | |||
29 | #include "volume.h" | |||
30 | #include "write.h" | |||
31 | #include "apple_proto.h" | |||
32 | #include "mac_label_proto.h" | |||
33 | #include <time.h> | |||
34 | #include <errno(*__errno()).h> | |||
35 | ||||
36 | #include <sys/types.h> | |||
37 | #include <sys/stat.h> | |||
38 | #include <fcntl.h> | |||
39 | ||||
40 | #ifdef HAVE_UNISTD_H1 | |||
41 | #include <unistd.h> | |||
42 | #endif | |||
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 NSECT16 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 | #ifdef APPLE_HYB1 | |||
71 | static int hfs_pad; | |||
72 | #endif /* APPLE_HYB */ | |||
73 | ||||
74 | static int root_gen __PR((void))(void); | |||
75 | static int generate_path_tables __PR((void))(void); | |||
76 | static int file_gen __PR((void))(void); | |||
77 | static int dirtree_dump __PR((void))(void); | |||
78 | ||||
79 | /* Routines to actually write the disc. We write sequentially so that | |||
80 | we could write a tape, or write the disc directly */ | |||
81 | ||||
82 | ||||
83 | #define FILL_SPACE(X)memset(vol_desc.X, ' ', sizeof(vol_desc.X)) memset(vol_desc.X, ' ', sizeof(vol_desc.X)) | |||
84 | ||||
85 | void FDECL2(set_721, char *, pnt, unsigned int, i)set_721(char * pnt, unsigned int i) | |||
86 | { | |||
87 | pnt[0] = i & 0xff; | |||
88 | pnt[1] = (i >> 8) & 0xff; | |||
89 | } | |||
90 | ||||
91 | void FDECL2(set_722, char *, pnt, unsigned int, i)set_722(char * pnt, unsigned int i) | |||
92 | { | |||
93 | pnt[0] = (i >> 8) & 0xff; | |||
94 | pnt[1] = i & 0xff; | |||
95 | } | |||
96 | ||||
97 | void FDECL2(set_723, char *, pnt, unsigned int, i)set_723(char * pnt, unsigned int i) | |||
98 | { | |||
99 | pnt[3] = pnt[0] = i & 0xff; | |||
100 | pnt[2] = pnt[1] = (i >> 8) & 0xff; | |||
101 | } | |||
102 | ||||
103 | void FDECL2(set_731, char *, pnt, unsigned int, i)set_731(char * pnt, unsigned int i) | |||
104 | { | |||
105 | pnt[0] = i & 0xff; | |||
106 | pnt[1] = (i >> 8) & 0xff; | |||
107 | pnt[2] = (i >> 16) & 0xff; | |||
108 | pnt[3] = (i >> 24) & 0xff; | |||
109 | } | |||
110 | ||||
111 | void FDECL2(set_732, char *, pnt, unsigned int, i)set_732(char * pnt, unsigned int i) | |||
112 | { | |||
113 | pnt[3] = i & 0xff; | |||
114 | pnt[2] = (i >> 8) & 0xff; | |||
115 | pnt[1] = (i >> 16) & 0xff; | |||
116 | pnt[0] = (i >> 24) & 0xff; | |||
117 | } | |||
118 | ||||
119 | int FDECL1(get_733, char *, p)get_733(char * p) | |||
120 | { | |||
121 | return ((p[0] & 0xff) | |||
122 | | ((p[1] & 0xff) << 8) | |||
123 | | ((p[2] & 0xff) << 16) | |||
124 | | ((p[3] & 0xff) << 24)); | |||
125 | } | |||
126 | ||||
127 | void FDECL2(set_733, char *, pnt, unsigned int, i)set_733(char * pnt, unsigned int i) | |||
128 | { | |||
129 | pnt[7] = pnt[0] = i & 0xff; | |||
130 | pnt[6] = pnt[1] = (i >> 8) & 0xff; | |||
131 | pnt[5] = pnt[2] = (i >> 16) & 0xff; | |||
132 | pnt[4] = pnt[3] = (i >> 24) & 0xff; | |||
133 | } | |||
134 | ||||
135 | void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)xfwrite(void * buffer, int count, int size, FILE * file) | |||
136 | { | |||
137 | /* | |||
138 | * This is a hack that could be made better. XXXIs this the only place? | |||
139 | * It is definitely needed on Operating Systems that do not | |||
140 | * allow to write files that are > 2GB. | |||
141 | * If the system is fast enough to be able to feed 1400 KB/s | |||
142 | * writing speed of a DVD-R drive, use stdout. | |||
143 | * If the system cannot do this reliable, you need to use this | |||
144 | * hacky option. | |||
145 | */ | |||
146 | static int idx = 0; | |||
147 | if (split_output != 0 && | |||
148 | (idx == 0 || ftell(file) >= (1024 * 1024 * 1024) )) { | |||
149 | char nbuf[512]; | |||
150 | extern char *outfile; | |||
151 | ||||
152 | if (idx == 0) | |||
153 | unlink(outfile); | |||
154 | snprintf(nbuf, sizeof nbuf, "%s_%02d", outfile, idx++); | |||
155 | file = freopen(nbuf, "wb", file); | |||
156 | if (file == NULL((void *)0)) { | |||
157 | fprintf(stderr(&__sF[2]), "Cannot open '%s'.\n", nbuf); | |||
158 | exit(1); | |||
159 | } | |||
160 | ||||
161 | } | |||
162 | while(count) | |||
163 | { | |||
164 | int got = fwrite(buffer,size,count,file); | |||
165 | ||||
166 | if(got<=0) | |||
167 | { | |||
168 | fprintf(stderr(&__sF[2]),"cannot fwrite %d*%d\n",size,count); | |||
169 | exit(1); | |||
170 | } | |||
171 | count-=got,*(char**)&buffer+=size*got; | |||
172 | } | |||
173 | } | |||
174 | ||||
175 | #ifdef APPLE_HYB1 | |||
176 | /* use the deferred_write struct to store info about the hfs_boot_file */ | |||
177 | static struct deferred_write mac_boot; | |||
178 | #endif /* APPLE_HYB */ | |||
179 | static struct deferred_write * dw_head = NULL((void *)0), * dw_tail = NULL((void *)0); | |||
180 | ||||
181 | unsigned int last_extent_written =0; | |||
182 | static int path_table_index; | |||
183 | static time_t begun; | |||
184 | ||||
185 | /* We recursively walk through all of the directories and assign extent | |||
186 | numbers to them. We have already assigned extent numbers to everything that | |||
187 | goes in front of them */ | |||
188 | ||||
189 | static int FDECL1(assign_directory_addresses, struct directory *, node)assign_directory_addresses(struct directory * node) | |||
190 | { | |||
191 | int dir_size; | |||
192 | struct directory * dpnt; | |||
193 | ||||
194 | dpnt = node; | |||
195 | ||||
196 | while (dpnt) | |||
197 | { | |||
198 | /* skip if it's hidden */ | |||
199 | if(dpnt->dir_flags & INHIBIT_ISO9660_ENTRY0x40) { | |||
200 | dpnt = dpnt->next; | |||
201 | continue; | |||
202 | } | |||
203 | ||||
204 | /* | |||
205 | * If we already have an extent for this (i.e. it came from | |||
206 | * a multisession disc), then don't reassign a new extent. | |||
207 | */ | |||
208 | dpnt->path_index = next_path_index++; | |||
209 | if( dpnt->extent == 0 ) | |||
210 | { | |||
211 | dpnt->extent = last_extent; | |||
212 | dir_size = (dpnt->size + (SECTOR_SIZE(2048) - 1)) >> 11; | |||
213 | ||||
214 | last_extent += dir_size; | |||
215 | ||||
216 | /* | |||
217 | * Leave room for the CE entries for this directory. Keep them | |||
218 | * close to the reference directory so that access will be | |||
219 | * quick. | |||
220 | */ | |||
221 | if(dpnt->ce_bytes) | |||
222 | { | |||
223 | last_extent += ROUND_UP(dpnt->ce_bytes)((dpnt->ce_bytes + ((2048) - 1)) & ~((2048) - 1)) >> 11; | |||
224 | } | |||
225 | } | |||
226 | ||||
227 | if(dpnt->subdir) | |||
228 | { | |||
229 | assign_directory_addresses(dpnt->subdir); | |||
230 | } | |||
231 | ||||
232 | dpnt = dpnt->next; | |||
233 | } | |||
234 | return 0; | |||
235 | } | |||
236 | ||||
237 | #ifdef APPLE_HYB1 | |||
238 | static void FDECL4(write_one_file, char *, filename,write_one_file(char * filename, unsigned int size, FILE * outfile , unsigned int off) | |||
239 | unsigned int, size, FILE *, outfile, unsigned int, off)write_one_file(char * filename, unsigned int size, FILE * outfile , unsigned int off) | |||
240 | #else | |||
241 | static void FDECL3(write_one_file, char *, filename,write_one_file(char * filename, unsigned int size, FILE * outfile ) | |||
242 | unsigned int, size, FILE *, outfile)write_one_file(char * filename, unsigned int size, FILE * outfile ) | |||
243 | #endif /* APPLE_HYB */ | |||
244 | { | |||
245 | char buffer[SECTOR_SIZE(2048) * NSECT16]; | |||
246 | FILE * infile; | |||
247 | int remain; | |||
248 | int use; | |||
249 | ||||
250 | ||||
251 | if ((infile = fopen(filename, "rb")) == NULL((void *)0)) | |||
252 | { | |||
253 | #if defined(sun) || defined(_AUX_SOURCE) | |||
254 | fprintf(stderr(&__sF[2]), "cannot open %s: (%d)\n", filename, errno(*__errno())); | |||
255 | #else | |||
256 | fprintf(stderr(&__sF[2]), "cannot open %s: %s\n", filename, strerror(errno(*__errno()))); | |||
257 | #endif | |||
258 | exit(1); | |||
259 | } | |||
260 | #ifdef APPLE_HYB1 | |||
261 | fseek(infile, off, SEEK_SET0); | |||
262 | #endif /* APPLE_HYB */ | |||
263 | remain = size; | |||
264 | ||||
265 | while(remain > 0) | |||
266 | { | |||
267 | use = (remain > SECTOR_SIZE(2048) * NSECT16 - 1 ? NSECT16*SECTOR_SIZE(2048) : remain); | |||
268 | use = ROUND_UP(use)((use + ((2048) - 1)) & ~((2048) - 1)); /* Round up to nearest sector boundary */ | |||
269 | memset(buffer, 0, use); | |||
270 | if (fread(buffer, 1, use, infile) == 0) | |||
271 | { | |||
272 | fprintf(stderr(&__sF[2]),"cannot read from %s\n",filename); | |||
273 | exit(1); | |||
274 | } | |||
275 | xfwrite(buffer, 1, use, outfile); | |||
276 | last_extent_written += use/SECTOR_SIZE(2048); | |||
277 | #if 0 | |||
278 | if((last_extent_written % 1000) < use/SECTOR_SIZE(2048)) | |||
279 | { | |||
280 | fprintf(stderr(&__sF[2]),"%d..", last_extent_written); | |||
281 | } | |||
282 | #else | |||
283 | if((last_extent_written % 5000) < use/SECTOR_SIZE(2048) | |||
284 | && verbose > 3) | |||
285 | { | |||
286 | time_t now; | |||
287 | time_t the_end; | |||
288 | double frac; | |||
289 | ||||
290 | time(&now); | |||
291 | frac = last_extent_written / (double)last_extent; | |||
292 | the_end = begun + (now - begun) / frac; | |||
293 | fprintf(stderr(&__sF[2]), "%6.2f%% done, estimate finish %s", | |||
294 | frac * 100., ctime(&the_end)); | |||
295 | } | |||
296 | #endif | |||
297 | remain -= use; | |||
298 | } | |||
299 | fclose(infile); | |||
300 | } /* write_one_file(... */ | |||
301 | ||||
302 | static void FDECL1(write_files, FILE *, outfile)write_files(FILE * outfile) | |||
303 | { | |||
304 | struct deferred_write * dwpnt, *dwnext; | |||
305 | dwpnt = dw_head; | |||
306 | while(dwpnt) | |||
307 | { | |||
308 | if(dwpnt->table) | |||
309 | { | |||
310 | xfwrite(dwpnt->table, 1, ROUND_UP(dwpnt->size)((dwpnt->size + ((2048) - 1)) & ~((2048) - 1)), outfile); | |||
311 | last_extent_written += ROUND_UP(dwpnt->size)((dwpnt->size + ((2048) - 1)) & ~((2048) - 1)) / SECTOR_SIZE(2048); | |||
312 | table_size += dwpnt->size; | |||
313 | /* fprintf(stderr,"Size %d ", dwpnt->size); */ | |||
314 | free(dwpnt->table); | |||
315 | } | |||
316 | else | |||
317 | { | |||
318 | ||||
319 | #ifdef VMS | |||
320 | vms_write_one_file(dwpnt->name, dwpnt->size, outfile); | |||
321 | #else | |||
322 | #ifdef APPLE_HYB1 | |||
323 | write_one_file(dwpnt->name, dwpnt->size, outfile, dwpnt->off); | |||
324 | #else | |||
325 | write_one_file(dwpnt->name, dwpnt->size, outfile); | |||
326 | #endif /* APPLE_HYB */ | |||
327 | #endif | |||
328 | free(dwpnt->name); | |||
329 | } | |||
330 | ||||
331 | #ifdef APPLE_HYB1 | |||
332 | if (apple_hyb) | |||
333 | { | |||
334 | /* we may have to pad out ISO files to work with | |||
335 | HFS clump sizes */ | |||
336 | char blk[SECTOR_SIZE(2048)]; | |||
337 | int i; | |||
338 | ||||
339 | for(i=0;i<dwpnt->pad;i++) | |||
340 | xfwrite(blk, 1, SECTOR_SIZE(2048), outfile); | |||
341 | ||||
342 | last_extent_written += dwpnt->pad; | |||
343 | } | |||
344 | #endif /* APPLE_HYB */ | |||
345 | ||||
346 | dwnext = dwpnt; | |||
347 | dwpnt = dwpnt->next; | |||
348 | free(dwnext); | |||
349 | } | |||
350 | } /* write_files(... */ | |||
351 | ||||
352 | #if 0 | |||
353 | static void dump_filelist() | |||
354 | { | |||
355 | struct deferred_write * dwpnt; | |||
356 | dwpnt = dw_head; | |||
357 | while(dwpnt) | |||
358 | { | |||
359 | fprintf(stderr(&__sF[2]), "File %s\n",dwpnt->name); | |||
360 | dwpnt = dwpnt->next; | |||
361 | } | |||
362 | fprintf(stderr(&__sF[2]),"\n"); | |||
363 | } | |||
364 | #endif | |||
365 | ||||
366 | static int FDECL2(compare_dirs, const void *, rr, const void *, ll)compare_dirs(const void * rr, const void * ll) | |||
367 | { | |||
368 | char * rpnt, *lpnt; | |||
369 | struct directory_entry ** r, **l; | |||
370 | ||||
371 | r = (struct directory_entry **) rr; | |||
372 | l = (struct directory_entry **) ll; | |||
373 | rpnt = (*r)->isorec.name; | |||
374 | lpnt = (*l)->isorec.name; | |||
375 | ||||
376 | #ifdef APPLE_HYB1 | |||
377 | /* resource fork MUST (not sure if this is true for HFS volumes) be | |||
378 | before the data fork - so force it here */ | |||
379 | if ((*r)->assoc && (*r)->assoc == (*l)) | |||
380 | return 1; | |||
381 | if ((*l)->assoc && (*l)->assoc == (*r)) | |||
382 | return -1; | |||
383 | #endif /* APPLE_HYB */ | |||
384 | ||||
385 | /* | |||
386 | * If the entries are the same, this is an error. | |||
387 | */ | |||
388 | if( strcmp(rpnt, lpnt) == 0 ) | |||
389 | { | |||
390 | sort_goof++; | |||
391 | } | |||
392 | ||||
393 | /* | |||
394 | * Put the '.' and '..' entries on the head of the sorted list. | |||
395 | * For normal ASCII, this always happens to be the case, but out of | |||
396 | * band characters cause this not to be the case sometimes. | |||
397 | * | |||
398 | * FIXME(eric) - these tests seem redundant, in taht the name is | |||
399 | * never assigned these values. It will instead be \000 or \001, | |||
400 | * and thus should always be sorted correctly. I need to figure | |||
401 | * out why I thought I needed this in the first place. | |||
402 | */ | |||
403 | #if 0 | |||
404 | if( strcmp(rpnt, ".") == 0 ) return -1; | |||
405 | if( strcmp(lpnt, ".") == 0 ) return 1; | |||
406 | ||||
407 | if( strcmp(rpnt, "..") == 0 ) return -1; | |||
408 | if( strcmp(lpnt, "..") == 0 ) return 1; | |||
409 | #else | |||
410 | /* | |||
411 | * The code above is wrong (as explained in Eric's comment), leading to incorrect | |||
412 | * sort order iff the -L option ("allow leading dots") is in effect and a directory | |||
413 | * contains entries that start with a dot. | |||
414 | * | |||
415 | * (TF, Tue Dec 29 13:49:24 CET 1998) | |||
416 | */ | |||
417 | if((*r)->isorec.name_len[0] == 1 && *rpnt == 0) return -1; /* '.' */ | |||
418 | if((*l)->isorec.name_len[0] == 1 && *lpnt == 0) return 1; | |||
419 | ||||
420 | if((*r)->isorec.name_len[0] == 1 && *rpnt == 1) return -1; /* '..' */ | |||
421 | if((*l)->isorec.name_len[0] == 1 && *lpnt == 1) return 1; | |||
422 | #endif | |||
423 | ||||
424 | while(*rpnt && *lpnt) | |||
425 | { | |||
426 | if(*rpnt == ';' && *lpnt != ';') return -1; | |||
427 | if(*rpnt != ';' && *lpnt == ';') return 1; | |||
428 | ||||
429 | if(*rpnt == ';' && *lpnt == ';') return 0; | |||
430 | ||||
431 | if(*rpnt == '.' && *lpnt != '.') return -1; | |||
432 | if(*rpnt != '.' && *lpnt == '.') return 1; | |||
433 | ||||
434 | if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1; | |||
435 | if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1; | |||
436 | rpnt++; lpnt++; | |||
437 | } | |||
438 | if(*rpnt) return 1; | |||
439 | if(*lpnt) return -1; | |||
440 | return 0; | |||
441 | } | |||
442 | ||||
443 | /* | |||
444 | * Function: sort_directory | |||
445 | * | |||
446 | * Purpose: Sort the directory in the appropriate ISO9660 | |||
447 | * order. | |||
448 | * | |||
449 | * Notes: Returns 0 if OK, returns > 0 if an error occurred. | |||
450 | */ | |||
451 | int FDECL1(sort_directory, struct directory_entry **, sort_dir)sort_directory(struct directory_entry ** sort_dir) | |||
452 | { | |||
453 | int dcount = 0; | |||
454 | int xcount = 0; | |||
455 | int j; | |||
456 | int i, len; | |||
457 | struct directory_entry * s_entry; | |||
458 | struct directory_entry ** sortlist; | |||
459 | ||||
460 | /* need to keep a count of how many entries are hidden */ | |||
461 | s_entry = *sort_dir; | |||
462 | while(s_entry) | |||
463 | { | |||
464 | if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY0x40) | |||
465 | xcount++; | |||
466 | dcount++; | |||
467 | s_entry = s_entry->next; | |||
468 | } | |||
469 | ||||
470 | if( dcount == 0 ) | |||
471 | { | |||
472 | return 0; | |||
473 | } | |||
474 | ||||
475 | /* | |||
476 | * OK, now we know how many there are. Build a vector for sorting. | |||
477 | */ | |||
478 | sortlist = (struct directory_entry **) | |||
479 | e_malloc(sizeof(struct directory_entry *) * dcount); | |||
480 | ||||
481 | j = dcount - 1; | |||
482 | dcount = 0; | |||
483 | s_entry = *sort_dir; | |||
484 | while(s_entry) | |||
485 | { | |||
486 | if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY0x40) | |||
487 | { | |||
488 | /* put any hidden entries at the end of the vector */ | |||
489 | sortlist[j--] = s_entry; | |||
490 | } | |||
491 | else | |||
492 | { | |||
493 | sortlist[dcount] = s_entry; | |||
494 | dcount++; | |||
495 | } | |||
496 | len = s_entry->isorec.name_len[0]; | |||
497 | s_entry->isorec.name[len] = 0; | |||
498 | s_entry = s_entry->next; | |||
499 | } | |||
500 | ||||
501 | /* | |||
502 | * Each directory is required to contain at least . and .. | |||
503 | */ | |||
504 | if( dcount < 2 ) | |||
505 | { | |||
506 | sort_goof = 1; | |||
507 | ||||
508 | } | |||
509 | else | |||
510 | { | |||
511 | /* only sort the non-hidden entries */ | |||
512 | sort_goof = 0; | |||
513 | #ifdef __STDC__1 | |||
514 | qsort(sortlist, dcount, sizeof(struct directory_entry *), | |||
515 | (int (*)(const void *, const void *))compare_dirs); | |||
516 | #else | |||
517 | qsort(sortlist, dcount, sizeof(struct directory_entry *), | |||
518 | compare_dirs); | |||
519 | #endif | |||
520 | ||||
521 | /* | |||
522 | * Now reassemble the linked list in the proper sorted order | |||
523 | * We still need the hidden entries, as they may be used in the | |||
524 | * Joliet tree. | |||
525 | */ | |||
526 | for(i=0; i<dcount+xcount-1; i++) | |||
527 | { | |||
528 | sortlist[i]->next = sortlist[i+1]; | |||
529 | } | |||
530 | ||||
531 | sortlist[dcount+xcount-1]->next = NULL((void *)0); | |||
532 | *sort_dir = sortlist[0]; | |||
533 | } | |||
534 | ||||
535 | free(sortlist); | |||
536 | return sort_goof; | |||
537 | } | |||
538 | ||||
539 | static int root_gen() | |||
540 | { | |||
541 | init_fstatbuf(); | |||
542 | ||||
543 | root_record.length[0] = 1 + sizeof(struct iso_directory_record) | |||
544 | - sizeof(root_record.name); | |||
545 | root_record.ext_attr_length[0] = 0; | |||
546 | set_733((char *) root_record.extent, root->extent); | |||
547 | set_733((char *) root_record.size, ROUND_UP(root->size)((root->size + ((2048) - 1)) & ~((2048) - 1))); | |||
548 | iso9660_date(root_record.date, root_statbuf.st_mtimest_mtim.tv_sec); | |||
549 | root_record.flags[0] = 2; | |||
550 | root_record.file_unit_size[0] = 0; | |||
551 | root_record.interleave[0] = 0; | |||
552 | set_723(root_record.volume_sequence_number, volume_sequence_number); | |||
553 | root_record.name_len[0] = 1; | |||
554 | return 0; | |||
555 | } | |||
556 | ||||
557 | static void FDECL1(assign_file_addresses, struct directory *, dpnt)assign_file_addresses(struct directory * dpnt) | |||
558 | { | |||
559 | struct directory * finddir; | |||
560 | struct directory_entry * s_entry; | |||
561 | struct file_hash *s_hash; | |||
562 | struct deferred_write * dwpnt; | |||
563 | char whole_path[1024]; | |||
564 | ||||
565 | while (dpnt) | |||
566 | { | |||
567 | s_entry = dpnt->contents; | |||
568 | for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) | |||
569 | { | |||
570 | /* | |||
571 | * If we already have an extent for this entry, | |||
572 | * then don't assign a new one. It must have come | |||
573 | * from a previous session on the disc. Note that | |||
574 | * we don't end up scheduling the thing for writing | |||
575 | * either. | |||
576 | */ | |||
577 | if( isonum_733((unsigned char *) s_entry->isorec.extent) != 0 ) | |||
578 | { | |||
579 | continue; | |||
580 | } | |||
581 | ||||
582 | /* | |||
583 | * This saves some space if there are symlinks present | |||
584 | */ | |||
585 | s_hash = find_hash(s_entry->dev, s_entry->inode); | |||
586 | if(s_hash) | |||
587 | { | |||
588 | if(verbose > 2) | |||
589 | { | |||
590 | fprintf(stderr(&__sF[2]), "Cache hit for %s%s%s\n",s_entry->filedir->de_name, | |||
591 | SPATH_SEPARATOR"/", s_entry->name); | |||
592 | } | |||
593 | set_733((char *) s_entry->isorec.extent, s_hash->starting_block); | |||
594 | set_733((char *) s_entry->isorec.size, s_hash->size); | |||
595 | continue; | |||
596 | } | |||
597 | ||||
598 | /* | |||
599 | * If this is for a directory that is not a . or a .. entry, | |||
600 | * then look up the information for the entry. We have already | |||
601 | * assigned extents for directories, so we just need to | |||
602 | * fill in the blanks here. | |||
603 | */ | |||
604 | if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && | |||
605 | s_entry->isorec.flags[0] == 2) | |||
606 | { | |||
607 | finddir = dpnt->subdir; | |||
608 | while(1==1) | |||
609 | { | |||
610 | if(finddir->self == s_entry) break; | |||
611 | finddir = finddir->next; | |||
612 | if(!finddir) | |||
613 | { | |||
614 | fprintf(stderr(&__sF[2]),"Fatal goof\n"); exit(1); | |||
615 | } | |||
616 | } | |||
617 | set_733((char *) s_entry->isorec.extent, finddir->extent); | |||
618 | s_entry->starting_block = finddir->extent; | |||
619 | s_entry->size = ROUND_UP(finddir->size)((finddir->size + ((2048) - 1)) & ~((2048) - 1)); | |||
620 | total_dir_size += s_entry->size; | |||
621 | add_hash(s_entry); | |||
622 | set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size)((finddir->size + ((2048) - 1)) & ~((2048) - 1))); | |||
623 | continue; | |||
624 | } | |||
625 | ||||
626 | ||||
627 | /* | |||
628 | * If this is . or .., then look up the relevant info from the | |||
629 | * tables. | |||
630 | */ | |||
631 | if(strcmp(s_entry->name,".") == 0) | |||
632 | { | |||
633 | set_733((char *) s_entry->isorec.extent, dpnt->extent); | |||
634 | ||||
635 | /* | |||
636 | * Set these so that the hash table has the | |||
637 | * correct information | |||
638 | */ | |||
639 | s_entry->starting_block = dpnt->extent; | |||
640 | s_entry->size = ROUND_UP(dpnt->size)((dpnt->size + ((2048) - 1)) & ~((2048) - 1)); | |||
641 | ||||
642 | add_hash(s_entry); | |||
643 | s_entry->starting_block = dpnt->extent; | |||
644 | set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size)((dpnt->size + ((2048) - 1)) & ~((2048) - 1))); | |||
645 | continue; | |||
646 | } | |||
647 | ||||
648 | if(strcmp(s_entry->name,"..") == 0) | |||
649 | { | |||
650 | if(dpnt == root) | |||
651 | { | |||
652 | total_dir_size += root->size; | |||
653 | } | |||
654 | set_733((char *) s_entry->isorec.extent, dpnt->parent->extent); | |||
655 | ||||
656 | /* | |||
657 | * Set these so that the hash table has the | |||
658 | * correct information | |||
659 | */ | |||
660 | s_entry->starting_block = dpnt->parent->extent; | |||
661 | s_entry->size = ROUND_UP(dpnt->parent->size)((dpnt->parent->size + ((2048) - 1)) & ~((2048) - 1 )); | |||
662 | ||||
663 | add_hash(s_entry); | |||
664 | s_entry->starting_block = dpnt->parent->extent; | |||
665 | set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size)((dpnt->parent->size + ((2048) - 1)) & ~((2048) - 1 ))); | |||
666 | continue; | |||
667 | } | |||
668 | ||||
669 | /* | |||
670 | * Some ordinary non-directory file. Just schedule the | |||
671 | * file to be written. This is all quite | |||
672 | * straightforward, just make a list and assign extents | |||
673 | * as we go. Once we get through writing all of the | |||
674 | * directories, we should be ready write out these | |||
675 | * files | |||
676 | */ | |||
677 | if(s_entry->size) | |||
678 | { | |||
679 | dwpnt = (struct deferred_write *) | |||
680 | e_malloc(sizeof(struct deferred_write)); | |||
681 | #ifdef APPLE_HYB1 | |||
682 | /* save this directory entry for later use */ | |||
683 | dwpnt->s_entry = s_entry; | |||
684 | /* set the initial padding to zero */ | |||
685 | dwpnt->pad = 0; | |||
686 | /* maybe an offset to start of the real file/fork */ | |||
687 | dwpnt->off = s_entry->hfs_off; | |||
688 | #endif /* APPLE_HYB */ | |||
689 | if(dw_tail) | |||
690 | { | |||
691 | dw_tail->next = dwpnt; | |||
692 | dw_tail = dwpnt; | |||
693 | } | |||
694 | else | |||
695 | { | |||
696 | dw_head = dwpnt; | |||
697 | dw_tail = dwpnt; | |||
698 | } | |||
699 | if(s_entry->inode == TABLE_INODE(sizeof(ino_t) >= 8 ? 0x7ffffffffffffffeLL : 0x7ffffffe)) | |||
700 | { | |||
701 | dwpnt->table = s_entry->table; | |||
702 | dwpnt->name = NULL((void *)0); | |||
703 | #ifdef APPLE_HYB1 | |||
704 | snprintf(whole_path, sizeof whole_path, "%s%s%s", | |||
705 | s_entry->filedir->whole_name, SPATH_SEPARATOR"/", | |||
706 | trans_tbl); | |||
707 | #else | |||
708 | snprintf(whole_path, sizeof whole_path, | |||
709 | "%s%sTRANS.TBL", | |||
710 | s_entry->filedir->whole_name, SPATH_SEPARATOR"/"); | |||
711 | #endif /* APPLE_HYB */ | |||
712 | } | |||
713 | else | |||
714 | { | |||
715 | dwpnt->table = NULL((void *)0); | |||
716 | strcpy(whole_path, s_entry->whole_name); | |||
717 | dwpnt->name = strdup(whole_path); | |||
718 | } | |||
719 | dwpnt->next = NULL((void *)0); | |||
720 | dwpnt->size = s_entry->size; | |||
721 | dwpnt->extent = last_extent; | |||
722 | set_733((char *) s_entry->isorec.extent, last_extent); | |||
723 | s_entry->starting_block = last_extent; | |||
724 | add_hash(s_entry); | |||
725 | last_extent += ROUND_UP(s_entry->size)((s_entry->size + ((2048) - 1)) & ~((2048) - 1)) >> 11; | |||
726 | if(verbose > 2) | |||
727 | { | |||
728 | fprintf(stderr(&__sF[2]),"%d %d %s\n", s_entry->starting_block, | |||
729 | last_extent-1, whole_path); | |||
730 | } | |||
731 | #ifdef DBG_ISO | |||
732 | if((ROUND_UP(s_entry->size)((s_entry->size + ((2048) - 1)) & ~((2048) - 1)) >> 11) > 500) | |||
733 | { | |||
734 | fprintf(stderr(&__sF[2]),"Warning: large file %s\n", whole_path); | |||
735 | fprintf(stderr(&__sF[2]),"Starting block is %d\n", s_entry->starting_block); | |||
736 | fprintf(stderr(&__sF[2]),"Reported file size is %d extents\n", s_entry->size); | |||
737 | ||||
738 | } | |||
739 | #endif | |||
740 | #ifdef NOT_NEEDED /* Never use this code if you like to create a DVD */ | |||
741 | ||||
742 | if(last_extent > (800000000 >> 11)) | |||
743 | { | |||
744 | /* | |||
745 | * More than 800Mb? Punt | |||
746 | */ | |||
747 | fprintf(stderr(&__sF[2]),"Extent overflow processing file %s\n", whole_path); | |||
748 | fprintf(stderr(&__sF[2]),"Starting block is %d\n", s_entry->starting_block); | |||
749 | fprintf(stderr(&__sF[2]),"Reported file size is %d extents\n", s_entry->size); | |||
750 | exit(1); | |||
751 | } | |||
752 | #endif | |||
753 | continue; | |||
754 | } | |||
755 | ||||
756 | /* | |||
757 | * This is for zero-length files. If we leave the extent 0, | |||
758 | * then we get screwed, because many readers simply drop files | |||
759 | * that have an extent of zero. Thus we leave the size 0, | |||
760 | * and just assign the extent number. | |||
761 | */ | |||
762 | set_733((char *) s_entry->isorec.extent, last_extent); | |||
763 | } | |||
764 | if(dpnt->subdir) | |||
765 | { | |||
766 | assign_file_addresses(dpnt->subdir); | |||
767 | } | |||
768 | dpnt = dpnt->next; | |||
769 | } | |||
770 | } /* assign_file_addresses(... */ | |||
771 | ||||
772 | static void FDECL1(free_one_directory, struct directory *, dpnt)free_one_directory(struct directory * dpnt) | |||
773 | { | |||
774 | struct directory_entry * s_entry; | |||
775 | struct directory_entry * s_entry_d; | |||
776 | ||||
777 | s_entry = dpnt->contents; | |||
778 | while(s_entry) | |||
779 | { | |||
780 | s_entry_d = s_entry; | |||
781 | s_entry = s_entry->next; | |||
782 | ||||
783 | if( s_entry_d->name != NULL((void *)0) ) | |||
784 | { | |||
785 | free (s_entry_d->name); | |||
786 | } | |||
787 | if( s_entry_d->whole_name != NULL((void *)0) ) | |||
788 | { | |||
789 | free (s_entry_d->whole_name); | |||
790 | } | |||
791 | #ifdef APPLE_HYB1 | |||
792 | if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc) | |||
793 | free(s_entry_d->hfs_ent); | |||
794 | #endif /* APPLE_HYB */ | |||
795 | ||||
796 | free (s_entry_d); | |||
797 | } | |||
798 | dpnt->contents = NULL((void *)0); | |||
799 | } /* free_one_directory(... */ | |||
800 | ||||
801 | static void FDECL1(free_directories, struct directory *, dpnt)free_directories(struct directory * dpnt) | |||
802 | { | |||
803 | while (dpnt) | |||
804 | { | |||
805 | free_one_directory(dpnt); | |||
806 | if(dpnt->subdir) free_directories(dpnt->subdir); | |||
807 | dpnt = dpnt->next; | |||
808 | } | |||
809 | } | |||
810 | ||||
811 | void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)generate_one_directory(struct directory * dpnt, FILE * outfile ) | |||
812 | { | |||
813 | unsigned int ce_address = 0; | |||
814 | char * ce_buffer; | |||
815 | unsigned int ce_index = 0; | |||
816 | unsigned int ce_size; | |||
817 | unsigned int dir_index; | |||
818 | char * directory_buffer; | |||
819 | int new_reclen; | |||
820 | struct directory_entry * s_entry; | |||
821 | struct directory_entry * s_entry_d; | |||
822 | unsigned int total_size; | |||
823 | ||||
824 | total_size = (dpnt->size + (SECTOR_SIZE(2048) - 1)) & ~(SECTOR_SIZE(2048) - 1); | |||
825 | directory_buffer = (char *) e_malloc(total_size); | |||
826 | memset(directory_buffer, 0, total_size); | |||
827 | dir_index = 0; | |||
828 | ||||
829 | ce_size = (dpnt->ce_bytes + (SECTOR_SIZE(2048) - 1)) & ~(SECTOR_SIZE(2048) - 1); | |||
830 | ce_buffer = NULL((void *)0); | |||
| ||||
831 | ||||
832 | if(ce_size) | |||
833 | { | |||
834 | ce_buffer = (char *) e_malloc(ce_size); | |||
835 | memset(ce_buffer, 0, ce_size); | |||
836 | ||||
837 | ce_index = 0; | |||
838 | ||||
839 | /* | |||
840 | * Absolute byte address of CE entries for this directory | |||
841 | */ | |||
842 | ce_address = last_extent_written + (total_size >> 11); | |||
843 | ce_address = ce_address << 11; | |||
844 | } | |||
845 | ||||
846 | s_entry = dpnt->contents; | |||
847 | while(s_entry) | |||
848 | { | |||
849 | /* skip if it's hidden */ | |||
850 | if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY0x40) { | |||
851 | s_entry = s_entry->next; | |||
852 | continue; | |||
853 | } | |||
854 | ||||
855 | /* | |||
856 | * We do not allow directory entries to cross sector boundaries. | |||
857 | * Simply pad, and then start the next entry at the next sector | |||
858 | */ | |||
859 | new_reclen = s_entry->isorec.length[0]; | |||
860 | if( (dir_index & (SECTOR_SIZE(2048) - 1)) + new_reclen >= SECTOR_SIZE(2048) ) | |||
861 | { | |||
862 | dir_index = (dir_index + (SECTOR_SIZE(2048) - 1)) & | |||
863 | ~(SECTOR_SIZE(2048) - 1); | |||
864 | } | |||
865 | ||||
866 | memcpy(directory_buffer + dir_index, &s_entry->isorec, | |||
867 | sizeof(struct iso_directory_record) - | |||
868 | sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]); | |||
869 | dir_index += sizeof(struct iso_directory_record) - | |||
870 | sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0]; | |||
871 | ||||
872 | /* | |||
873 | * Add the Rock Ridge attributes, if present | |||
874 | */ | |||
875 | if(s_entry->rr_attr_size) | |||
876 | { | |||
877 | if(dir_index & 1) | |||
878 | { | |||
879 | directory_buffer[dir_index++] = 0; | |||
880 | } | |||
881 | ||||
882 | /* | |||
883 | * If the RR attributes were too long, then write the | |||
884 | * CE records, as required. | |||
885 | */ | |||
886 | if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) | |||
887 | { | |||
888 | unsigned char * pnt; | |||
889 | int len, nbytes; | |||
890 | ||||
891 | /* | |||
892 | * Go through the entire record and fix up the CE entries | |||
893 | * so that the extent and offset are correct | |||
894 | */ | |||
895 | ||||
896 | pnt = s_entry->rr_attributes; | |||
897 | len = s_entry->total_rr_attr_size; | |||
898 | while(len > 3) | |||
899 | { | |||
900 | #ifdef DEBUG | |||
901 | if (!ce_size) | |||
902 | { | |||
903 | fprintf(stderr(&__sF[2]),"Warning: ce_index(%d) && ce_address(%d) not initialized\n", | |||
904 | ce_index, ce_address); | |||
905 | } | |||
906 | #endif | |||
907 | ||||
908 | if(pnt[0] == 'C' && pnt[1] == 'E') | |||
909 | { | |||
910 | nbytes = get_733( (char *) pnt+20); | |||
911 | ||||
912 | if((ce_index & (SECTOR_SIZE(2048) - 1)) + nbytes >= | |||
913 | SECTOR_SIZE(2048)) | |||
914 | { | |||
915 | ce_index = ROUND_UP(ce_index)((ce_index + ((2048) - 1)) & ~((2048) - 1)); | |||
916 | } | |||
917 | ||||
918 | set_733( (char *) pnt+4, | |||
919 | (ce_address + ce_index) >> 11); | |||
920 | set_733( (char *) pnt+12, | |||
921 | (ce_address + ce_index) & (SECTOR_SIZE(2048) - 1)); | |||
922 | ||||
923 | ||||
924 | /* | |||
925 | * Now store the block in the ce buffer | |||
926 | */ | |||
927 | memcpy(ce_buffer + ce_index, | |||
| ||||
928 | pnt + pnt[2], nbytes); | |||
929 | ce_index += nbytes; | |||
930 | if(ce_index & 1) | |||
931 | { | |||
932 | ce_index++; | |||
933 | } | |||
934 | } | |||
935 | len -= pnt[2]; | |||
936 | pnt += pnt[2]; | |||
937 | } | |||
938 | ||||
939 | } | |||
940 | ||||
941 | rockridge_size += s_entry->total_rr_attr_size; | |||
942 | memcpy(directory_buffer + dir_index, s_entry->rr_attributes, | |||
943 | s_entry->rr_attr_size); | |||
944 | dir_index += s_entry->rr_attr_size; | |||
945 | } | |||
946 | if(dir_index & 1) | |||
947 | { | |||
948 | directory_buffer[dir_index++] = 0; | |||
949 | } | |||
950 | ||||
951 | s_entry_d = s_entry; | |||
952 | s_entry = s_entry->next; | |||
953 | ||||
954 | /* | |||
955 | * Joliet doesn't use the Rock Ridge attributes, so we free it here. | |||
956 | */ | |||
957 | if (s_entry_d->rr_attributes) | |||
958 | { | |||
959 | free(s_entry_d->rr_attributes); | |||
960 | s_entry_d->rr_attributes = NULL((void *)0); | |||
961 | } | |||
962 | } | |||
963 | ||||
964 | if(dpnt->size != dir_index) | |||
965 | { | |||
966 | fprintf(stderr(&__sF[2]),"Unexpected directory length %d %d %s\n",dpnt->size, | |||
967 | dir_index, dpnt->de_name); | |||
968 | } | |||
969 | ||||
970 | xfwrite(directory_buffer, 1, total_size, outfile); | |||
971 | last_extent_written += total_size >> 11; | |||
972 | free(directory_buffer); | |||
973 | ||||
974 | if(ce_size) | |||
975 | { | |||
976 | if(ce_index != dpnt->ce_bytes) | |||
977 | { | |||
978 | fprintf(stderr(&__sF[2]),"Continuation entry record length mismatch (%d %d).\n", | |||
979 | ce_index, dpnt->ce_bytes); | |||
980 | } | |||
981 | xfwrite(ce_buffer, 1, ce_size, outfile); | |||
982 | last_extent_written += ce_size >> 11; | |||
983 | free(ce_buffer); | |||
984 | } | |||
985 | ||||
986 | } /* generate_one_directory(... */ | |||
987 | ||||
988 | static | |||
989 | void FDECL1(build_pathlist, struct directory *, node)build_pathlist(struct directory * node) | |||
990 | { | |||
991 | struct directory * dpnt; | |||
992 | ||||
993 | dpnt = node; | |||
994 | ||||
995 | while (dpnt) | |||
996 | { | |||
997 | /* skip if it's hidden */ | |||
998 | if( (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY0x40) == 0 ) | |||
999 | pathlist[dpnt->path_index] = dpnt; | |||
1000 | ||||
1001 | if(dpnt->subdir) build_pathlist(dpnt->subdir); | |||
1002 | dpnt = dpnt->next; | |||
1003 | } | |||
1004 | } /* build_pathlist(... */ | |||
1005 | ||||
1006 | static int FDECL2(compare_paths, void const *, r, void const *, l)compare_paths(void const * r, void const * l) | |||
1007 | { | |||
1008 | struct directory const *ll = *(struct directory * const *)l; | |||
1009 | struct directory const *rr = *(struct directory * const *)r; | |||
1010 | ||||
1011 | if (rr->parent->path_index < ll->parent->path_index) | |||
1012 | { | |||
1013 | return -1; | |||
1014 | } | |||
1015 | ||||
1016 | if (rr->parent->path_index > ll->parent->path_index) | |||
1017 | { | |||
1018 | return 1; | |||
1019 | } | |||
1020 | ||||
1021 | return strcmp(rr->self->isorec.name, ll->self->isorec.name); | |||
1022 | ||||
1023 | } /* compare_paths(... */ | |||
1024 | ||||
1025 | static int generate_path_tables() | |||
1026 | { | |||
1027 | struct directory_entry * de; | |||
1028 | struct directory * dpnt; | |||
1029 | int fix; | |||
1030 | int i; | |||
1031 | int j; | |||
1032 | int namelen; | |||
1033 | char * npnt; | |||
1034 | char * npnt1; | |||
1035 | int tablesize; | |||
1036 | ||||
1037 | /* | |||
1038 | * First allocate memory for the tables and initialize the memory | |||
1039 | */ | |||
1040 | tablesize = path_blocks << 11; | |||
1041 | path_table_m = (char *) e_malloc(tablesize); | |||
1042 | path_table_l = (char *) e_malloc(tablesize); | |||
1043 | memset(path_table_l, 0, tablesize); | |||
1044 | memset(path_table_m, 0, tablesize); | |||
1045 | ||||
1046 | /* | |||
1047 | * Now start filling in the path tables. Start with root directory | |||
1048 | */ | |||
1049 | if( next_path_index > 0xffff ) | |||
1050 | { | |||
1051 | fprintf(stderr(&__sF[2]), "Unable to generate sane path tables - too many directories (%d)\n", | |||
1052 | next_path_index); | |||
1053 | exit(1); | |||
1054 | } | |||
1055 | ||||
1056 | path_table_index = 0; | |||
1057 | pathlist = (struct directory **) e_malloc(sizeof(struct directory *) | |||
1058 | * next_path_index); | |||
1059 | memset(pathlist, 0, sizeof(struct directory *) * next_path_index); | |||
1060 | build_pathlist(root); | |||
1061 | ||||
1062 | do | |||
1063 | { | |||
1064 | fix = 0; | |||
1065 | #ifdef __STDC__1 | |||
1066 | qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), | |||
1067 | (int (*)(const void *, const void *))compare_paths); | |||
1068 | #else | |||
1069 | qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), | |||
1070 | compare_paths); | |||
1071 | #endif | |||
1072 | ||||
1073 | for(j=1; j<next_path_index; j++) | |||
1074 | { | |||
1075 | if(pathlist[j]->path_index != j) | |||
1076 | { | |||
1077 | pathlist[j]->path_index = j; | |||
1078 | fix++; | |||
1079 | } | |||
1080 | } | |||
1081 | } while(fix); | |||
1082 | ||||
1083 | for(j=1; j<next_path_index; j++) | |||
1084 | { | |||
1085 | dpnt = pathlist[j]; | |||
1086 | if(!dpnt) | |||
1087 | { | |||
1088 | fprintf(stderr(&__sF[2]),"Entry %d not in path tables\n", j); | |||
1089 | exit(1); | |||
1090 | } | |||
1091 | npnt = dpnt->de_name; | |||
1092 | ||||
1093 | /* | |||
1094 | * So the root comes out OK | |||
1095 | */ | |||
1096 | if( (*npnt == 0) || (dpnt == root) ) | |||
1097 | { | |||
1098 | npnt = "."; | |||
1099 | } | |||
1100 | npnt1 = strrchr(npnt, PATH_SEPARATOR'/'); | |||
1101 | if(npnt1) | |||
1102 | { | |||
1103 | npnt = npnt1 + 1; | |||
1104 | } | |||
1105 | ||||
1106 | de = dpnt->self; | |||
1107 | if(!de) | |||
1108 | { | |||
1109 | fprintf(stderr(&__sF[2]),"Fatal goof\n"); | |||
1110 | exit(1); | |||
1111 | } | |||
1112 | ||||
1113 | ||||
1114 | namelen = de->isorec.name_len[0]; | |||
1115 | ||||
1116 | path_table_l[path_table_index] = namelen; | |||
1117 | path_table_m[path_table_index] = namelen; | |||
1118 | path_table_index += 2; | |||
1119 | ||||
1120 | set_731(path_table_l + path_table_index, dpnt->extent); | |||
1121 | set_732(path_table_m + path_table_index, dpnt->extent); | |||
1122 | path_table_index += 4; | |||
1123 | ||||
1124 | set_721(path_table_l + path_table_index, | |||
1125 | dpnt->parent->path_index); | |||
1126 | set_722(path_table_m + path_table_index, | |||
1127 | dpnt->parent->path_index); | |||
1128 | path_table_index += 2; | |||
1129 | ||||
1130 | for(i =0; i<namelen; i++) | |||
1131 | { | |||
1132 | path_table_l[path_table_index] = de->isorec.name[i]; | |||
1133 | path_table_m[path_table_index] = de->isorec.name[i]; | |||
1134 | path_table_index++; | |||
1135 | } | |||
1136 | if(path_table_index & 1) | |||
1137 | { | |||
1138 | path_table_index++; /* For odd lengths we pad */ | |||
1139 | } | |||
1140 | } | |||
1141 | ||||
1142 | free(pathlist); | |||
1143 | if(path_table_index != path_table_size) | |||
1144 | { | |||
1145 | fprintf(stderr(&__sF[2]),"Path table lengths do not match %d %d\n", | |||
1146 | path_table_index, | |||
1147 | path_table_size); | |||
1148 | } | |||
1149 | return 0; | |||
1150 | } /* generate_path_tables(... */ | |||
1151 | ||||
1152 | void | |||
1153 | FDECL3(memcpy_max, char *, to, char *, from, int, max)memcpy_max(char * to, char * from, int max) | |||
1154 | { | |||
1155 | int n = strlen(from); | |||
1156 | if (n > max) | |||
1157 | { | |||
1158 | n = max; | |||
1159 | } | |||
1160 | memcpy(to, from, n); | |||
1161 | ||||
1162 | } /* memcpy_max(... */ | |||
1163 | ||||
1164 | void FDECL1(outputlist_insert, struct output_fragment *, frag)outputlist_insert(struct output_fragment * frag) | |||
1165 | { | |||
1166 | if( out_tail == NULL((void *)0) ) | |||
1167 | { | |||
1168 | out_list = out_tail = frag; | |||
1169 | } | |||
1170 | else | |||
1171 | { | |||
1172 | out_tail->of_next = frag; | |||
1173 | out_tail = frag; | |||
1174 | } | |||
1175 | } | |||
1176 | ||||
1177 | static int FDECL1(file_write, FILE *, outfile)file_write(FILE * outfile) | |||
1178 | { | |||
1179 | int should_write; | |||
1180 | #ifdef APPLE_HYB1 | |||
1181 | char buffer[2048]; | |||
1182 | ||||
1183 | memset(buffer, 0, sizeof(buffer)); | |||
1184 | ||||
1185 | if (apple_hyb) { | |||
1186 | ||||
1187 | int i; | |||
1188 | ||||
1189 | /* write out padding to round up to HFS allocation block */ | |||
1190 | for(i=0;i<hfs_pad;i++) | |||
1191 | xfwrite(buffer, 1, sizeof(buffer), outfile); | |||
1192 | ||||
1193 | last_extent_written += hfs_pad; | |||
1194 | } | |||
1195 | #endif /* APPLE_HYB */ | |||
1196 | ||||
1197 | /* | |||
1198 | * OK, all done with that crap. Now write out the directories. | |||
1199 | * This is where the fur starts to fly, because we need to keep track of | |||
1200 | * each file as we find it and keep track of where we put it. | |||
1201 | */ | |||
1202 | ||||
1203 | should_write = last_extent - session_start; | |||
1204 | ||||
1205 | if( print_size > 0 ) | |||
1206 | { | |||
1207 | #ifdef APPLE_HYB1 | |||
1208 | if (apple_hyb) | |||
1209 | fprintf(stderr(&__sF[2]),"Total extents scheduled to be written (inc HFS) = %d\n", | |||
1210 | last_extent - session_start); | |||
1211 | else | |||
1212 | #endif | |||
1213 | fprintf(stderr(&__sF[2]),"Total extents scheduled to be written = %d\n", | |||
1214 | last_extent - session_start); | |||
1215 | exit(0); | |||
1216 | } | |||
1217 | if( verbose > 2 ) | |||
1218 | { | |||
1219 | #ifdef DBG_ISO | |||
1220 | fprintf(stderr(&__sF[2]),"Total directory extents being written = %d\n", last_extent); | |||
1221 | #endif | |||
1222 | ||||
1223 | #ifdef APPLE_HYB1 | |||
1224 | if (apple_hyb) | |||
1225 | fprintf(stderr(&__sF[2]),"Total extents scheduled to be written (inc HFS) = %d\n", | |||
1226 | last_extent - session_start); | |||
1227 | else | |||
1228 | #endif | |||
1229 | fprintf(stderr(&__sF[2]),"Total extents scheduled to be written = %d\n", | |||
1230 | last_extent - session_start); | |||
1231 | } | |||
1232 | ||||
1233 | /* | |||
1234 | * Now write all of the files that we need. | |||
1235 | */ | |||
1236 | write_files(outfile); | |||
1237 | ||||
1238 | #ifdef APPLE_HYB1 | |||
1239 | /* write out extents/catalog/dt file */ | |||
1240 | if (apple_hyb) { | |||
1241 | ||||
1242 | xfwrite(hce->hfs_ce, hce->hfs_tot_size, HFS_BLOCKSZ512, outfile); | |||
1243 | ||||
1244 | /* round up to a whole CD block */ | |||
1245 | if (H_ROUND_UP(hce->hfs_tot_size)((((hce->hfs_tot_size)*512) + ((2048) - 1)) & ~((2048) - 1)) - hce->hfs_tot_size*HFS_BLOCKSZ512) | |||
1246 | xfwrite(buffer, 1, H_ROUND_UP(hce->hfs_tot_size)((((hce->hfs_tot_size)*512) + ((2048) - 1)) & ~((2048) - 1)) - hce->hfs_tot_size*HFS_BLOCKSZ512, outfile); | |||
1247 | ||||
1248 | last_extent_written += ROUND_UP(hce->hfs_tot_size*HFS_BLOCKSZ)((hce->hfs_tot_size*512 + ((2048) - 1)) & ~((2048) - 1 ))/SECTOR_SIZE(2048); | |||
1249 | ||||
1250 | /* write out HFS boot block */ | |||
1251 | if (mac_boot.name) | |||
1252 | write_one_file(mac_boot.name, mac_boot.size, outfile, mac_boot.off); | |||
1253 | } | |||
1254 | #endif /* APPLE_HYB */ | |||
1255 | ||||
1256 | /* | |||
1257 | * The rest is just fluff. | |||
1258 | */ | |||
1259 | if( verbose == 0 ) | |||
1260 | { | |||
1261 | return 0; | |||
1262 | } | |||
1263 | ||||
1264 | #ifdef APPLE_HYB1 | |||
1265 | if (apple_hyb) { | |||
1266 | fprintf(stderr(&__sF[2]), "Total extents actually written (inc HFS) = %d\n", | |||
1267 | last_extent_written - session_start); | |||
1268 | fprintf(stderr(&__sF[2]), "(Size of ISO volume = %d, HFS extra = %d)\n", | |||
1269 | last_extent_written - session_start - hfs_extra, hfs_extra); | |||
1270 | } | |||
1271 | else | |||
1272 | #else | |||
1273 | fprintf(stderr(&__sF[2]),"Total extents actually written = %d\n", | |||
1274 | last_extent_written - session_start); | |||
1275 | #endif /* APPLE_HYB */ | |||
1276 | /* | |||
1277 | * Hard links throw us off here | |||
1278 | */ | |||
1279 | if(should_write != last_extent - session_start) | |||
1280 | { | |||
1281 | fprintf(stderr(&__sF[2]),"Number of extents written not what was predicted. Please fix.\n"); | |||
1282 | fprintf(stderr(&__sF[2]),"Predicted = %d, written = %d\n", should_write, last_extent); | |||
1283 | } | |||
1284 | ||||
1285 | fprintf(stderr(&__sF[2]),"Total translation table size: %d\n", table_size); | |||
1286 | fprintf(stderr(&__sF[2]),"Total rockridge attributes bytes: %d\n", rockridge_size); | |||
1287 | fprintf(stderr(&__sF[2]),"Total directory bytes: %d\n", total_dir_size); | |||
1288 | fprintf(stderr(&__sF[2]),"Path table size(bytes): %d\n", path_table_size); | |||
1289 | ||||
1290 | #ifdef DEBUG | |||
1291 | fprintf(stderr(&__sF[2]), "next extent, last_extent, last_extent_written %d %d %d\n", | |||
1292 | next_extent, last_extent, last_extent_written); | |||
1293 | #endif | |||
1294 | ||||
1295 | return 0; | |||
1296 | ||||
1297 | } /* iso_write(... */ | |||
1298 | ||||
1299 | /* | |||
1300 | * Function to write the PVD for the disc. | |||
1301 | */ | |||
1302 | static int FDECL1(pvd_write, FILE *, outfile)pvd_write(FILE * outfile) | |||
1303 | { | |||
1304 | char iso_time[17]; | |||
1305 | int should_write; | |||
1306 | struct tm local; | |||
1307 | struct tm gmt; | |||
1308 | ||||
1309 | ||||
1310 | time(&begun); | |||
1311 | ||||
1312 | local = *localtime(&begun); | |||
1313 | gmt = *gmtime(&begun); | |||
1314 | ||||
1315 | /* | |||
1316 | * This will break in the year 2000, I supose, but there is no good way | |||
1317 | * to get the top two digits of the year. | |||
1318 | */ | |||
1319 | snprintf(iso_time, sizeof iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", | |||
1320 | 1900 + local.tm_year, | |||
1321 | local.tm_mon+1, local.tm_mday, | |||
1322 | local.tm_hour, local.tm_min, local.tm_sec); | |||
1323 | ||||
1324 | local.tm_min -= gmt.tm_min; | |||
1325 | local.tm_hour -= gmt.tm_hour; | |||
1326 | local.tm_yday -= gmt.tm_yday; | |||
1327 | iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15; | |||
1328 | ||||
1329 | /* | |||
1330 | * Next we write out the primary descriptor for the disc | |||
1331 | */ | |||
1332 | memset(&vol_desc, 0, sizeof(vol_desc)); | |||
1333 | vol_desc.type[0] = ISO_VD_PRIMARY1; | |||
1334 | memcpy(vol_desc.id, ISO_STANDARD_ID"CD001", sizeof(ISO_STANDARD_ID"CD001") - 1); | |||
1335 | vol_desc.version[0] = 1; | |||
1336 | ||||
1337 | memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id)); | |||
1338 | memcpy_max(vol_desc.system_id, system_id, strlen(system_id)); | |||
1339 | ||||
1340 | memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id)); | |||
1341 | memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id)); | |||
1342 | ||||
1343 | should_write = last_extent - session_start; | |||
1344 | set_733((char *) vol_desc.volume_space_size, should_write); | |||
1345 | set_723(vol_desc.volume_set_size, volume_set_size); | |||
1346 | set_723(vol_desc.volume_sequence_number, volume_sequence_number); | |||
1347 | set_723(vol_desc.logical_block_size, 2048); | |||
1348 | ||||
1349 | /* | |||
1350 | * The path tables are used by DOS based machines to cache directory | |||
1351 | * locations | |||
1352 | */ | |||
1353 | ||||
1354 | set_733((char *) vol_desc.path_table_size, path_table_size); | |||
1355 | set_731(vol_desc.type_l_path_table, path_table[0]); | |||
1356 | set_731(vol_desc.opt_type_l_path_table, path_table[1]); | |||
1357 | set_732(vol_desc.type_m_path_table, path_table[2]); | |||
1358 | set_732(vol_desc.opt_type_m_path_table, path_table[3]); | |||
1359 | ||||
1360 | /* | |||
1361 | * Now we copy the actual root directory record | |||
1362 | */ | |||
1363 | memcpy(vol_desc.root_directory_record, &root_record, | |||
1364 | sizeof(vol_desc.root_directory_record)); | |||
1365 | ||||
1366 | /* | |||
1367 | * The rest is just fluff. It looks nice to fill in many of these fields, | |||
1368 | * though. | |||
1369 | */ | |||
1370 | FILL_SPACE(volume_set_id)memset(vol_desc.volume_set_id, ' ', sizeof(vol_desc.volume_set_id )); | |||
1371 | if(volset_id) memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id)); | |||
1372 | ||||
1373 | FILL_SPACE(publisher_id)memset(vol_desc.publisher_id, ' ', sizeof(vol_desc.publisher_id )); | |||
1374 | if(publisher) memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher)); | |||
1375 | ||||
1376 | FILL_SPACE(preparer_id)memset(vol_desc.preparer_id, ' ', sizeof(vol_desc.preparer_id )); | |||
1377 | if(preparer) memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer)); | |||
1378 | ||||
1379 | FILL_SPACE(application_id)memset(vol_desc.application_id, ' ', sizeof(vol_desc.application_id )); | |||
1380 | if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid)); | |||
1381 | ||||
1382 | FILL_SPACE(copyright_file_id)memset(vol_desc.copyright_file_id, ' ', sizeof(vol_desc.copyright_file_id )); | |||
1383 | if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright, | |||
1384 | strlen(copyright)); | |||
1385 | ||||
1386 | FILL_SPACE(abstract_file_id)memset(vol_desc.abstract_file_id, ' ', sizeof(vol_desc.abstract_file_id )); | |||
1387 | if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract, | |||
1388 | strlen(abstract)); | |||
1389 | ||||
1390 | FILL_SPACE(bibliographic_file_id)memset(vol_desc.bibliographic_file_id, ' ', sizeof(vol_desc.bibliographic_file_id )); | |||
1391 | if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio, | |||
1392 | strlen(biblio)); | |||
1393 | ||||
1394 | FILL_SPACE(creation_date)memset(vol_desc.creation_date, ' ', sizeof(vol_desc.creation_date )); | |||
1395 | FILL_SPACE(modification_date)memset(vol_desc.modification_date, ' ', sizeof(vol_desc.modification_date )); | |||
1396 | FILL_SPACE(expiration_date)memset(vol_desc.expiration_date, ' ', sizeof(vol_desc.expiration_date )); | |||
1397 | FILL_SPACE(effective_date)memset(vol_desc.effective_date, ' ', sizeof(vol_desc.effective_date )); | |||
1398 | vol_desc.file_structure_version[0] = 1; | |||
1399 | FILL_SPACE(application_data)memset(vol_desc.application_data, ' ', sizeof(vol_desc.application_data )); | |||
1400 | ||||
1401 | memcpy(vol_desc.creation_date, iso_time, 17); | |||
1402 | memcpy(vol_desc.modification_date, iso_time, 17); | |||
1403 | memcpy(vol_desc.expiration_date, "0000000000000000", 17); | |||
1404 | memcpy(vol_desc.effective_date, iso_time, 17); | |||
1405 | ||||
1406 | /* | |||
1407 | * if not a bootable cd do it the old way | |||
1408 | */ | |||
1409 | xfwrite(&vol_desc, 1, 2048, outfile); | |||
1410 | last_extent_written++; | |||
1411 | return 0; | |||
1412 | } | |||
1413 | ||||
1414 | /* | |||
1415 | * Function to write the EVD for the disc. | |||
1416 | */ | |||
1417 | static int FDECL1(evd_write, FILE *, outfile)evd_write(FILE * outfile) | |||
1418 | { | |||
1419 | struct iso_primary_descriptor evol_desc; | |||
1420 | ||||
1421 | /* | |||
1422 | * Now write the end volume descriptor. Much simpler than the other one | |||
1423 | */ | |||
1424 | memset(&evol_desc, 0, sizeof(evol_desc)); | |||
1425 | evol_desc.type[0] = ISO_VD_END255; | |||
1426 | memcpy(evol_desc.id, ISO_STANDARD_ID"CD001", sizeof(ISO_STANDARD_ID"CD001") - 1); | |||
1427 | evol_desc.version[0] = 1; | |||
1428 | xfwrite(&evol_desc, 1, 2048, outfile); | |||
1429 | last_extent_written += 1; | |||
1430 | return 0; | |||
1431 | } | |||
1432 | ||||
1433 | /* | |||
1434 | * Function to write the EVD for the disc. | |||
1435 | */ | |||
1436 | static int FDECL1(pathtab_write, FILE *, outfile)pathtab_write(FILE * outfile) | |||
1437 | { | |||
1438 | /* | |||
1439 | * Next we write the path tables | |||
1440 | */ | |||
1441 | xfwrite(path_table_l, 1, path_blocks << 11, outfile); | |||
1442 | xfwrite(path_table_m, 1, path_blocks << 11, outfile); | |||
1443 | last_extent_written += 2*path_blocks; | |||
1444 | free(path_table_l); | |||
1445 | free(path_table_m); | |||
1446 | path_table_l = NULL((void *)0); | |||
1447 | path_table_m = NULL((void *)0); | |||
1448 | return 0; | |||
1449 | } | |||
1450 | ||||
1451 | static int FDECL1(exten_write, FILE *, outfile)exten_write(FILE * outfile) | |||
1452 | { | |||
1453 | xfwrite(extension_record, 1, SECTOR_SIZE(2048), outfile); | |||
1454 | last_extent_written++; | |||
1455 | return 0; | |||
1456 | } | |||
1457 | ||||
1458 | /* | |||
1459 | * Functions to describe padding block at the start of the disc. | |||
1460 | */ | |||
1461 | int FDECL1(oneblock_size, int, starting_extent)oneblock_size(int starting_extent) | |||
1462 | { | |||
1463 | last_extent++; | |||
1464 | return 0; | |||
1465 | } | |||
1466 | ||||
1467 | /* | |||
1468 | * Functions to describe padding block at the start of the disc. | |||
1469 | */ | |||
1470 | static int FDECL1(pathtab_size, int, starting_extent)pathtab_size(int starting_extent) | |||
1471 | { | |||
1472 | path_table[0] = starting_extent; | |||
1473 | ||||
1474 | path_table[1] = 0; | |||
1475 | path_table[2] = path_table[0] + path_blocks; | |||
1476 | path_table[3] = 0; | |||
1477 | last_extent += 2*path_blocks; | |||
1478 | return 0; | |||
1479 | } | |||
1480 | ||||
1481 | static int FDECL1(padblock_size, int, starting_extent)padblock_size(int starting_extent) | |||
1482 | { | |||
1483 | last_extent += 16; | |||
1484 | return 0; | |||
1485 | } | |||
1486 | ||||
1487 | static int file_gen() | |||
1488 | { | |||
1489 | #ifdef APPLE_HYB1 | |||
1490 | int start_extent = last_extent; /* orig ISO files start */ | |||
1491 | #endif /* APPLE_HYB */ | |||
1492 | assign_file_addresses(root); | |||
1493 | #ifdef APPLE_HYB1 | |||
1494 | /* put this here for the time being - may when I've worked out how | |||
1495 | to use Eric's new system for creating/writing parts of the image | |||
1496 | it may move to it's own routine */ | |||
1497 | ||||
1498 | if (apple_hyb) | |||
1499 | { | |||
1500 | int Csize; /* clump size for HFS vol */ | |||
1501 | int loop = CTC_LOOP4; | |||
1502 | int last_extent_save = last_extent; | |||
1503 | ||||
1504 | /* allocate memory for the libhfs/mkisofs extra info */ | |||
1505 | hce = (hce_mem *)e_malloc(sizeof(hce_mem)); | |||
1506 | ||||
1507 | hce->error = (char *)e_malloc(ERROR_SIZE1024); | |||
1508 | ||||
1509 | /* mark as unallocated for use later */ | |||
1510 | hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0; | |||
1511 | ||||
1512 | /* reserve space for the label partition - if it is needed */ | |||
1513 | if (gen_pt) | |||
1514 | hce->hfs_map_size = HFS_MAP_SIZE16; | |||
1515 | else | |||
1516 | hce->hfs_map_size = 0; | |||
1517 | ||||
1518 | /* set the intial factor to increase Catalog file size */ | |||
1519 | hce->ctc_size = CTC2; | |||
1520 | ||||
1521 | /* "create" the HFS volume (just the header, catalog/extents files) | |||
1522 | if there's a problem with the Catalog file being too small, | |||
1523 | we keep on increasing the size (up to CTC_LOOP) times and try again. | |||
1524 | Unfortunately I don't know enough about the inner workings of | |||
1525 | HFS, so I can't workout the size of the Catalog file in | |||
1526 | advance (and I don't want to "grow" as is is normally allowed to), | |||
1527 | therefore, this approach is a bit over the top as it involves | |||
1528 | throwing away the "volume" we have created and trying again ... */ | |||
1529 | do | |||
1530 | { | |||
1531 | hce->error[0] = '\0'; | |||
1532 | ||||
1533 | /* attempt to create the Mac volume */ | |||
1534 | Csize = make_mac_volume(root, start_extent); | |||
1535 | ||||
1536 | /* if we have a problem ... */ | |||
1537 | if (Csize < 0) | |||
1538 | { | |||
1539 | /* we've made too many attempts, or got some other error */ | |||
1540 | if (loop == 0 || errno(*__errno()) != HCE_ERROR-9999) | |||
1541 | { | |||
1542 | /* HCE_ERROR is not a valid errno value */ | |||
1543 | if (errno(*__errno()) == HCE_ERROR-9999) | |||
1544 | errno(*__errno()) = 0; | |||
1545 | ||||
1546 | /* exit with the error */ | |||
1547 | if (*hce->error) | |||
1548 | fprintf(stderr(&__sF[2]), "%s\n", hce->error); | |||
1549 | err(1, "%s", hfs_error); | |||
1550 | } | |||
1551 | else | |||
1552 | { | |||
1553 | /* increase Catalog file size factor */ | |||
1554 | hce->ctc_size *= CTC2; | |||
1555 | ||||
1556 | /* reset the initial "last_extent" and try again */ | |||
1557 | last_extent = last_extent_save; | |||
1558 | } | |||
1559 | } | |||
1560 | else | |||
1561 | /* everything OK - just carry on ... */ | |||
1562 | loop = 0; | |||
1563 | } | |||
1564 | while (loop--); | |||
1565 | ||||
1566 | hfs_extra = H_ROUND_UP(hce->hfs_tot_size)((((hce->hfs_tot_size)*512) + ((2048) - 1)) & ~((2048) - 1))/SECTOR_SIZE(2048); | |||
1567 | ||||
1568 | last_extent += hfs_extra; | |||
1569 | ||||
1570 | /* generate the Mac label and HFS partition maps */ | |||
1571 | mac_boot.name = hfs_boot_file; | |||
1572 | ||||
1573 | /* only generate the partition tables etc. if we are making a bootable | |||
1574 | CD - or if the -part option is given */ | |||
1575 | if (gen_pt) { | |||
1576 | if (gen_mac_label(&mac_boot)) { | |||
1577 | if (*hce->error) | |||
1578 | fprintf(stderr(&__sF[2]), "%s\n", hce->error); | |||
1579 | err(1, "%s", hfs_error); | |||
1580 | } | |||
1581 | } | |||
1582 | ||||
1583 | /* set Autostart filename if required */ | |||
1584 | if (autoname) { | |||
1585 | if(autostart()) | |||
1586 | errx(1, "Autostart filename must less than 12 characters"); | |||
1587 | } | |||
1588 | ||||
1589 | /* finished with any HFS type errors */ | |||
1590 | free(hce->error); | |||
1591 | hce->error = 0; | |||
1592 | ||||
1593 | /* the ISO files need to start on a multiple of the HFS allocation | |||
1594 | blocks, so find out how much padding we need */ | |||
1595 | ||||
1596 | /* take in accout alignment of files wrt HFS volume start */ | |||
1597 | hfs_pad = V_ROUND_UP(start_extent*SECTOR_SIZE + (hce->hfs_hdr_size + hce->hfs_map_size)*HFS_BLOCKSZ, Csize)(((start_extent*(2048) + (hce->hfs_hdr_size + hce->hfs_map_size )*512 + (Csize - 1)) / Csize) * Csize)/SECTOR_SIZE(2048); | |||
1598 | ||||
1599 | hfs_pad -= (start_extent + (hce->hfs_hdr_size + hce->hfs_map_size)/BLK_CONV((2048)/512)); | |||
1600 | } | |||
1601 | #endif /* APPLE_HYB */ | |||
1602 | return 0; | |||
1603 | } | |||
1604 | ||||
1605 | static int dirtree_dump() | |||
1606 | { | |||
1607 | if (verbose > 2) | |||
1608 | { | |||
1609 | dump_tree(root); | |||
1610 | } | |||
1611 | return 0; | |||
1612 | } | |||
1613 | ||||
1614 | static int FDECL1(dirtree_fixup, int, starting_extent)dirtree_fixup(int starting_extent) | |||
1615 | { | |||
1616 | if (use_RockRidge && reloc_dir) | |||
1617 | finish_cl_pl_entries(); | |||
1618 | ||||
1619 | if (use_RockRidge ) | |||
1620 | update_nlink_field(root); | |||
1621 | return 0; | |||
1622 | } | |||
1623 | ||||
1624 | static int FDECL1(dirtree_size, int, starting_extent)dirtree_size(int starting_extent) | |||
1625 | { | |||
1626 | assign_directory_addresses(root); | |||
1627 | return 0; | |||
1628 | } | |||
1629 | ||||
1630 | static int FDECL1(ext_size, int, starting_extent)ext_size(int starting_extent) | |||
1631 | { | |||
1632 | extern int extension_record_size; | |||
1633 | struct directory_entry * s_entry; | |||
1634 | extension_record_extent = starting_extent; | |||
1635 | s_entry = root->contents; | |||
1636 | set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24, | |||
1637 | extension_record_extent); | |||
1638 | set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8, | |||
1639 | extension_record_size); | |||
1640 | last_extent++; | |||
1641 | return 0; | |||
1642 | } | |||
1643 | ||||
1644 | static int FDECL1(dirtree_write, FILE *, outfile)dirtree_write(FILE * outfile) | |||
1645 | { | |||
1646 | generate_iso9660_directories(root, outfile); | |||
1647 | return 0; | |||
1648 | } | |||
1649 | ||||
1650 | static int FDECL1(dirtree_cleanup, FILE *, outfile)dirtree_cleanup(FILE * outfile) | |||
1651 | { | |||
1652 | free_directories(root); | |||
1653 | return 0; | |||
1654 | } | |||
1655 | ||||
1656 | static int FDECL1(padblock_write, FILE *, outfile)padblock_write(FILE * outfile) | |||
1657 | { | |||
1658 | char buffer[2048]; | |||
1659 | int i; | |||
1660 | #ifdef APPLE_HYB1 | |||
1661 | int n = 0; | |||
1662 | #endif /* APPLE_HYB */ | |||
1663 | ||||
1664 | memset(buffer, 0, sizeof(buffer)); | |||
1665 | ||||
1666 | #ifdef APPLE_HYB1 | |||
1667 | if (apple_hyb) | |||
1668 | { | |||
1669 | int r; /* HFS hdr output */ | |||
1670 | int tot_size = hce->hfs_map_size + hce->hfs_hdr_size; | |||
1671 | ||||
1672 | /* get size in CD blocks == 4xHFS_BLOCKSZ == 2048 */ | |||
1673 | n = tot_size/BLK_CONV((2048)/512); | |||
1674 | r = tot_size%BLK_CONV((2048)/512); | |||
1675 | ||||
1676 | /* write out HFS volume header info */ | |||
1677 | xfwrite(hce->hfs_map, tot_size, HFS_BLOCKSZ512, outfile); | |||
1678 | ||||
1679 | /* write out any partial CD block */ | |||
1680 | if (r) | |||
1681 | { | |||
1682 | xfwrite(buffer, BLK_CONV((2048)/512)-r, HFS_BLOCKSZ512, outfile); | |||
1683 | n++; | |||
1684 | } | |||
1685 | } | |||
1686 | ||||
1687 | /* write out the remainder of the ISO header */ | |||
1688 | for(i=n; i<16; i++) | |||
1689 | #else | |||
1690 | for(i=0; i<16; i++) | |||
1691 | #endif /* APPLE_HYB */ | |||
1692 | { | |||
1693 | xfwrite(buffer, 1, sizeof(buffer), outfile); | |||
1694 | } | |||
1695 | ||||
1696 | last_extent_written += 16; | |||
1697 | return 0; | |||
1698 | } | |||
1699 | ||||
1700 | #ifdef APPLE_HYB1 | |||
1701 | ||||
1702 | /* | |||
1703 | ** get_adj_size: get the ajusted size of the volume with the HFS | |||
1704 | ** allocation block size for each file | |||
1705 | */ | |||
1706 | int FDECL1(get_adj_size, int, Csize)get_adj_size(int Csize) | |||
1707 | { | |||
1708 | struct deferred_write *dw; | |||
1709 | int size = 0; | |||
1710 | int count = 0; | |||
1711 | ||||
1712 | /* loop through all the files finding the new total size */ | |||
1713 | for(dw = dw_head; dw; dw = dw->next) | |||
1714 | { | |||
1715 | size += V_ROUND_UP(dw->size, Csize)(((dw->size + (Csize - 1)) / Csize) * Csize); | |||
1716 | count++; | |||
1717 | } | |||
1718 | ||||
1719 | /* crude attempt to prevent overflows - HFS can only cope with a | |||
1720 | maximum of about 65536 forks (actually less) - this will trap | |||
1721 | cases when we have far too many files */ | |||
1722 | if (count >= 65536) | |||
1723 | return (-1); | |||
1724 | else | |||
1725 | return(size); | |||
1726 | } | |||
1727 | /* | |||
1728 | ** adj_size: adjust the ISO record entries for all files | |||
1729 | ** based on the HFS allocation block size | |||
1730 | */ | |||
1731 | int FDECL3(adj_size, int, Csize, int, start_extent, int, extra)adj_size(int Csize, int start_extent, int extra) | |||
1732 | { | |||
1733 | struct deferred_write *dw; | |||
1734 | struct directory_entry *s_entry; | |||
1735 | int size; | |||
1736 | ||||
1737 | /* get the adjusted start_extent (with padding) */ | |||
1738 | /* take in accout alignment of files wrt HFS volume start */ | |||
1739 | ||||
1740 | start_extent = V_ROUND_UP(start_extent*SECTOR_SIZE + extra *HFS_BLOCKSZ, Csize)(((start_extent*(2048) + extra *512 + (Csize - 1)) / Csize) * Csize)/SECTOR_SIZE(2048); | |||
1741 | ||||
1742 | start_extent -= (extra/BLK_CONV((2048)/512)); | |||
1743 | ||||
1744 | /* initialise file hash */ | |||
1745 | flush_hash(); | |||
1746 | ||||
1747 | /* loop through all files changing their starting blocks and | |||
1748 | finding any padding needed to written out latter */ | |||
1749 | for(dw = dw_head; dw; dw = dw->next) | |||
1750 | { | |||
1751 | s_entry = dw->s_entry; | |||
1752 | s_entry->starting_block = dw->extent = start_extent; | |||
1753 | set_733((char *) s_entry->isorec.extent, start_extent); | |||
1754 | size = V_ROUND_UP(dw->size, Csize)(((dw->size + (Csize - 1)) / Csize) * Csize)/SECTOR_SIZE(2048); | |||
1755 | dw->pad = size - ROUND_UP(dw->size)((dw->size + ((2048) - 1)) & ~((2048) - 1))/SECTOR_SIZE(2048); | |||
1756 | ||||
1757 | /* cache non-HFS files - as there may be multiple links to | |||
1758 | these files (HFS files can't have multiple links). We will | |||
1759 | need to change the starting extent of the other links later */ | |||
1760 | if (!s_entry->hfs_ent) | |||
1761 | add_hash(s_entry); | |||
1762 | ||||
1763 | start_extent += size; | |||
1764 | } | |||
1765 | ||||
1766 | return(start_extent); | |||
1767 | } | |||
1768 | ||||
1769 | /* | |||
1770 | ** adj_size_other: adjust any non-HFS files that may be linked | |||
1771 | ** to an existing file (i.e. not have a deferred_write | |||
1772 | ** entry of it's own | |||
1773 | */ | |||
1774 | void FDECL1(adj_size_other, struct directory *, dpnt)adj_size_other(struct directory * dpnt) | |||
1775 | { | |||
1776 | struct directory_entry * s_entry; | |||
1777 | struct file_hash *s_hash; | |||
1778 | ||||
1779 | while (dpnt) | |||
1780 | { | |||
1781 | s_entry = dpnt->contents; | |||
1782 | for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) | |||
1783 | { | |||
1784 | /* if it's an HFS file or a directory - then ignore | |||
1785 | (we're after non-HFS files) */ | |||
1786 | if (s_entry->hfs_ent || (s_entry->isorec.flags[0] & 2)) | |||
1787 | continue; | |||
1788 | ||||
1789 | /* find any cached entry and assign new starting extent */ | |||
1790 | s_hash = find_hash(s_entry->dev, s_entry->inode); | |||
1791 | if(s_hash) | |||
1792 | { | |||
1793 | set_733((char *) s_entry->isorec.extent, s_hash->starting_block); | |||
1794 | /* not vital - but tidy */ | |||
1795 | s_entry->starting_block = s_hash->starting_block; | |||
1796 | } | |||
1797 | ||||
1798 | } | |||
1799 | if(dpnt->subdir) | |||
1800 | { | |||
1801 | adj_size_other(dpnt->subdir); | |||
1802 | } | |||
1803 | dpnt = dpnt->next; | |||
1804 | } | |||
1805 | ||||
1806 | /* clear file hash */ | |||
1807 | flush_hash(); | |||
1808 | } | |||
1809 | ||||
1810 | #endif /* APPLE_HYB */ | |||
1811 | ||||
1812 | struct output_fragment padblock_desc = {NULL((void *)0), padblock_size, NULL((void *)0), padblock_write}; | |||
1813 | struct output_fragment voldesc_desc = {NULL((void *)0), oneblock_size, root_gen, pvd_write}; | |||
1814 | struct output_fragment end_vol = {NULL((void *)0), oneblock_size, NULL((void *)0), evd_write}; | |||
1815 | struct output_fragment pathtable_desc = {NULL((void *)0), pathtab_size, generate_path_tables, pathtab_write}; | |||
1816 | struct output_fragment dirtree_desc = {NULL((void *)0), dirtree_size, NULL((void *)0), dirtree_write}; | |||
1817 | struct output_fragment dirtree_clean = {NULL((void *)0), dirtree_fixup, dirtree_dump, dirtree_cleanup}; | |||
1818 | struct output_fragment extension_desc = {NULL((void *)0), ext_size, NULL((void *)0), exten_write}; | |||
1819 | struct output_fragment files_desc = {NULL((void *)0), NULL((void *)0), file_gen, file_write}; |