summaryrefslogtreecommitdiff
path: root/amiga/stat.c
blob: 6075c21d873b7fc44b466d35f5daca9b1a4ea28d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/*
  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.

  See the accompanying file LICENSE, version 2000-Apr-09 or later
  (the contents of which are also included in zip.h) for terms of use.
  If, for some reason, all these files are missing, the Info-ZIP license
  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
*/
/* Here we have a handmade stat() function because Aztec's c.lib stat() */
/* does not support an st_mode field, which we need... also a chmod().  */

/* This stat() is by Paul Wells, modified by Paul Kienitz. */
/* Originally for use with Aztec C >= 5.0 and Lattice C <= 4.01  */
/* Adapted for SAS/C 6.5x by Haidinger Walter */

/* POLICY DECISION: We will not attempt to remove global variables from */
/* this source file for Aztec C.  These routines are essentially just   */
/* augmentations of Aztec's c.lib, which is itself not reentrant.  If   */
/* we want to produce a fully reentrant UnZip, we will have to use a    */
/* suitable startup module, such as purify.a for Aztec by Paul Kienitz. */

#ifndef __amiga_stat_c
#define __amiga_stat_c

#include <exec/types.h>
#include <exec/memory.h>
#include "amiga/z-stat.h"             /* fake version of stat.h */
#include <string.h>

#ifdef AZTEC_C
#  include <libraries/dos.h>
#  include <libraries/dosextens.h>
#  include <clib/exec_protos.h>
#  include <clib/dos_protos.h>
#  include <pragmas/exec_lib.h>
#  include <pragmas/dos_lib.h>
#endif
#ifdef __SASC
#  include <sys/dir.h>               /* SAS/C dir function prototypes */
#  include <sys/types.h>
#  include <proto/exec.h>
#  include <proto/dos.h>
#endif

#ifndef SUCCESS
#  define SUCCESS (-1)
#  define FAILURE (0)
#endif


void close_leftover_open_dirs(void);    /* prototype */

static DIR *dir_cleanup_list = NULL;    /* for resource tracking */

/* CALL THIS WHEN HANDLING CTRL-C OR OTHER UNEXPECTED EXIT! */
void close_leftover_open_dirs(void)
{
    while (dir_cleanup_list)
        closedir(dir_cleanup_list);
}


unsigned short disk_not_mounted;

extern int stat(const char *file, struct stat *buf);

stat(file,buf)
const char *file;
struct stat *buf;
{

        struct FileInfoBlock *inf;
        BPTR lock;
        time_t ftime;
        struct tm local_tm;

        if( (lock = Lock((char *)file,SHARED_LOCK))==0 )
                /* file not found */
                return(-1);

        if( !(inf = (struct FileInfoBlock *)AllocMem(
                (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
        {
                UnLock(lock);
                return(-1);
        }

        if( Examine(lock,inf)==FAILURE )
        {
                FreeMem((char *)inf,(long)sizeof(*inf));
                UnLock(lock);
                return(-1);
        }

        /* fill in buf */
        buf->st_dev         =
        buf->st_nlink       =
        buf->st_uid         =
        buf->st_gid         =
        buf->st_rdev        = 0;
        buf->st_ino         = inf->fib_DiskKey;
        buf->st_blocks      = inf->fib_NumBlocks;
        buf->st_size        = inf->fib_Size;

        /* now the date.  AmigaDOS has weird datestamps---
         *      ds_Days is the number of days since 1-1-1978;
         *      however, as Unix wants date since 1-1-1970...
         */

        ftime =
                (inf->fib_Date.ds_Days * 86400 )                +
                (inf->fib_Date.ds_Minute * 60 )                 +
                (inf->fib_Date.ds_Tick / TICKS_PER_SECOND )     +
                (86400 * 8 * 365 )                              +
                (86400 * 2 );  /* two leap years */

        /* tzset(); */  /* this should be handled by mktime(), instead */
        /* ftime += timezone; */
        local_tm = *gmtime(&ftime);
        local_tm.tm_isdst = -1;
        ftime = mktime(&local_tm);

        buf->st_ctime =
        buf->st_atime =
        buf->st_mtime = ftime;

        buf->st_mode = (inf->fib_DirEntryType < 0 ? S_IFREG : S_IFDIR);

        /* lastly, throw in the protection bits */
        buf->st_mode |= ((inf->fib_Protection ^ 0xF) & 0xFF);

        FreeMem((char *)inf, (long)sizeof(*inf));
        UnLock((BPTR)lock);

        return(0);

}

int fstat(int handle, struct stat *buf)
{
    /* fake some reasonable values for stdin */
    buf->st_mode = (S_IREAD|S_IWRITE|S_IFREG);
    buf->st_size = -1;
    buf->st_mtime = time(&buf->st_mtime);
    return 0;
}


/* opendir(), readdir(), closedir(), rmdir(), and chmod() by Paul Kienitz. */

DIR *opendir(const char *path)
{
    DIR *dd = AllocMem(sizeof(DIR), MEMF_PUBLIC);
    if (!dd) return NULL;
    if (!(dd->d_parentlock = Lock((char *)path, MODE_OLDFILE))) {
        disk_not_mounted = IoErr() == ERROR_DEVICE_NOT_MOUNTED;
        FreeMem(dd, sizeof(DIR));
        return NULL;
    } else
        disk_not_mounted = 0;
    if (!Examine(dd->d_parentlock, &dd->d_fib) || dd->d_fib.fib_EntryType < 0) {
        UnLock(dd->d_parentlock);
        FreeMem(dd, sizeof(DIR));
        return NULL;
    }
    dd->d_cleanuplink = dir_cleanup_list;       /* track them resources */
    if (dir_cleanup_list)
        dir_cleanup_list->d_cleanupparent = &dd->d_cleanuplink;
    dd->d_cleanupparent = &dir_cleanup_list;
    dir_cleanup_list = dd;
    return dd;
}

void closedir(DIR *dd)
{
    if (dd) {
        if (dd->d_cleanuplink)
            dd->d_cleanuplink->d_cleanupparent = dd->d_cleanupparent;
        *(dd->d_cleanupparent) = dd->d_cleanuplink;
        if (dd->d_parentlock)
            UnLock(dd->d_parentlock);
        FreeMem(dd, sizeof(DIR));
    }
}

struct dirent *readdir(DIR *dd)
{
    return (ExNext(dd->d_parentlock, &dd->d_fib) ? (struct dirent *)dd : NULL);
}


#ifdef AZTEC_C

int rmdir(const char *path)
{
    return (DeleteFile((char *)path) ? 0 : IoErr());
}

int chmod(const char *filename, int bits)       /* bits are as for st_mode */
{
    long protmask = (bits & 0xFF) ^ 0xF;
    return !SetProtection((char *)filename, protmask);
}


/* This here removes unnecessary bulk from the executable with Aztec: */
void _wb_parse(void)  { }

/* fake a unix function that does not apply to amigados: */
int umask(void)  { return 0; }


#  include <signal.h>

/* C library signal() messes up debugging yet adds no actual usefulness */
typedef void (*__signal_return_type)(int);
__signal_return_type signal()  { return SIG_ERR; }


/* The following replaces Aztec's argv-parsing function for compatibility with
Unix-like syntax used on other platforms.  It also fixes the problem the
standard _cli_parse() has of accepting only lower-ascii characters. */

int _argc, _arg_len;
char **_argv, *_arg_lin;

void _cli_parse(struct Process *pp, long alen, register UBYTE *aptr)
{
    register UBYTE *cp;
    register struct CommandLineInterface *cli;
    register short c;
    register short starred = 0;
#  ifdef PRESTART_HOOK
    void Prestart_Hook(void);
#  endif

    cli = (struct CommandLineInterface *) (pp->pr_CLI << 2);
    cp = (UBYTE *) (cli->cli_CommandName << 2);
    _arg_len = cp[0] + alen + 2;
    if (!(_arg_lin = AllocMem((long) _arg_len, 0L)))
        return;
    c = cp[0];
    strncpy(_arg_lin, cp + 1, c);
    _arg_lin[c] = 0;
    for (cp = _arg_lin + c + 1; alen && (*aptr < '\n' || *aptr > '\r'); alen--)
        *cp++ = *aptr++;
    *cp = 0;
    aptr = cp = _arg_lin + c + 1;
    for (_argc = 1; ; _argc++) {
        while (*cp == ' ' || *cp == '\t')
            cp++;
        if (!*cp)
            break;
        if (*cp == '"') {
            cp++;
            while (c = *cp++) {
                if (c == '"' && !starred) {
                    *aptr++ = 0;
                    starred = 0;
                    break;
                } else if (c == '\\' && !starred)
                    starred = 1;
                else {
                    *aptr++ = c;
                    starred = 0;
                }
            }
        } else {
            while ((c = *cp++) && c != ' ' && c != '\t')
                *aptr++ = c;
            *aptr++ = 0;
        }
        if (c == 0)
            --cp;
    }
    *aptr = 0;
    if (!(_argv = AllocMem((_argc + 1) * sizeof(*_argv), 0L))) {
        _argc = 0;
        return;
    }
    for (c = 0, cp = _arg_lin; c < _argc; c++) {
        _argv[c] = cp;
        cp += strlen(cp) + 1;
    }
    _argv[c] = NULL;
#  ifdef PRESTART_HOOK
    Prestart_Hook();
#  endif
}

#endif /* AZTEC_C */

#endif /* __amiga_stat_c */