home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
mint
/
mntlib16.lzh
/
MNTLIB16
/
STAT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
8KB
|
309 lines
/*
* 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);
}