GRUB-1.98 changes
[grub2/jjazz.git] / util / mkisofs / joliet.c
blobb3c7557929bd819b54f6a510b450e67738f0f1d7
1 /*
2 * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
4 Copyright 1997 Eric Youngdale.
6 Copyright (C) 2009 Free Software Foundation, Inc.
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 3, or (at your option)
11 any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 * Joliet extensions for ISO9660. These are spottily documented by
24 * Microsoft. In their infinite stupidity, they completely ignored
25 * the possibility of using an SUSP record with the long filename
26 * in it, and instead wrote out a duplicate directory tree with the
27 * long filenames in it.
29 * I am not sure why they did this. One reason is that they get the path
30 * tables with the long filenames in them.
32 * There are two basic principles to Joliet, and the non-Unicode variant
33 * known as Romeo. Long filenames seem to be the main one, and the second
34 * is that the character set and a few other things is substantially relaxed.
36 * The SVD is identical to the PVD, except:
38 * Id is 2, not 1 (indicates SVD).
39 * escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
40 * The root directory record points to a different extent (with different
41 * size).
42 * There are different path tables for the two sets of directory trees.
44 * The following fields are recorded in Unicode:
45 * system_id
46 * volume_id
47 * volume_set_id
48 * publisher_id
49 * preparer_id
50 * application_id
51 * copyright_file_id
52 * abstract_file_id
53 * bibliographic_file_id
55 * Unicode strings are always encoded in big-endian format.
57 * In a directory record, everything is the same as with iso9660, except
58 * that the name is recorded in unicode. The name length is specified in
59 * total bytes, not in number of unicode characters.
61 * The character set used for the names is different with UCS - the
62 * restrictions are that the following are not allowed:
64 * Characters (00)(00) through (00)(1f) (control chars)
65 * (00)(2a) '*'
66 * (00)(2f) '/'
67 * (00)(3a) ':'
68 * (00)(3b) ';'
69 * (00)(3f) '?'
70 * (00)(5c) '\'
72 #include "config.h"
73 #include "mkisofs.h"
74 #include "iso9660.h"
76 #include <stdint.h>
77 #include <stdlib.h>
78 #include <time.h>
80 static unsigned int jpath_table_index;
81 static struct directory ** jpathlist;
82 static int next_jpath_index = 1;
83 static int sort_goof;
85 static int generate_joliet_path_tables __PR((void));
86 static int DECL(joliet_sort_directory, (struct directory_entry ** sort_dir));
87 static void DECL(assign_joliet_directory_addresses, (struct directory * node));
88 static int jroot_gen __PR((void));
91 * Function: convert_to_unicode
93 * Purpose: Perform a 1/2 assed unicode conversion on a text
94 * string.
96 * Notes:
98 static void FDECL3(convert_to_unicode, unsigned char *, buffer, int, size, char *, source )
100 unsigned char * tmpbuf;
101 int i;
102 int j;
105 * If we get a NULL pointer for the source, it means we have an inplace
106 * copy, and we need to make a temporary working copy first.
108 if( source == NULL )
110 tmpbuf = (uint8_t *) e_malloc(size);
111 memcpy( tmpbuf, buffer, size);
113 else
115 tmpbuf = (uint8_t *)source;
119 * Now start copying characters. If the size was specified to be 0, then
120 * assume the input was 0 terminated.
122 j = 0;
123 for(i=0; i < size ; i += 2, j++)
125 buffer[i] = 0;
127 * JS integrated from: Achim_Kaiser@t-online.de
129 * Let all valid unicode characters pass through (assuming ISO-8859-1).
130 * Others are set to '_' .
132 if( tmpbuf[j] != 0 &&
133 (tmpbuf[j] <= 0x1f || (tmpbuf[j] >= 0x7F && tmpbuf[j] <= 0xA0)) )
135 buffer[i+1] = '_';
137 else
139 switch(tmpbuf[j])
141 case '*':
142 case '/':
143 case ':':
144 case ';':
145 case '?':
146 case '\\':
148 * Even Joliet has some standards as to what is allowed in a pathname.
149 * Pretty tame in comparison to what DOS restricts you to.
151 buffer[i+1] = '_';
152 break;
153 default:
154 buffer[i+1] = tmpbuf[j];
155 break;
160 if( source == NULL )
162 free(tmpbuf);
167 * Function: joliet_strlen
169 * Purpose: Return length in bytes of string after conversion to unicode.
171 * Notes: This is provided mainly as a convenience so that when more intelligent
172 * Unicode conversion for either Multibyte or 8-bit codes is available that
173 * we can easily adapt.
175 static int FDECL1(joliet_strlen, const char *, string)
177 int rtn;
179 rtn = strlen(string) << 1;
182 * We do clamp the maximum length of a Joliet string to be the
183 * maximum path size. This helps to ensure that we don't completely
184 * bolix things up with very long paths. The Joliet specs say
185 * that the maximum length is 128 bytes, or 64 unicode characters.
187 if( rtn > 0x80)
189 rtn = 0x80;
191 return rtn;
195 * Function: get_joliet_vol_desc
197 * Purpose: generate a Joliet compatible volume desc.
199 * Notes: Assume that we have the non-joliet vol desc
200 * already present in the buffer. Just modifiy the
201 * appropriate fields.
203 static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, jvol_desc)
205 jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
208 * For now, always do Unicode level 3. I don't really know what 1 and 2
209 * are - perhaps a more limited Unicode set.
211 * FIXME(eric) - how does Romeo fit in here? As mkisofs just
212 * "expands" 8 bit character codes to 16 bits and does nothing
213 * special with the Unicode characters, therefore shouldn't mkisofs
214 * really be stating that it's using UCS-2 Level 1, not Level 3 for
215 * the Joliet directory tree.
217 strcpy(jvol_desc->escape_sequences, "%/@");
220 * Until we have Unicode path tables, leave these unset.
222 set_733((char *) jvol_desc->path_table_size, jpath_table_size);
223 set_731(jvol_desc->type_l_path_table, jpath_table[0]);
224 set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]);
225 set_732(jvol_desc->type_m_path_table, jpath_table[2]);
226 set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]);
229 * Set this one up.
231 memcpy(jvol_desc->root_directory_record, &jroot_record,
232 sizeof(struct iso_directory_record));
235 * Finally, we have a bunch of strings to convert to Unicode.
236 * FIXME(eric) - I don't know how to do this in general, so we will
237 * just be really lazy and do a char -> short conversion. We probably
238 * will want to filter any characters >= 0x80.
240 convert_to_unicode((uint8_t *)jvol_desc->system_id, sizeof(jvol_desc->system_id), NULL);
241 convert_to_unicode((uint8_t *)jvol_desc->volume_id, sizeof(jvol_desc->volume_id), NULL);
242 convert_to_unicode((uint8_t *)jvol_desc->volume_set_id, sizeof(jvol_desc->volume_set_id), NULL);
243 convert_to_unicode((uint8_t *)jvol_desc->publisher_id, sizeof(jvol_desc->publisher_id), NULL);
244 convert_to_unicode((uint8_t *)jvol_desc->preparer_id, sizeof(jvol_desc->preparer_id), NULL);
245 convert_to_unicode((uint8_t *)jvol_desc->application_id, sizeof(jvol_desc->application_id), NULL);
246 convert_to_unicode((uint8_t *)jvol_desc->copyright_file_id, sizeof(jvol_desc->copyright_file_id), NULL);
247 convert_to_unicode((uint8_t *)jvol_desc->abstract_file_id, sizeof(jvol_desc->abstract_file_id), NULL);
248 convert_to_unicode((uint8_t *)jvol_desc->bibliographic_file_id, sizeof(jvol_desc->bibliographic_file_id), NULL);
253 static void FDECL1(assign_joliet_directory_addresses, struct directory *, node)
255 int dir_size;
256 struct directory * dpnt;
258 dpnt = node;
260 while (dpnt)
262 if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
265 * If we already have an extent for this (i.e. it came from
266 * a multisession disc), then don't reassign a new extent.
268 dpnt->jpath_index = next_jpath_index++;
269 if( dpnt->jextent == 0 )
271 dpnt->jextent = last_extent;
272 dir_size = (dpnt->jsize + (SECTOR_SIZE - 1)) >> 11;
273 last_extent += dir_size;
277 /* skip if hidden - but not for the rr_moved dir */
278 if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir))
280 assign_joliet_directory_addresses(dpnt->subdir);
282 dpnt = dpnt->next;
286 static
287 void FDECL1(build_jpathlist, struct directory *, node)
289 struct directory * dpnt;
291 dpnt = node;
293 while (dpnt)
296 if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
298 jpathlist[dpnt->jpath_index] = dpnt;
300 if(dpnt->subdir) build_jpathlist(dpnt->subdir);
301 dpnt = dpnt->next;
303 } /* build_jpathlist(... */
305 static int FDECL2(joliet_compare_paths, void const *, r, void const *, l)
307 struct directory const *ll = *(struct directory * const *)l;
308 struct directory const *rr = *(struct directory * const *)r;
309 int rparent, lparent;
311 rparent = rr->parent->jpath_index;
312 lparent = ll->parent->jpath_index;
313 if( rr->parent == reloc_dir )
315 rparent = rr->self->parent_rec->filedir->jpath_index;
318 if( ll->parent == reloc_dir )
320 lparent = ll->self->parent_rec->filedir->jpath_index;
323 if (rparent < lparent)
325 return -1;
328 if (rparent > lparent)
330 return 1;
333 return strcmp(rr->self->name, ll->self->name);
335 } /* compare_paths(... */
337 static int generate_joliet_path_tables()
339 struct directory_entry * de;
340 struct directory * dpnt;
341 int fix;
342 int j;
343 int namelen;
344 char * npnt;
345 char * npnt1;
346 int tablesize;
349 * First allocate memory for the tables and initialize the memory
351 tablesize = jpath_blocks << 11;
352 jpath_table_m = (char *) e_malloc(tablesize);
353 jpath_table_l = (char *) e_malloc(tablesize);
354 memset(jpath_table_l, 0, tablesize);
355 memset(jpath_table_m, 0, tablesize);
357 if( next_jpath_index > 0xffff )
359 fprintf (stderr, _("Unable to generate sane path tables - too many directories (%d)\n"),
360 next_jpath_index);
361 exit (1);
364 * Now start filling in the path tables. Start with root directory
366 jpath_table_index = 0;
367 jpathlist = (struct directory **) e_malloc(sizeof(struct directory *)
368 * next_jpath_index);
369 memset(jpathlist, 0, sizeof(struct directory *) * next_jpath_index);
370 build_jpathlist(root);
374 fix = 0;
375 #ifdef __STDC__
376 qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *),
377 (int (*)(const void *, const void *))joliet_compare_paths);
378 #else
379 qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *),
380 joliet_compare_paths);
381 #endif
383 for(j=1; j<next_jpath_index; j++)
385 if(jpathlist[j]->jpath_index != j)
387 jpathlist[j]->jpath_index = j;
388 fix++;
391 } while(fix);
393 for(j=1; j<next_jpath_index; j++)
395 dpnt = jpathlist[j];
396 if(!dpnt)
398 fprintf (stderr, _("Entry %d not in path tables\n"), j);
399 exit (1);
401 npnt = dpnt->de_name;
403 npnt1 = strrchr(npnt, PATH_SEPARATOR);
404 if(npnt1)
406 npnt = npnt1 + 1;
409 de = dpnt->self;
410 if(!de)
412 fprintf (stderr, _("Fatal goof - directory has amnesia\n"));
413 exit (1);
416 namelen = joliet_strlen(de->name);
418 if( dpnt == root )
420 jpath_table_l[jpath_table_index] = 1;
421 jpath_table_m[jpath_table_index] = 1;
423 else
425 jpath_table_l[jpath_table_index] = namelen;
426 jpath_table_m[jpath_table_index] = namelen;
428 jpath_table_index += 2;
430 set_731(jpath_table_l + jpath_table_index, dpnt->jextent);
431 set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
432 jpath_table_index += 4;
434 if( dpnt->parent != reloc_dir )
436 set_721(jpath_table_l + jpath_table_index,
437 dpnt->parent->jpath_index);
438 set_722(jpath_table_m + jpath_table_index,
439 dpnt->parent->jpath_index);
441 else
443 set_721(jpath_table_l + jpath_table_index,
444 dpnt->self->parent_rec->filedir->jpath_index);
445 set_722(jpath_table_m + jpath_table_index,
446 dpnt->self->parent_rec->filedir->jpath_index);
449 jpath_table_index += 2;
452 * The root directory is still represented in non-unicode fashion.
454 if( dpnt == root )
456 jpath_table_l[jpath_table_index] = 0;
457 jpath_table_m[jpath_table_index] = 0;
458 jpath_table_index ++;
460 else
462 convert_to_unicode((uint8_t *)jpath_table_l + jpath_table_index,
463 namelen, de->name);
464 convert_to_unicode((uint8_t *)jpath_table_m + jpath_table_index,
465 namelen, de->name);
466 jpath_table_index += namelen;
469 if(jpath_table_index & 1)
471 jpath_table_index++; /* For odd lengths we pad */
475 free(jpathlist);
476 if(jpath_table_index != jpath_table_size)
478 fprintf(stderr, _("Joliet path table lengths do not match %d %d\n"),
479 jpath_table_index,
480 jpath_table_size);
482 return 0;
483 } /* generate_path_tables(... */
485 static void FDECL2(generate_one_joliet_directory, struct directory *, dpnt, FILE *, outfile)
487 unsigned int dir_index;
488 char * directory_buffer;
489 int new_reclen;
490 struct directory_entry * s_entry;
491 struct directory_entry * s_entry1;
492 struct iso_directory_record jrec;
493 unsigned int total_size;
494 int cvt_len;
495 struct directory * finddir;
497 total_size = (dpnt->jsize + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1);
498 directory_buffer = (char *) e_malloc(total_size);
499 memset(directory_buffer, 0, total_size);
500 dir_index = 0;
502 s_entry = dpnt->jcontents;
503 while(s_entry)
505 if(s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
506 s_entry = s_entry->jnext;
507 continue;
511 * If this entry was a directory that was relocated, we have a bit
512 * of trouble here. We need to dig out the real thing and put it
513 * back here. In the Joliet tree, there is no relocated rock
514 * ridge, as there are no depth limits to a directory tree.
516 if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 )
518 for(s_entry1 = reloc_dir->contents; s_entry1; s_entry1 = s_entry1->next)
520 if( s_entry1->parent_rec == s_entry )
522 break;
525 if( s_entry1 == NULL )
528 * We got trouble.
530 fprintf (stderr, _("Unable to locate relocated directory\n"));
531 exit (1);
534 else
536 s_entry1 = s_entry;
540 * We do not allow directory entries to cross sector boundaries.
541 * Simply pad, and then start the next entry at the next sector
543 new_reclen = s_entry1->jreclen;
544 if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
546 dir_index = (dir_index + (SECTOR_SIZE - 1)) &
547 ~(SECTOR_SIZE - 1);
550 memcpy(&jrec, &s_entry1->isorec, sizeof(struct iso_directory_record) -
551 sizeof(s_entry1->isorec.name));
553 cvt_len = joliet_strlen(s_entry1->name);
556 * Fix the record length - this was the non-Joliet version we
557 * were seeing.
559 jrec.name_len[0] = cvt_len;
560 jrec.length[0] = s_entry1->jreclen;
563 * If this is a directory, fix the correct size and extent
564 * number.
566 if( (jrec.flags[0] & 2) != 0 )
568 if(strcmp(s_entry1->name,".") == 0)
570 jrec.name_len[0] = 1;
571 set_733((char *) jrec.extent, dpnt->jextent);
572 set_733((char *) jrec.size, ROUND_UP(dpnt->jsize));
574 else if(strcmp(s_entry1->name,"..") == 0)
576 jrec.name_len[0] = 1;
577 if( dpnt->parent == reloc_dir )
579 set_733((char *) jrec.extent, dpnt->self->parent_rec->filedir->jextent);
580 set_733((char *) jrec.size, ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
582 else
585 set_733((char *) jrec.extent, dpnt->parent->jextent);
586 set_733((char *) jrec.size, ROUND_UP(dpnt->parent->jsize));
589 else
591 if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 )
593 finddir = reloc_dir->subdir;
595 else
597 finddir = dpnt->subdir;
599 while(1==1)
601 if(finddir->self == s_entry1) break;
602 finddir = finddir->next;
603 if(!finddir)
605 fprintf (stderr, _("Fatal goof - unable to find directory location\n"));
606 exit (1);
609 set_733((char *) jrec.extent, finddir->jextent);
610 set_733((char *) jrec.size, ROUND_UP(finddir->jsize));
614 memcpy(directory_buffer + dir_index, &jrec,
615 sizeof(struct iso_directory_record) -
616 sizeof(s_entry1->isorec.name));
619 dir_index += sizeof(struct iso_directory_record) -
620 sizeof (s_entry1->isorec.name);
623 * Finally dump the Unicode version of the filename.
624 * Note - . and .. are the same as with non-Joliet discs.
626 if( (jrec.flags[0] & 2) != 0
627 && strcmp(s_entry1->name, ".") == 0 )
629 directory_buffer[dir_index++] = 0;
631 else if( (jrec.flags[0] & 2) != 0
632 && strcmp(s_entry1->name, "..") == 0 )
634 directory_buffer[dir_index++] = 1;
636 else
638 convert_to_unicode((uint8_t *)directory_buffer + dir_index,
639 cvt_len,
640 s_entry1->name);
641 dir_index += cvt_len;
644 if(dir_index & 1)
646 directory_buffer[dir_index++] = 0;
649 s_entry = s_entry->jnext;
652 if(dpnt->jsize != dir_index)
654 fprintf (stderr, _("Unexpected joliet directory length %d %d %s\n"),
655 dpnt->jsize, dir_index, dpnt->de_name);
658 xfwrite(directory_buffer, 1, total_size, outfile);
659 last_extent_written += total_size >> 11;
660 free(directory_buffer);
661 } /* generate_one_joliet_directory(... */
663 static int FDECL1(joliet_sort_n_finish, struct directory *, this_dir)
665 struct directory_entry * s_entry;
666 int status = 0;
668 /* don't want to skip this directory if it's the reloc_dir at the moment */
669 if(this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY)
671 return 0;
674 for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
676 /* skip hidden entries */
677 if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 )
679 continue;
683 * First update the path table sizes for directories.
685 * Finally, set the length of the directory entry if Joliet is used.
686 * The name is longer, but no Rock Ridge is ever used here, so
687 * depending upon the options the entry size might turn out to be about
688 * the same. The Unicode name is always a multiple of 2 bytes, so
689 * we always add 1 to make it an even number.
691 if(s_entry->isorec.flags[0] == 2)
693 if (strcmp(s_entry->name,".") && strcmp(s_entry->name,".."))
695 jpath_table_size += joliet_strlen(s_entry->name) + sizeof(struct iso_path_table) - 1;
696 if (jpath_table_size & 1)
698 jpath_table_size++;
701 else
703 if (this_dir == root && strlen(s_entry->name) == 1)
705 jpath_table_size += sizeof(struct iso_path_table);
706 if (jpath_table_size & 1) jpath_table_size++;
711 if (strcmp(s_entry->name,".") && strcmp(s_entry->name,".."))
713 s_entry->jreclen = sizeof(struct iso_directory_record)
714 - sizeof(s_entry->isorec.name)
715 + joliet_strlen(s_entry->name)
716 + 1;
718 else
721 * Special - for '.' and '..' we generate the same records we
722 * did for non-Joliet discs.
724 s_entry->jreclen = sizeof(struct iso_directory_record)
725 - sizeof(s_entry->isorec.name)
726 + 1;
732 if( (this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0 )
734 return 0;
737 this_dir->jcontents = this_dir->contents;
738 status = joliet_sort_directory(&this_dir->jcontents);
741 * Now go through the directory and figure out how large this one will be.
742 * Do not split a directory entry across a sector boundary
744 s_entry = this_dir->jcontents;
746 * XXX Is it ok to comment this out?
748 /*XXX JS this_dir->ce_bytes = 0;*/
749 for(s_entry = this_dir->jcontents; s_entry; s_entry = s_entry->jnext)
751 int jreclen;
753 if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 )
755 continue;
758 jreclen = s_entry->jreclen;
760 if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >= SECTOR_SIZE)
762 this_dir->jsize = (this_dir->jsize + (SECTOR_SIZE - 1)) &
763 ~(SECTOR_SIZE - 1);
765 this_dir->jsize += jreclen;
767 return status;
771 * Similar to the iso9660 case, except here we perform a full sort based upon the
772 * regular name of the file, not the 8.3 version.
774 static int FDECL2(joliet_compare_dirs, const void *, rr, const void *, ll)
776 char * rpnt, *lpnt;
777 struct directory_entry ** r, **l;
779 r = (struct directory_entry **) rr;
780 l = (struct directory_entry **) ll;
781 rpnt = (*r)->name;
782 lpnt = (*l)->name;
785 * If the entries are the same, this is an error.
787 if( strcmp(rpnt, lpnt) == 0 )
789 sort_goof++;
793 * Put the '.' and '..' entries on the head of the sorted list.
794 * For normal ASCII, this always happens to be the case, but out of
795 * band characters cause this not to be the case sometimes.
797 if( strcmp(rpnt, ".") == 0 ) return -1;
798 if( strcmp(lpnt, ".") == 0 ) return 1;
800 if( strcmp(rpnt, "..") == 0 ) return -1;
801 if( strcmp(lpnt, "..") == 0 ) return 1;
803 while(*rpnt && *lpnt)
805 if(*rpnt == ';' && *lpnt != ';') return -1;
806 if(*rpnt != ';' && *lpnt == ';') return 1;
808 if(*rpnt == ';' && *lpnt == ';') return 0;
811 * Extensions are not special here. Don't treat the dot as something that
812 * must be bumped to the start of the list.
814 #if 0
815 if(*rpnt == '.' && *lpnt != '.') return -1;
816 if(*rpnt != '.' && *lpnt == '.') return 1;
817 #endif
819 if(*rpnt < *lpnt) return -1;
820 if(*rpnt > *lpnt) return 1;
821 rpnt++; lpnt++;
823 if(*rpnt) return 1;
824 if(*lpnt) return -1;
825 return 0;
830 * Function: sort_directory
832 * Purpose: Sort the directory in the appropriate ISO9660
833 * order.
835 * Notes: Returns 0 if OK, returns > 0 if an error occurred.
837 static int FDECL1(joliet_sort_directory, struct directory_entry **, sort_dir)
839 int dcount = 0;
840 int i;
841 struct directory_entry * s_entry;
842 struct directory_entry ** sortlist;
844 s_entry = *sort_dir;
845 while(s_entry)
847 /* skip hidden entries */
848 if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY))
849 dcount++;
850 s_entry = s_entry->next;
854 * OK, now we know how many there are. Build a vector for sorting.
856 sortlist = (struct directory_entry **)
857 e_malloc(sizeof(struct directory_entry *) * dcount);
859 dcount = 0;
860 s_entry = *sort_dir;
861 while(s_entry)
863 /* skip hidden entries */
864 if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) {
865 sortlist[dcount] = s_entry;
866 dcount++;
868 s_entry = s_entry->next;
871 sort_goof = 0;
872 #ifdef __STDC__
873 qsort(sortlist, dcount, sizeof(struct directory_entry *),
874 (int (*)(const void *, const void *))joliet_compare_dirs);
875 #else
876 qsort(sortlist, dcount, sizeof(struct directory_entry *),
877 joliet_compare_dirs);
878 #endif
881 * Now reassemble the linked list in the proper sorted order
883 for(i=0; i<dcount-1; i++)
885 sortlist[i]->jnext = sortlist[i+1];
888 sortlist[dcount-1]->jnext = NULL;
889 *sort_dir = sortlist[0];
891 free(sortlist);
892 return sort_goof;
895 int FDECL1(joliet_sort_tree, struct directory *, node)
897 struct directory * dpnt;
898 int ret = 0;
900 dpnt = node;
902 while (dpnt){
903 ret = joliet_sort_n_finish(dpnt);
904 if( ret )
906 break;
908 if(dpnt->subdir) ret = joliet_sort_tree(dpnt->subdir);
909 if( ret )
911 break;
913 dpnt = dpnt->next;
915 return ret;
918 static void FDECL2(generate_joliet_directories, struct directory *, node, FILE*, outfile){
919 struct directory * dpnt;
921 dpnt = node;
923 while (dpnt)
925 if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
928 * In theory we should never reuse a directory, so this doesn't
929 * make much sense.
931 if( dpnt->jextent > session_start )
933 generate_one_joliet_directory(dpnt, outfile);
936 /* skip if hidden - but not for the rr_moved dir */
937 if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir))
938 generate_joliet_directories(dpnt->subdir, outfile);
939 dpnt = dpnt->next;
945 * Function to write the EVD for the disc.
947 static int FDECL1(jpathtab_write, FILE *, outfile)
950 * Next we write the path tables
952 xfwrite(jpath_table_l, 1, jpath_blocks << 11, outfile);
953 xfwrite(jpath_table_m, 1, jpath_blocks << 11, outfile);
954 last_extent_written += 2*jpath_blocks;
955 free(jpath_table_l);
956 free(jpath_table_m);
957 jpath_table_l = NULL;
958 jpath_table_m = NULL;
959 return 0;
962 static int FDECL1(jdirtree_size, int, starting_extent)
964 assign_joliet_directory_addresses(root);
965 return 0;
968 static int jroot_gen()
970 jroot_record.length[0] = 1 + sizeof(struct iso_directory_record)
971 - sizeof(jroot_record.name);
972 jroot_record.ext_attr_length[0] = 0;
973 set_733((char *) jroot_record.extent, root->jextent);
974 set_733((char *) jroot_record.size, ROUND_UP(root->jsize));
975 iso9660_date(jroot_record.date, root_statbuf.st_mtime);
976 jroot_record.flags[0] = 2;
977 jroot_record.file_unit_size[0] = 0;
978 jroot_record.interleave[0] = 0;
979 set_723(jroot_record.volume_sequence_number, volume_sequence_number);
980 jroot_record.name_len[0] = 1;
981 return 0;
984 static int FDECL1(jdirtree_write, FILE *, outfile)
986 generate_joliet_directories(root, outfile);
987 return 0;
991 * Function to write the EVD for the disc.
993 static int FDECL1(jvd_write, FILE *, outfile)
995 struct iso_primary_descriptor jvol_desc;
998 * Next we write out the boot volume descriptor for the disc
1000 jvol_desc = vol_desc;
1001 get_joliet_vol_desc(&jvol_desc);
1002 xfwrite(&jvol_desc, 1, 2048, outfile);
1003 last_extent_written ++;
1004 return 0;
1008 * Functions to describe padding block at the start of the disc.
1010 static int FDECL1(jpathtab_size, int, starting_extent)
1012 jpath_table[0] = starting_extent;
1013 jpath_table[1] = 0;
1014 jpath_table[2] = jpath_table[0] + jpath_blocks;
1015 jpath_table[3] = 0;
1017 last_extent += 2*jpath_blocks;
1018 return 0;
1021 struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen,jvd_write};
1022 struct output_fragment jpathtable_desc= {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write};
1023 struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write};