1457 lines
36 KiB
C
1457 lines
36 KiB
C
|
/* @(#)joliet.c 1.68 15/12/30 joerg */
|
||
|
#include <schily/mconfig.h>
|
||
|
#ifndef lint
|
||
|
static UConst char sccsid[] =
|
||
|
"@(#)joliet.c 1.68 15/12/30 joerg";
|
||
|
#endif
|
||
|
/*
|
||
|
* File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
|
||
|
*
|
||
|
* Copyright 1997 Eric Youngdale.
|
||
|
* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 22/2/2000
|
||
|
* Copyright (c) 1999-2015 J. Schilling
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||
|
* any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Joliet extensions for ISO9660. These are spottily documented by
|
||
|
* Microsoft. In their infinite stupidity, they completely ignored
|
||
|
* the possibility of using an SUSP record with the long filename
|
||
|
* in it, and instead wrote out a duplicate directory tree with the
|
||
|
* long filenames in it.
|
||
|
*
|
||
|
* I am not sure why they did this. One reason is that they get the path
|
||
|
* tables with the long filenames in them.
|
||
|
*
|
||
|
* There are two basic principles to Joliet, and the non-Unicode variant
|
||
|
* known as Romeo. Long filenames seem to be the main one, and the second
|
||
|
* is that the character set and a few other things is substantially relaxed.
|
||
|
*
|
||
|
* The SVD is identical to the PVD, except:
|
||
|
*
|
||
|
* Id is 2, not 1 (indicates SVD).
|
||
|
* escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
|
||
|
* The root directory record points to a different extent (with different
|
||
|
* size).
|
||
|
* There are different path tables for the two sets of directory trees.
|
||
|
*
|
||
|
* The Unicode level is coded in the SVD as follows:
|
||
|
*
|
||
|
* Standard Level ASCII escape code
|
||
|
* UCS-2 Level-1 %/@
|
||
|
* UCS-2 Level-2 %/C
|
||
|
* UCS-2 Level-3 %/E
|
||
|
*
|
||
|
* The following fields are recorded in Unicode:
|
||
|
* system_id
|
||
|
* volume_id
|
||
|
* volume_set_id
|
||
|
* publisher_id
|
||
|
* preparer_id
|
||
|
* application_id
|
||
|
* copyright_file_id
|
||
|
* abstract_file_id
|
||
|
* bibliographic_file_id
|
||
|
*
|
||
|
* Unicode strings are always encoded in big-endian format.
|
||
|
*
|
||
|
* In a directory record, everything is the same as with iso9660, except
|
||
|
* that the name is recorded in unicode. The name length is specified in
|
||
|
* total bytes, not in number of unicode characters.
|
||
|
*
|
||
|
* The character set used for the names is different with UCS - the
|
||
|
* restrictions are that the following are not allowed:
|
||
|
*
|
||
|
* Characters (00)(00) through (00)(1f) (control chars)
|
||
|
* (00)(2a) '*'
|
||
|
* (00)(2f) '/'
|
||
|
* (00)(3a) ':'
|
||
|
* (00)(3b) ';'
|
||
|
* (00)(3f) '?'
|
||
|
* (00)(5c) '\'
|
||
|
*/
|
||
|
#include "mkisofs.h"
|
||
|
#include <schily/time.h>
|
||
|
#include <schily/utypes.h>
|
||
|
#include <schily/intcvt.h>
|
||
|
#include <schily/schily.h>
|
||
|
#include <schily/errno.h>
|
||
|
|
||
|
LOCAL Uint jpath_table_index;
|
||
|
LOCAL struct directory **jpathlist;
|
||
|
LOCAL int next_jpath_index = 1;
|
||
|
LOCAL int jsort_goof;
|
||
|
LOCAL int jsort_glen;
|
||
|
|
||
|
LOCAL char ucs_codes[] = {
|
||
|
'\0', /* UCS-level 0 is illegal */
|
||
|
'@', /* UCS-level 1 */
|
||
|
'C', /* UCS-level 2 */
|
||
|
'E', /* UCS-level 3 */
|
||
|
};
|
||
|
|
||
|
#ifdef UDF
|
||
|
EXPORT void convert_to_unicode __PR((unsigned char *buffer,
|
||
|
int size, char *source,
|
||
|
siconvt_t *inls));
|
||
|
EXPORT int joliet_strlen __PR((const char *string, size_t maxlen,
|
||
|
siconvt_t *inls));
|
||
|
#else
|
||
|
LOCAL void convert_to_unicode __PR((unsigned char *buffer,
|
||
|
int size, char *source,
|
||
|
siconvt_t *inls));
|
||
|
LOCAL int joliet_strlen __PR((const char *string, size_t maxlen,
|
||
|
siconvt_t *inls));
|
||
|
#endif
|
||
|
LOCAL void get_joliet_vol_desc __PR((struct iso_primary_descriptor *jvol_desc));
|
||
|
LOCAL void assign_joliet_directory_addresses __PR((struct directory *node));
|
||
|
LOCAL void build_jpathlist __PR((struct directory *node));
|
||
|
LOCAL int joliet_compare_paths __PR((void const *r, void const *l));
|
||
|
LOCAL int generate_joliet_path_tables __PR((void));
|
||
|
LOCAL void generate_one_joliet_directory __PR((struct directory *dpnt,
|
||
|
FILE *outfile));
|
||
|
LOCAL int joliet_sort_n_finish __PR((struct directory *this_dir));
|
||
|
|
||
|
LOCAL int joliet_compare_dirs __PR((const void *rr, const void *ll));
|
||
|
|
||
|
LOCAL int joliet_sort_directory __PR((struct directory_entry **sort_dir));
|
||
|
EXPORT int joliet_sort_tree __PR((struct directory *node));
|
||
|
LOCAL void generate_joliet_directories __PR((struct directory *node,
|
||
|
FILE *outfile));
|
||
|
LOCAL int jpathtab_write __PR((FILE *outfile));
|
||
|
LOCAL int jdirtree_size __PR((UInt32_t starting_extent));
|
||
|
LOCAL int jroot_gen __PR((void));
|
||
|
LOCAL int jdirtree_write __PR((FILE *outfile));
|
||
|
LOCAL int jvd_write __PR((FILE *outfile));
|
||
|
LOCAL int jpathtab_size __PR((UInt32_t starting_extent));
|
||
|
|
||
|
/*
|
||
|
* conv_charset: convert to/from charsets via Unicode.
|
||
|
*
|
||
|
* Any unknown character is set to '_'
|
||
|
*
|
||
|
*/
|
||
|
EXPORT void
|
||
|
conv_charset(to, tosizep, from, fromsizep, inls, onls)
|
||
|
unsigned char *to;
|
||
|
size_t *tosizep;
|
||
|
unsigned char *from;
|
||
|
size_t *fromsizep;
|
||
|
siconvt_t *inls;
|
||
|
siconvt_t *onls;
|
||
|
{
|
||
|
UInt16_t unichar;
|
||
|
size_t fromsize = *fromsizep;
|
||
|
size_t tosize = *tosizep;
|
||
|
Uchar ob[2]; /* 2 octets (16 Bit) UCS-2 */
|
||
|
|
||
|
if (fromsize == 0 || tosize == 0)
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
* If we have a null mapping, just return the input character
|
||
|
*/
|
||
|
if (inls->sic_name == onls->sic_name) {
|
||
|
*to = *from;
|
||
|
(*fromsizep)--;
|
||
|
(*tosizep)--;
|
||
|
return;
|
||
|
}
|
||
|
#ifdef USE_ICONV
|
||
|
#ifdef HAVE_ICONV_CONST
|
||
|
#define __IC_CONST const
|
||
|
#else
|
||
|
#define __IC_CONST
|
||
|
#endif
|
||
|
if (use_iconv(inls)) {
|
||
|
char *obuf = (char *)ob;
|
||
|
size_t osize = 2; /* UCS-2 character size */
|
||
|
|
||
|
if (iconv(inls->sic_cd2uni, (__IC_CONST char **)&from,
|
||
|
fromsizep,
|
||
|
&obuf, &osize) == -1) {
|
||
|
int err = geterrno();
|
||
|
|
||
|
if ((err == EINVAL || err == EILSEQ) &&
|
||
|
*fromsizep == fromsize) {
|
||
|
ob[0] = 0; ob[1] = '_';
|
||
|
(*fromsizep)--;
|
||
|
}
|
||
|
}
|
||
|
unichar = ob[0] * 256 + ob[1]; /* Compute 16 Bit UCS-2 char */
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
unsigned char c = *from;
|
||
|
|
||
|
unichar = sic_c2uni(inls, c); /* Get the UNICODE char */
|
||
|
(*fromsizep)--;
|
||
|
|
||
|
if (unichar == 0)
|
||
|
unichar = '_';
|
||
|
|
||
|
ob[0] = unichar >> 8 & 0xFF; /* Compute 2 octet variant */
|
||
|
ob[1] = unichar & 0xFF;
|
||
|
}
|
||
|
|
||
|
#ifdef USE_ICONV
|
||
|
if (use_iconv(onls)) {
|
||
|
char *ibuf = (char *)ob;
|
||
|
size_t isize = 2; /* UCS-2 character size */
|
||
|
|
||
|
if (iconv(onls->sic_uni2cd, (__IC_CONST char **)&ibuf, &isize,
|
||
|
(char **)&to, tosizep) == -1) {
|
||
|
int err = geterrno();
|
||
|
|
||
|
if ((err == EINVAL || err == EILSEQ) &&
|
||
|
*tosizep == tosize) {
|
||
|
*to = '_';
|
||
|
(*tosizep)--;
|
||
|
}
|
||
|
}
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
*to = sic_uni2c(onls, unichar); /* Get the backconverted char */
|
||
|
(*tosizep)--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Function: convert_to_unicode
|
||
|
*
|
||
|
* Purpose: Perform a unicode conversion on a text string
|
||
|
* using the supplied input character set.
|
||
|
*
|
||
|
* Notes:
|
||
|
*/
|
||
|
#ifdef UDF
|
||
|
EXPORT void
|
||
|
#else
|
||
|
LOCAL void
|
||
|
#endif
|
||
|
convert_to_unicode(buffer, size, source, inls)
|
||
|
unsigned char *buffer;
|
||
|
int size;
|
||
|
char *source;
|
||
|
siconvt_t *inls;
|
||
|
{
|
||
|
unsigned char *tmpbuf;
|
||
|
int i;
|
||
|
int j;
|
||
|
UInt16_t unichar;
|
||
|
unsigned char uc;
|
||
|
int jsize = size;
|
||
|
|
||
|
/*
|
||
|
* If we get a NULL pointer for the source, it means we have an
|
||
|
* inplace copy, and we need to make a temporary working copy first.
|
||
|
*/
|
||
|
if (source == NULL) {
|
||
|
tmpbuf = (Uchar *) e_malloc(size);
|
||
|
memcpy(tmpbuf, buffer, size);
|
||
|
} else {
|
||
|
tmpbuf = (Uchar *) source;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Now start copying characters. If the size was specified to be 0,
|
||
|
* then assume the input was 0 terminated.
|
||
|
*/
|
||
|
j = 0;
|
||
|
for (i = 0; (i + 1) < size; i += 2, j++) { /* Size may be odd! */
|
||
|
/*
|
||
|
* Let all valid unicode characters pass
|
||
|
* through (according to charset). Others are set to '_' .
|
||
|
*/
|
||
|
if (j < jsize)
|
||
|
uc = tmpbuf[j]; /* temporary copy */
|
||
|
else
|
||
|
uc = '\0';
|
||
|
if (uc == '\0') {
|
||
|
jsize = j;
|
||
|
unichar = 0;
|
||
|
} else { /* must be converted */
|
||
|
#ifdef USE_ICONV
|
||
|
if (use_iconv(inls)) {
|
||
|
Uchar ob[2];
|
||
|
__IC_CONST char *inbuf = (char *)&tmpbuf[j];
|
||
|
size_t isize = 3;
|
||
|
char *obuf = (char *)ob;
|
||
|
size_t osize = 2;
|
||
|
|
||
|
/*
|
||
|
* iconv() from glibc ignores osize and thus
|
||
|
* may try to access more than a single multi
|
||
|
* byte character from the input and read from
|
||
|
* non-existent memory.
|
||
|
*/
|
||
|
if (iconv(inls->sic_cd2uni, &inbuf, &isize,
|
||
|
&obuf, &osize) == -1) {
|
||
|
int err = geterrno();
|
||
|
|
||
|
if ((err == EINVAL || err == EILSEQ) &&
|
||
|
isize == 3) {
|
||
|
ob[0] = ob[1] = 0;
|
||
|
isize--;
|
||
|
}
|
||
|
}
|
||
|
unichar = ob[0] * 256 + ob[1];
|
||
|
j += 2 - isize;
|
||
|
} else
|
||
|
#endif
|
||
|
unichar = sic_c2uni(inls, uc); /* Get the UNICODE */
|
||
|
|
||
|
/*
|
||
|
* This code is currently also used for UDF formatting.
|
||
|
* Do not enforce silly Microsoft limitations in case
|
||
|
* that we only create UDF extensions.
|
||
|
*/
|
||
|
if (!use_Joliet)
|
||
|
goto all_chars;
|
||
|
|
||
|
if (unichar <= 0x1f || unichar == 0x7f)
|
||
|
unichar = '\0'; /* control char */
|
||
|
|
||
|
switch (unichar) { /* test special characters */
|
||
|
|
||
|
case '*':
|
||
|
case '/':
|
||
|
case ':':
|
||
|
case ';':
|
||
|
case '?':
|
||
|
case '\\':
|
||
|
case '\0': /* illegal char mark */
|
||
|
/*
|
||
|
* Even Joliet has some standards as to what is
|
||
|
* allowed in a pathname. Pretty tame in
|
||
|
* comparison to what DOS restricts you to.
|
||
|
*/
|
||
|
unichar = '_';
|
||
|
}
|
||
|
all_chars:
|
||
|
;
|
||
|
}
|
||
|
buffer[i] = unichar >> 8 & 0xFF; /* final UNICODE */
|
||
|
buffer[i + 1] = unichar & 0xFF; /* conversion */
|
||
|
}
|
||
|
|
||
|
if (size & 1) { /* beautification */
|
||
|
buffer[size - 1] = 0;
|
||
|
}
|
||
|
if (source == NULL) {
|
||
|
free(tmpbuf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: joliet_strlen
|
||
|
*
|
||
|
* Purpose: Return length in bytes of string after conversion to unicode.
|
||
|
*
|
||
|
* Notes: This is provided mainly as a convenience so that when more
|
||
|
* intelligent Unicode conversion for either Multibyte or 8-bit
|
||
|
* codes is available that we can easily adapt.
|
||
|
*/
|
||
|
#ifdef UDF
|
||
|
EXPORT int
|
||
|
#else
|
||
|
LOCAL int
|
||
|
#endif
|
||
|
joliet_strlen(string, maxlen, inls)
|
||
|
const char *string;
|
||
|
size_t maxlen;
|
||
|
siconvt_t *inls;
|
||
|
{
|
||
|
int rtn = 0;
|
||
|
|
||
|
#ifdef USE_ICONV
|
||
|
if (use_iconv(inls)) {
|
||
|
int j = 0;
|
||
|
|
||
|
while (string[j] != '\0') {
|
||
|
Uchar ob[2];
|
||
|
__IC_CONST char *inbuf = (char *)&string[j];
|
||
|
size_t isize = 3;
|
||
|
char *obuf = (char *)ob;
|
||
|
size_t osize = 2;
|
||
|
|
||
|
/*
|
||
|
* iconv() from glibc ignores osize and thus
|
||
|
* may try to access more than a single multi
|
||
|
* byte character from the input and read from
|
||
|
* non-existent memory.
|
||
|
*/
|
||
|
if (iconv(inls->sic_cd2uni, &inbuf, &isize,
|
||
|
&obuf, &osize) == -1) {
|
||
|
int err = geterrno();
|
||
|
|
||
|
if ((err == EINVAL || err == EILSEQ) &&
|
||
|
isize == 3) {
|
||
|
ob[0] = ob[1] = 0;
|
||
|
isize--;
|
||
|
}
|
||
|
}
|
||
|
j += 3 - isize;
|
||
|
rtn += 2;
|
||
|
}
|
||
|
} else
|
||
|
#endif
|
||
|
rtn = strlen(string) << 1;
|
||
|
|
||
|
/*
|
||
|
* We do clamp the maximum length of a Joliet or UDF string to be the
|
||
|
* maximum path size.
|
||
|
*/
|
||
|
if (rtn > 2*maxlen) {
|
||
|
rtn = 2*maxlen;
|
||
|
}
|
||
|
return (rtn);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: get_joliet_vol_desc
|
||
|
*
|
||
|
* Purpose: generate a Joliet compatible volume desc.
|
||
|
*
|
||
|
* Notes: Assume that we have the non-joliet vol desc
|
||
|
* already present in the buffer. Just modifiy the
|
||
|
* appropriate fields.
|
||
|
*/
|
||
|
LOCAL void
|
||
|
get_joliet_vol_desc(jvol_desc)
|
||
|
struct iso_primary_descriptor *jvol_desc;
|
||
|
{
|
||
|
jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
|
||
|
jvol_desc->version[0] = 1;
|
||
|
jvol_desc->file_structure_version[0] = 1;
|
||
|
/*
|
||
|
* For now, always do Unicode level 3.
|
||
|
* I don't really know what 1 and 2 are - perhaps a more limited
|
||
|
* Unicode set.
|
||
|
* FIXME(eric) - how does Romeo fit in here?
|
||
|
*/
|
||
|
sprintf(jvol_desc->escape_sequences, "%%/%c", ucs_codes[ucs_level]);
|
||
|
|
||
|
/* Until we have Unicode path tables, leave these unset. */
|
||
|
set_733((char *)jvol_desc->path_table_size, jpath_table_size);
|
||
|
set_731(jvol_desc->type_l_path_table, jpath_table[0]);
|
||
|
set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]);
|
||
|
set_732(jvol_desc->type_m_path_table, jpath_table[2]);
|
||
|
set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]);
|
||
|
|
||
|
/* Set this one up. */
|
||
|
memcpy(jvol_desc->root_directory_record, &jroot_record,
|
||
|
offsetof(struct iso_directory_record, name[0]) + 1);
|
||
|
|
||
|
/*
|
||
|
* Finally, we have a bunch of strings to convert to Unicode.
|
||
|
* FIXME(eric) - I don't know how to do this in general,
|
||
|
* so we will just be really lazy and do a char -> short conversion.
|
||
|
* We probably will want to filter any characters >= 0x80.
|
||
|
*/
|
||
|
convert_to_unicode((Uchar *)jvol_desc->system_id,
|
||
|
sizeof (jvol_desc->system_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->volume_id,
|
||
|
sizeof (jvol_desc->volume_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->volume_set_id,
|
||
|
sizeof (jvol_desc->volume_set_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->publisher_id,
|
||
|
sizeof (jvol_desc->publisher_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->preparer_id,
|
||
|
sizeof (jvol_desc->preparer_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->application_id,
|
||
|
sizeof (jvol_desc->application_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->copyright_file_id,
|
||
|
sizeof (jvol_desc->copyright_file_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->abstract_file_id,
|
||
|
sizeof (jvol_desc->abstract_file_id), NULL, in_nls);
|
||
|
convert_to_unicode((Uchar *)jvol_desc->bibliographic_file_id,
|
||
|
sizeof (jvol_desc->bibliographic_file_id), NULL, in_nls);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Asssign Joliet & UDF addresses
|
||
|
* We ignore all files that are neither in the Joliet nor in the UDF tree
|
||
|
*/
|
||
|
LOCAL void
|
||
|
assign_joliet_directory_addresses(node)
|
||
|
struct directory *node;
|
||
|
{
|
||
|
int dir_size;
|
||
|
struct directory *dpnt;
|
||
|
|
||
|
dpnt = node;
|
||
|
|
||
|
while (dpnt) {
|
||
|
if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
|
||
|
/*
|
||
|
* If we already have an extent for this
|
||
|
* (i.e. it came from a multisession disc), then
|
||
|
* don't reassign a new extent.
|
||
|
*/
|
||
|
dpnt->jpath_index = next_jpath_index++;
|
||
|
if (dpnt->jextent == 0) {
|
||
|
dpnt->jextent = last_extent;
|
||
|
dir_size = ISO_BLOCKS(dpnt->jsize);
|
||
|
last_extent += dir_size;
|
||
|
}
|
||
|
}
|
||
|
/* skip if hidden - but not for the rr_moved dir */
|
||
|
if (dpnt->subdir &&
|
||
|
((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ||
|
||
|
dpnt == reloc_dir)) {
|
||
|
assign_joliet_directory_addresses(dpnt->subdir);
|
||
|
}
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LOCAL void
|
||
|
build_jpathlist(node)
|
||
|
struct directory *node;
|
||
|
{
|
||
|
struct directory *dpnt;
|
||
|
|
||
|
dpnt = node;
|
||
|
|
||
|
while (dpnt) {
|
||
|
if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
|
||
|
jpathlist[dpnt->jpath_index] = dpnt;
|
||
|
}
|
||
|
if (dpnt->subdir)
|
||
|
build_jpathlist(dpnt->subdir);
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
} /* build_jpathlist(... */
|
||
|
|
||
|
LOCAL int
|
||
|
joliet_compare_paths(r, l)
|
||
|
void const *r;
|
||
|
void const *l;
|
||
|
{
|
||
|
struct directory const *ll = *(struct directory * const *) l;
|
||
|
struct directory const *rr = *(struct directory * const *) r;
|
||
|
int rparent,
|
||
|
lparent;
|
||
|
char *rpnt,
|
||
|
*lpnt;
|
||
|
unsigned char rtmp[2],
|
||
|
ltmp[2];
|
||
|
siconvt_t *rinls, *linls;
|
||
|
|
||
|
/* make sure root directory is first */
|
||
|
if (rr == root)
|
||
|
return (-1);
|
||
|
|
||
|
if (ll == root)
|
||
|
return (1);
|
||
|
|
||
|
rparent = rr->parent->jpath_index;
|
||
|
lparent = ll->parent->jpath_index;
|
||
|
if (rr->parent == reloc_dir) {
|
||
|
rparent = rr->self->parent_rec->filedir->jpath_index;
|
||
|
}
|
||
|
if (ll->parent == reloc_dir) {
|
||
|
lparent = ll->self->parent_rec->filedir->jpath_index;
|
||
|
}
|
||
|
if (rparent < lparent) {
|
||
|
return (-1);
|
||
|
}
|
||
|
if (rparent > lparent) {
|
||
|
return (1);
|
||
|
}
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* we may be using the HFS name - so select the correct input
|
||
|
* charset
|
||
|
*/
|
||
|
if (USE_MAC_NAME(rr->self)) {
|
||
|
rpnt = rr->self->hfs_ent->name;
|
||
|
rinls = hfs_inls;
|
||
|
} else {
|
||
|
rpnt = rr->self->name;
|
||
|
rinls = in_nls;
|
||
|
}
|
||
|
|
||
|
if (USE_MAC_NAME(ll->self)) {
|
||
|
lpnt = ll->self->hfs_ent->name;
|
||
|
linls = hfs_inls;
|
||
|
} else {
|
||
|
lpnt = ll->self->name;
|
||
|
linls = in_nls;
|
||
|
}
|
||
|
#else
|
||
|
rpnt = rr->self->name;
|
||
|
lpnt = ll->self->name;
|
||
|
linls = rinls = in_nls;
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
/* compare the Unicode names */
|
||
|
|
||
|
while (*rpnt && *lpnt) {
|
||
|
convert_to_unicode(rtmp, 2, rpnt, rinls);
|
||
|
convert_to_unicode(ltmp, 2, lpnt, linls);
|
||
|
|
||
|
if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
|
||
|
return (-1);
|
||
|
if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
|
||
|
return (1);
|
||
|
|
||
|
rpnt++;
|
||
|
lpnt++;
|
||
|
}
|
||
|
|
||
|
if (*rpnt)
|
||
|
return (1);
|
||
|
if (*lpnt)
|
||
|
return (-1);
|
||
|
|
||
|
return (0);
|
||
|
|
||
|
} /* compare_paths(... */
|
||
|
|
||
|
LOCAL int
|
||
|
generate_joliet_path_tables()
|
||
|
{
|
||
|
struct directory_entry *de;
|
||
|
struct directory *dpnt;
|
||
|
int fix;
|
||
|
int j;
|
||
|
int namelen;
|
||
|
char *npnt;
|
||
|
char *npnt1;
|
||
|
int tablesize;
|
||
|
unsigned int jpindex;
|
||
|
|
||
|
/* First allocate memory for the tables and initialize the memory */
|
||
|
tablesize = jpath_blocks << 11;
|
||
|
jpath_table_m = (char *)e_malloc(tablesize);
|
||
|
jpath_table_l = (char *)e_malloc(tablesize);
|
||
|
memset(jpath_table_l, 0, tablesize);
|
||
|
memset(jpath_table_m, 0, tablesize);
|
||
|
|
||
|
/* Now start filling in the path tables. Start with root directory */
|
||
|
jpath_table_index = 0;
|
||
|
jpathlist = (struct directory **)e_malloc(sizeof (struct directory *)
|
||
|
* next_jpath_index);
|
||
|
memset(jpathlist, 0, sizeof (struct directory *) * next_jpath_index);
|
||
|
build_jpathlist(root);
|
||
|
|
||
|
do {
|
||
|
fix = 0;
|
||
|
#ifdef PROTOTYPES
|
||
|
qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
|
||
|
(int (*) (const void *, const void *)) joliet_compare_paths);
|
||
|
#else
|
||
|
qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
|
||
|
joliet_compare_paths);
|
||
|
#endif
|
||
|
|
||
|
for (j = 1; j < next_jpath_index; j++) {
|
||
|
if (jpathlist[j]->jpath_index != j) {
|
||
|
jpathlist[j]->jpath_index = j;
|
||
|
fix++;
|
||
|
}
|
||
|
}
|
||
|
} while (fix);
|
||
|
|
||
|
for (j = 1; j < next_jpath_index; j++) {
|
||
|
dpnt = jpathlist[j];
|
||
|
if (!dpnt) {
|
||
|
comerrno(EX_BAD, _("Entry %d not in path tables\n"), j);
|
||
|
}
|
||
|
npnt = dpnt->de_name;
|
||
|
|
||
|
npnt1 = strrchr(npnt, PATH_SEPARATOR);
|
||
|
if (npnt1) {
|
||
|
npnt = npnt1 + 1;
|
||
|
}
|
||
|
de = dpnt->self;
|
||
|
if (!de) {
|
||
|
comerrno(EX_BAD,
|
||
|
_("Fatal Joliet goof - directory has amnesia\n"));
|
||
|
}
|
||
|
#ifdef APPLE_HYB
|
||
|
if (USE_MAC_NAME(de))
|
||
|
namelen = joliet_strlen(de->hfs_ent->name, jlen, hfs_inls);
|
||
|
else
|
||
|
#endif /* APPLE_HYB */
|
||
|
namelen = joliet_strlen(de->name, jlen, in_nls);
|
||
|
|
||
|
if (dpnt == root) {
|
||
|
jpath_table_l[jpath_table_index] = 1;
|
||
|
jpath_table_m[jpath_table_index] = 1;
|
||
|
} else {
|
||
|
jpath_table_l[jpath_table_index] = namelen;
|
||
|
jpath_table_m[jpath_table_index] = namelen;
|
||
|
}
|
||
|
jpath_table_index += 2;
|
||
|
|
||
|
set_731(jpath_table_l + jpath_table_index, dpnt->jextent);
|
||
|
set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
|
||
|
jpath_table_index += 4;
|
||
|
|
||
|
|
||
|
if (dpnt->parent != reloc_dir) {
|
||
|
set_721(jpath_table_l + jpath_table_index,
|
||
|
dpnt->parent->jpath_index);
|
||
|
set_722(jpath_table_m + jpath_table_index,
|
||
|
dpnt->parent->jpath_index);
|
||
|
jpindex = dpnt->parent->jpath_index;
|
||
|
} else {
|
||
|
set_721(jpath_table_l + jpath_table_index,
|
||
|
dpnt->self->parent_rec->filedir->jpath_index);
|
||
|
set_722(jpath_table_m + jpath_table_index,
|
||
|
dpnt->self->parent_rec->filedir->jpath_index);
|
||
|
jpindex = dpnt->self->parent_rec->filedir->jpath_index;
|
||
|
}
|
||
|
|
||
|
if (jpindex > 0xffff) {
|
||
|
static int warned = 0;
|
||
|
|
||
|
if (!warned) {
|
||
|
warned++;
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Unable to generate sane Joliet path tables - too many directories (%u)\n"),
|
||
|
jpindex);
|
||
|
if (!nolimitpathtables)
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Try to use the option -no-limit-pathtables\n"));
|
||
|
}
|
||
|
if (!nolimitpathtables)
|
||
|
exit(EX_BAD);
|
||
|
/*
|
||
|
* Let it point to the root directory instead.
|
||
|
*/
|
||
|
set_721(jpath_table_l + jpath_table_index, 1);
|
||
|
set_722(jpath_table_m + jpath_table_index, 1);
|
||
|
}
|
||
|
|
||
|
jpath_table_index += 2;
|
||
|
|
||
|
/*
|
||
|
* The root directory is still represented in non-unicode
|
||
|
* fashion.
|
||
|
*/
|
||
|
if (dpnt == root) {
|
||
|
jpath_table_l[jpath_table_index] = 0;
|
||
|
jpath_table_m[jpath_table_index] = 0;
|
||
|
jpath_table_index++;
|
||
|
} else {
|
||
|
#ifdef APPLE_HYB
|
||
|
if (USE_MAC_NAME(de)) {
|
||
|
convert_to_unicode((Uchar *) jpath_table_l +
|
||
|
jpath_table_index,
|
||
|
namelen, de->hfs_ent->name, hfs_inls);
|
||
|
convert_to_unicode((Uchar *) jpath_table_m +
|
||
|
jpath_table_index,
|
||
|
namelen, de->hfs_ent->name, hfs_inls);
|
||
|
} else {
|
||
|
#endif /* APPLE_HYB */
|
||
|
convert_to_unicode((Uchar *) jpath_table_l +
|
||
|
jpath_table_index,
|
||
|
namelen, de->name, in_nls);
|
||
|
convert_to_unicode((Uchar *) jpath_table_m +
|
||
|
jpath_table_index,
|
||
|
namelen, de->name, in_nls);
|
||
|
#ifdef APPLE_HYB
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
jpath_table_index += namelen;
|
||
|
}
|
||
|
|
||
|
if (jpath_table_index & 1) {
|
||
|
jpath_table_index++; /* For odd lengths we pad */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(jpathlist);
|
||
|
if (jpath_table_index != jpath_table_size) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Joliet path table lengths do not match %d expected: %d\n"),
|
||
|
jpath_table_index,
|
||
|
jpath_table_size);
|
||
|
}
|
||
|
return (0);
|
||
|
} /* generate_path_tables(... */
|
||
|
|
||
|
LOCAL void
|
||
|
generate_one_joliet_directory(dpnt, outfile)
|
||
|
struct directory *dpnt;
|
||
|
FILE *outfile;
|
||
|
{
|
||
|
unsigned int dir_index;
|
||
|
char *directory_buffer;
|
||
|
int new_reclen;
|
||
|
struct directory_entry *s_entry;
|
||
|
struct directory_entry *s_entry1;
|
||
|
struct iso_directory_record jrec;
|
||
|
unsigned int total_size;
|
||
|
int cvt_len;
|
||
|
struct directory *finddir;
|
||
|
|
||
|
total_size = ISO_ROUND_UP(dpnt->jsize);
|
||
|
directory_buffer = (char *)e_malloc(total_size);
|
||
|
memset(directory_buffer, 0, total_size);
|
||
|
dir_index = 0;
|
||
|
|
||
|
s_entry = dpnt->jcontents;
|
||
|
while (s_entry) {
|
||
|
if (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
|
||
|
s_entry = s_entry->jnext;
|
||
|
continue;
|
||
|
}
|
||
|
/*
|
||
|
* If this entry was a directory that was relocated,
|
||
|
* we have a bit of trouble here. We need to dig out the real
|
||
|
* thing and put it back here. In the Joliet tree, there is
|
||
|
* no relocated rock ridge, as there are no depth limits to a
|
||
|
* directory tree.
|
||
|
*/
|
||
|
if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
|
||
|
for (s_entry1 = reloc_dir->contents; s_entry1;
|
||
|
s_entry1 = s_entry1->next) {
|
||
|
if (s_entry1->parent_rec == s_entry) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (s_entry1 == NULL) {
|
||
|
/* We got trouble. */
|
||
|
comerrno(EX_BAD,
|
||
|
_("Unable to locate relocated directory\n"));
|
||
|
}
|
||
|
} else {
|
||
|
s_entry1 = s_entry;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* We do not allow directory entries to cross sector
|
||
|
* boundaries. Simply pad, and then start the next entry at
|
||
|
* the next sector
|
||
|
*/
|
||
|
new_reclen = s_entry1->jreclen;
|
||
|
if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) {
|
||
|
dir_index = ISO_ROUND_UP(dir_index);
|
||
|
}
|
||
|
memcpy(&jrec, &s_entry1->isorec, offsetof(struct iso_directory_record, name[0]));
|
||
|
|
||
|
#ifdef APPLE_HYB
|
||
|
/* Use the HFS name if it exists */
|
||
|
if (USE_MAC_NAME(s_entry1))
|
||
|
cvt_len = joliet_strlen(s_entry1->hfs_ent->name, jlen, hfs_inls);
|
||
|
else
|
||
|
#endif /* APPLE_HYB */
|
||
|
cvt_len = joliet_strlen(s_entry1->name, jlen, in_nls);
|
||
|
|
||
|
/*
|
||
|
* Fix the record length
|
||
|
* - this was the non-Joliet version we were seeing.
|
||
|
*/
|
||
|
jrec.name_len[0] = cvt_len;
|
||
|
jrec.length[0] = s_entry1->jreclen;
|
||
|
|
||
|
/*
|
||
|
* If this is a directory,
|
||
|
* fix the correct size and extent number.
|
||
|
*/
|
||
|
if ((jrec.flags[0] & ISO_DIRECTORY) != 0) {
|
||
|
if (strcmp(s_entry1->name, ".") == 0) {
|
||
|
jrec.name_len[0] = 1;
|
||
|
set_733((char *)jrec.extent, dpnt->jextent);
|
||
|
set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->jsize));
|
||
|
} else if (strcmp(s_entry1->name, "..") == 0) {
|
||
|
jrec.name_len[0] = 1;
|
||
|
if (dpnt->parent == reloc_dir) {
|
||
|
set_733((char *)jrec.extent, dpnt->self->parent_rec->filedir->jextent);
|
||
|
set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
|
||
|
} else {
|
||
|
set_733((char *)jrec.extent, dpnt->parent->jextent);
|
||
|
set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->parent->jsize));
|
||
|
}
|
||
|
} else {
|
||
|
if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
|
||
|
finddir = reloc_dir->subdir;
|
||
|
} else {
|
||
|
finddir = dpnt->subdir;
|
||
|
}
|
||
|
while (finddir && finddir->self != s_entry1) {
|
||
|
finddir = finddir->next;
|
||
|
}
|
||
|
if (!finddir) {
|
||
|
comerrno(EX_BAD,
|
||
|
_("Fatal goof - unable to find directory location\n"));
|
||
|
}
|
||
|
set_733((char *)jrec.extent, finddir->jextent);
|
||
|
set_733((char *)jrec.size,
|
||
|
ISO_ROUND_UP(finddir->jsize));
|
||
|
}
|
||
|
}
|
||
|
memcpy(directory_buffer + dir_index, &jrec,
|
||
|
offsetof(struct iso_directory_record, name[0]));
|
||
|
|
||
|
dir_index += offsetof(struct iso_directory_record, name[0]);
|
||
|
|
||
|
/*
|
||
|
* Finally dump the Unicode version of the filename.
|
||
|
* Note - . and .. are the same as with non-Joliet discs.
|
||
|
*/
|
||
|
if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
|
||
|
strcmp(s_entry1->name, ".") == 0) {
|
||
|
directory_buffer[dir_index++] = 0;
|
||
|
} else if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
|
||
|
strcmp(s_entry1->name, "..") == 0) {
|
||
|
directory_buffer[dir_index++] = 1;
|
||
|
} else {
|
||
|
#ifdef APPLE_HYB
|
||
|
if (USE_MAC_NAME(s_entry1)) {
|
||
|
/* Use the HFS name if it exists */
|
||
|
convert_to_unicode(
|
||
|
(Uchar *) directory_buffer+dir_index,
|
||
|
cvt_len,
|
||
|
s_entry1->hfs_ent->name, hfs_inls);
|
||
|
} else
|
||
|
#endif /* APPLE_HYB */
|
||
|
{
|
||
|
convert_to_unicode(
|
||
|
(Uchar *) directory_buffer+dir_index,
|
||
|
cvt_len,
|
||
|
s_entry1->name, in_nls);
|
||
|
}
|
||
|
dir_index += cvt_len;
|
||
|
}
|
||
|
|
||
|
if (dir_index & 1) {
|
||
|
directory_buffer[dir_index++] = 0;
|
||
|
}
|
||
|
s_entry = s_entry->jnext;
|
||
|
}
|
||
|
|
||
|
if (dpnt->jsize != dir_index) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Unexpected joliet directory length %d expected: %d '%s'\n"),
|
||
|
dpnt->jsize,
|
||
|
dir_index, dpnt->de_name);
|
||
|
}
|
||
|
xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
|
||
|
last_extent_written += total_size >> 11;
|
||
|
free(directory_buffer);
|
||
|
} /* generate_one_joliet_directory(... */
|
||
|
|
||
|
LOCAL int
|
||
|
joliet_sort_n_finish(this_dir)
|
||
|
struct directory *this_dir;
|
||
|
{
|
||
|
struct directory_entry *s_entry;
|
||
|
int status = 0;
|
||
|
|
||
|
/*
|
||
|
* don't want to skip this directory if it's the reloc_dir
|
||
|
* at the moment
|
||
|
*/
|
||
|
if (this_dir != reloc_dir &&
|
||
|
this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
|
||
|
return (0);
|
||
|
}
|
||
|
for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
|
||
|
/* skip hidden entries */
|
||
|
if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
|
||
|
continue;
|
||
|
}
|
||
|
/*
|
||
|
* First update the path table sizes for directories.
|
||
|
*
|
||
|
* Finally, set the length of the directory entry if Joliet is
|
||
|
* used. The name is longer, but no Rock Ridge is ever used
|
||
|
* here, so depending upon the options the entry size might
|
||
|
* turn out to be about the same. The Unicode name is always
|
||
|
* a multiple of 2 bytes, so we always add 1 to make it an
|
||
|
* even number.
|
||
|
*/
|
||
|
if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
|
||
|
if (strcmp(s_entry->name, ".") != 0 &&
|
||
|
strcmp(s_entry->name, "..") != 0) {
|
||
|
#ifdef APPLE_HYB
|
||
|
if (USE_MAC_NAME(s_entry))
|
||
|
/* Use the HFS name if it exists */
|
||
|
jpath_table_size +=
|
||
|
joliet_strlen(s_entry->hfs_ent->name, jlen, hfs_inls) +
|
||
|
offsetof(struct iso_path_table, name[0]);
|
||
|
else
|
||
|
#endif /* APPLE_HYB */
|
||
|
jpath_table_size +=
|
||
|
joliet_strlen(s_entry->name, jlen, in_nls) +
|
||
|
offsetof(struct iso_path_table, name[0]);
|
||
|
if (jpath_table_size & 1) {
|
||
|
jpath_table_size++;
|
||
|
}
|
||
|
} else {
|
||
|
if (this_dir == root &&
|
||
|
strlen(s_entry->name) == 1) {
|
||
|
|
||
|
jpath_table_size += 1 + offsetof(struct iso_path_table, name[0]);
|
||
|
if (jpath_table_size & 1)
|
||
|
jpath_table_size++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (strcmp(s_entry->name, ".") != 0 &&
|
||
|
strcmp(s_entry->name, "..") != 0) {
|
||
|
#ifdef APPLE_HYB
|
||
|
if (USE_MAC_NAME(s_entry))
|
||
|
/* Use the HFS name if it exists */
|
||
|
s_entry->jreclen =
|
||
|
offsetof(struct iso_directory_record, name[0])
|
||
|
+ joliet_strlen(s_entry->hfs_ent->name, jlen, hfs_inls)
|
||
|
+ 1;
|
||
|
else
|
||
|
#endif /* APPLE_HYB */
|
||
|
s_entry->jreclen =
|
||
|
offsetof(struct iso_directory_record, name[0])
|
||
|
+ joliet_strlen(s_entry->name, jlen, in_nls)
|
||
|
+ 1;
|
||
|
} else {
|
||
|
/*
|
||
|
* Special - for '.' and '..' we generate the same
|
||
|
* records we did for non-Joliet discs.
|
||
|
*/
|
||
|
s_entry->jreclen =
|
||
|
offsetof(struct iso_directory_record, name[0])
|
||
|
+ 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0) {
|
||
|
return (0);
|
||
|
}
|
||
|
this_dir->jcontents = this_dir->contents;
|
||
|
status = joliet_sort_directory(&this_dir->jcontents);
|
||
|
|
||
|
/*
|
||
|
* Now go through the directory and figure out how large this one will
|
||
|
* be. Do not split a directory entry across a sector boundary
|
||
|
*/
|
||
|
s_entry = this_dir->jcontents;
|
||
|
/*
|
||
|
* XXX Is it ok to comment this out?
|
||
|
*/
|
||
|
/*XXX JS this_dir->ce_bytes = 0;*/
|
||
|
for (s_entry = this_dir->jcontents; s_entry;
|
||
|
s_entry = s_entry->jnext) {
|
||
|
int jreclen;
|
||
|
|
||
|
if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
|
||
|
continue;
|
||
|
}
|
||
|
jreclen = s_entry->jreclen;
|
||
|
|
||
|
if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >=
|
||
|
SECTOR_SIZE) {
|
||
|
this_dir->jsize = ISO_ROUND_UP(this_dir->jsize);
|
||
|
}
|
||
|
this_dir->jsize += jreclen;
|
||
|
}
|
||
|
return (status);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Similar to the iso9660 case,
|
||
|
* except here we perform a full sort based upon the
|
||
|
* regular name of the file, not the 8.3 version.
|
||
|
*/
|
||
|
LOCAL int
|
||
|
joliet_compare_dirs(rr, ll)
|
||
|
const void *rr;
|
||
|
const void *ll;
|
||
|
{
|
||
|
char *rpnt,
|
||
|
*lpnt;
|
||
|
struct directory_entry **r,
|
||
|
**l;
|
||
|
unsigned char rtmp[2],
|
||
|
ltmp[2];
|
||
|
siconvt_t *linls, *rinls;
|
||
|
|
||
|
r = (struct directory_entry **)rr;
|
||
|
l = (struct directory_entry **)ll;
|
||
|
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* we may be using the HFS name - so select the correct input
|
||
|
* charset
|
||
|
*/
|
||
|
if (USE_MAC_NAME(*r)) {
|
||
|
rpnt = (*r)->hfs_ent->name;
|
||
|
rinls = hfs_inls;
|
||
|
} else {
|
||
|
rpnt = (*r)->name;
|
||
|
rinls = in_nls;
|
||
|
}
|
||
|
|
||
|
if (USE_MAC_NAME(*l)) {
|
||
|
lpnt = (*l)->hfs_ent->name;
|
||
|
linls = hfs_inls;
|
||
|
} else {
|
||
|
lpnt = (*l)->name;
|
||
|
linls = in_nls;
|
||
|
}
|
||
|
#else
|
||
|
rpnt = (*r)->name;
|
||
|
lpnt = (*l)->name;
|
||
|
rinls = linls = in_nls;
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
/*
|
||
|
* If the entries are the same, this is an error.
|
||
|
* Joliet specs allow for a maximum of 64 characters.
|
||
|
* If we see different multi extent parts, it is OK to
|
||
|
* have the same name more than once.
|
||
|
*/
|
||
|
if (strncmp(rpnt, lpnt, jlen) == 0) {
|
||
|
#ifdef USE_LARGEFILES
|
||
|
if ((*r)->mxpart == (*l)->mxpart)
|
||
|
#endif
|
||
|
{
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Error: %s and %s have the same Joliet name\n"),
|
||
|
(*r)->whole_name, (*l)->whole_name);
|
||
|
jsort_goof++;
|
||
|
{
|
||
|
char *p1 = rpnt;
|
||
|
char *p2 = lpnt;
|
||
|
int len = 0;
|
||
|
|
||
|
for (; *p1 == *p2; p1++, p2++, len++) {
|
||
|
if (*p1 == '\0')
|
||
|
break;
|
||
|
}
|
||
|
if (len > jsort_glen)
|
||
|
jsort_glen = len;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Put the '.' and '..' entries on the head of the sorted list.
|
||
|
* For normal ASCII, this always happens to be the case, but out of
|
||
|
* band characters cause this not to be the case sometimes.
|
||
|
*/
|
||
|
if (strcmp(rpnt, ".") == 0)
|
||
|
return (-1);
|
||
|
if (strcmp(lpnt, ".") == 0)
|
||
|
return (1);
|
||
|
|
||
|
if (strcmp(rpnt, "..") == 0)
|
||
|
return (-1);
|
||
|
if (strcmp(lpnt, "..") == 0)
|
||
|
return (1);
|
||
|
|
||
|
#ifdef DVD_AUD_VID
|
||
|
/*
|
||
|
* There're rumors claiming that some players assume VIDEO_TS.IFO
|
||
|
* to be the first file in VIDEO_TS/ catalog. Well, it's basically
|
||
|
* the only file a player has to actually look for, as the whole
|
||
|
* video content can be "rolled down" from this file alone.
|
||
|
* <appro@fy.chalmers.se>
|
||
|
*/
|
||
|
/*
|
||
|
* XXX This code has to be moved from the Joliet implementation
|
||
|
* XXX to the UDF implementation if we implement decent UDF support
|
||
|
* XXX with a separate name space for the UDF file tree.
|
||
|
*/
|
||
|
if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
|
||
|
if (strcmp(rpnt, "VIDEO_TS.IFO") == 0)
|
||
|
return (-1);
|
||
|
if (strcmp(lpnt, "VIDEO_TS.IFO") == 0)
|
||
|
return (1);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
while (*rpnt && *lpnt) {
|
||
|
if (*rpnt == ';' && *lpnt != ';')
|
||
|
return (-1);
|
||
|
if (*rpnt != ';' && *lpnt == ';')
|
||
|
return (1);
|
||
|
|
||
|
if (*rpnt == ';' && *lpnt == ';')
|
||
|
return (0);
|
||
|
|
||
|
/*
|
||
|
* Extensions are not special here.
|
||
|
* Don't treat the dot as something that must be bumped to
|
||
|
* the start of the list.
|
||
|
*/
|
||
|
#if 0
|
||
|
if (*rpnt == '.' && *lpnt != '.')
|
||
|
return (-1);
|
||
|
if (*rpnt != '.' && *lpnt == '.')
|
||
|
return (1);
|
||
|
#endif
|
||
|
|
||
|
convert_to_unicode(rtmp, 2, rpnt, rinls);
|
||
|
convert_to_unicode(ltmp, 2, lpnt, linls);
|
||
|
|
||
|
if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
|
||
|
return (-1);
|
||
|
if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
|
||
|
return (1);
|
||
|
|
||
|
rpnt++;
|
||
|
lpnt++;
|
||
|
}
|
||
|
if (*rpnt)
|
||
|
return (1);
|
||
|
if (*lpnt)
|
||
|
return (-1);
|
||
|
#ifdef USE_LARGEFILES
|
||
|
/*
|
||
|
* (*r)->mxpart == (*l)->mxpart cannot happen here
|
||
|
*/
|
||
|
if ((*r)->mxpart < (*l)->mxpart)
|
||
|
return (-1);
|
||
|
else if ((*r)->mxpart > (*l)->mxpart)
|
||
|
return (1);
|
||
|
#endif
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Function: sort_directory
|
||
|
*
|
||
|
* Purpose: Sort the directory in the appropriate ISO9660
|
||
|
* order.
|
||
|
*
|
||
|
* Notes: Returns 0 if OK, returns > 0 if an error occurred.
|
||
|
*/
|
||
|
LOCAL int
|
||
|
joliet_sort_directory(sort_dir)
|
||
|
struct directory_entry **sort_dir;
|
||
|
{
|
||
|
int dcount = 0;
|
||
|
int i;
|
||
|
struct directory_entry *s_entry;
|
||
|
struct directory_entry **sortlist;
|
||
|
|
||
|
s_entry = *sort_dir;
|
||
|
while (s_entry) {
|
||
|
/*
|
||
|
* only colletc non-hidden entries
|
||
|
*/
|
||
|
if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
|
||
|
(INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY))
|
||
|
dcount++;
|
||
|
s_entry = s_entry->next;
|
||
|
}
|
||
|
|
||
|
/* OK, now we know how many there are. Build a vector for sorting. */
|
||
|
sortlist = (struct directory_entry **)
|
||
|
e_malloc(sizeof (struct directory_entry *) * dcount);
|
||
|
|
||
|
dcount = 0;
|
||
|
s_entry = *sort_dir;
|
||
|
while (s_entry) {
|
||
|
/*
|
||
|
* only collect non-hidden entries
|
||
|
*/
|
||
|
if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
|
||
|
(INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) {
|
||
|
sortlist[dcount] = s_entry;
|
||
|
dcount++;
|
||
|
}
|
||
|
s_entry = s_entry->next;
|
||
|
}
|
||
|
|
||
|
jsort_goof = 0;
|
||
|
jsort_glen = 0;
|
||
|
#ifdef PROTOTYPES
|
||
|
qsort(sortlist, dcount, sizeof (struct directory_entry *),
|
||
|
(int (*) (const void *, const void *)) joliet_compare_dirs);
|
||
|
#else
|
||
|
qsort(sortlist, dcount, sizeof (struct directory_entry *),
|
||
|
joliet_compare_dirs);
|
||
|
#endif
|
||
|
|
||
|
if (jsort_goof) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Joliet file names differ after %d chars\n"),
|
||
|
jsort_glen);
|
||
|
if (jsort_glen > JLONGMAX) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Cannot use Joliet, please remove -J from the option list.\n"));
|
||
|
} else if (jsort_glen > JMAX) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Try to use the option -joliet-long\n"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Now reassemble the linked list in the proper sorted order */
|
||
|
for (i = 0; i < dcount - 1; i++) {
|
||
|
sortlist[i]->jnext = sortlist[i + 1];
|
||
|
}
|
||
|
|
||
|
sortlist[dcount - 1]->jnext = NULL;
|
||
|
*sort_dir = sortlist[0];
|
||
|
|
||
|
free(sortlist);
|
||
|
return (jsort_goof);
|
||
|
}
|
||
|
|
||
|
EXPORT int
|
||
|
joliet_sort_tree(node)
|
||
|
struct directory *node;
|
||
|
{
|
||
|
struct directory *dpnt;
|
||
|
int ret = 0;
|
||
|
|
||
|
dpnt = node;
|
||
|
|
||
|
while (dpnt) {
|
||
|
ret = joliet_sort_n_finish(dpnt);
|
||
|
if (ret) {
|
||
|
break;
|
||
|
}
|
||
|
if (dpnt->subdir)
|
||
|
ret = joliet_sort_tree(dpnt->subdir);
|
||
|
if (ret) {
|
||
|
break;
|
||
|
}
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
return (ret);
|
||
|
}
|
||
|
|
||
|
LOCAL void
|
||
|
generate_joliet_directories(node, outfile)
|
||
|
struct directory *node;
|
||
|
FILE *outfile;
|
||
|
{
|
||
|
struct directory *dpnt;
|
||
|
|
||
|
dpnt = node;
|
||
|
|
||
|
while (dpnt) {
|
||
|
if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
|
||
|
/*
|
||
|
* In theory we should never reuse a directory, so this
|
||
|
* doesn't make much sense.
|
||
|
*/
|
||
|
if (dpnt->jextent > session_start) {
|
||
|
generate_one_joliet_directory(dpnt, outfile);
|
||
|
}
|
||
|
}
|
||
|
/* skip if hidden - but not for the rr_moved dir */
|
||
|
if (dpnt->subdir &&
|
||
|
(!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) ||
|
||
|
dpnt == reloc_dir)) {
|
||
|
generate_joliet_directories(dpnt->subdir, outfile);
|
||
|
}
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Function to write the EVD for the disc.
|
||
|
*/
|
||
|
LOCAL int
|
||
|
jpathtab_write(outfile)
|
||
|
FILE *outfile;
|
||
|
{
|
||
|
/* Next we write the path tables */
|
||
|
xfwrite(jpath_table_l, jpath_blocks << 11, 1, outfile, 0, FALSE);
|
||
|
xfwrite(jpath_table_m, jpath_blocks << 11, 1, outfile, 0, FALSE);
|
||
|
last_extent_written += 2 * jpath_blocks;
|
||
|
free(jpath_table_l);
|
||
|
free(jpath_table_m);
|
||
|
jpath_table_l = NULL;
|
||
|
jpath_table_m = NULL;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
LOCAL int
|
||
|
jdirtree_size(starting_extent)
|
||
|
UInt32_t starting_extent;
|
||
|
{
|
||
|
assign_joliet_directory_addresses(root);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
LOCAL int
|
||
|
jroot_gen()
|
||
|
{
|
||
|
jroot_record.length[0] =
|
||
|
1 + offsetof(struct iso_directory_record, name[0]);
|
||
|
jroot_record.ext_attr_length[0] = 0;
|
||
|
set_733((char *)jroot_record.extent, root->jextent);
|
||
|
set_733((char *)jroot_record.size, ISO_ROUND_UP(root->jsize));
|
||
|
iso9660_date(jroot_record.date, root_statbuf.st_mtime);
|
||
|
jroot_record.flags[0] = ISO_DIRECTORY;
|
||
|
jroot_record.file_unit_size[0] = 0;
|
||
|
jroot_record.interleave[0] = 0;
|
||
|
set_723(jroot_record.volume_sequence_number, volume_sequence_number);
|
||
|
jroot_record.name_len[0] = 1;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
LOCAL int
|
||
|
jdirtree_write(outfile)
|
||
|
FILE *outfile;
|
||
|
{
|
||
|
generate_joliet_directories(root, outfile);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function to write the EVD for the disc.
|
||
|
*/
|
||
|
LOCAL int
|
||
|
jvd_write(outfile)
|
||
|
FILE *outfile;
|
||
|
{
|
||
|
struct iso_primary_descriptor jvol_desc;
|
||
|
|
||
|
/* Next we write out the boot volume descriptor for the disc */
|
||
|
jvol_desc = vol_desc;
|
||
|
get_joliet_vol_desc(&jvol_desc);
|
||
|
xfwrite(&jvol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
|
||
|
last_extent_written++;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Functions to describe padding block at the start of the disc.
|
||
|
*/
|
||
|
LOCAL int
|
||
|
jpathtab_size(starting_extent)
|
||
|
UInt32_t starting_extent;
|
||
|
{
|
||
|
jpath_table[0] = starting_extent;
|
||
|
jpath_table[1] = 0;
|
||
|
jpath_table[2] = jpath_table[0] + jpath_blocks;
|
||
|
jpath_table[3] = 0;
|
||
|
|
||
|
last_extent += 2 * jpath_blocks;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen, jvd_write, "Joliet Volume Descriptor" };
|
||
|
struct output_fragment jpathtable_desc = {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write, "Joliet path table" };
|
||
|
struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write, "Joliet directory tree" };
|