1/*
2  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
3
4  See the accompanying file LICENSE, version 2000-Apr-09 or later
5  (the contents of which are also included in zip.h) for terms of use.
6  If, for some reason, all these files are missing, the Info-ZIP license
7  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8*/
9/* Here we have a handmade stat() function because Aztec's c.lib stat() */
10/* does not support an st_mode field, which we need... also a chmod().  */
11
12/* This stat() is by Paul Wells, modified by Paul Kienitz. */
13/* Originally for use with Aztec C >= 5.0 and Lattice C <= 4.01  */
14/* Adapted for SAS/C 6.5x by Haidinger Walter */
15
16/* POLICY DECISION: We will not attempt to remove global variables from */
17/* this source file for Aztec C.  These routines are essentially just   */
18/* augmentations of Aztec's c.lib, which is itself not reentrant.  If   */
19/* we want to produce a fully reentrant UnZip, we will have to use a    */
20/* suitable startup module, such as purify.a for Aztec by Paul Kienitz. */
21
22#ifndef __amiga_stat_c
23#define __amiga_stat_c
24
25#include <exec/types.h>
26#include <exec/memory.h>
27#include "amiga/z-stat.h"             /* fake version of stat.h */
28#include <string.h>
29
30#ifdef AZTEC_C
31#  include <libraries/dos.h>
32#  include <libraries/dosextens.h>
33#  include <clib/exec_protos.h>
34#  include <clib/dos_protos.h>
35#  include <pragmas/exec_lib.h>
36#  include <pragmas/dos_lib.h>
37#endif
38#ifdef __SASC
39#  include <sys/dir.h>               /* SAS/C dir function prototypes */
40#  include <sys/types.h>
41#  include <proto/exec.h>
42#  include <proto/dos.h>
43#endif
44
45#ifndef SUCCESS
46#  define SUCCESS (-1)
47#  define FAILURE (0)
48#endif
49
50
51void close_leftover_open_dirs(void);    /* prototype */
52
53static DIR *dir_cleanup_list = NULL;    /* for resource tracking */
54
55/* CALL THIS WHEN HANDLING CTRL-C OR OTHER UNEXPECTED EXIT! */
56void close_leftover_open_dirs(void)
57{
58    while (dir_cleanup_list)
59        closedir(dir_cleanup_list);
60}
61
62
63unsigned short disk_not_mounted;
64
65extern int stat(const char *file, struct stat *buf);
66
67stat(file,buf)
68const char *file;
69struct stat *buf;
70{
71
72        struct FileInfoBlock *inf;
73        BPTR lock;
74        time_t ftime;
75        struct tm local_tm;
76
77        if( (lock = Lock((char *)file,SHARED_LOCK))==0 )
78                /* file not found */
79                return(-1);
80
81        if( !(inf = (struct FileInfoBlock *)AllocMem(
82                (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
83        {
84                UnLock(lock);
85                return(-1);
86        }
87
88        if( Examine(lock,inf)==FAILURE )
89        {
90                FreeMem((char *)inf,(long)sizeof(*inf));
91                UnLock(lock);
92                return(-1);
93        }
94
95        /* fill in buf */
96        buf->st_dev         =
97        buf->st_nlink       =
98        buf->st_uid         =
99        buf->st_gid         =
100        buf->st_rdev        = 0;
101        buf->st_ino         = inf->fib_DiskKey;
102        buf->st_blocks      = inf->fib_NumBlocks;
103        buf->st_size        = inf->fib_Size;
104
105        /* now the date.  AmigaDOS has weird datestamps---
106         *      ds_Days is the number of days since 1-1-1978;
107         *      however, as Unix wants date since 1-1-1970...
108         */
109
110        ftime =
111                (inf->fib_Date.ds_Days * 86400 )                +
112                (inf->fib_Date.ds_Minute * 60 )                 +
113                (inf->fib_Date.ds_Tick / TICKS_PER_SECOND )     +
114                (86400 * 8 * 365 )                              +
115                (86400 * 2 );  /* two leap years */
116
117        /* tzset(); */  /* this should be handled by mktime(), instead */
118        /* ftime += timezone; */
119        local_tm = *gmtime(&ftime);
120        local_tm.tm_isdst = -1;
121        ftime = mktime(&local_tm);
122
123        buf->st_ctime =
124        buf->st_atime =
125        buf->st_mtime = ftime;
126
127        buf->st_mode = (inf->fib_DirEntryType < 0 ? S_IFREG : S_IFDIR);
128
129        /* lastly, throw in the protection bits */
130        buf->st_mode |= ((inf->fib_Protection ^ 0xF) & 0xFF);
131
132        FreeMem((char *)inf, (long)sizeof(*inf));
133        UnLock((BPTR)lock);
134
135        return(0);
136
137}
138
139int fstat(int handle, struct stat *buf)
140{
141    /* fake some reasonable values for stdin */
142    buf->st_mode = (S_IREAD|S_IWRITE|S_IFREG);
143    buf->st_size = -1;
144    buf->st_mtime = time(&buf->st_mtime);
145    return 0;
146}
147
148
149/* opendir(), readdir(), closedir(), rmdir(), and chmod() by Paul Kienitz. */
150
151DIR *opendir(const char *path)
152{
153    DIR *dd = AllocMem(sizeof(DIR), MEMF_PUBLIC);
154    if (!dd) return NULL;
155    if (!(dd->d_parentlock = Lock((char *)path, MODE_OLDFILE))) {
156        disk_not_mounted = IoErr() == ERROR_DEVICE_NOT_MOUNTED;
157        FreeMem(dd, sizeof(DIR));
158        return NULL;
159    } else
160        disk_not_mounted = 0;
161    if (!Examine(dd->d_parentlock, &dd->d_fib) || dd->d_fib.fib_EntryType < 0) {
162        UnLock(dd->d_parentlock);
163        FreeMem(dd, sizeof(DIR));
164        return NULL;
165    }
166    dd->d_cleanuplink = dir_cleanup_list;       /* track them resources */
167    if (dir_cleanup_list)
168        dir_cleanup_list->d_cleanupparent = &dd->d_cleanuplink;
169    dd->d_cleanupparent = &dir_cleanup_list;
170    dir_cleanup_list = dd;
171    return dd;
172}
173
174void closedir(DIR *dd)
175{
176    if (dd) {
177        if (dd->d_cleanuplink)
178            dd->d_cleanuplink->d_cleanupparent = dd->d_cleanupparent;
179        *(dd->d_cleanupparent) = dd->d_cleanuplink;
180        if (dd->d_parentlock)
181            UnLock(dd->d_parentlock);
182        FreeMem(dd, sizeof(DIR));
183    }
184}
185
186struct dirent *readdir(DIR *dd)
187{
188    return (ExNext(dd->d_parentlock, &dd->d_fib) ? (struct dirent *)dd : NULL);
189}
190
191
192#ifdef AZTEC_C
193
194int rmdir(const char *path)
195{
196    return (DeleteFile((char *)path) ? 0 : IoErr());
197}
198
199int chmod(const char *filename, int bits)       /* bits are as for st_mode */
200{
201    long protmask = (bits & 0xFF) ^ 0xF;
202    return !SetProtection((char *)filename, protmask);
203}
204
205
206/* This here removes unnecessary bulk from the executable with Aztec: */
207void _wb_parse(void)  { }
208
209/* fake a unix function that does not apply to amigados: */
210int umask(void)  { return 0; }
211
212
213#  include <signal.h>
214
215/* C library signal() messes up debugging yet adds no actual usefulness */
216typedef void (*__signal_return_type)(int);
217__signal_return_type signal()  { return SIG_ERR; }
218
219
220/* The following replaces Aztec's argv-parsing function for compatibility with
221Unix-like syntax used on other platforms.  It also fixes the problem the
222standard _cli_parse() has of accepting only lower-ascii characters. */
223
224int _argc, _arg_len;
225char **_argv, *_arg_lin;
226
227void _cli_parse(struct Process *pp, long alen, register UBYTE *aptr)
228{
229    register UBYTE *cp;
230    register struct CommandLineInterface *cli;
231    register short c;
232    register short starred = 0;
233#  ifdef PRESTART_HOOK
234    void Prestart_Hook(void);
235#  endif
236
237    cli = (struct CommandLineInterface *) (pp->pr_CLI << 2);
238    cp = (UBYTE *) (cli->cli_CommandName << 2);
239    _arg_len = cp[0] + alen + 2;
240    if (!(_arg_lin = AllocMem((long) _arg_len, 0L)))
241        return;
242    c = cp[0];
243    strncpy(_arg_lin, cp + 1, c);
244    _arg_lin[c] = 0;
245    for (cp = _arg_lin + c + 1; alen && (*aptr < '\n' || *aptr > '\r'); alen--)
246        *cp++ = *aptr++;
247    *cp = 0;
248    aptr = cp = _arg_lin + c + 1;
249    for (_argc = 1; ; _argc++) {
250        while (*cp == ' ' || *cp == '\t')
251            cp++;
252        if (!*cp)
253            break;
254        if (*cp == '"') {
255            cp++;
256            while (c = *cp++) {
257                if (c == '"' && !starred) {
258                    *aptr++ = 0;
259                    starred = 0;
260                    break;
261                } else if (c == '\\' && !starred)
262                    starred = 1;
263                else {
264                    *aptr++ = c;
265                    starred = 0;
266                }
267            }
268        } else {
269            while ((c = *cp++) && c != ' ' && c != '\t')
270                *aptr++ = c;
271            *aptr++ = 0;
272        }
273        if (c == 0)
274            --cp;
275    }
276    *aptr = 0;
277    if (!(_argv = AllocMem((_argc + 1) * sizeof(*_argv), 0L))) {
278        _argc = 0;
279        return;
280    }
281    for (c = 0, cp = _arg_lin; c < _argc; c++) {
282        _argv[c] = cp;
283        cp += strlen(cp) + 1;
284    }
285    _argv[c] = NULL;
286#  ifdef PRESTART_HOOK
287    Prestart_Hook();
288#  endif
289}
290
291#endif /* AZTEC_C */
292
293#endif /* __amiga_stat_c */
294