home *** CD-ROM | disk | FTP | other *** search
- /*
- * stat, fstat, lstat emulation for TOS
- * written by Eric R. Smith and placed in the public domain
- */
-
- #include <limits.h>
- #include <types.h>
- #include <stat.h>
- #include <ctype.h>
- #include <errno.h>
- #include <osbind.h>
- #include <mintbind.h>
- #include <string.h>
- #include <time.h>
- #include <unistd.h>
- #include <ioctl.h> /* for FSTAT */
- #include "lib.h"
-
- extern int __mint;
-
- ino_t __inode = 32; /* used in readdir also */
-
- /* for backwards compatibilty: if nonzero, files are checked to see if
- * they have the TOS executable magic number in them
- */
-
- int _x_Bit_set_in_stat = 0;
-
-
-
- /* date for files (like root directories) that don't have one */
- #define OLDDATE _unixtime(0,0)
-
- /*
- * macro for converting a long in DOS format to one in Unix format. "x"
- * _must_ be an lvalue!
- */
-
- #define CONVERT(x) (x = _unixtime( ((short *)&x)[0], ((short *)&x)[1] ))
-
- /*
- * common routine for stat() and lstat(); if "lflag" is 0, then symbolic
- * links are automatically followed (like stat), if 1 then they are not
- * (like lstat)
- */
-
- static int
- do_stat(_path, st, lflag)
- const char *_path;
- struct stat *st;
- int lflag;
- {
- long r, olddta;
- int nval;
- char path[PATH_MAX];
- char *ext, drv;
- int fd;
- short magic;
- _DTA d;
- int isdot = 0;
-
- if (!_path) {
- errno = EFAULT;
- return -1;
- }
-
- /*
- * _unx2dos returns 1 for device names (like /dev/con)
- */
- nval = _unx2dos(_path, path);
-
- /* for MiNT 0.9 and up, we use the built in stat() call */
- if (__mint >= 9) {
- r = Fxattr(lflag, path, st);
- if (r) {
- errno = -r;
- return -1;
- }
- CONVERT(st->st_mtime);
- CONVERT(st->st_atime);
- CONVERT(st->st_ctime);
- /* Most versions of Unix count in 512 byte blocks */
- st->st_blocks = (st->st_blocks * st->st_blksize) / 512;
- return 0;
- }
-
- /* otherwise, check to see if we have a name like CON: or AUX: */
- if (nval == 1) {
- st->st_mode = S_IFCHR | 0600;
- st->st_attr = 0;
- st->st_ino = ++__inode;
- st->st_rdev = 0;
- st->st_mtime = st->st_ctime = st->st_atime =
- time((time_t *)0) - 2;
- st->st_dev = 0;
- st->st_nlink = 1;
- st->st_uid = geteuid();
- st->st_gid = getegid();
- st->st_size = st->st_blocks = 0;
- st->st_blksize = 1024;
- return 0;
- }
-
- /* A file name: check for root directory of a drive */
- if (path[0] == '\\' && path[1] == 0) {
- drv = Dgetdrv() + 'A';
- goto rootdir;
- }
-
- if ( (drv = path[0]) && path[1] == ':' &&
- (path[2] == 0 || (path[2] == '\\' && path[3] == 0)) ) {
- rootdir:
- st->st_mode = S_IFDIR | 0755;
- st->st_attr = FA_DIR;
- st->st_dev = isupper(drv) ? drv - 'A' : drv - 'a';
- st->st_ino = 2;
- st->st_mtime = st->st_ctime = st->st_atime = OLDDATE;
- goto fill_dir;
- }
-
- /* forbid wildcards in path names */
- if (index(path, '*') || index(path, '?')) {
- errno = ENOENT;
- return -1;
- }
-
- /* OK, here we're going to have to do an Fsfirst to get the date */
- /* NOTE: Fsfirst(".",-1) or Fsfirst("..",-1) both fail under TOS,
- * so we kludge around this by using the fact that Fsfirst(".\*.*"
- * or "..\*.*" will return the correct file first (except, of course,
- * in root directories :-( ).
- */
-
- /* find the end of the string */
- for (ext = path; ext[0] && ext[1]; ext++) ;
-
- /* add appropriate kludge if necessary */
- if (*ext == '.' && (ext == path || ext[-1] == '\\' || ext[-1] == '.')) {
- isdot = 1;
- strcat(path, "\\*.*");
- }
- olddta = Fgetdta();
- Fsetdta(&d);
- r = Fsfirst(path, 0xff);
- Fsetdta(olddta);
- if (r < 0) {
- if (isdot && r == -ENOENT) goto rootdir;
- errno = -r;
- return -1;
- }
-
- if (isdot && ((d.dta_name[0] != '.') || (d.dta_name[1]))) {
- goto rootdir;
- }
-
- st->st_mtime = st->st_ctime = st->st_atime =
- _unixtime(d.dta_time, d.dta_date);
- if ((drv = *path) && path[1] == ':')
- st->st_dev = toupper(drv) - 'A';
- else
- st->st_dev = Dgetdrv();
-
- st->st_ino = __inode++;
- st->st_attr = d.dta_attribute;
- if (__mint && st->st_dev == ('Q' - 'A'))
- st->st_mode = 0644 | S_IFIFO;
- else {
- st->st_mode = 0644 | (st->st_attr & FA_DIR ?
- S_IFDIR | 0111 : S_IFREG);
- }
-
- if (st->st_attr & FA_RDONLY)
- st->st_mode &= ~0222; /* no write permission */
- if (st->st_attr & FA_HIDDEN)
- st->st_mode &= ~0444; /* no read permission */
-
- /* check for a file with an executable extension */
- ext = strrchr(_path, '.');
- if (ext) {
- if (!strcmp(ext, ".ttp") || !strcmp(ext, ".prg") ||
- !strcmp(ext, ".tos") || !strcmp(ext, ".g") ||
- !strcmp(ext, ".sh") || !strcmp(ext, ".bat")) {
- st->st_mode |= 0111;
- }
- }
- if ( (st->st_mode & S_IFMT) == S_IFREG) {
- if (_x_Bit_set_in_stat) {
- if ((fd = Fopen(path,0)) < 0) {
- errno = -fd;
- return -1;
- }
- magic = 0;
- (void)Fread(fd,2,(char *)&magic);
- (void)Fclose(fd);
- if (magic == 0x601A /* TOS executable */
- || magic == 0x2321) /* "#!" shell file */
- st->st_mode |= 0111;
- }
- st->st_size = d.dta_size;
- /* in Unix, blocks are measured in 512 bytes */
- st->st_blocks = (st->st_size + 511) / 512;
- st->st_nlink = 1; /* we dont have hard links */
- } else {
- fill_dir:
- st->st_size = 1024;
- st->st_blocks = 2;
- st->st_nlink = 2; /* "foo" && "foo/.." */
- }
-
- st->st_rdev = 0;
- st->st_uid = geteuid(); /* the current user owns every file */
- st->st_gid = getegid();
- st->st_blksize = 1024;
- return 0;
- }
-
-
- /*
- * fstat: if we're not running under MiNT, this is pretty bogus.
- * what we can really find is:
- * modification time: via Fdatime()
- * file size: via Fseek()
- * fortunately, these are the things most programs are interested in.
- * BUG: passing an invalid file descriptor gets back a stat structure for
- * a tty.
- */
-
- int
- fstat(fd, st)
- int fd;
- struct stat *st;
- {
- long oldplace, r;
- short timeptr[2];
- short magic;
-
- if (__mint >= 9) { /* use FSTAT Fcntl */
- r = Fcntl(fd, st, (long)FSTAT);
- if (r) {
- errno = -r;
- return -1;
- }
- CONVERT(st->st_mtime);
- CONVERT(st->st_atime);
- CONVERT(st->st_ctime);
- st->st_blocks = (st->st_blocks * st->st_blksize) / 512;
- return 0;
- }
-
- r = Fdatime(timeptr, fd, 0);
- if (r < 0) { /* assume TTY */
- st->st_mode = S_IFCHR | 0600;
- st->st_attr = 0;
- st->st_mtime = st->st_ctime = st->st_atime =
- time((time_t *)0) - 2;
- st->st_size = 0;
- } else {
- st->st_mtime = st->st_atime = st->st_ctime =
- _unixtime(timeptr[0], timeptr[1]);
- st->st_mode = S_IFREG | 0644; /* this may be false */
- st->st_attr = 0; /* because this is */
-
- /* get current file location */
- oldplace = Fseek(0L, fd, SEEK_CUR);
- if (oldplace < 0) { /* can't seek -- must be pipe */
- st->st_mode = S_IFIFO | 0644;
- st->st_size = 1024;
- } else {
- r = Fseek(0L, fd, SEEK_END); /* go to end of file */
- st->st_size = r;
- (void)Fseek(0L, fd, SEEK_SET); /* go to start of file */
- /* check for executable file */
- if (Fread(fd, 2, (char *)&magic) == 2) {
- if (magic == 0x601a || magic == 0x2321)
- st->st_mode |= 0111;
- }
- (void)Fseek(oldplace, fd, SEEK_SET);
- }
- }
-
- /* all this stuff is likely bogus as well. sigh. */
- st->st_dev = Dgetdrv();
- st->st_rdev = 0;
- st->st_uid = getuid();
- st->st_gid = getgid();
- st->st_blksize = 1024;
- /* note: most Unixes measure st_blocks in 512 byte units */
- st->st_blocks = (st->st_size + 511) / 512;
- st->st_ino = ++__inode;
- st->st_nlink = 1;
- return 0;
- }
-
- int
- lstat(path, st)
- const char *path;
- struct stat *st;
- {
- return do_stat(path, st, 1);
- }
-
- int
- stat(path, st)
- const char *path;
- struct stat *st;
- {
- return do_stat(path, st, 0);
- }
-