File: | src/gnu/usr.sbin/mkhybrid/mkhybrid/../src/multi.c |
Warning: | line 1154, column 7 Value stored to 'lstatus' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * File multi.c - scan existing iso9660 image and merge into |
3 | * iso9660 filesystem. Used for multisession support. |
4 | * |
5 | * Written by Eric Youngdale (1996). |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2, or (at your option) |
10 | * any later version. |
11 | * |
12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU General Public License |
18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 | */ |
21 | |
22 | #include <stdlib.h> |
23 | #include <string.h> |
24 | #include <time.h> |
25 | #include <errno(*__errno()).h> |
26 | #include <sys/types.h> |
27 | #include <sys/stat.h> |
28 | |
29 | #include "config.h" |
30 | |
31 | #ifndef VMS |
32 | |
33 | #ifdef HAVE_UNISTD_H1 |
34 | #include <unistd.h> |
35 | #endif |
36 | |
37 | #else |
38 | #include <sys/file.h> |
39 | #include <vms/fabdef.h> |
40 | #include "vms.h" |
41 | extern char * strdup(const char *); |
42 | #endif |
43 | |
44 | #include "mkisofs.h" |
45 | #include "iso9660.h" |
46 | |
47 | #define TF_CREATE1 1 |
48 | #define TF_MODIFY2 2 |
49 | #define TF_ACCESS4 4 |
50 | #define TF_ATTRIBUTES8 8 |
51 | |
52 | static int isonum_711 __PR((unsigned char * p))(unsigned char * p); |
53 | static int isonum_721 __PR((unsigned char * p))(unsigned char * p); |
54 | static int isonum_723 __PR((unsigned char * p))(unsigned char * p); |
55 | static int isonum_731 __PR((unsigned char * p))(unsigned char * p); |
56 | |
57 | static int DECL(merge_old_directory_into_tree, (struct directory_entry *,merge_old_directory_into_tree (struct directory_entry *, struct directory *) |
58 | struct directory *))merge_old_directory_into_tree (struct directory_entry *, struct directory *); |
59 | |
60 | #ifdef __STDC__1 |
61 | static int |
62 | isonum_711 (unsigned char * p) |
63 | #else |
64 | static int |
65 | isonum_711 (p) |
66 | unsigned char * p; |
67 | #endif |
68 | { |
69 | return (*p & 0xff); |
70 | } |
71 | |
72 | #ifdef __STDC__1 |
73 | static int |
74 | isonum_721 (unsigned char * p) |
75 | #else |
76 | static int |
77 | isonum_721 (p) |
78 | unsigned char * p; |
79 | #endif |
80 | { |
81 | return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); |
82 | } |
83 | |
84 | #ifdef __STDC__1 |
85 | static int |
86 | isonum_723 (unsigned char * p) |
87 | #else |
88 | static int |
89 | isonum_723 (p) |
90 | unsigned char * p; |
91 | #endif |
92 | { |
93 | #if 0 |
94 | if (p[0] != p[3] || p[1] != p[2]) { |
95 | fprintf (stderr(&__sF[2]), "invalid format 7.2.3 number\n"); |
96 | exit (1); |
97 | } |
98 | #endif |
99 | return (isonum_721 (p)); |
100 | } |
101 | |
102 | #ifdef __STDC__1 |
103 | static int |
104 | isonum_731 (unsigned char * p) |
105 | #else |
106 | static int |
107 | isonum_731 (p) |
108 | unsigned char * p; |
109 | #endif |
110 | { |
111 | return ((p[0] & 0xff) |
112 | | ((p[1] & 0xff) << 8) |
113 | | ((p[2] & 0xff) << 16) |
114 | | ((p[3] & 0xff) << 24)); |
115 | } |
116 | |
117 | #ifdef __STDC__1 |
118 | int |
119 | isonum_733 (unsigned char * p) |
120 | #else |
121 | int |
122 | isonum_733 (p) |
123 | unsigned char * p; |
124 | #endif |
125 | { |
126 | return (isonum_731 (p)); |
127 | } |
128 | |
129 | FILE * in_image = NULL((void *)0); |
130 | |
131 | #ifndef USE_SCG |
132 | /* |
133 | * Don't define readsecs if mkisofs is linked with |
134 | * the SCSI library. |
135 | * readsecs() will be implemented as SCSI command in this case. |
136 | * |
137 | * Use global var in_image directly in readsecs() |
138 | * the SCSI equivalent will not use a FILE* for I/O. |
139 | * |
140 | * The main point of this pointless abstraction is that Solaris won't let |
141 | * you read 2K sectors from the cdrom driver. The fact that 99.9% of the |
142 | * discs out there have a 2K sectorsize doesn't seem to matter that much. |
143 | * Anyways, this allows the use of a scsi-generics type of interface on |
144 | * Solaris. |
145 | */ |
146 | #ifdef __STDC__1 |
147 | static int |
148 | readsecs(int startsecno, void *buffer, int sectorcount) |
149 | #else |
150 | static int |
151 | readsecs(startsecno, buffer, sectorcount) |
152 | int startsecno; |
153 | void *buffer; |
154 | int sectorcount; |
155 | #endif |
156 | { |
157 | int f = fileno(in_image)(!__isthreaded ? ((in_image)->_file) : (fileno)(in_image)); |
158 | |
159 | if (lseek(f, (off_t)startsecno * SECTOR_SIZE(2048), 0) == (off_t)-1) { |
160 | fprintf(stderr(&__sF[2])," Seek error on old image\n"); |
161 | exit(10); |
162 | } |
163 | return (read(f, buffer, sectorcount * SECTOR_SIZE(2048))); |
164 | } |
165 | #endif |
166 | |
167 | /* |
168 | * Parse the RR attributes so we can find the file name. |
169 | */ |
170 | static int |
171 | FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt)parse_rr(unsigned char * pnt, int len, struct directory_entry * dpnt) |
172 | { |
173 | int cont_extent, cont_offset, cont_size; |
174 | char name_buf[256]; |
175 | |
176 | cont_extent = cont_offset = cont_size = 0; |
177 | |
178 | while(len >= 4){ |
179 | if(pnt[3] != 1) { |
180 | fprintf(stderr(&__sF[2]),"**BAD RRVERSION"); |
181 | return -1; |
182 | }; |
183 | if(strncmp((char *) pnt, "NM", 2) == 0) { |
184 | strncpy(name_buf, (char *) pnt+5, pnt[2] - 5); |
185 | name_buf[pnt[2] - 5] = 0; |
186 | dpnt->name = strdup(name_buf); |
187 | dpnt->got_rr_name = 1; |
188 | return 0; |
189 | } |
190 | |
191 | if(strncmp((char *) pnt, "CE", 2) == 0) { |
192 | cont_extent = isonum_733(pnt+4); |
193 | cont_offset = isonum_733(pnt+12); |
194 | cont_size = isonum_733(pnt+20); |
195 | }; |
196 | |
197 | len -= pnt[2]; |
198 | pnt += pnt[2]; |
199 | if(len <= 3 && cont_extent) { |
200 | unsigned char sector[SECTOR_SIZE(2048)]; |
201 | readsecs(cont_extent, sector, 1); |
202 | parse_rr(§or[cont_offset], cont_size, dpnt); |
203 | }; |
204 | }; |
205 | |
206 | /* Fall back to the iso name if no RR name found */ |
207 | if (dpnt->name == NULL((void *)0)) { |
208 | char *cp; |
209 | |
210 | strcpy(name_buf, dpnt->isorec.name); |
211 | cp = strchr(name_buf, ';'); |
212 | if (cp != NULL((void *)0)) { |
213 | *cp = '\0'; |
214 | } |
215 | |
216 | dpnt->name = strdup(name_buf); |
217 | } |
218 | |
219 | return 0; |
220 | } /* parse_rr */ |
221 | |
222 | |
223 | static int |
224 | FDECL4(check_rr_dates, struct directory_entry *, dpnt,check_rr_dates(struct directory_entry * dpnt, struct directory_entry * current, struct stat * statbuf, struct stat * lstatbuf) |
225 | struct directory_entry *, current,check_rr_dates(struct directory_entry * dpnt, struct directory_entry * current, struct stat * statbuf, struct stat * lstatbuf) |
226 | struct stat *, statbuf,check_rr_dates(struct directory_entry * dpnt, struct directory_entry * current, struct stat * statbuf, struct stat * lstatbuf) |
227 | struct stat *,lstatbuf)check_rr_dates(struct directory_entry * dpnt, struct directory_entry * current, struct stat * statbuf, struct stat * lstatbuf) |
228 | { |
229 | int cont_extent, cont_offset, cont_size; |
230 | int offset; |
231 | unsigned char * pnt; |
232 | int len; |
233 | int same_file; |
234 | int same_file_type; |
235 | mode_t mode; |
236 | char time_buf[7]; |
237 | |
238 | |
239 | cont_extent = cont_offset = cont_size = 0; |
240 | same_file = 1; |
241 | same_file_type = 1; |
242 | |
243 | pnt = dpnt->rr_attributes; |
244 | len = dpnt->rr_attr_size; |
245 | /* |
246 | * We basically need to parse the rr attributes again, and |
247 | * dig out the dates and file types. |
248 | */ |
249 | while(len >= 4){ |
250 | if(pnt[3] != 1) { |
251 | fprintf(stderr(&__sF[2]),"**BAD RRVERSION"); |
252 | return -1; |
253 | }; |
254 | |
255 | /* |
256 | * If we have POSIX file modes, make sure that the file type |
257 | * is the same. If it isn't, then we must always |
258 | * write the new file. |
259 | */ |
260 | if(strncmp((char *) pnt, "PX", 2) == 0) { |
261 | mode = isonum_733(pnt + 4); |
262 | if( (lstatbuf->st_mode & S_IFMT0170000) != (mode & S_IFMT0170000) ) |
263 | { |
264 | same_file_type = 0; |
265 | same_file = 0; |
266 | } |
267 | } |
268 | |
269 | if(strncmp((char *) pnt, "TF", 2) == 0) { |
270 | offset = 5; |
271 | if( pnt[4] & TF_CREATE1 ) |
272 | { |
273 | iso9660_date((char *) time_buf, lstatbuf->st_ctimest_ctim.tv_sec); |
274 | if(memcmp(time_buf, pnt+offset, 7) == 0) |
275 | same_file = 0; |
276 | offset += 7; |
277 | } |
278 | if( pnt[4] & TF_MODIFY2 ) |
279 | { |
280 | iso9660_date((char *) time_buf, lstatbuf->st_mtimest_mtim.tv_sec); |
281 | if(memcmp(time_buf, pnt+offset, 7) == 0) |
282 | same_file = 0; |
283 | offset += 7; |
284 | } |
285 | } |
286 | |
287 | if(strncmp((char *) pnt, "CE", 2) == 0) { |
288 | cont_extent = isonum_733(pnt+4); |
289 | cont_offset = isonum_733(pnt+12); |
290 | cont_size = isonum_733(pnt+20); |
291 | }; |
292 | |
293 | len -= pnt[2]; |
294 | pnt += pnt[2]; |
295 | if(len <= 3 && cont_extent) { |
296 | unsigned char sector[SECTOR_SIZE(2048)]; |
297 | |
298 | readsecs(cont_extent, sector, 1); |
299 | parse_rr(§or[cont_offset], cont_size, dpnt); |
300 | }; |
301 | }; |
302 | |
303 | /* |
304 | * If we have the same fundamental file type, then it is clearly |
305 | * safe to reuse the TRANS.TBL entry. |
306 | */ |
307 | if( same_file_type ) |
308 | { |
309 | current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY0x01; |
310 | } |
311 | |
312 | return same_file; |
313 | } |
314 | |
315 | struct directory_entry ** |
316 | FDECL2(read_merging_directory, struct iso_directory_record *, mrootp,read_merging_directory(struct iso_directory_record * mrootp, int * nent) |
317 | int *, nent)read_merging_directory(struct iso_directory_record * mrootp, int * nent) |
318 | { |
319 | unsigned char * cpnt; |
320 | unsigned char * cpnt1; |
321 | char * dirbuff; |
322 | int i; |
323 | struct iso_directory_record * idr; |
324 | int len; |
325 | struct directory_entry **pnt; |
326 | int rlen; |
327 | struct directory_entry **rtn; |
328 | int seen_rockridge; |
329 | unsigned char * tt_buf; |
330 | int tt_extent; |
331 | int tt_size; |
332 | |
333 | static int warning_given = 0; |
334 | |
335 | /* |
336 | * First, allocate a buffer large enough to read in the entire |
337 | * directory. |
338 | */ |
339 | dirbuff = (char *) e_malloc(isonum_733((unsigned char *)mrootp->size)); |
340 | |
341 | readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff, |
342 | isonum_733((unsigned char *)mrootp->size)/SECTOR_SIZE(2048)); |
343 | |
344 | /* |
345 | * Next look over the directory, and count up how many entries we |
346 | * have. |
347 | */ |
348 | len = isonum_733((unsigned char *)mrootp->size); |
349 | i = 0; |
350 | *nent = 0; |
351 | while(i < len ) |
352 | { |
353 | idr = (struct iso_directory_record *) &dirbuff[i]; |
354 | if(idr->length[0] == 0) |
355 | { |
356 | i = (i + SECTOR_SIZE(2048) - 1) & ~(SECTOR_SIZE(2048) - 1); |
357 | continue; |
358 | } |
359 | (*nent)++; |
360 | i += idr->length[0]; |
361 | } |
362 | |
363 | /* |
364 | * Now allocate the buffer which will hold the array we are |
365 | * about to return. |
366 | */ |
367 | rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn)); |
368 | |
369 | /* |
370 | * Finally, scan the directory one last time, and pick out the |
371 | * relevant bits of information, and store it in the relevant |
372 | * bits of the structure. |
373 | */ |
374 | i = 0; |
375 | pnt = rtn; |
376 | tt_extent = 0; |
377 | seen_rockridge = 0; |
378 | tt_size = 0; |
379 | while(i < len ) |
380 | { |
381 | idr = (struct iso_directory_record *) &dirbuff[i]; |
382 | if(idr->length[0] == 0) |
383 | { |
384 | i = (i + SECTOR_SIZE(2048) - 1) & ~(SECTOR_SIZE(2048) - 1); |
385 | continue; |
386 | } |
387 | *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn)); |
388 | (*pnt)->next = NULL((void *)0); |
389 | (*pnt)->isorec = *idr; |
390 | (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent); |
391 | (*pnt)->size = isonum_733((unsigned char *)idr->size); |
392 | (*pnt)->priority = 0; |
393 | (*pnt)->name = NULL((void *)0); |
394 | (*pnt)->got_rr_name = 0; |
395 | (*pnt)->table = NULL((void *)0); |
396 | (*pnt)->whole_name = NULL((void *)0); |
397 | (*pnt)->filedir = NULL((void *)0); |
398 | (*pnt)->parent_rec = NULL((void *)0); |
399 | /* |
400 | * Set this information so that we correctly cache previous |
401 | * session bits of information. |
402 | */ |
403 | (*pnt)->inode = (*pnt)->starting_block; |
404 | (*pnt)->dev = PREV_SESS_DEV(sizeof(dev_t) >= 4 ? 0x7ffffffd : 0x7ffd); |
405 | (*pnt)->rr_attributes = NULL((void *)0); |
406 | (*pnt)->rr_attr_size = 0; |
407 | (*pnt)->total_rr_attr_size = 0; |
408 | (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY0x01; |
409 | |
410 | /* |
411 | * Check for and parse any RR attributes for the file. |
412 | * All we are really looking for here is the original name |
413 | * of the file. |
414 | */ |
415 | rlen = idr->length[0] & 0xff; |
416 | cpnt = (unsigned char *) idr; |
417 | |
418 | rlen -= sizeof(struct iso_directory_record); |
419 | cpnt += sizeof(struct iso_directory_record); |
420 | |
421 | rlen += sizeof(idr->name); |
422 | cpnt -= sizeof(idr->name); |
423 | |
424 | rlen -= idr->name_len[0]; |
425 | cpnt += idr->name_len[0]; |
426 | |
427 | if((idr->name_len[0] & 1) == 0){ |
428 | cpnt++; |
429 | rlen--; |
430 | }; |
431 | |
432 | if( rlen != 0 ) |
433 | { |
434 | (*pnt)->total_rr_attr_size = (*pnt)->rr_attr_size = rlen; |
435 | (*pnt)->rr_attributes = e_malloc(rlen); |
436 | memcpy((*pnt)->rr_attributes, cpnt, rlen); |
437 | seen_rockridge = 1; |
438 | } |
439 | |
440 | /* |
441 | * Now zero out the remainder of the name field. |
442 | */ |
443 | cpnt = (unsigned char *) &(*pnt)->isorec.name; |
444 | cpnt += idr->name_len[0]; |
445 | memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]); |
446 | |
447 | parse_rr((*pnt)->rr_attributes, rlen, *pnt); |
448 | |
449 | if( ((*pnt)->isorec.name_len[0] == 1) |
450 | && ( ((*pnt)->isorec.name[0] == 0) |
451 | || ((*pnt)->isorec.name[0] == 1)) ) |
452 | { |
453 | if( (*pnt)->name != NULL((void *)0) ) |
454 | { |
455 | free((*pnt)->name); |
456 | } |
457 | if( (*pnt)->whole_name != NULL((void *)0) ) |
458 | { |
459 | free((*pnt)->whole_name); |
460 | } |
461 | if( (*pnt)->isorec.name[0] == 0 ) |
462 | { |
463 | (*pnt)->name = strdup("."); |
464 | } |
465 | else |
466 | { |
467 | (*pnt)->name = strdup(".."); |
468 | } |
469 | } |
470 | |
471 | #ifdef DEBUG |
472 | fprintf(stderr(&__sF[2]), "got DE name: %s\n", (*pnt)->name); |
473 | #endif |
474 | |
475 | #ifdef APPLE_HYB1 |
476 | if( strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0) |
477 | #else |
478 | if( strncmp(idr->name, "TRANS.TBL", 9) == 0) |
479 | #endif /* APPLE_HYB */ |
480 | { |
481 | if( (*pnt)->name != NULL((void *)0) ) |
482 | { |
483 | free((*pnt)->name); |
484 | } |
485 | if( (*pnt)->whole_name != NULL((void *)0) ) |
486 | { |
487 | free((*pnt)->whole_name); |
488 | } |
489 | (*pnt)->name = strdup("<translation table>"); |
490 | tt_extent = isonum_733((unsigned char *)idr->extent); |
491 | tt_size = isonum_733((unsigned char *)idr->size); |
492 | } |
493 | |
494 | pnt++; |
495 | i += idr->length[0]; |
496 | } |
497 | |
498 | /* |
499 | * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it |
500 | * to get the filenames of the files. Also, save the table info, just |
501 | * in case we need to use it. |
502 | */ |
503 | if( tt_extent != 0 && tt_size != 0 ) |
504 | { |
505 | tt_buf = (unsigned char *) e_malloc(tt_size); |
506 | readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE(2048)); |
507 | |
508 | /* |
509 | * Loop through the file, examine each entry, and attempt to |
510 | * attach it to the correct entry. |
511 | */ |
512 | cpnt = tt_buf; |
513 | cpnt1 = tt_buf; |
514 | while( cpnt - tt_buf < tt_size ) |
515 | { |
516 | while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++; |
517 | *cpnt1 = '\0'; |
518 | |
519 | for(pnt = rtn, i = 0; i <*nent; i++, pnt++) |
520 | { |
521 | rlen = isonum_711((*pnt)->isorec.name_len); |
522 | if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name, |
523 | rlen) == 0 |
524 | && cpnt[2+rlen] == ' ') |
525 | { |
526 | (*pnt)->table = e_malloc(strlen((char*)cpnt) - 33); |
527 | sprintf((*pnt)->table, "%c\t%s\n", |
528 | *cpnt, cpnt+37); |
529 | if( !(*pnt)->got_rr_name ) |
530 | { |
531 | if ((*pnt)->name != NULL((void *)0)) { |
532 | free((*pnt)->name); |
533 | } |
534 | (*pnt)->name = strdup((char *) cpnt+37); |
535 | } |
536 | break; |
537 | } |
538 | } |
539 | cpnt = cpnt1 + 1; |
540 | cpnt1 = cpnt; |
541 | } |
542 | |
543 | free(tt_buf); |
544 | } |
545 | else if( !seen_rockridge && !warning_given ) |
546 | { |
547 | /* |
548 | * Warn the user that iso (8.3) names were used because neither |
549 | * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were found. |
550 | */ |
551 | fprintf(stderr(&__sF[2]),"Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) \n"); |
552 | fprintf(stderr(&__sF[2]),"name translations were found on previous session.\n"); |
553 | fprintf(stderr(&__sF[2]),"ISO (8.3) file names have been used instead.\n"); |
554 | warning_given = 1; |
555 | } |
556 | |
557 | if( dirbuff != NULL((void *)0) ) |
558 | { |
559 | free(dirbuff); |
560 | } |
561 | |
562 | return rtn; |
563 | } /* read_merging_directory */ |
564 | |
565 | /* |
566 | * Free any associated data related to the structures. |
567 | */ |
568 | int |
569 | FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len )free_mdinfo(struct directory_entry ** ptr, int len) |
570 | { |
571 | int i; |
572 | struct directory_entry **p; |
573 | |
574 | p = ptr; |
575 | for(i=0; i<len; i++, p++) |
576 | { |
577 | /* |
578 | * If the tree-handling code decided that it needed an entry, |
579 | * it will have removed it from the list. Thus we must allow |
580 | * for null pointers here. |
581 | */ |
582 | if( *p == NULL((void *)0) ) |
583 | { |
584 | continue; |
585 | } |
586 | |
587 | if( (*p)->name != NULL((void *)0) ) |
588 | { |
589 | free((*p)->name); |
590 | } |
591 | |
592 | if( (*p)->whole_name != NULL((void *)0) ) |
593 | { |
594 | free((*p)->whole_name); |
595 | } |
596 | |
597 | if( (*p)->rr_attributes != NULL((void *)0) ) |
598 | { |
599 | free((*p)->rr_attributes); |
600 | } |
601 | |
602 | if( (*p)->table != NULL((void *)0) ) |
603 | { |
604 | free((*p)->table); |
605 | } |
606 | |
607 | free(*p); |
608 | |
609 | } |
610 | |
611 | free(ptr); |
612 | return 0; |
613 | } |
614 | |
615 | /* |
616 | * Search the list to see if we have any entries from the previous |
617 | * session that match this entry. If so, copy the extent number |
618 | * over so we don't bother to write it out to the new session. |
619 | */ |
620 | |
621 | int |
622 | FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len,check_prev_session(struct directory_entry ** ptr, int len, struct directory_entry * curr_entry, struct stat * statbuf, struct stat * lstatbuf, struct directory_entry ** odpnt) |
623 | struct directory_entry *, curr_entry,check_prev_session(struct directory_entry ** ptr, int len, struct directory_entry * curr_entry, struct stat * statbuf, struct stat * lstatbuf, struct directory_entry ** odpnt) |
624 | struct stat *, statbuf, struct stat *, lstatbuf,check_prev_session(struct directory_entry ** ptr, int len, struct directory_entry * curr_entry, struct stat * statbuf, struct stat * lstatbuf, struct directory_entry ** odpnt) |
625 | struct directory_entry **, odpnt)check_prev_session(struct directory_entry ** ptr, int len, struct directory_entry * curr_entry, struct stat * statbuf, struct stat * lstatbuf, struct directory_entry ** odpnt) |
626 | { |
627 | int i; |
628 | |
629 | for( i=0; i < len; i++ ) |
630 | { |
631 | if( ptr[i] == NULL((void *)0) ) |
632 | { |
633 | continue; |
634 | } |
635 | |
636 | #if 0 |
637 | if( ptr[i]->name != NULL((void *)0) && ptr[i]->isorec.name_len[0] == 1 |
638 | && ptr[i]->name[0] == '\0' ) |
639 | { |
640 | continue; |
641 | } |
642 | if( ptr[i]->name != NULL((void *)0) && ptr[i]->isorec.name_len[0] == 1 |
643 | && ptr[i]->name[0] == 1) |
644 | { |
645 | continue; |
646 | } |
647 | #else |
648 | if( ptr[i]->name != NULL((void *)0) && strcmp(ptr[i]->name, ".") == 0 ) |
649 | { |
650 | continue; |
651 | } |
652 | if( ptr[i]->name != NULL((void *)0) && strcmp(ptr[i]->name, "..") == 0 ) |
653 | { |
654 | continue; |
655 | } |
656 | #endif |
657 | |
658 | if( ptr[i]->name != NULL((void *)0) |
659 | && strcmp(ptr[i]->name, curr_entry->name) != 0 ) |
660 | { |
661 | continue; |
662 | } |
663 | |
664 | /* |
665 | * We know that the files have the same name. If they also have |
666 | * the same file type (i.e. file, dir, block, etc), then we |
667 | * can safely reuse the TRANS.TBL entry for this file. |
668 | * The check_rr_dates function will do this for us. |
669 | * |
670 | * Verify that the file type and dates are consistent. |
671 | * If not, we probably have a different file, and we need |
672 | * to write it out again. |
673 | */ |
674 | if( (ptr[i]->rr_attributes != NULL((void *)0)) |
675 | && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) ) |
676 | { |
677 | goto found_it; |
678 | } |
679 | |
680 | |
681 | /* |
682 | * Verify size and timestamp. If rock ridge is in use, we need |
683 | * to compare dates from RR too. Directories are special, we |
684 | * calculate their size later. |
685 | */ |
686 | if( (curr_entry->isorec.flags[0] & 2) == 0 |
687 | && ptr[i]->size != curr_entry->size ) |
688 | { |
689 | goto found_it; |
690 | } |
691 | |
692 | if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 ) |
693 | { |
694 | goto found_it; |
695 | } |
696 | |
697 | /* |
698 | * Never ever reuse directory extents. See comments in |
699 | * tree.c for an explaination of why this must be the case. |
700 | */ |
701 | if( (curr_entry->isorec.flags[0] & 2) != 0 ) |
702 | { |
703 | goto found_it; |
704 | } |
705 | |
706 | memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8); |
707 | curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY0x01; |
708 | goto found_it; |
709 | } |
710 | return 0; |
711 | |
712 | found_it: |
713 | if( odpnt != NULL((void *)0) ) |
714 | { |
715 | *odpnt = ptr[i]; |
716 | } |
717 | else |
718 | { |
719 | free(ptr[i]); |
720 | } |
721 | ptr[i] = NULL((void *)0); |
722 | return 0; |
723 | } |
724 | |
725 | /* |
726 | * merge_isofs: Scan an existing image, and return a pointer |
727 | * to the root directory for this image. |
728 | */ |
729 | struct iso_directory_record * FDECL1(merge_isofs, char *, path)merge_isofs(char * path) |
730 | { |
731 | char buffer[SECTOR_SIZE(2048)]; |
732 | int file_addr; |
733 | int i; |
734 | struct iso_primary_descriptor * pri = NULL((void *)0); |
735 | struct iso_directory_record * rootp; |
736 | struct iso_volume_descriptor * vdp; |
737 | |
738 | /* |
739 | * Start by opening up the image and searching for the volume header. |
740 | * Ultimately, we need to search for volume headers in multiple places |
741 | * because we might be starting with a multisession image. |
742 | * FIXME(eric). |
743 | */ |
744 | |
745 | #ifndef USE_SCG |
746 | in_image = fopen(path, "rb"); |
747 | if( in_image == NULL((void *)0) ) |
748 | { |
749 | return NULL((void *)0); |
750 | } |
751 | #else |
752 | if (strchr(path, '/')) { |
753 | in_image = fopen(path, "rb"); |
754 | if( in_image == NULL((void *)0) ) { |
755 | return NULL((void *)0); |
756 | } |
757 | } else { |
758 | if (scsidev_open(path) < 0) |
759 | return NULL((void *)0); |
760 | } |
761 | #endif |
762 | |
763 | get_session_start(&file_addr); |
764 | |
765 | for(i = 0; i< 100; i++) |
766 | { |
767 | if (readsecs(file_addr/SECTOR_SIZE(2048), &buffer, |
768 | sizeof(buffer)/SECTOR_SIZE(2048)) != sizeof(buffer)) |
769 | { |
770 | fprintf(stderr(&__sF[2])," Read error on old image %s\n", path); |
771 | exit(10); |
772 | } |
773 | |
774 | vdp = (struct iso_volume_descriptor *)buffer; |
775 | |
776 | if( (strncmp(vdp->id, ISO_STANDARD_ID"CD001", sizeof vdp->id) == 0) |
777 | && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY1) ) |
778 | { |
779 | break; |
780 | } |
781 | file_addr += SECTOR_SIZE(2048); |
782 | } |
783 | |
784 | if( i == 100 ) |
785 | { |
786 | return NULL((void *)0); |
787 | } |
788 | |
789 | pri = (struct iso_primary_descriptor *)vdp; |
790 | |
791 | /* |
792 | * Check the blocksize of the image to make sure it is compatible. |
793 | */ |
794 | if( (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE(2048)) |
795 | || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) ) |
796 | { |
797 | return NULL((void *)0); |
798 | } |
799 | |
800 | /* |
801 | * Get the location and size of the root directory. |
802 | */ |
803 | rootp = calloc(1, sizeof(struct iso_directory_record)); |
804 | |
805 | memcpy(rootp, pri->root_directory_record, sizeof(pri->root_directory_record)); |
806 | |
807 | return rootp; |
808 | } |
809 | |
810 | void FDECL3(merge_remaining_entries, struct directory *, this_dir,merge_remaining_entries(struct directory * this_dir, struct directory_entry ** pnt, int n_orig) |
811 | struct directory_entry **, pnt,merge_remaining_entries(struct directory * this_dir, struct directory_entry ** pnt, int n_orig) |
812 | int, n_orig)merge_remaining_entries(struct directory * this_dir, struct directory_entry ** pnt, int n_orig) |
813 | { |
814 | int i; |
815 | struct directory_entry * s_entry; |
816 | unsigned int ttbl_extent = 0; |
817 | unsigned int ttbl_index = 0; |
818 | char whole_path[1024]; |
819 | |
820 | /* |
821 | * Whatever is leftover in the list needs to get merged back |
822 | * into the directory. |
823 | */ |
824 | for( i=0; i < n_orig; i++ ) |
825 | { |
826 | if( pnt[i] == NULL((void *)0) ) |
827 | { |
828 | continue; |
829 | } |
830 | |
831 | if( pnt[i]->name != NULL((void *)0) && pnt[i]->whole_name == NULL((void *)0)) |
832 | { |
833 | /* |
834 | * Set the name for this directory. |
835 | */ |
836 | strcpy(whole_path, this_dir->de_name); |
837 | strcat(whole_path, SPATH_SEPARATOR"/"); |
838 | strcat(whole_path, pnt[i]->name); |
839 | |
840 | pnt[i]->whole_name = strdup(whole_path); |
841 | } |
842 | |
843 | if( pnt[i]->name != NULL((void *)0) |
844 | && strcmp(pnt[i]->name, "<translation table>") == 0 ) |
845 | { |
846 | ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent); |
847 | ttbl_index = i; |
848 | continue; |
849 | } |
850 | /* |
851 | * Skip directories for now - these need to be treated |
852 | * differently. |
853 | */ |
854 | if( (pnt[i]->isorec.flags[0] & 2) != 0 ) |
855 | { |
856 | /* |
857 | * FIXME - we need to insert this directory into the |
858 | * tree, so that the path tables we generate will |
859 | * be correct. |
860 | */ |
861 | if( (strcmp(pnt[i]->name, ".") == 0) |
862 | || (strcmp(pnt[i]->name, "..") == 0) ) |
863 | { |
864 | free(pnt[i]); |
865 | pnt[i] = NULL((void *)0); |
866 | continue; |
867 | } |
868 | else |
869 | { |
870 | merge_old_directory_into_tree(pnt[i], this_dir); |
871 | } |
872 | } |
873 | pnt[i]->next = this_dir->contents; |
874 | pnt[i]->filedir = this_dir; |
875 | this_dir->contents = pnt[i]; |
876 | pnt[i] = NULL((void *)0); |
877 | } |
878 | |
879 | |
880 | /* |
881 | * If we don't have an entry for the translation table, then |
882 | * don't bother trying to copy the starting extent over. |
883 | * Note that it is possible that if we are copying the entire |
884 | * directory, the entry for the translation table will have already |
885 | * been inserted into the linked list and removed from the old |
886 | * entries list, in which case we want to leave the extent number |
887 | * as it was before. |
888 | */ |
889 | if( ttbl_extent == 0 ) |
890 | { |
891 | return; |
892 | } |
893 | |
894 | /* |
895 | * Finally, check the directory we are creating to see whether |
896 | * there are any new entries in it. If there are not, we can |
897 | * reuse the same translation table. |
898 | */ |
899 | for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) |
900 | { |
901 | /* |
902 | * Don't care about '.' or '..'. They are never in the table |
903 | * anyways. |
904 | */ |
905 | if( s_entry->name != NULL((void *)0) && strcmp(s_entry->name, ".") == 0 ) |
906 | { |
907 | continue; |
908 | } |
909 | if( s_entry->name != NULL((void *)0) && strcmp(s_entry->name, "..") == 0 ) |
910 | { |
911 | continue; |
912 | } |
913 | if( strcmp(s_entry->name, "<translation table>") == 0) |
914 | { |
915 | continue; |
916 | } |
917 | if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY0x01) == 0 ) |
918 | { |
919 | return; |
920 | } |
921 | } |
922 | |
923 | /* |
924 | * Locate the translation table, and re-use the same extent. |
925 | * It isn't clear that there should ever be one in there already |
926 | * so for now we try and muddle through the best we can. |
927 | */ |
928 | for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) |
929 | { |
930 | if( strcmp(s_entry->name, "<translation table>") == 0) |
931 | { |
932 | fprintf(stderr(&__sF[2]),"Should never get here\n"); |
933 | set_733(s_entry->isorec.extent, ttbl_extent); |
934 | return; |
935 | } |
936 | } |
937 | |
938 | pnt[ttbl_index]->next = this_dir->contents; |
939 | pnt[ttbl_index]->filedir = this_dir; |
940 | this_dir->contents = pnt[ttbl_index]; |
941 | pnt[ttbl_index] = NULL((void *)0); |
942 | } |
943 | |
944 | |
945 | /* |
946 | * Here we have a case of a directory that has completely disappeared from |
947 | * the face of the earth on the tree we are mastering from. Go through and |
948 | * merge it into the tree, as well as everything beneath it. |
949 | * |
950 | * Note that if a directory has been moved for some reason, this will |
951 | * incorrectly pick it up and attempt to merge it back into the old |
952 | * location. FIXME(eric). |
953 | */ |
954 | static int |
955 | FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt,merge_old_directory_into_tree(struct directory_entry * dpnt, struct directory * parent) |
956 | struct directory *, parent)merge_old_directory_into_tree(struct directory_entry * dpnt, struct directory * parent) |
957 | { |
958 | struct directory_entry **contents = NULL((void *)0); |
959 | int i; |
960 | int n_orig; |
961 | struct directory * this_dir, *next_brother; |
962 | char whole_path[1024]; |
963 | |
964 | this_dir = (struct directory *) e_malloc(sizeof(struct directory)); |
965 | memset(this_dir, 0, sizeof(struct directory)); |
966 | this_dir->next = NULL((void *)0); |
967 | this_dir->subdir = NULL((void *)0); |
968 | this_dir->self = dpnt; |
969 | this_dir->contents = NULL((void *)0); |
970 | this_dir->size = 0; |
971 | this_dir->extent = 0; |
972 | this_dir->depth = parent->depth + 1; |
973 | this_dir->parent = parent; |
974 | if(!parent->subdir) |
975 | parent->subdir = this_dir; |
976 | else { |
977 | next_brother = parent->subdir; |
978 | while(next_brother->next) next_brother = next_brother->next; |
979 | next_brother->next = this_dir; |
980 | } |
981 | |
982 | /* |
983 | * Set the name for this directory. |
984 | */ |
985 | strcpy(whole_path, parent->de_name); |
986 | strcat(whole_path, SPATH_SEPARATOR"/"); |
987 | strcat(whole_path, dpnt->name); |
988 | this_dir->de_name = strdup(whole_path); |
989 | this_dir->whole_name = strdup(whole_path); |
990 | |
991 | /* |
992 | * Now fill this directory using information from the previous |
993 | * session. |
994 | */ |
995 | contents = read_merging_directory(&dpnt->isorec, &n_orig); |
996 | /* |
997 | * Start by simply copying the '.', '..' and non-directory |
998 | * entries to this directory. Technically we could let |
999 | * merge_remaining_entries handle this, but it gets rather confused |
1000 | * by the '.' and '..' entries. |
1001 | */ |
1002 | for(i=0; i < n_orig; i ++ ) |
1003 | { |
1004 | /* |
1005 | * We can always reuse the TRANS.TBL in this particular case. |
1006 | */ |
1007 | contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY0x01; |
1008 | |
1009 | if( ((contents[i]->isorec.flags[0] & 2) != 0) |
1010 | && (i >= 2) ) |
1011 | { |
1012 | continue; |
1013 | } |
1014 | |
1015 | /* |
1016 | * If we have a directory, don't reuse the extent number. |
1017 | */ |
1018 | if( (contents[i]->isorec.flags[0] & 2) != 0 ) |
1019 | { |
1020 | memset(contents[i]->isorec.extent, 0, 8); |
1021 | |
1022 | if( strcmp(contents[i]->name, ".") == 0 ) |
1023 | this_dir->dir_flags |= DIR_HAS_DOT0x02; |
1024 | |
1025 | if( strcmp(contents[i]->name, "..") == 0 ) |
1026 | this_dir->dir_flags |= DIR_HAS_DOTDOT0x04; |
1027 | } |
1028 | |
1029 | /* |
1030 | * Set the whole name for this file. |
1031 | */ |
1032 | strcpy(whole_path, this_dir->whole_name); |
1033 | strcat(whole_path, SPATH_SEPARATOR"/"); |
1034 | strcat(whole_path, contents[i]->name); |
1035 | |
1036 | contents[i]->whole_name = strdup(whole_path); |
1037 | |
1038 | contents[i]->next = this_dir->contents; |
1039 | contents[i]->filedir = this_dir; |
1040 | this_dir->contents = contents[i]; |
1041 | contents[i] = NULL((void *)0); |
1042 | } |
1043 | |
1044 | /* |
1045 | * Zero the extent number for ourselves. |
1046 | */ |
1047 | memset(dpnt->isorec.extent, 0, 8); |
1048 | |
1049 | /* |
1050 | * Anything that is left are other subdirectories that need to be merged. |
1051 | */ |
1052 | merge_remaining_entries(this_dir, contents, n_orig); |
1053 | free_mdinfo(contents, n_orig); |
1054 | #if 0 |
1055 | /* |
1056 | * This is no longer required. The post-scan sort will handle |
1057 | * all of this for us. |
1058 | */ |
1059 | sort_n_finish(this_dir); |
1060 | #endif |
1061 | |
1062 | return 0; |
1063 | } |
1064 | |
1065 | |
1066 | char * cdwrite_data = NULL((void *)0); |
1067 | |
1068 | int |
1069 | FDECL1(get_session_start, int *, file_addr)get_session_start(int * file_addr) |
1070 | { |
1071 | char * pnt; |
1072 | |
1073 | #ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS |
1074 | /* |
1075 | * FIXME(eric). We need to coordinate with cdwrite to obtain |
1076 | * the parameters. For now, we assume we are writing the 2nd session, |
1077 | * so we start from the session that starts at 0. |
1078 | */ |
1079 | |
1080 | *file_addr = (16 << 11); |
1081 | |
1082 | /* |
1083 | * We need to coordinate with cdwrite to get the next writable address |
1084 | * from the device. Here is where we use it. |
1085 | */ |
1086 | session_start = last_extent = last_extent_written = cdwrite_result(); |
1087 | |
1088 | #else |
1089 | |
1090 | if( cdwrite_data == NULL((void *)0) ) |
1091 | { |
1092 | fprintf(stderr(&__sF[2]),"Special parameters for cdwrite not specified with -C\n"); |
1093 | exit(1); |
1094 | } |
1095 | |
1096 | /* |
1097 | * Next try and find the ',' in there which delimits the two numbers. |
1098 | */ |
1099 | pnt = strchr(cdwrite_data, ','); |
1100 | if( pnt == NULL((void *)0) ) |
1101 | { |
1102 | fprintf(stderr(&__sF[2]), "Malformed cdwrite parameters\n"); |
1103 | exit(1); |
1104 | } |
1105 | |
1106 | *pnt = '\0'; |
1107 | if (file_addr != NULL((void *)0)) { |
1108 | *file_addr = atol(cdwrite_data) * SECTOR_SIZE(2048); |
1109 | } |
1110 | pnt++; |
1111 | |
1112 | session_start = last_extent = last_extent_written = atol(pnt); |
1113 | |
1114 | pnt--; |
1115 | *pnt = ','; |
1116 | |
1117 | #endif |
1118 | return 0; |
1119 | } |
1120 | |
1121 | /* |
1122 | * This function scans the directory tree, looking for files, and it makes |
1123 | * note of everything that is found. We also begin to construct the ISO9660 |
1124 | * directory entries, so that we can determine how large each directory is. |
1125 | */ |
1126 | |
1127 | int |
1128 | FDECL2(merge_previous_session,struct directory *, this_dir,merge_previous_session(struct directory * this_dir, struct iso_directory_record * mrootp) |
1129 | struct iso_directory_record *, mrootp)merge_previous_session(struct directory * this_dir, struct iso_directory_record * mrootp) |
1130 | { |
1131 | struct directory_entry **orig_contents = NULL((void *)0); |
1132 | struct directory_entry * odpnt = NULL((void *)0); |
1133 | int n_orig; |
1134 | struct directory_entry * s_entry; |
1135 | int status, lstatus; |
1136 | struct stat statbuf, lstatbuf; |
1137 | |
1138 | /* |
1139 | * Parse the same directory in the image that we are merging |
1140 | * for multisession stuff. |
1141 | */ |
1142 | orig_contents = read_merging_directory(mrootp, &n_orig); |
1143 | if( orig_contents == NULL((void *)0) ) |
1144 | { |
1145 | return 0; |
1146 | } |
1147 | |
1148 | |
1149 | /* Now we scan the directory itself, and look at what is inside of it. */ |
1150 | |
1151 | for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) |
1152 | { |
1153 | status = stat_filter(s_entry->whole_name, &statbuf); |
1154 | lstatus = lstat_filter(s_entry->whole_name, &lstatbuf); |
Value stored to 'lstatus' is never read | |
1155 | |
1156 | /* |
1157 | * We always should create an entirely new directory tree whenever |
1158 | * we generate a new session, unless there were *no* changes whatsoever |
1159 | * to any of the directories, in which case it would be kind of pointless |
1160 | * to generate a new session. |
1161 | * |
1162 | * I believe it is possible to rigorously prove that any change anywhere |
1163 | * in the filesystem will force the entire tree to be regenerated |
1164 | * because the modified directory will get a new extent number. Since |
1165 | * each subdirectory of the changed directory has a '..' entry, all of |
1166 | * them will need to be rewritten too, and since the parent directory |
1167 | * of the modified directory will have an extent pointer to the directory |
1168 | * it too will need to be rewritten. Thus we will never be able to reuse |
1169 | * any directory information when writing new sessions. |
1170 | * |
1171 | * We still check the previous session so we can mark off the equivalent |
1172 | * entry in the list we got from the original disc, however. |
1173 | */ |
1174 | |
1175 | /* |
1176 | * The check_prev_session function looks for an identical entry in |
1177 | * the previous session. If we see it, then we copy the extent |
1178 | * number to s_entry, and cross it off the list. |
1179 | */ |
1180 | check_prev_session(orig_contents, n_orig, s_entry, |
1181 | &statbuf, &lstatbuf, &odpnt); |
1182 | |
1183 | if(S_ISDIR(statbuf.st_mode)((statbuf.st_mode & 0170000) == 0040000) && odpnt != NULL((void *)0)) |
1184 | { |
1185 | int dflag; |
1186 | |
1187 | if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) |
1188 | { |
1189 | struct directory * child; |
1190 | |
1191 | child = find_or_create_directory(this_dir, |
1192 | s_entry->whole_name, |
1193 | s_entry, 1); |
1194 | dflag = merge_previous_session(child, |
1195 | &odpnt->isorec); |
1196 | /* If unable to scan directory, mark this as a non-directory */ |
1197 | if(!dflag) |
1198 | lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT0170000) | S_IFREG0100000; |
1199 | free(odpnt); |
1200 | odpnt = NULL((void *)0); |
1201 | } |
1202 | } |
1203 | } |
1204 | |
1205 | /* |
1206 | * Whatever is left over, are things which are no longer in the tree |
1207 | * on disk. We need to also merge these into the tree. |
1208 | */ |
1209 | merge_remaining_entries(this_dir, orig_contents, n_orig); |
1210 | free_mdinfo(orig_contents, n_orig); |
1211 | |
1212 | return 1; |
1213 | } |
1214 |