patch genisoimage multi extent
[platform/upstream/cdrkit.git] / genisoimage / name.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)name.c   1.28 04/03/05 joerg */
14 /*
15  * File name.c - map full Unix file names to unique 8.3 names that
16  * would be valid on DOS.
17  *
18  *
19  * Written by Eric Youngdale (1993).
20  * Almost totally rewritten by J. Schilling (2000).
21  *
22  * Copyright 1993 Yggdrasil Computing, Incorporated
23  * Copyright (c) 1999,2000 J. Schilling
24  *
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)
28  * any later version.
29  *
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.
34  *
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.
38  */
39
40 #include <mconfig.h>
41 #include "genisoimage.h"
42 #include <standard.h>
43 #include <schily.h>
44 #include <ctype.h>
45
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,
50                                                                   int dirflag);
51
52 void
53 iso9660_check(struct iso_directory_record *idr, 
54                                   struct directory_entry *ndr)
55 {
56         int     nlen;
57         char    schar;
58         char    *p;
59         char    *np;
60
61         nlen = idr->name_len[0];
62         schar = idr->name[nlen];
63
64         if (nlen == 1 && (idr->name[0] == '\0' || idr->name[0] == '\001'))
65                 return;
66
67         idr->name[nlen] = '\0';         /* Make it null terminated */
68         if ((p = strrchr(idr->name, ';')) != NULL) {
69                 *p = '\0';              /* Strip off old version # */
70         }
71         iso9660_file_length(idr->name, ndr,
72                                 (idr->flags[0] & ISO_DIRECTORY) != 0);
73
74         if ((np = strrchr(ndr->isorec.name, ';')) != NULL) {
75                 *np = '\0';             /* Strip off new version # */
76         }
77         if (strcmp(idr->name, ndr->isorec.name)) {
78                 if (p)
79                         *p = ';';       /* Restore old version # */
80                 if (np)
81                         *np = ';';      /* Restore new version # */
82                 errmsgno(EX_BAD,
83                         "Old session has illegal name '%.*s' length %d\n",
84                         idr->name_len[0],
85                         idr->name,
86                         idr->name_len[0]);
87                 errmsgno(EX_BAD,
88                         "New session will use    name '%s'\n",
89                         ndr->isorec.name);
90         }
91         if (p)
92                 *p = ';';               /* Restore old version # */
93         if (np)
94                 *np = ';';              /* Restore new version # */
95         idr->name[nlen] = schar;        /* Restore old iso record*/
96 }
97
98 /*
99  * Function:    iso9660_file_length
100  *
101  * Purpose:     Map file name to 8.3 format, return length
102  *              of result.
103  *
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.
107  *
108  * Note:        name being const * is a bug introduced by Eric but hard to
109  *              fix without going through the whole source.
110  */
111 int
112 iso9660_file_length(const char *name /* Not really const !!! */, 
113                                                   struct directory_entry *sresult, int dirflag)
114 {
115         char            c;
116         char            *cp;
117         int             before_dot = 8;
118         int             after_dot = 3;
119         int             chars_after_dot = 0;
120         int             chars_before_dot = 0;
121         int             current_length = 0;
122         int             extra = 0;
123         int             ignore = 0;
124         char            *last_dot;
125         const char      *pnt;
126         int             priority = 32767;
127         char            *result;
128         int             ochars_after_dot;
129         int             ochars_before_dot;
130         int             seen_dot = 0;
131         int             seen_semic = 0;
132         int             tildes = 0;
133
134         result = sresult->isorec.name;
135
136         if (sresult->priority)
137                 priority = sresult->priority;
138
139         /*
140          * For the '.' entry, generate the correct record, and return 1 for
141          * the length.
142          */
143         if (strcmp(name, ".") == 0) {
144                 *result = 0;
145                 return (1);
146         }
147         /*
148          * For the '..' entry, generate the correct record, and return 1
149          * for the length.
150          */
151         if (strcmp(name, "..") == 0) {
152                 *result++ = 1;
153                 *result++ = 0;
154                 return (1);
155         }
156         /*
157          * Now scan the directory one character at a time, and figure out
158          * what to do.
159          */
160         pnt = name;
161
162         /*
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
166          * searching.
167          */
168         last_dot = strrchr(pnt, '.');
169         if ((last_dot != NULL) &&
170             ((last_dot[1] == '~') || (last_dot[1] == '\0'))) {
171                 cp = last_dot;
172                 *cp = '\0';
173                 last_dot = strrchr(pnt, '.');
174                 *cp = '.';
175                 /*
176                  * If we found no better '.' back up to the last match.
177                  */
178                 if (last_dot == NULL)
179                         last_dot = cp;
180         }
181
182         if (last_dot != NULL) {
183                 ochars_after_dot = strlen(last_dot);    /* dot counts */
184                 ochars_before_dot = last_dot - pnt;
185         } else {
186                 ochars_before_dot = 128;
187                 ochars_after_dot = 0;
188         }
189         /*
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.
194          */
195         if (full_iso9660_filenames || iso9660_level > 1) {
196                 before_dot = iso9660_namelen;
197                 after_dot = before_dot - 1;
198
199                 if (!dirflag) {
200                         if (ochars_after_dot > ((iso9660_namelen/2)+1)) {
201                                 /*
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.
206                                  */
207                                 before_dot = iso9660_namelen/2;
208                                 after_dot = ochars_after_dot;
209                         } else {
210                                 before_dot -= ochars_after_dot; /* dot counts */
211                                 after_dot = ochars_after_dot;
212                         }
213                 }
214         }
215
216         while (*pnt) {
217 #ifdef VMS
218                 if (strcmp(pnt, ".DIR;1") == 0) {
219                         break;
220                 }
221 #endif
222
223 #ifdef          Eric_code_does_not_work
224                 /*
225                  * XXX If we make this code active we get corrupted direcrory
226                  * XXX trees with infinite loops.
227                  */
228                 /*
229                  * This character indicates a Unix style of backup file
230                  * generated by some editors.  Lower the priority of the file.
231                  */
232                 if (iso_translate && *pnt == '#') {
233                         priority = 1;
234                         pnt++;
235                         continue;
236                 }
237                 /*
238                  * This character indicates a Unix style of backup file
239                  * generated by some editors.  Lower the priority of the file.
240                  */
241                 if (iso_translate && *pnt == '~') {
242                         priority = 1;
243                         tildes++;
244                         pnt++;
245                         continue;
246                 }
247 #endif
248                 /*
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.
255                  */
256                 if (use_fileversion && *pnt == ';' && seen_dot) {
257                         /*
258                          * Check if a valid version number follows.
259                          * The maximum valid version number is 32767.
260                          */
261                         for (c = 1, cp = (char *)&pnt[1]; c < 6 && *cp; c++, cp++) {
262                                 if (*cp < '0' || *cp > '9')
263                                         break;
264                         }
265                         if (c <= 6 && *cp == '\0' && atoi(&pnt[1]) <= 32767)
266                                 seen_semic++;
267                 }
268                 /*
269                  * If we have a name with multiple '.' characters, we ignore
270                  * everything after we have gotten the extension.
271                  */
272                 if (ignore) {
273                         pnt++;
274                         continue;
275                 }
276                 if (current_length >= iso9660_namelen) {
277 #ifdef  nono
278                         /*
279                          * Does not work as we may truncate before the dot.
280                          */
281                         fprintf(stderr, "Truncating '%s' to '%.*s'.\n",
282                                 name,
283                                 current_length, sresult->isorec.name);
284                         ignore++;
285 #endif
286                         pnt++;
287                         continue;
288                 }
289                 /* Spin past any iso9660 version number we might have. */
290                 if (seen_semic) {
291                         if (seen_semic == 1) {
292                                 seen_semic++;
293                                 *result++ = ';';
294                         }
295                         if (*pnt >= '0' && *pnt <= '9') {
296                                 *result++ = *pnt;
297                         }
298                         extra++;
299                         pnt++;
300                         continue;
301                 }
302
303                 if (*pnt == '.') {
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";
309                         }
310
311                         if (!chars_before_dot && !allow_leading_dots) {
312                                 /*
313                                  * DOS can't read files with dot first
314                                  */
315                                 chars_before_dot++;
316                                 *result++ = '_'; /* Substitute underscore */
317
318                         } else if (pnt == last_dot) {
319                                 if (seen_dot) {
320                                         ignore++;
321                                         continue;
322                                 }
323                                 *result++ = '.';
324                                 seen_dot++;
325                         } else if (allow_multidot) {
326                                 if (chars_before_dot < before_dot) {
327                                         chars_before_dot++;
328                                         *result++ = '.';
329                                 }
330                         } else {
331                                 /*
332                                  * If this isn't the dot that we use
333                                  * for the extension, then change the
334                                  * character into a '_' instead.
335                                  */
336                                 if (chars_before_dot < before_dot) {
337                                         chars_before_dot++;
338                                         *result++ = '_';
339                                 }
340                         }
341                 } else {
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)) {
346
347                                 c = *pnt;
348                                 if (c & 0x80) {
349                                         /*
350                                          * We allow 8 bit chars if -iso-level
351                                          * is at least 4
352                                          *
353                                          * XXX We should check if the output
354                                          * XXX character set is a 7 Bit ASCI
355                                          * extension.
356                                          */
357                                         if (iso9660_level >= 4) {
358                                                 c = conv_charset(c, in_nls, out_nls);
359                                         } else {
360                                                 c = '_';
361                                         }
362                                 } else if (!allow_lowercase) {
363                                         c = islower((unsigned char)c) ?
364                                                 toupper((unsigned char)c) : c;
365                                 }
366                                 if (relaxed_filenames) {
367                                         /*
368                                          * Here we allow a more relaxed syntax.
369                                          */
370                                         if (c == '/')
371                                                 c = '_';
372                                         *result++ = c;
373                                 } else switch (c) {
374                                         /*
375                                          * Dos style filenames.
376                                          * We really restrict the names here.
377                                          */
378
379                                 default:
380                                         *result++ = c;
381                                         break;
382
383                                 /*
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.
390                                  */
391                                 /* separators */
392                                 case '+':
393                                 case '=':
394                                 case '%': /* not legal DOS */
395                                                 /* filename */
396                                 case ':':
397                                 case ';': /* already handled */
398                                 case '.': /* already handled */
399                                 case ',': /* already handled */
400                                 case '\t':
401                                 case ' ':
402                                 /* V1 only separators */
403                                 case '/':
404                                 case '"':
405                                 case '[':
406                                 case ']':
407                                 /* terminators */
408                                 case '>':
409                                 case '<':
410                                 case '|':
411                                 /*
412                                  * Other characters that are not valid ISO-9660
413                                  * characters.
414                                  */
415                                 case '!':
416 /*                              case '#':*/
417                                 case '$':
418                                 case '&':
419                                 case '\'':
420                                 case '(':
421                                 case ')':
422                                 case '*':
423 /*                              case '-':*/
424                                 case '?':
425                                 case '@':
426                                 case '\\':
427                                 case '^':
428                                 case '`':
429                                 case '{':
430                                 case '}':
431 /*                              case '~':*/
432                                 /*
433                                  * All characters below 32 (space) are not
434                                  * allowed too.
435                                  */
436                                 case 1: case 2: case 3: case 4:
437                                 case 5: case 6: case 7: case 8:
438                                 /* case 9: */
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:
446                                 case 31:
447
448                                         /*
449                                          * Hmm - what to do here? Skip? Win95
450                                          * looks like it substitutes '_'
451                                          */
452                                         *result++ = '_';
453                                         break;
454
455                                 case '#':
456                                 case '-':
457                                 case '~':
458                                         /*
459                                          * Check if we should allow these
460                                          * illegal characters used by
461                                          * Microsoft.
462                                          */
463                                         if (iso_translate)
464                                                 *result++ = '_';
465                                         else
466                                                 *result++ = c;
467                                         break;
468                                 }       /* switch (*pnt) */
469                         } else {        /* if (chars_{after,before}_dot) ... */
470                                 pnt++;
471                                 continue;
472                         }
473                 }       /* else *pnt == '.' */
474                 current_length++;
475                 pnt++;
476         }       /* while (*pnt) */
477
478         /*
479          * OK, that wraps up the scan of the name.  Now tidy up a few other
480          * things.
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
484          * the 'extension'.
485          */
486         if (tildes == 2) {
487                 int     prio1 = 0;
488
489                 pnt = name;
490                 while (*pnt && *pnt != '~') {
491                         pnt++;
492                 }
493                 if (*pnt) {
494                         pnt++;
495                 }
496                 while (*pnt && *pnt != '~') {
497                         prio1 = 10 * prio1 + *pnt - '0';
498                         pnt++;
499                 }
500                 priority = prio1;
501         }
502         /*
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.
505          */
506         if (!dirflag) {
507                 if (!seen_dot && !omit_period) {
508                         if (chars_before_dot >= (iso9660_namelen-1)) {
509                                 chars_before_dot--;
510                                 result--;
511                         }
512                         *result++ = '.';
513                         extra++;
514                 }
515                 if (!omit_version_number && !seen_semic) {
516                         *result++ = ';';
517                         *result++ = '1';
518                         extra += 2;
519                 }
520         }
521         *result++ = 0;
522         sresult->priority = priority;
523
524 /*#define       DEBBUG*/
525 #ifdef  DEBBUG
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);
529 #endif
530         return (chars_before_dot + chars_after_dot + seen_dot + extra);
531 }