Rev 6764 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6725 | siemargl | 1 | /* |
2 | Kolibri OS port for gcc 5.4 |
||
3 | |||
4 | Started by Siemargl @Nov 2016 |
||
5 | Borrowed code parts from other unzip ports |
||
6 | |||
7 | howto make: |
||
8 | go in unzip60 directory (below this file) and |
||
9 | >make -f kolibri\makefile.gcc |
||
10 | |||
11 | Contains: |
||
12 | version() |
||
13 | mapattr() |
||
6745 | siemargl | 14 | mapname() |
6725 | siemargl | 15 | checkdir() |
6745 | siemargl | 16 | close_outfile() |
17 | get_extattribs() |
||
18 | do_wild() |
||
6775 | siemargl | 19 | set_direc_attribs() |
20 | defer_dir_attribs() |
||
6725 | siemargl | 21 | |
6745 | siemargl | 22 | todo |
6775 | siemargl | 23 | datetime restore for dirs. buf in unzip - crash when SET_DIR_ATTRIB |
24 | fixed partial |
||
25 | -d dir error (only in unicode). Use -ddir or -d dir/ |
||
26 | russian filenames in arhives. Now works cp866 version, unicode need to fix @kos32.c:470 (GETPATH) |
||
6725 | siemargl | 27 | */ |
28 | |||
29 | #define FATTR FS_HIDDEN+FS_SYSTEM+FS_SUBDIR |
||
30 | |||
31 | |||
32 | |||
33 | #define UNZIP_INTERNAL |
||
34 | #include "unzip.h" |
||
35 | |||
36 | // Siemargl fork of Kolibri system API |
||
37 | #include "kos32sys1.h" |
||
6775 | siemargl | 38 | |
39 | static ZCONST char CannotSetItemTimestamps[] = |
||
40 | "warning: cannot set modif./access times for %s\n %s\n"; |
||
41 | static ZCONST char CannotGetTimestamps[] = |
||
42 | " (warning) cannot get fileinfo for %s\n"; |
||
43 | |||
6725 | siemargl | 44 | |
45 | /********************************************************************************************************************/ |
||
46 | /*** Function version() */ |
||
47 | /********************************************************************************************************************/ |
||
48 | |||
49 | void version(__G) |
||
50 | __GDEF |
||
51 | { |
||
52 | sprintf((char *)slide, LoadFarString(CompiledWith), |
||
53 | #if defined(__TINYC__) |
||
54 | "TinyC", "", |
||
55 | #elif defined(__GNUC__) |
||
56 | "GNU C ", __VERSION__, |
||
57 | #else |
||
58 | "(unknown compiler) ","", |
||
59 | #endif |
||
60 | "KolibriOS ", |
||
61 | |||
62 | #ifdef __POWERPC__ |
||
63 | "(PowerPC)", |
||
64 | #else |
||
65 | # ifdef __INTEL__ |
||
66 | "(x86)", |
||
67 | # else |
||
68 | "(unknown)", /* someday we may have other architectures... */ |
||
69 | # endif |
||
70 | #endif |
||
71 | |||
72 | #ifdef __DATE__ |
||
73 | " on ", __DATE__ |
||
74 | #else |
||
75 | "", "" |
||
76 | #endif |
||
77 | ); |
||
78 | |||
79 | (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0); |
||
80 | |||
81 | } /* end function version() */ |
||
82 | |||
83 | |||
84 | /********************************************************************************************************************/ |
||
85 | /*** Function mapattr() */ |
||
86 | /********************************************************************************************************************/ |
||
87 | |||
88 | /* Identical to MS-DOS, OS/2 versions. However, NT has a lot of extra |
||
89 | * permission stuff, so this function should probably be extended in the |
||
90 | * future. */ |
||
91 | |||
92 | int mapattr(__G) |
||
93 | __GDEF |
||
94 | { |
||
95 | /* set archive bit for file entries (file is not backed up): */ |
||
96 | G.pInfo->file_attr = ((unsigned)G.crec.external_file_attributes | |
||
97 | (G.crec.external_file_attributes & FS_SUBDIR ? |
||
98 | |||
99 | return 0; |
||
100 | |||
101 | } /* end function mapattr() */ |
||
102 | |||
103 | |||
104 | /********************************************************************************************************************/ |
||
6727 | siemargl | 105 | /*** Function mapname() */ |
6725 | siemargl | 106 | /********************************************************************************************************************/ |
107 | |||
108 | int mapname(__G__ renamed) |
||
109 | __GDEF |
||
110 | int renamed; |
||
111 | /* |
||
112 | * returns: |
||
113 | * MPN_OK - no problem detected |
||
114 | * MPN_INF_TRUNC - caution (truncated filename) |
||
115 | * MPN_INF_SKIP - info "skip entry" (dir doesn't exist) |
||
116 | * MPN_ERR_SKIP - error -> skip entry |
||
117 | * MPN_ERR_TOOLONG - error -> path is too long |
||
118 | * MPN_NOMEM - error (memory allocation failed) -> skip entry |
||
119 | * [also MPN_VOL_LABEL, MPN_CREATED_DIR] |
||
120 | */ |
||
121 | { |
||
122 | char pathcomp[FILNAMSIZ]; /* path-component buffer */ |
||
123 | char *pp, *cp=(char *)NULL; /* character pointers */ |
||
124 | char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */ |
||
125 | #ifdef ACORN_FTYPE_NFS |
||
126 | char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */ |
||
127 | RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */ |
||
128 | #endif |
||
129 | int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ |
||
130 | int error = MPN_OK; |
||
131 | register unsigned workch; /* hold the character being tested */ |
||
132 | |||
133 | |||
134 | /*--------------------------------------------------------------------------- |
||
135 | Initialize various pointers and counters and stuff. |
||
136 | ---------------------------------------------------------------------------*/ |
||
137 | |||
138 | if (G.pInfo->vollabel) |
||
139 | return MPN_VOL_LABEL; /* can't set disk volume labels in Unix */ |
||
140 | |||
141 | /* can create path as long as not just freshening, or if user told us */ |
||
142 | G.create_dirs = (!uO.fflag || renamed); |
||
143 | |||
144 | G.created_dir = FALSE; /* not yet */ |
||
145 | |||
146 | /* user gave full pathname: don't prepend rootpath */ |
||
147 | G.renamed_fullpath = (renamed && (*G.filename == '/')); |
||
148 | |||
149 | if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM) |
||
150 | return MPN_NOMEM; /* initialize path buffer, unless no memory */ |
||
151 | |||
152 | *pathcomp = '\0'; /* initialize translation buffer */ |
||
153 | pp = pathcomp; /* point to translation buffer */ |
||
154 | if (uO.jflag) /* junking directories */ |
||
155 | cp = (char *)strrchr(G.filename, '/'); |
||
156 | if (cp == (char *)NULL) /* no '/' or not junking dirs */ |
||
157 | cp = G.filename; /* point to internal zipfile-member pathname */ |
||
158 | else |
||
159 | ++cp; /* point to start of last component of path */ |
||
160 | |||
6775 | siemargl | 161 | Trace((stderr, "mapname start[%s]\n", cp)); |
6764 | siemargl | 162 | |
6725 | siemargl | 163 | /*--------------------------------------------------------------------------- |
164 | Begin main loop through characters in filename. |
||
165 | ---------------------------------------------------------------------------*/ |
||
166 | |||
167 | while ((workch = (uch)*cp++) != 0) { |
||
168 | |||
169 | switch (workch) { |
||
170 | case '/': /* can assume -j flag not given */ |
||
171 | *pp = '\0'; |
||
172 | if (strcmp(pathcomp, ".") == 0) { |
||
173 | /* don't bother appending "./" to the path */ |
||
174 | *pathcomp = '\0'; |
||
175 | } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) { |
||
176 | /* "../" dir traversal detected, skip over it */ |
||
177 | *pathcomp = '\0'; |
||
178 | killed_ddot = TRUE; /* set "show message" flag */ |
||
179 | } |
||
180 | /* when path component is not empty, append it now */ |
||
181 | if (*pathcomp != '\0' && |
||
182 | ((error = checkdir(__G__ pathcomp, APPEND_DIR)) |
||
183 | & MPN_MASK) > MPN_INF_TRUNC) |
||
184 | return error; |
||
185 | pp = pathcomp; /* reset conversion buffer for next piece */ |
||
186 | lastsemi = (char *)NULL; /* leave direct. semi-colons alone */ |
||
187 | break; |
||
188 | |||
6764 | siemargl | 189 | #ifdef KOS32 /* Cygwin runs on Win32, apply FAT/NTFS filename rules */ |
6725 | siemargl | 190 | case ':': /* drive spec not stored, so no colon allowed */ |
191 | case '\\': /* '\\' may come as normal filename char (not */ |
||
192 | case '<': /* dir sep char!) from unix-like file system */ |
||
193 | case '>': /* no redirection symbols allowed either */ |
||
194 | case '|': /* no pipe signs allowed */ |
||
195 | case '"': /* no double quotes allowed */ |
||
196 | case '?': /* no wildcards allowed */ |
||
197 | case '*': |
||
198 | *pp++ = '_'; /* these rules apply equally to FAT and NTFS */ |
||
199 | break; |
||
200 | #endif |
||
201 | |||
202 | case ';': /* VMS version (or DEC-20 attrib?) */ |
||
203 | lastsemi = pp; |
||
204 | *pp++ = ';'; /* keep for now; remove VMS ";##" */ |
||
205 | break; /* later, if requested */ |
||
206 | |||
207 | #ifdef ACORN_FTYPE_NFS |
||
208 | case ',': /* NFS filetype extension */ |
||
209 | lastcomma = pp; |
||
210 | *pp++ = ','; /* keep for now; may need to remove */ |
||
211 | break; /* later, if requested */ |
||
212 | #endif |
||
213 | |||
6764 | siemargl | 214 | #ifdef KOS32 |
6725 | siemargl | 215 | case ' ': /* change spaces to underscore under */ |
216 | *pp++ = '_'; /* MTS; leave as spaces under Unix */ |
||
217 | break; |
||
218 | #endif |
||
219 | |||
220 | default: |
||
221 | /* disable control character filter when requested, |
||
222 | * else allow 8-bit characters (e.g. UTF-8) in filenames: |
||
223 | */ |
||
6727 | siemargl | 224 | if ((isprint(workch) || (128 <= workch && workch <= 254))) |
225 | *pp++ = (char)workch; |
||
6725 | siemargl | 226 | } /* end switch */ |
227 | |||
228 | } /* end while loop */ |
||
229 | |||
230 | /* Show warning when stripping insecure "parent dir" path components */ |
||
231 | if (killed_ddot && QCOND2) { |
||
232 | Info(slide, 0, ((char *)slide, |
||
233 | "warning: skipped \"../\" path component(s) in %s\n", |
||
234 | FnFilter1(G.filename))); |
||
235 | if (!(error & ~MPN_MASK)) |
||
236 | error = (error & MPN_MASK) | PK_WARN; |
||
237 | } |
||
238 | |||
239 | /*--------------------------------------------------------------------------- |
||
240 | Report if directory was created (and no file to create: filename ended |
||
241 | in '/'), check name to be sure it exists, and combine path and name be- |
||
242 | fore exiting. |
||
243 | ---------------------------------------------------------------------------*/ |
||
244 | |||
245 | if (G.filename[strlen(G.filename) - 1] == '/') { |
||
246 | checkdir(__G__ G.filename, GETPATH); |
||
247 | if (G.created_dir) { |
||
248 | if (QCOND2) { |
||
249 | Info(slide, 0, ((char *)slide, " creating: %s\n", |
||
250 | FnFilter1(G.filename))); |
||
251 | } |
||
252 | #ifndef NO_CHMOD |
||
253 | /* Filter out security-relevant attributes bits. */ |
||
254 | G.pInfo->file_attr = filtattr(__G__ G.pInfo->file_attr); |
||
255 | /* When extracting non-UNIX directories or when extracting |
||
256 | * without UID/GID restoration or SGID preservation, any |
||
257 | * SGID flag inherited from the parent directory should be |
||
258 | * maintained to allow files extracted into this new folder |
||
259 | * to inherit the GID setting from the parent directory. |
||
260 | */ |
||
261 | if (G.pInfo->hostnum != UNIX_ || !(uO.X_flag || uO.K_flag)) { |
||
262 | /* preserve SGID bit when inherited from parent dir */ |
||
263 | if (!SSTAT(G.filename, &G.statbuf)) { |
||
264 | G.pInfo->file_attr |= G.statbuf.st_mode & S_ISGID; |
||
265 | } else { |
||
266 | perror("Could not read directory attributes"); |
||
267 | } |
||
268 | } |
||
269 | |||
270 | /* set approx. dir perms (make sure can still read/write in dir) */ |
||
271 | if (chmod(G.filename, G.pInfo->file_attr | 0700)) |
||
272 | perror("chmod (directory attributes) error"); |
||
273 | #endif |
||
274 | /* set dir time (note trailing '/') */ |
||
275 | return (error & ~MPN_MASK) | MPN_CREATED_DIR; |
||
276 | } |
||
277 | /* dir existed already; don't look for data to extract */ |
||
278 | return (error & ~MPN_MASK) | MPN_INF_SKIP; |
||
279 | } |
||
280 | |||
281 | *pp = '\0'; /* done with pathcomp: terminate it */ |
||
282 | |||
283 | /* if not saving them, remove VMS version numbers (appended ";###") */ |
||
284 | if (!uO.V_flag && lastsemi) { |
||
285 | pp = lastsemi + 1; |
||
286 | while (isdigit((uch)(*pp))) |
||
287 | ++pp; |
||
288 | if (*pp == '\0') /* only digits between ';' and end: nuke */ |
||
289 | *lastsemi = '\0'; |
||
290 | } |
||
291 | |||
292 | /* On UNIX (and compatible systems), "." and ".." are reserved for |
||
293 | * directory navigation and cannot be used as regular file names. |
||
294 | * These reserved one-dot and two-dot names are mapped to "_" and "__". |
||
295 | */ |
||
296 | if (strcmp(pathcomp, ".") == 0) |
||
297 | *pathcomp = '_'; |
||
298 | else if (strcmp(pathcomp, "..") == 0) |
||
299 | strcpy(pathcomp, "__"); |
||
300 | |||
301 | #ifdef ACORN_FTYPE_NFS |
||
302 | /* translate Acorn filetype information if asked to do so */ |
||
303 | if (uO.acorn_nfs_ext && |
||
304 | (ef_spark = (RO_extra_block *) |
||
305 | getRISCOSexfield(G.extra_field, G.lrec.extra_field_length)) |
||
306 | != (RO_extra_block *)NULL) |
||
307 | { |
||
308 | /* file *must* have a RISC OS extra field */ |
||
309 | long ft = (long)makelong(ef_spark->loadaddr); |
||
310 | /*32-bit*/ |
||
311 | if (lastcomma) { |
||
312 | pp = lastcomma + 1; |
||
313 | while (isxdigit((uch)(*pp))) ++pp; |
||
314 | if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */ |
||
315 | } |
||
316 | if ((ft & 1<<31)==0) ft=0x000FFD00; |
||
317 | sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF); |
||
318 | } |
||
319 | #endif /* ACORN_FTYPE_NFS */ |
||
320 | |||
321 | if (*pathcomp == '\0') { |
||
322 | Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n", |
||
323 | FnFilter1(G.filename))); |
||
324 | return (error & ~MPN_MASK) | MPN_ERR_SKIP; |
||
325 | } |
||
326 | |||
327 | checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */ |
||
328 | checkdir(__G__ G.filename, GETPATH); |
||
329 | |||
6775 | siemargl | 330 | Trace((stderr, "mapname end[%s]\n", pathcomp)); |
6764 | siemargl | 331 | |
332 | |||
6725 | siemargl | 333 | return error; |
334 | |||
335 | } /* end function mapname() */ |
||
336 | |||
337 | |||
338 | |||
339 | |||
340 | #if 0 /*========== NOTES ==========*/ |
||
341 | |||
342 | extract-to dir: a:path/ |
||
343 | buildpath: path1/path2/ ... (NULL-terminated) |
||
344 | pathcomp: filename |
||
345 | |||
346 | mapname(): |
||
347 | loop over chars in zipfile member name |
||
348 | checkdir(path component, COMPONENT | CREATEDIR) --> map as required? |
||
349 | (d:/tmp/unzip/) (disk:[tmp.unzip.) |
||
350 | (d:/tmp/unzip/jj/) (disk:[tmp.unzip.jj.) |
||
351 | (d:/tmp/unzip/jj/temp/) (disk:[tmp.unzip.jj.temp.) |
||
352 | finally add filename itself and check for existence? (could use with rename) |
||
353 | (d:/tmp/unzip/jj/temp/msg.outdir) (disk:[tmp.unzip.jj.temp]msg.outdir) |
||
354 | checkdir(name, GETPATH) --> copy path to name and free space |
||
355 | |||
356 | #endif /* 0 */ |
||
357 | |||
358 | |||
359 | |||
360 | |||
6727 | siemargl | 361 | /********************************************************************************************************************/ |
362 | /*** Function checkdir() */ |
||
363 | /********************************************************************************************************************/ |
||
6725 | siemargl | 364 | |
6727 | siemargl | 365 | |
6725 | siemargl | 366 | int checkdir(__G__ pathcomp, flag) |
367 | __GDEF |
||
368 | char *pathcomp; |
||
369 | int flag; |
||
370 | /* |
||
371 | * returns: |
||
372 | * MPN_OK - no problem detected |
||
373 | * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename |
||
374 | * MPN_INF_SKIP - path doesn't exist, not allowed to create |
||
375 | * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path |
||
376 | * exists and is not a directory, but is supposed to be |
||
377 | * MPN_ERR_TOOLONG - path is too long |
||
378 | * MPN_NOMEM - can't allocate memory for filename buffers |
||
379 | */ |
||
380 | { |
||
381 | /* static int rootlen = 0; */ /* length of rootpath */ |
||
382 | /* static char *rootpath; */ /* user's "extract-to" directory */ |
||
383 | /* static char *buildpath; */ /* full path (so far) to extracted file */ |
||
384 | /* static char *end; */ /* pointer to end of buildpath ('\0') */ |
||
385 | |||
386 | # define FN_MASK 7 |
||
387 | # define FUNCTION (flag & FN_MASK) |
||
388 | |||
389 | |||
390 | |||
391 | /*--------------------------------------------------------------------------- |
||
392 | APPEND_DIR: append the path component to the path being built and check |
||
393 | for its existence. If doesn't exist and we are creating directories, do |
||
394 | so for this one; else signal success or error as appropriate. |
||
395 | ---------------------------------------------------------------------------*/ |
||
396 | |||
397 | if (FUNCTION == APPEND_DIR) { |
||
398 | int too_long = FALSE; |
||
399 | #ifdef SHORT_NAMES |
||
400 | char *old_end = end; |
||
401 | #endif |
||
402 | |||
403 | Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp))); |
||
404 | while ((*G.end = *pathcomp++) != '\0') |
||
405 | ++G.end; |
||
406 | #ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */ |
||
407 | if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */ |
||
408 | *(G.end = old_end + FILENAME_MAX) = '\0'; |
||
409 | #endif |
||
410 | |||
411 | /* GRR: could do better check, see if overrunning buffer as we go: |
||
412 | * check end-buildpath after each append, set warning variable if |
||
413 | * within 20 of FILNAMSIZ; then if var set, do careful check when |
||
414 | * appending. Clear variable when begin new path. */ |
||
415 | |||
416 | /* next check: need to append '/', at least one-char name, '\0' */ |
||
417 | if ((G.end-G.buildpath) > FILNAMSIZ-3) |
||
418 | too_long = TRUE; /* check if extracting dir? */ |
||
419 | if (SSTAT(G.buildpath, &G.statbuf)) { /* path doesn't exist */ |
||
420 | if (!G.create_dirs) { /* told not to create (freshening) */ |
||
421 | free(G.buildpath); |
||
422 | return MPN_INF_SKIP; /* path doesn't exist: nothing to do */ |
||
423 | } |
||
424 | if (too_long) { |
||
425 | Info(slide, 1, ((char *)slide, |
||
426 | "checkdir error: path too long: %s\n", |
||
427 | FnFilter1(G.buildpath))); |
||
428 | free(G.buildpath); |
||
429 | /* no room for filenames: fatal */ |
||
430 | return MPN_ERR_TOOLONG; |
||
431 | } |
||
432 | if (mkdir(G.buildpath, 0777) == -1) { /* create the directory */ |
||
433 | Info(slide, 1, ((char *)slide, |
||
434 | "checkdir error: cannot create %s\n\ |
||
435 | %s\n\ |
||
436 | unable to process %s.\n", |
||
437 | FnFilter2(G.buildpath), |
||
438 | strerror(errno), |
||
439 | FnFilter1(G.filename))); |
||
440 | free(G.buildpath); |
||
441 | /* path didn't exist, tried to create, failed */ |
||
442 | return MPN_ERR_SKIP; |
||
443 | } |
||
444 | G.created_dir = TRUE; |
||
445 | } else if (!S_ISDIR(G.statbuf.st_mode)) { |
||
446 | Info(slide, 1, ((char *)slide, |
||
447 | "checkdir error: %s exists but is not directory\n\ |
||
448 | unable to process %s.\n", |
||
449 | FnFilter2(G.buildpath), FnFilter1(G.filename))); |
||
450 | free(G.buildpath); |
||
451 | /* path existed but wasn't dir */ |
||
452 | return MPN_ERR_SKIP; |
||
453 | } |
||
454 | if (too_long) { |
||
455 | Info(slide, 1, ((char *)slide, |
||
456 | "checkdir error: path too long: %s\n", FnFilter1(G.buildpath))); |
||
457 | free(G.buildpath); |
||
458 | /* no room for filenames: fatal */ |
||
459 | return MPN_ERR_TOOLONG; |
||
460 | } |
||
461 | *G.end++ = '/'; |
||
462 | *G.end = '\0'; |
||
463 | Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath))); |
||
464 | return MPN_OK; |
||
465 | |||
466 | } /* end if (FUNCTION == APPEND_DIR) */ |
||
467 | |||
468 | /*--------------------------------------------------------------------------- |
||
469 | GETPATH: copy full path to the string pointed at by pathcomp, and free |
||
470 | G.buildpath. |
||
471 | ---------------------------------------------------------------------------*/ |
||
472 | if (FUNCTION == GETPATH) { |
||
6775 | siemargl | 473 | // kolibri UTf8 support |
474 | #ifdef UNICODE_SUPPORT |
||
6764 | siemargl | 475 | if(G.native_is_utf8) |
476 | { |
||
6775 | siemargl | 477 | if (G.buildpath[0] == '/') |
478 | { |
||
479 | pathcomp[0] = '/'; // kolibri utf8 flag |
||
480 | pathcomp[1] = 3; // kolibri utf8 flag |
||
481 | strcpy(pathcomp + 2, G.buildpath); |
||
482 | } else |
||
483 | { |
||
484 | pathcomp[0] = 3; // kolibri utf8 flag |
||
485 | strcpy(pathcomp + 1, G.buildpath); |
||
486 | } |
||
6764 | siemargl | 487 | } |
6775 | siemargl | 488 | else |
489 | #endif // UNICODE_SUPPORT |
||
6725 | siemargl | 490 | strcpy(pathcomp, G.buildpath); |
491 | Trace((stderr, "getting and freeing path [%s]\n", |
||
492 | FnFilter1(pathcomp))); |
||
493 | free(G.buildpath); |
||
494 | G.buildpath = G.end = (char *)NULL; |
||
495 | return MPN_OK; |
||
496 | } |
||
497 | |||
498 | /*--------------------------------------------------------------------------- |
||
499 | APPEND_NAME: assume the path component is the filename; append it and |
||
500 | return without checking for existence. |
||
501 | ---------------------------------------------------------------------------*/ |
||
502 | |||
503 | if (FUNCTION == APPEND_NAME) { |
||
504 | #ifdef SHORT_NAMES |
||
505 | char *old_end = end; |
||
506 | #endif |
||
507 | |||
508 | Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp))); |
||
509 | while ((*G.end = *pathcomp++) != '\0') { |
||
510 | ++G.end; |
||
511 | #ifdef SHORT_NAMES /* truncate name at 14 characters, typically */ |
||
512 | if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */ |
||
513 | *(G.end = old_end + FILENAME_MAX) = '\0'; |
||
514 | #endif |
||
515 | if ((G.end-G.buildpath) >= FILNAMSIZ) { |
||
516 | *--G.end = '\0'; |
||
517 | Info(slide, 0x201, ((char *)slide, |
||
518 | "checkdir warning: path too long; truncating\n\ |
||
519 | %s\n -> %s\n", |
||
520 | FnFilter1(G.filename), FnFilter2(G.buildpath))); |
||
521 | return MPN_INF_TRUNC; /* filename truncated */ |
||
522 | } |
||
523 | } |
||
524 | Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath))); |
||
525 | /* could check for existence here, prompt for new name... */ |
||
526 | return MPN_OK; |
||
527 | } |
||
528 | |||
529 | /*--------------------------------------------------------------------------- |
||
530 | INIT: allocate and initialize buffer space for the file currently being |
||
531 | extracted. If file was renamed with an absolute path, don't prepend the |
||
532 | extract-to path. |
||
533 | ---------------------------------------------------------------------------*/ |
||
534 | |||
535 | /* GRR: for VMS and TOPS-20, add up to 13 to strlen */ |
||
536 | |||
537 | if (FUNCTION == INIT) { |
||
538 | Trace((stderr, "initializing buildpath to ")); |
||
539 | #ifdef ACORN_FTYPE_NFS |
||
540 | if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+ |
||
541 | (uO.acorn_nfs_ext ? 5 : 1))) |
||
542 | #else |
||
543 | if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1)) |
||
544 | #endif |
||
545 | == (char *)NULL) |
||
546 | return MPN_NOMEM; |
||
547 | if ((G.rootlen > 0) && !G.renamed_fullpath) { |
||
548 | strcpy(G.buildpath, G.rootpath); |
||
549 | G.end = G.buildpath + G.rootlen; |
||
550 | } else { |
||
551 | *G.buildpath = '\0'; |
||
552 | G.end = G.buildpath; |
||
553 | } |
||
554 | Trace((stderr, "[%s]\n", FnFilter1(G.buildpath))); |
||
555 | return MPN_OK; |
||
556 | } |
||
557 | |||
558 | /*--------------------------------------------------------------------------- |
||
559 | ROOT: if appropriate, store the path in rootpath and create it if |
||
560 | necessary; else assume it's a zipfile member and return. This path |
||
561 | segment gets used in extracting all members from every zipfile specified |
||
562 | on the command line. |
||
563 | ---------------------------------------------------------------------------*/ |
||
564 | |||
565 | #if (!defined(SFX) || defined(SFX_EXDIR)) |
||
566 | if (FUNCTION == ROOT) { |
||
567 | Trace((stderr, "initializing root path to [%s]\n", |
||
568 | FnFilter1(pathcomp))); |
||
569 | if (pathcomp == (char *)NULL) { |
||
570 | G.rootlen = 0; |
||
571 | return MPN_OK; |
||
572 | } |
||
573 | if (G.rootlen > 0) /* rootpath was already set, nothing to do */ |
||
574 | return MPN_OK; |
||
575 | if ((G.rootlen = strlen(pathcomp)) > 0) { |
||
576 | char *tmproot; |
||
577 | |||
578 | if ((tmproot = (char *)malloc(G.rootlen+2)) == (char *)NULL) { |
||
579 | G.rootlen = 0; |
||
580 | return MPN_NOMEM; |
||
581 | } |
||
582 | strcpy(tmproot, pathcomp); |
||
583 | if (tmproot[G.rootlen-1] == '/') { |
||
584 | tmproot[--G.rootlen] = '\0'; |
||
585 | } |
||
586 | if (G.rootlen > 0 && (SSTAT(tmproot, &G.statbuf) || |
||
587 | !S_ISDIR(G.statbuf.st_mode))) |
||
588 | { /* path does not exist */ |
||
589 | if (!G.create_dirs /* || iswild(tmproot) */ ) { |
||
590 | free(tmproot); |
||
591 | G.rootlen = 0; |
||
592 | /* skip (or treat as stored file) */ |
||
593 | return MPN_INF_SKIP; |
||
594 | } |
||
595 | /* create the directory (could add loop here scanning tmproot |
||
596 | * to create more than one level, but why really necessary?) */ |
||
597 | if (mkdir(tmproot, 0777) == -1) { |
||
598 | Info(slide, 1, ((char *)slide, |
||
599 | "checkdir: cannot create extraction directory: %s\n\ |
||
600 | %s\n", |
||
601 | FnFilter1(tmproot), strerror(errno))); |
||
602 | free(tmproot); |
||
603 | G.rootlen = 0; |
||
604 | /* path didn't exist, tried to create, and failed: */ |
||
605 | /* file exists, or 2+ subdir levels required */ |
||
606 | return MPN_ERR_SKIP; |
||
607 | } |
||
608 | } |
||
609 | tmproot[G.rootlen++] = '/'; |
||
610 | tmproot[G.rootlen] = '\0'; |
||
611 | if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) { |
||
612 | free(tmproot); |
||
613 | G.rootlen = 0; |
||
614 | return MPN_NOMEM; |
||
615 | } |
||
616 | Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath))); |
||
617 | } |
||
618 | return MPN_OK; |
||
619 | } |
||
620 | #endif /* !SFX || SFX_EXDIR */ |
||
621 | |||
622 | /*--------------------------------------------------------------------------- |
||
623 | END: free rootpath, immediately prior to program exit. |
||
624 | ---------------------------------------------------------------------------*/ |
||
625 | |||
626 | if (FUNCTION == END) { |
||
627 | Trace((stderr, "freeing rootpath\n")); |
||
628 | if (G.rootlen > 0) { |
||
629 | free(G.rootpath); |
||
630 | G.rootlen = 0; |
||
631 | } |
||
632 | return MPN_OK; |
||
633 | } |
||
634 | |||
635 | return MPN_INVALID; /* should never reach */ |
||
636 | |||
637 | } /* end function checkdir() */ |
||
638 | |||
639 | |||
640 | /****************************/ |
||
6775 | siemargl | 641 | /* Function dos_to_kolibri_time() */ |
642 | /****************************/ |
||
643 | void dos_to_kolibri_time(unsigned dos_datetime, unsigned *fdat, unsigned *ftim) |
||
644 | { |
||
645 | char* pc = (char*)fdat; |
||
646 | *pc++ = (dos_datetime >> 16) & 0x1F; // day |
||
647 | *pc++ = (dos_datetime >> 21) & 0xF; // month |
||
648 | short *ps = (short*)pc; |
||
649 | *ps = (dos_datetime >> 25) + 1980; // year |
||
650 | *ftim = 0; |
||
651 | pc = (char*)ftim; |
||
652 | *pc++ = (dos_datetime & 0x1F) << 1; // sec |
||
653 | *pc++ = (dos_datetime >> 5) & 0x3F; // min |
||
654 | *pc = (dos_datetime >> 11) & 0x1F; // hour |
||
655 | } /* end function dos_to_kolibri_time() */ |
||
656 | |||
657 | |||
658 | /****************************/ |
||
6725 | siemargl | 659 | /* Function close_outfile() */ |
660 | /****************************/ |
||
661 | |||
662 | void close_outfile(__G) /* GRR: change to return PK-style warning level */ |
||
663 | __GDEF |
||
664 | { |
||
665 | |||
666 | #if (defined(NO_FCHOWN)) |
||
667 | fclose(G.outfile); |
||
6745 | siemargl | 668 | Trace((stdout, "File (%s) closed\n", FnFilter1(G.filename))); |
6725 | siemargl | 669 | #endif |
670 | |||
671 | /* skip restoring time stamps on user's request */ |
||
672 | if (uO.D_flag <= 1) { |
||
6775 | siemargl | 673 | /* set the file's access and modification times */ |
674 | /* siemargl: dont using extra fields */ |
||
675 | unsigned ftim, fdat; |
||
676 | dos_to_kolibri_time(G.lrec.last_mod_dos_datetime, &fdat, &ftim); |
||
677 | |||
678 | fileinfo_t finfo; |
||
679 | if (get_fileinfo(G.filename, &finfo)) |
||
680 | { |
||
681 | Info(slide, 1, ((char *)slide, CannotGetTimestamps, |
||
682 | FnFilter1(G.filename))); |
||
683 | return; |
||
684 | } |
||
685 | finfo.flags = G.pInfo->file_attr; |
||
686 | finfo.cr_time = finfo.acc_time = finfo.mod_time = ftim; |
||
687 | finfo.cr_date = finfo.acc_date = finfo.mod_date = fdat; |
||
688 | Trace((stderr, "Trying to set fileinfo[%s] date %X, time %X, attr %X\n", FnFilter1(G.filename), fdat, ftim, finfo.flags)); |
||
689 | |||
690 | if (set_fileinfo(G.filename, &finfo)) |
||
691 | { |
||
692 | Info(slide, 1, ((char *)slide, CannotSetItemTimestamps, |
||
693 | FnFilter1(G.filename), strerror(errno))); |
||
694 | return; |
||
695 | } |
||
6725 | siemargl | 696 | } |
697 | |||
698 | #if (defined(NO_FCHOWN) || defined(NO_FCHMOD)) |
||
699 | /*--------------------------------------------------------------------------- |
||
700 | Change the file permissions from default ones to those stored in the |
||
701 | zipfile. |
||
702 | ---------------------------------------------------------------------------*/ |
||
703 | |||
704 | #ifndef NO_CHMOD |
||
705 | if (chmod(G.filename, filtattr(__G__ G.pInfo->file_attr))) |
||
706 | perror("chmod (file attributes) error"); |
||
707 | #endif |
||
708 | #endif /* NO_FCHOWN || NO_FCHMOD */ |
||
709 | |||
710 | |||
711 | } /* end function close_outfile() */ |
||
712 | |||
713 | |||
714 | /**********************/ |
||
715 | /* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */ |
||
716 | /**********************/ |
||
717 | |||
718 | char *do_wild(__G__ wildspec) |
||
719 | __GDEF |
||
720 | ZCONST char *wildspec; /* only used first time on a given dir */ |
||
721 | { |
||
722 | /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in unxcfg.h: |
||
723 | static DIR *wild_dir = (DIR *)NULL; |
||
724 | static ZCONST char *wildname; |
||
725 | static char *dirname, matchname[FILNAMSIZ]; |
||
726 | static int notfirstcall=FALSE, have_dirname, dirnamelen; |
||
727 | */ |
||
728 | struct dirent *file; |
||
729 | |||
730 | /* Even when we're just returning wildspec, we *always* do so in |
||
731 | * matchname[]--calling routine is allowed to append four characters |
||
732 | * to the returned string, and wildspec may be a pointer to argv[]. |
||
733 | */ |
||
734 | if (!G.notfirstcall) { /* first call: must initialize everything */ |
||
735 | G.notfirstcall = TRUE; |
||
736 | |||
737 | if (!iswild(wildspec)) { |
||
738 | strncpy(G.matchname, wildspec, FILNAMSIZ); |
||
739 | G.matchname[FILNAMSIZ-1] = '\0'; |
||
740 | G.have_dirname = FALSE; |
||
741 | G.wild_dir = NULL; |
||
742 | return G.matchname; |
||
743 | } |
||
744 | |||
745 | /* break the wildspec into a directory part and a wildcard filename */ |
||
746 | if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL) { |
||
747 | G.dirname = "."; |
||
748 | G.dirnamelen = 1; |
||
749 | G.have_dirname = FALSE; |
||
750 | G.wildname = wildspec; |
||
751 | } else { |
||
752 | ++G.wildname; /* point at character after '/' */ |
||
753 | G.dirnamelen = G.wildname - wildspec; |
||
754 | if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == (char *)NULL) { |
||
755 | Info(slide, 0x201, ((char *)slide, |
||
756 | "warning: cannot allocate wildcard buffers\n")); |
||
757 | strncpy(G.matchname, wildspec, FILNAMSIZ); |
||
758 | G.matchname[FILNAMSIZ-1] = '\0'; |
||
759 | return G.matchname; /* but maybe filespec was not a wildcard */ |
||
760 | } |
||
761 | strncpy(G.dirname, wildspec, G.dirnamelen); |
||
762 | G.dirname[G.dirnamelen] = '\0'; /* terminate for strcpy below */ |
||
763 | G.have_dirname = TRUE; |
||
764 | } |
||
765 | |||
766 | if ((G.wild_dir = (zvoid *)opendir(G.dirname)) != (zvoid *)NULL) { |
||
767 | while ((file = readdir((DIR *)G.wild_dir)) != |
||
768 | (struct dirent *)NULL) { |
||
769 | Trace((stderr, "do_wild: readdir returns %s\n", |
||
770 | FnFilter1(file->d_name))); |
||
771 | if (file->d_name[0] == '.' && G.wildname[0] != '.') |
||
772 | continue; /* Unix: '*' and '?' do not match leading dot */ |
||
773 | if (match(file->d_name, G.wildname, 0 WISEP) &&/*0=case sens.*/ |
||
774 | /* skip "." and ".." directory entries */ |
||
775 | strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) { |
||
776 | Trace((stderr, "do_wild: match() succeeds\n")); |
||
777 | if (G.have_dirname) { |
||
778 | strcpy(G.matchname, G.dirname); |
||
779 | strcpy(G.matchname+G.dirnamelen, file->d_name); |
||
780 | } else |
||
781 | strcpy(G.matchname, file->d_name); |
||
782 | return G.matchname; |
||
783 | } |
||
784 | } |
||
785 | /* if we get to here directory is exhausted, so close it */ |
||
786 | closedir((DIR *)G.wild_dir); |
||
787 | G.wild_dir = (zvoid *)NULL; |
||
788 | } |
||
789 | Trace((stderr, "do_wild: opendir(%s) returns NULL\n", |
||
790 | FnFilter1(G.dirname))); |
||
791 | |||
792 | /* return the raw wildspec in case that works (e.g., directory not |
||
793 | * searchable, but filespec was not wild and file is readable) */ |
||
794 | strncpy(G.matchname, wildspec, FILNAMSIZ); |
||
795 | G.matchname[FILNAMSIZ-1] = '\0'; |
||
796 | return G.matchname; |
||
797 | } |
||
798 | |||
799 | /* last time through, might have failed opendir but returned raw wildspec */ |
||
800 | if ((DIR *)G.wild_dir == (DIR *)NULL) { |
||
801 | G.notfirstcall = FALSE; /* nothing left--reset for new wildspec */ |
||
802 | if (G.have_dirname) |
||
803 | free(G.dirname); |
||
804 | return (char *)NULL; |
||
805 | } |
||
806 | |||
807 | /* If we've gotten this far, we've read and matched at least one entry |
||
808 | * successfully (in a previous call), so dirname has been copied into |
||
809 | * matchname already. |
||
810 | */ |
||
811 | while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) { |
||
812 | Trace((stderr, "do_wild: readdir returns %s\n", |
||
813 | FnFilter1(file->d_name))); |
||
814 | if (file->d_name[0] == '.' && G.wildname[0] != '.') |
||
815 | continue; /* Unix: '*' and '?' do not match leading dot */ |
||
816 | if (match(file->d_name, G.wildname, 0 WISEP)) { /* 0 == case sens. */ |
||
817 | Trace((stderr, "do_wild: match() succeeds\n")); |
||
818 | if (G.have_dirname) { |
||
819 | /* strcpy(G.matchname, G.dirname); */ |
||
820 | strcpy(G.matchname+G.dirnamelen, file->d_name); |
||
821 | } else |
||
822 | strcpy(G.matchname, file->d_name); |
||
823 | return G.matchname; |
||
824 | } |
||
825 | } |
||
826 | |||
827 | closedir((DIR *)G.wild_dir); /* at least one entry read; nothing left */ |
||
828 | G.wild_dir = (zvoid *)NULL; |
||
829 | G.notfirstcall = FALSE; /* reset for new wildspec */ |
||
830 | if (G.have_dirname) |
||
831 | free(G.dirname); |
||
832 | return (char *)NULL; |
||
833 | |||
834 | } /* end function do_wild() */ |
||
6775 | siemargl | 835 | |
836 | #ifdef SET_DIR_ATTRIB |
||
837 | int defer_dir_attribs(__G__ pd) |
||
838 | __GDEF |
||
839 | direntry **pd; |
||
840 | { |
||
841 | // do nothing |
||
842 | return PK_OK; |
||
843 | } |
||
844 | |||
845 | int set_direc_attribs(__G__ d) |
||
846 | __GDEF |
||
847 | direntry *d; |
||
848 | { |
||
849 | /* skip restoring time stamps on user's request */ |
||
850 | if (uO.D_flag <= 0) { |
||
851 | /* set the file's access and modification times */ |
||
852 | /* siemargl: dont using extra fields */ |
||
853 | unsigned ftim, fdat; |
||
854 | dos_to_kolibri_time(G.lrec.last_mod_dos_datetime, &fdat, &ftim); |
||
855 | |||
856 | fileinfo_t finfo; |
||
857 | if (get_fileinfo(G.filename, &finfo)) |
||
858 | { |
||
859 | Info(slide, 1, ((char *)slide, CannotGetTimestamps, |
||
860 | FnFilter1(G.filename))); |
||
861 | return PK_WARN; |
||
862 | } |
||
863 | finfo.flags = G.pInfo->file_attr; |
||
864 | finfo.cr_time = finfo.acc_time = finfo.mod_time = ftim; |
||
865 | finfo.cr_date = finfo.acc_date = finfo.mod_date = fdat; |
||
866 | Trace((stderr, "Trying to set dirinfo[%s] date %X, time %X, attr %X\n", FnFilter1(G.filename), fdat, ftim, finfo.flags)); |
||
867 | |||
868 | if (set_fileinfo(G.filename, &finfo)) |
||
869 | { |
||
870 | Info(slide, 1, ((char *)slide, CannotSetItemTimestamps, |
||
871 | FnFilter1(G.filename), strerror(errno))); |
||
872 | return PK_WARN; |
||
873 | } |
||
874 | } |
||
875 | |||
876 | return PK_OK; |
||
877 | } /* end function set_direc_attribs() */ |
||
878 | |||
879 | #endif // SET_DIR_ATTRIB=>=>><>31)==0)><31)==0)>=>=>':> |
||
6725 | siemargl | 880 |