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