2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)name.c 1.28 04/03/05 joerg */
15 * File name.c - map full Unix file names to unique 8.3 names that
16 * would be valid on DOS.
19 * Written by Eric Youngdale (1993).
20 * Almost totally rewritten by J. Schilling (2000).
22 * Copyright 1993 Yggdrasil Computing, Incorporated
23 * Copyright (c) 1999,2000 J. Schilling
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 2, or (at your option)
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
41 #include "genisoimage.h"
46 void iso9660_check(struct iso_directory_record *idr,
47 struct directory_entry *ndr);
48 int iso9660_file_length(const char *name,
49 struct directory_entry *sresult,
53 iso9660_check(struct iso_directory_record *idr,
54 struct directory_entry *ndr)
61 nlen = idr->name_len[0];
62 schar = idr->name[nlen];
64 if (nlen == 1 && (idr->name[0] == '\0' || idr->name[0] == '\001'))
67 idr->name[nlen] = '\0'; /* Make it null terminated */
68 if ((p = strrchr(idr->name, ';')) != NULL) {
69 *p = '\0'; /* Strip off old version # */
71 iso9660_file_length(idr->name, ndr,
72 (idr->flags[0] & ISO_DIRECTORY) != 0);
74 if ((np = strrchr(ndr->isorec.name, ';')) != NULL) {
75 *np = '\0'; /* Strip off new version # */
77 if (strcmp(idr->name, ndr->isorec.name)) {
79 *p = ';'; /* Restore old version # */
81 *np = ';'; /* Restore new version # */
83 "Old session has illegal name '%.*s' length %d\n",
88 "New session will use name '%s'\n",
92 *p = ';'; /* Restore old version # */
94 *np = ';'; /* Restore new version # */
95 idr->name[nlen] = schar; /* Restore old iso record*/
99 * Function: iso9660_file_length
101 * Purpose: Map file name to 8.3 format, return length
104 * Arguments: name file name we need to map.
105 * sresult directory entry structure to contain mapped name.
106 * dirflag flag indicating whether this is a directory or not.
108 * Note: name being const * is a bug introduced by Eric but hard to
109 * fix without going through the whole source.
112 iso9660_file_length(const char *name /* Not really const !!! */,
113 struct directory_entry *sresult, int dirflag)
119 int chars_after_dot = 0;
120 int chars_before_dot = 0;
121 int current_length = 0;
126 int priority = 32767;
128 int ochars_after_dot;
129 int ochars_before_dot;
134 result = sresult->isorec.name;
136 if (sresult->priority)
137 priority = sresult->priority;
140 * For the '.' entry, generate the correct record, and return 1 for
143 if (strcmp(name, ".") == 0) {
148 * For the '..' entry, generate the correct record, and return 1
151 if (strcmp(name, "..") == 0) {
157 * Now scan the directory one character at a time, and figure out
163 * Find the '.' that we intend to use for the extension.
164 * Usually this is the last dot, but if we have . followed by nothing
165 * or a ~, we would consider this to be unsatisfactory, and we keep
168 last_dot = strrchr(pnt, '.');
169 if ((last_dot != NULL) &&
170 ((last_dot[1] == '~') || (last_dot[1] == '\0'))) {
173 last_dot = strrchr(pnt, '.');
176 * If we found no better '.' back up to the last match.
178 if (last_dot == NULL)
182 if (last_dot != NULL) {
183 ochars_after_dot = strlen(last_dot); /* dot counts */
184 ochars_before_dot = last_dot - pnt;
186 ochars_before_dot = 128;
187 ochars_after_dot = 0;
190 * If we have full names, the names we generate will not work
191 * on a DOS machine, since they are not guaranteed to be 8.3.
192 * Nonetheless, in many cases this is a useful option. We
193 * still only allow one '.' character in the name, however.
195 if (full_iso9660_filenames || iso9660_level > 1) {
196 before_dot = iso9660_namelen;
197 after_dot = before_dot - 1;
200 if (ochars_after_dot > ((iso9660_namelen/2)+1)) {
202 * The minimum number of characters before
203 * the dot is 3 to allow renaming.
204 * Let us allow to have 15 characters after
205 * dot to give more rational filenames.
207 before_dot = iso9660_namelen/2;
208 after_dot = ochars_after_dot;
210 before_dot -= ochars_after_dot; /* dot counts */
211 after_dot = ochars_after_dot;
218 if (strcmp(pnt, ".DIR;1") == 0) {
223 #ifdef Eric_code_does_not_work
225 * XXX If we make this code active we get corrupted direcrory
226 * XXX trees with infinite loops.
229 * This character indicates a Unix style of backup file
230 * generated by some editors. Lower the priority of the file.
232 if (iso_translate && *pnt == '#') {
238 * This character indicates a Unix style of backup file
239 * generated by some editors. Lower the priority of the file.
241 if (iso_translate && *pnt == '~') {
249 * This might come up if we had some joker already try and put
250 * iso9660 version numbers into the file names. This would be
251 * a silly thing to do on a Unix box, but we check for it
252 * anyways. If we see this, then we don't have to add our own
253 * version number at the end. UNLESS the ';' is part of the
254 * filename and no valid version number is following.
256 if (use_fileversion && *pnt == ';' && seen_dot) {
258 * Check if a valid version number follows.
259 * The maximum valid version number is 32767.
261 for (c = 1, cp = (char *)&pnt[1]; c < 6 && *cp; c++, cp++) {
262 if (*cp < '0' || *cp > '9')
265 if (c <= 6 && *cp == '\0' && atoi(&pnt[1]) <= 32767)
269 * If we have a name with multiple '.' characters, we ignore
270 * everything after we have gotten the extension.
276 if (current_length >= iso9660_namelen) {
279 * Does not work as we may truncate before the dot.
281 fprintf(stderr, "Truncating '%s' to '%.*s'.\n",
283 current_length, sresult->isorec.name);
289 /* Spin past any iso9660 version number we might have. */
291 if (seen_semic == 1) {
295 if (*pnt >= '0' && *pnt <= '9') {
304 if (!allow_multidot) {
305 if (strcmp(pnt, ".tar.gz") == 0)
306 pnt = last_dot = ".tgz";
307 if (strcmp(pnt, ".ps.gz") == 0)
308 pnt = last_dot = ".psz";
311 if (!chars_before_dot && !allow_leading_dots) {
313 * DOS can't read files with dot first
316 *result++ = '_'; /* Substitute underscore */
318 } else if (pnt == last_dot) {
325 } else if (allow_multidot) {
326 if (chars_before_dot < before_dot) {
332 * If this isn't the dot that we use
333 * for the extension, then change the
334 * character into a '_' instead.
336 if (chars_before_dot < before_dot) {
342 if ((seen_dot && (chars_after_dot < after_dot) &&
343 ++chars_after_dot) ||
344 (!seen_dot && (chars_before_dot < before_dot) &&
345 ++chars_before_dot)) {
350 * We allow 8 bit chars if -iso-level
353 * XXX We should check if the output
354 * XXX character set is a 7 Bit ASCI
357 if (iso9660_level >= 4) {
358 c = conv_charset(c, in_nls, out_nls);
362 } else if (!allow_lowercase) {
363 c = islower((unsigned char)c) ?
364 toupper((unsigned char)c) : c;
366 if (relaxed_filenames) {
368 * Here we allow a more relaxed syntax.
375 * Dos style filenames.
376 * We really restrict the names here.
384 * Descriptions of DOS's 'Parse Filename'
385 * (function 29H) describes V1 and V2.0+
386 * separator and terminator characters. These
387 * characters in a DOS name make the file
388 * visible but un-manipulable (all useful
389 * operations error off.
394 case '%': /* not legal DOS */
397 case ';': /* already handled */
398 case '.': /* already handled */
399 case ',': /* already handled */
402 /* V1 only separators */
412 * Other characters that are not valid ISO-9660
433 * All characters below 32 (space) are not
436 case 1: case 2: case 3: case 4:
437 case 5: case 6: case 7: case 8:
439 case 10: case 11: case 12:
440 case 13: case 14: case 15:
441 case 16: case 17: case 18:
442 case 19: case 20: case 21:
443 case 22: case 23: case 24:
444 case 25: case 26: case 27:
445 case 28: case 29: case 30:
449 * Hmm - what to do here? Skip? Win95
450 * looks like it substitutes '_'
459 * Check if we should allow these
460 * illegal characters used by
468 } /* switch (*pnt) */
469 } else { /* if (chars_{after,before}_dot) ... */
473 } /* else *pnt == '.' */
479 * OK, that wraps up the scan of the name. Now tidy up a few other
481 * Look for emacs style of numbered backups, like foo.c.~3~. If we
482 * see this, convert the version number into the priority number.
483 * In case of name conflicts, this is what would end up being used as
490 while (*pnt && *pnt != '~') {
496 while (*pnt && *pnt != '~') {
497 prio1 = 10 * prio1 + *pnt - '0';
503 * If this is not a directory, force a '.' in case we haven't seen one,
504 * and add a version number if we haven't seen one of those either.
507 if (!seen_dot && !omit_period) {
508 if (chars_before_dot >= (iso9660_namelen-1)) {
515 if (!omit_version_number && !seen_semic) {
522 sresult->priority = priority;
526 fprintf(stderr, "NAME: '%s'\n", sresult->isorec.name);
527 fprintf(stderr, "chars_before_dot %d chars_after_dot %d seen_dot %d extra %d\n",
528 chars_before_dot, chars_after_dot, seen_dot, extra);
530 return (chars_before_dot + chars_after_dot + seen_dot + extra);