|
|
1.1 root 1: /*---------------------------------------------------------------------------
2:
3: mapname.c
4:
5: This routine changes DEC-20, VAX/VMS, and DOS-style filenames into normal
6: Unix names (and vice versa, in some cases); it also creates any necessary
7: directories, if the -d switch was specified.
8:
9: ---------------------------------------------------------------------------
10:
11: Notes:
12:
13: - This routine REALLY needs to be rewritten (different routines for
14: each output OS, with different rules for different parts of the path
15: name). If each zip program stores local-format names (like the VMS
16: one did at one time), it would probably be best to convert to an in-
17: termediate format first (assuming we're not extracting under the same
18: OS as that under which the zipfile was created), then from that to
19: the current operating system's format.
20: - The strcpy and strcat operations on both cdp and filename may over-
21: write memory, since they don't check lengths. With a kilobyte in
22: which to work, this is probably not that big a deal, but it could
23: cause problems eventually.
24:
25: ---------------------------------------------------------------------------*/
26:
27:
28: #include "unzip.h"
29:
30:
31: /*******************/
32: /* Mapname Defines */
33: /*******************/
34:
35: #ifdef VMS
36: # define PERMS 0
37: #else
38: # define PERMS 0777
39: #endif
40:
41: #ifndef NO_MKDIR
42: # if (defined(DOS_OS2) && !defined(__GO32__))
43: # if (_MSC_VER >= 600) /* have special MSC mkdir prototype */
44: # include <direct.h>
45: # else /* own prototype because dir.h conflicts? */
46: int mkdir(const char *path);
47: # endif /* ?(MSC 6.0 or later) */
48: # define MKDIR(path,mode) mkdir(path)
49: # else /* !DOS_OS2 || __GO32__ */
50: # ifdef MACOS
51: # define MKDIR(path,mode) macmkdir(path,gnVRefNum,glDirID)
52: # else /* !MACOS */
53: # define MKDIR(path,mode) mkdir(path,mode)
54: # endif /* ?MACOS */
55: # endif /* ?(DOS_OS2 && !__GO32__) */
56: #endif /* !NO_MKDIR */
57:
58:
59:
60:
61: /************************/
62: /* Function mapname() */
63: /************************/
64:
65: int mapname(create_dirs) /* return 0 if no error, 1 if caution (filename */
66: int create_dirs; /* truncated), 2 if warning (skip file because */
67: { /* dir doesn't exist), 3 if error (skip file) */
68: #ifdef NO_MKDIR
69: char command[FILNAMSIZ+40]; /* buffer for system() call */
70: #endif
71: #ifdef VMS
72: int stat_val; /* temp. holder for stat() return value */
73: char *dp, *xp; /* pointers to directory name */
74: char *np; /* pointer into filename */
75: #endif /* VMS */
76: #ifdef DOS_VMS
77: char *last_dot=NULL; /* last dot not converted to underscore */
78: #endif /* DOS_VMS */
79: #ifdef OS2
80: char *last;
81: extern char longfilename[]; /* AFTER file created and closed */
82: extern int longname; /* used also in file_io.c: set EAs */
83: int longdir;
84: #endif /* OS2 */
85: char name[FILNAMSIZ]; /* file name buffer */
86: char *pp, *cp, *cdp; /* character pointers */
87: char delim = '\0'; /* directory delimiter */
88: int quote = FALSE; /* flags */
89: int indir = FALSE;
90: int done = FALSE;
91: int created = FALSE;
92: register unsigned workch; /* hold the character being tested */
93:
94:
95: /*---------------------------------------------------------------------------
96: Initialize various pointers and counters and stuff.
97: ---------------------------------------------------------------------------*/
98:
99: #ifdef MAP_DEBUG
100: fprintf(stderr, "%s ", filename); /* echo name of this file */
101: #endif
102: cdp = (char *)NULL;
103: pp = name; /* point to translation buffer */
104: *name = '\0'; /* initialize buffer */
105: if (!jflag) { /* -j => junk pathnames */
106: cdp = (char *)malloc(strlen(filename) + 3); /* place for holding */
107: if (cdp == (char *)NULL) { /* directory name */
108: fprintf(stderr, "mapname: out of memory [%s]\n", filename);
109: return 3;
110: }
111: #ifdef VMS
112: *cdp++ = '[';
113: xp = cdp; /* always points to last non-NULL char */
114: *cdp++ = '.';
115: #endif /* VMS */
116: #ifdef MACOS
117: *cdp = ':'; /* the Mac uses ':' as a directory separator */
118: cdp[1] = '\0';
119: #else /* !MACOS */
120: *cdp = '\0';
121: #endif /* ?MACOS */
122: }
123:
124: /*---------------------------------------------------------------------------
125: Begin main loop through characters in filename.
126: ---------------------------------------------------------------------------*/
127:
128: for (cp = filename; (workch = (unsigned char) *cp++) != 0 && !done;) {
129:
130: if (quote) { /* if char quoted, */
131: *pp++ = (char) workch; /* include it literally */
132: quote = FALSE;
133: } else if (indir) { /* if in directory name, */
134: if (workch == (unsigned)delim) /* look for end delimiter */
135: indir = FALSE;
136: } else
137: switch (workch) {
138: case '<': /* discard DEC-20 directory name */
139: indir = TRUE;
140: delim = '>';
141: break;
142: case '[': /* discard VMS directory name */
143: indir = TRUE;
144: delim = ']';
145: break;
146: case '/': /* discard Unix path name */
147: case '\\': /* or MS-DOS path name... */
148: /* iff -j flag was given */
149: /*
150: * Special processing case: if -j flag was not specified on
151: * command line and create_dirs is TRUE, create any necessary
152: * directories included in the pathname. Creation of dirs is
153: * straightforward on BSD and MS-DOS machines but requires use
154: * of the system() command on SysV systems (or any others which
155: * don't have mkdir()). The stat() check is necessary with
156: * MSC because it doesn't have an EEXIST errno, and it saves
157: * the overhead of multiple system() calls on SysV machines.
158: */
159:
160: if (!jflag) {
161: *pp = '\0';
162: #ifdef VMS
163: dp = name;
164: while (*++xp = *dp++); /* copy name to cdp */
165: last_dot = NULL; /* dir name: no dots allowed */
166: strcpy(xp, ".dir"); /* add extension for stat check */
167: stat_val = stat(cdp, &statbuf);
168: *xp = '\0'; /* remove extension for all else */
169: if (stat_val) { /* doesn't exist, so create */
170: #else /* !VMS */
171: #ifdef MSDOS
172: if (last_dot != NULL) { /* one dot in dir name is legal */
173: *last_dot = '.';
174: last_dot = NULL;
175: }
176: #endif /* MSDOS */
177: strcat(cdp, name);
178: #ifdef OS2
179: if ((longdir = !IsFileNameValid(cdp)) != 0) {
180: last = strrchr(cdp, '/');
181: strcpy(longfilename, last ? last + 1 : cdp);
182: fprintf(stderr, "renaming directory \"%s\"", cdp);
183: ChangeNameForFAT(cdp);
184: fprintf(stderr, " to \"%s\"\n", cdp);
185: }
186: #endif /* OS2 */
187: if (stat(cdp, &statbuf)) { /* doesn't exist, so create */
188: #endif /* ?VMS */
189: if (!create_dirs) /* told not to create (freshening) */
190: return 2;
191: #ifdef NO_MKDIR
192: sprintf(command,
193: "IFS=\" \t\n\" /bin/mkdir %s 2>/dev/null", cdp);
194: if (system(command)) {
195: #else /* !NO_MKDIR */
196: if (MKDIR(cdp, PERMS) == -1) {
197: #endif /* ?NO_MKDIR */
198: perror(cdp);
199: free(cdp);
200: fprintf(stderr, "mapame: unable to process [%s]\n",
201: filename);
202: return 3;
203: }
204: created = TRUE;
205: #ifdef OS2
206: if (longdir)
207: SetLongNameEA(cdp, longfilename);
208: #endif /* OS2 */
209: } else if (!(statbuf.st_mode & S_IFDIR)) {
210: fprintf(stderr,
211: "mapname: %s exists but is not a directory\n", cdp);
212: free(cdp);
213: fprintf(stderr, "mapame: unable to process [%s]\n",
214: filename);
215: return 3;
216: }
217: #ifdef VMS
218: *xp = '/'; /* for now... (mkdir()) */
219: #else /* !VMS */
220: #ifdef MACOS
221: strcat(cdp, ":");
222: #else /* !MACOS */
223: strcat(cdp, "/");
224: #endif /* ?MACOS */
225: #endif /* ?VMS */
226: }
227: pp = name;
228: break;
229: case ':':
230: #ifdef UNIX /* colon is a valid character in Unix */
231: *pp++ = workch; /* filenames, so keep it; anywhere else, */
232: #else /* !UNIX */ /* change it to an underscore (should */
233: *pp++ = '_'; /* NOT have stored drive/node names!!) */
234: #endif /* ?UNIX */
235: /* pp = name; (OLD) discard DEC dev: or node:: name */
236: break;
237: case '.': /* DEC-20 generation number or */
238: #ifdef DOS_VMS /* MS-DOS or VMS separator */
239: last_dot = pp; /* point at last dot so far... */
240: *pp++ = '_'; /* convert dot to underscore */
241: #else /* !DOS_VMS */
242: *pp++ = workch;
243: #endif /* ?DOS_VMS */
244: break;
245: case ';': /* VMS generation or DEC-20 attrib */
246: #ifdef MACOS
247: if (V_flag || macflag)
248: #else /* !MACOS */
249: if (V_flag) /* if requested, save VMS ";##" */
250: #endif /* ?MACOS */ /* version info or Macintosh */
251: *pp++ = (char) workch; /* (?) info; otherwise discard */
252: else /* everything starting with */
253: done = TRUE; /* semicolon. (Worry about */
254: break; /* DEC-20 later.) */
255: case '\026': /* control-V quote for special chars */
256: quote = TRUE; /* set flag for next character */
257: break;
258: case ' ':
259: #if (defined(VMS) || defined(MTS))
260: *pp++ = '_'; /* change spaces to underscore */
261: #else /* !(VMS || MTS) */ /* under VMS and MTS, and under DOS */
262: #ifdef DOS_OS2 /* and OS/2 if -s not specified. */
263: if (!sflag)
264: *pp++ = '_';
265: else
266: #endif /* DOS_OS2 */
267: *pp++ = (char) workch; /* otherwise, leave as spaces */
268: #endif /* ?(VMS || MTS) */
269: break;
270: default:
271: #ifdef MACOS
272: if ((macflag && ((unsigned)workch > 0x1F)) || isprint(workch))
273: #else /* !MACOS */
274: #if (defined(DOS_OS2) || (defined(UNIX) && !defined(VMS))) /* allow non-US */
275: if (isprint(workch) || (128 <= workch && workch <= 254))
276: #else /* !(DOS_OS2 || UNIX) */
277: if (isprint(workch)) /* other printable, just keep */
278: #endif /* ?(DOS_OS2 || UNIX) */
279: #endif /* ?MACOS */
280: *pp++ = (char) workch;
281: } /* end switch */
282: } /* end for loop */
283: *pp = '\0'; /* done with name: terminate it */
284: #ifdef DOS_VMS /* and put a dot back in if VMS */
285: if (last_dot != NULL) /* or MS-DOS */
286: *last_dot = '.';
287: #endif /* DOS_VMS */
288:
289: /*---------------------------------------------------------------------------
290: We COULD check for existing names right now, create a "unique" name, etc.
291: At present, we do this in extract_or_test_files() (immediately after we
292: return from here). If conversion went bad, the name'll either be nulled
293: out (in which case we'll return non-0), or following procedures won't be
294: able to create the extracted file and other error msgs will result.
295: ---------------------------------------------------------------------------*/
296:
297: if (filename[strlen(filename) - 1] == '/') {
298: /* A directory was extracted. It had a trailing /,
299: * don't report the error below. */
300: if (created) {
301: printf(" Creating: %s", filename);
302: #ifdef OS2
303: SetPathInfo(filename, lrec.last_mod_file_date,
304: lrec.last_mod_file_time, -1);
305: if (extra_field)
306: SetEAs(filename, extra_field);
307: #endif
308: printf("\n");
309: }
310: return 2; /* but skip file */
311: }
312:
313: if (*name == '\0') {
314: fprintf(stderr, "mapname: conversion of [%s] failed\n", filename);
315: return 3;
316: }
317:
318: #ifdef OS2
319: if (!longname && ((longname = !IsFileNameValid(name)) != 0)) {
320: /* in case of second call after user renamed the file, skip this */
321: last = strrchr(name, '/'); /* THIS time, save for file_io */
322: last = last ? last + 1 : name; /* only last component */
323: strcpy(longfilename, last);
324: fprintf(stderr, "renaming \"%s\"", name);
325: ChangeNameForFAT(last);
326: fprintf(stderr, " to \"%s\"\n", name);
327: }
328: #endif /* OS2 */
329:
330: #ifdef VMS
331: /* convert filename to legal VMS one, substituting underscores for
332: * all invalid characters */
333: for (np = name; *np; ++np)
334: if (!(isdigit(*np) || isalpha(*np) || (*np == '$') ||
335: (*np == '-') || (*np == '_') || (*np == '.') || (*np == ';')))
336: *np = '_';
337: #endif /* VMS */
338:
339: if (!jflag) {
340: #ifdef VMS
341: *xp++ = ']'; /* proper end-of-dir-name delimiter */
342: if (xp == cdp) { /* no path-name stuff, so... */
343: strcpy(filename, name); /* copy file name into global */
344: cdp -= 2; /* prepare to free malloc'd space */
345: } else { /* we've added path-name stuff... */
346: *xp = '\0'; /* so terminate and convert to */
347: dp = cdp; /* VMS subdir separators (skip */
348: while (*++dp) /* first char: better not be */
349: if (*dp == '/') /* "/"): change all slashes */
350: *dp = '.'; /* to dots */
351: cdp -= 2; /* include leading bracket and dot */
352: strcpy(filename, cdp); /* copy VMS-style path name into global */
353: strcat(filename, name); /* concatenate file name to global */
354: }
355: #else /* !VMS */
356: strcpy(filename, cdp); /* either "" or slash-terminated path */
357: strcat(filename, name); /* append file name to path name */
358: #endif /* ?VMS */
359: free(cdp);
360: } else
361: strcpy(filename, name); /* copy converted name into global */
362:
363: #if PATH_MAX < (FILNAMSIZ - 1)
364: /* check the length of the file name and truncate if necessary */
365: if (PATH_MAX < strlen(filename)) {
366: fprintf(stderr, "caution: truncating filename\n");
367: filename[PATH_MAX] = '\0';
368: fprintf(stderr, "[ %s ]\n", filename);
369: return 1; /* 1: warning error */
370: }
371: #endif
372:
373: return 0;
374: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.