Subversion Repositories Kolibri OS

Rev

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() */
965
} /* end function do_wild() */