summaryrefslogtreecommitdiff
path: root/theos/_stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'theos/_stat.c')
-rw-r--r--theos/_stat.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/theos/_stat.c b/theos/_stat.c
new file mode 100644
index 0000000..6855d28
--- /dev/null
+++ b/theos/_stat.c
@@ -0,0 +1,461 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#pragma library
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sc.h>
+#include <peek.h>
+#include <lub.h>
+#include <fdb.h>
+#include <fsa.h>
+#include "theos/stat.h"
+
+/* replacement for standard library functions stat and fstat */
+
+int _stat_(struct stat* st, struct fdb* fdb);
+int _dstat_(struct stat* st);
+
+#define peekucb() peeknuc()
+
+/* map THEOS protection code to Unix modes */
+
+unsigned short _tm2um_(char protect)
+{
+ unsigned short umask = 0;
+
+ if (!(protect & _FDB_READ_PROTECT))
+ umask = S_IRUSR|S_IRGRP;
+
+ if (!(protect & _FDB_WRITE_PROTECT))
+ umask |= S_IWUSR|S_IWGRP;
+
+ if (!(protect & _FDB_EXECUTE_PROTECT))
+ umask |= S_IXUSR|S_IXGRP;
+
+ if (!(protect & _FDB_ERASE_PROTECT))
+ umask |= S_IEUSR|S_IEGRP;
+
+ if (!(protect & _FDB_SHARED_READ_PROTECT)) {
+ if (_osmajor > 3)
+ umask |= S_IROTH|S_IXOTH;
+ else
+ umask |= S_IROTH;
+ }
+
+ if (!(protect & _FDB_SHARED_WRITE_PROTECT))
+ umask |= S_IWOTH;
+
+ if (!(protect & _FDB_MODIFIED)) {
+ if (_osmajor > 3)
+ umask |= S_IMODF;
+ else
+ umask |= S_IXOTH;
+ }
+
+ if (protect & _FDB_NOT_HIDDEN)
+ umask |= S_INHID;
+
+ return umask;
+}
+
+/* map Unix modes to THEOS protections */
+
+char _um2tm_(unsigned short mask)
+{
+ char protect = 0;
+
+ if (!(mask & (S_IRUSR|S_IRGRP)))
+ protect |= _FDB_READ_PROTECT;
+
+ if (!(mask & (S_IWUSR|S_IWGRP)))
+ protect |= _FDB_WRITE_PROTECT;
+
+ if (!(mask & (S_IXUSR|S_IXGRP)))
+ protect |= _FDB_EXECUTE_PROTECT;
+
+ if (!(mask & (S_IEUSR|S_IEGRP)))
+ protect |= _FDB_ERASE_PROTECT;
+
+ if (_osmajor < 4) {
+ if (!(mask & S_IROTH))
+ protect |= _FDB_SHARED_READ_PROTECT;
+ } else {
+ if (!(mask & (S_IROTH|S_IXOTH)))
+ protect |= _FDB_SHARED_READ_PROTECT;
+ }
+
+ if (!(mask & S_IWOTH))
+ protect |= _FDB_SHARED_WRITE_PROTECT;
+
+ if (mask & S_IMODF && _osmajor > 3)
+ protect |= _FDB_MODIFIED;
+
+ if (mask & S_INHID && _osmajor > 3)
+ protect |= _FDB_NOT_HIDDEN;
+
+ return protect;
+}
+
+/* root directory stat */
+
+static int rdirstat(const char* fn, struct stat *st)
+{
+ register char* p = strchr(fn, ':');
+ char drive;
+
+ drive = p ? p[1] : 'S';
+
+ if (drive >= 'a' && drive <= 'Z')
+ drive -= 0x40;
+
+ memset(st, 0, sizeof(struct stat));
+
+ if (getlub(drive - 'A') != 255) {
+ st->st_org = _FDB_STAT_DIRECTORY;
+ st->st_mode = S_IFDIR|S_IRUSR|S_IWUSR|S_IROTH|S_IWOTH;
+ st->st_nlink = 1;
+ st->st_dev = st->st_rdev = drive - 'A';
+ st->st_uid = st->st_gid = getuid();
+ st->st_protect = _FDB_ERASE_PROTECT;
+ return 0;
+ }
+ errno = _errnum = ENOENT;
+ _errarg = fn;
+ return -1;
+}
+
+#ifdef LOCATE_BUG
+
+/* locate fails when stating a file in root dir from a directory with a
+ * relative path. Workaround by setting directory to root dir
+ * getting the file directory block, then restoring the current directory.
+ */
+
+struct fdb* __locate(const char* fn, char* buf, short* drv)
+{
+ struct fdb* fdb;
+ char buf2[FILENAME_MAX];
+ char cwd[FILENAME_MAX];
+ char drive[3];
+ char* p;
+ char* q;
+
+ /* return if file found */
+ if (fdb = _locate(fn, buf, drv))
+ return fdb;
+
+ /* if file name does not contain a path delimiter it really does not exist.
+ */
+ strcpy(buf2, fn);
+
+ if ((p = strrchr(buf2, '/')) == NULL)
+ return NULL;
+
+ /* get drive name from file path */
+ q = strrchr(buf2, ':');
+
+ /* cat drive name if any to directory path */
+ if (q) {
+ strncpy(drive, q, 2);
+ drive[2] = '\0';
+ strcpy(p, q);
+ } else
+ *p = '\0';
+ /* save current directory */
+ getcwd(cwd, FILENAME_MAX);
+ /* chdir to directory path */
+ chdir(buf2);
+ /* get File Directory Block */
+ p = strrchr(fn, '/');
+ fdb = _locate(p + 1, buf, drv);
+ /* restore current directory */
+ chdir(cwd);
+ return fdb;
+}
+
+#undef _locate
+#define _locate() __locate()
+
+/* same cause, same consequence for fopen and open.
+*/
+
+FILE* _fopen(const char* fn, const char* mode)
+{
+ FILE* fp;
+ char buf[FILENAME_MAX];
+ short drv;
+
+ /* prepend a path to current dir to avoid use of default library */
+ if (*fn != '.' && *fn != '/') {
+ strcpy(buf, "./");
+ strcat(buf, fn);
+ return fopen(buf, mode);
+ }
+
+ if (fp = fopen(fn, mode))
+ return fp;
+
+ /* see comment for _locate */
+ if (_locate(fn, buf, &drv)) {
+ fn = strrchr(fn, '/');
+ return fopen(fn, mode);
+ }
+ return NULL;
+}
+
+#undef open
+int open(const char*, int, ...);
+
+int __open(const char* fn, int mode)
+{
+ int fd;
+ char buf[FILENAME_MAX];
+ short drv;
+
+ /* prepend a path to current dir to avoid use of default library */
+ if (*fn != '.' && *fn != '/') {
+ strcpy(buf, "./");
+ strcat(buf, fn);
+ return open(buf, mode);
+ }
+
+ if ((fd = open(fn, mode)) != EOF)
+ return fd;
+
+ /* see comment for _locate */
+ if (_locate(fn, buf, &drv)) {
+ fn = strrchr(fn, '/');
+ if (fn)
+ return open(fn, mode);
+ }
+ return EOF;
+}
+#endif
+
+/* replacement for standard file stat */
+
+int _stat(const char *_fn, struct stat *st)
+{
+ char buf[FILENAME_MAX], buf2[FILENAME_MAX], buf3[FILENAME_MAX];
+ register struct fdb* fdb;
+ register char* p;
+ register char* fn;
+
+ fn = strcpy(buf3, _fn);
+
+ if (p = strrchr(fn, ':'))
+ *p = 0;
+
+ /* on current drive ./:d and .:m point to current dir
+ * on another drive to root directory, workaround to avoid it */
+
+ if (! strcmp(fn, "/") || ! strcmp(fn, ".") || ! strcmp(fn, "./")) {
+ if (p == NULL) {
+ /* current dir on current drive */
+ fn = getcwd(buf2, FILENAME_MAX);
+ /* getcwd returns NULL on root dir on drive S */
+ if (fn == NULL)
+ fn = strcpy(buf2, "/:S");
+ /* getcwd returns /:d on root dir on any other drive */
+ if (fn[1] == ':')
+ return rdirstat(fn, st);
+ } else {
+ *p = ':';
+ return rdirstat(fn, st);
+ }
+ if (p)
+ *p = ':';
+ } else {
+ if (p)
+ *p = ':';
+ if (*fn != '.' && *fn != '/') {
+ strcpy(buf2, "./");
+ fn = strcat(buf2, fn);
+ }
+ }
+
+ if (buf2 != fn)
+ strcpy(buf2, fn);
+ /* remove trailing slash before optional disk name */
+ if (p = strrchr(buf2, '/')) {
+ if (p[1] == ':') {
+ *p = p[1];
+ p[1] = p[2];
+ p[2] = p[3];
+ } else if (p[1] == '\0')
+ *p = '\0';
+ }
+ /* if fn is a file get file directory block structure and device */
+ if (fdb = _locate(buf2, buf, &st->st_dev)) {
+ /* is it a file from another user... */
+ if (strchr(buf2, '\\')
+ /* a public system file... */
+ || fdb->fileowner == 0
+ /* or a file from the current user account ? */
+ || fdb->fileowner == getuid())
+ /* yes, return stat */
+ return _stat_(st, fdb);
+ else {
+ /* no, say file doesn't exist */
+ errno = _errnum = ENOENT;
+ _errarg = fn;
+ return -1;
+ }
+ }
+ /* else should be a device, get device number from device name */
+ st->st_rdev = st->st_dev = _lub_name(*fn == ':' ? fn+1 : fn);
+ /* if it is really a device return device status */
+ if (st->st_dev != -1 && getlub(st->st_dev) != 255)
+ return _dstat_(st);
+ /* neither an existing file or a device name, return EOF */
+ st->st_rdev = st->st_dev = 0;
+ errno = _errnum = ENOENT;
+ _errarg = fn;
+ return -1;
+}
+
+/* replacement for fstat */
+
+int _fstat(int fd, struct stat *st)
+{
+ unsigned short fsanum;
+ struct fsa fsa;
+ register FILE *fp;
+ int status;
+ register int i;
+ register char *p;
+
+ if (fd < FOPEN_MAX) {
+ fp = &stdin[fd];
+ /* get File Save Area number */
+ if (_fcntl(fp,1,0) & 0x80) {
+ fsanum = (unsigned short) _fcntl(fp,83,0);
+ st->st_dev = (unsigned short) _fcntl(fp,5,0);
+
+ if (st->st_dev >= A_DISK && st->st_dev <= Z_DISK) {
+ /* if opened file is a disk file */
+ /* copy far fsa in protected segment to local fsa */
+ for (i = 0, fsanum *= sizeof(fsa), p = (char *) &fsa;
+ i < (sizeof(fsa));
+ i++, fsanum++, p++)
+ *p = _peekfsa((char *) fsanum);
+ /* build stat structure from fsa */
+ status = _stat_(st, (struct fdb*) &fsa);
+ /* get blocksize */
+ if ((st->st_blksize = _fcntl(fp,817,0)) == 0)
+ st->st_blksize = BUFSIZ;
+ return status;
+ }
+ /* return device status */
+ return _dstat_(st);
+ }
+ }
+ errno = _errnum = EBADF;
+ return -1;
+}
+
+static int _isprt(int dev)
+{
+ return IS_PRT_LUB(dev);
+}
+
+/* device stat */
+
+int _dstat_(st)
+register struct stat* st;
+{
+ register struct ucb* ucb;
+
+ ucb = getucb(st->st_dev);
+ st->st_ino = 0;
+ if (st->st_dev <= Z_DISK
+ || (st->st_dev >= TAPE1 && st->st_dev <= TAPE4)) {
+ st->st_mode = S_IFBLK | S_IWUSR | S_IRUSR;
+ if (peekucb(&ucb->devowner) == 255)
+ st->st_mode |= S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH;
+ } else {
+ st->st_mode = S_IFCHR | S_IWUSR;
+ if (_isprt(st->st_dev))
+ st->st_mode |= S_IRUSR;
+ if (peekucb(&ucb->devowner) == 255) {
+ st->st_mode |= S_IWGRP | S_IWOTH;
+ if (_isprt(st->st_dev))
+ st->st_mode |= S_IRGRP | S_IROTH;
+ }
+ }
+ st->st_nlink = 1;
+ st->st_uid = st->st_gid = getuid();
+ st->st_size = 0;
+ st->st_atime = st->st_mtime = st->st_ctime = 0;
+ st->st_rlen = 0;
+ st->st_klen = 0;
+ st->st_grow = 0;
+ st->st_blksize = 0;
+ return 0;
+}
+
+/* regular file stat */
+
+int _stat_(st, fdb)
+register struct stat* st;
+register struct fdb* fdb;
+{
+ st->st_rdev = st->st_dev;
+ st->st_ino = 0;
+ st->st_org = fdb->filestat;
+
+ /* map fdb file status to stat mode */
+ switch (fdb->filestat) {
+ case _FDB_STAT_LIBRARY: st->st_mode = S_IFLIB; break;
+ case _FDB_STAT_DIRECTORY: st->st_mode = S_IFDIR; break;
+ case _FDB_STAT_STREAM: st->st_mode = S_IFREG; break;
+ case _FDB_STAT_RELATIVE: st->st_mode = S_IFREL; break;
+ case _FDB_STAT_KEYED: st->st_mode = S_IFKEY; break;
+ case _FDB_STAT_INDEXED: st->st_mode = S_IFIND; break;
+ case _FDB_STAT_RANDOM: st->st_mode = S_IFRND; break;
+ case _FDB_STAT_PROGRAM: st->st_mode = S_IFR16; break;
+ case _FDB_STAT_16_BIT_PROGRAM: st->st_mode = S_IFP16; break;
+ case _FDB_STAT_32_BIT_PROGRAM: st->st_mode = S_IFP32; break;
+ }
+
+ /* map theos file protection codes to stat mode */
+ st->st_mode |= _tm2um_(st->st_protect = fdb->protect);
+ st->st_nlink = 1;
+ st->st_uid = st->st_gid = fdb->fileowner;
+ st->st_size = fdb->filesize;
+ st->st_atime = st->st_mtime = st->st_ctime = getfiledate(fdb);
+ st->st_blksize = 0;
+ /* specific theos information */
+ st->st_rlen = fdb->reclen;
+ st->st_klen = fdb->keylen;
+ st->st_grow = fdb->filegrow;
+ return 0;
+}
+
+#include <direct.h>
+
+/* standard diropen fails on path endung with a '/', workaround */
+
+struct dirent* _opendir(const char* dirpath)
+{
+ int l;
+ char dirp[FILENAME_MAX];
+ struct dirent* dir;
+
+ if (dirpath && (l = strlen(dirpath))) {
+ if (dirpath[l - 1] == '/') {
+ strcpy(dirp, dirpath);
+ dirp[l - 1] = '\0';
+ return opendir(dirp);
+ }
+ }
+ return opendir(dirpath);
+}