Files
2015-04-16 09:16:48 +02:00

211 lines
6.6 KiB
C

/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Markus M. Wild
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* __fstat.c,v 1.1.1.1 1994/04/04 04:30:08 amiga Exp
*
* __fstat.c,v
* Revision 1.1.1.1 1994/04/04 04:30:08 amiga
* Initial CVS check in.
*
* Revision 1.2 1993/11/05 21:49:59 mw
* "grp/oth-perms,
*
* Revision 1.1 1992/05/14 19:55:40 mwild
* Initial revision
*
*/
#define _KERNEL
#include <string.h>
#include <stdio.h>
#include "ixemul.h"
#include "kprintf.h"
#ifndef ACTION_EXAMINE_FH
#define ACTION_EXAMINE_FH 1034
#endif
/************************************************************************/
/* */
/* fstat() function. */
/* */
/************************************************************************/
int
__fstat(struct file *f)
{
long len, pos, bytesperblock;
struct FileInfoBlock *fib;
struct InfoData *info;
BPTR lock;
int omask;
BOOL res;
int is_interactive = IsInteractive(CTOBPTR(f->f_fh));
struct stat *st = &f->f_stb;
usetup;
omask = syscall (SYS_sigsetmask, ~0);
__get_file (f);
if (!(f->f_stb_dirty & FSDF_OWNER))
{
st->st_uid = -2;
st->st_gid = -2;
}
/* take special care of NIL:, /dev/null and friends ;-) */
if (HANDLER_NIL(f))
{
st->st_mode = S_IFCHR | 0777;
st->st_nlink = 1;
st->st_blksize = ix.ix_fs_buf_factor * 512;
st->st_blocks = 0;
goto end;
}
info = alloca (sizeof (*info) + 2);
info = LONG_ALIGN (info);
fib = alloca (sizeof (*fib) + 2);
fib = LONG_ALIGN (fib);
fib->fib_OwnerUID = fib->fib_OwnerGID = 0;
/* we now have two possibilities.. either the filesystem understands the
* new ACTION_EXAMINE_FH packet, or we have to do some guesses at fields.. */
if (ExamineFH(CTOBPTR(f->f_fh), fib))
{
int mode = fill_stat_mode(st, fib); /* see stat.c */
/* read the uid/gid data */
if (!(f->f_stb_dirty & FSDF_OWNER))
{
st->st_uid = __amiga2unixid(fib->fib_OwnerUID);
st->st_gid = __amiga2unixid(fib->fib_OwnerGID);
}
if (!(f->f_stb_dirty & FSDF_MODE))
st->st_mode = mode;
else
st->st_mode |= (mode & 0170000);
/* ARGLLLLL !!!
Some (newer, hi Bill Hawes ;-)) handlers support EXAMINE_FH, but
don't know yet about ST_PIPEFILE. So console windows claim they're
plain files... Until this problem is fixed in a majority of
handlers, do an explicit SEEK here to find those fakers.. */
if (is_interactive || Seek(CTOBPTR(f->f_fh), 0, OFFSET_CURRENT) == -1)
st->st_mode = (st->st_mode & ~S_IFREG) | S_IFCHR;
/* some kind of a default-size for directories... */
st->st_size = fib->fib_DirEntryType < 0 ? fib->fib_Size : 1024;
st->st_handler = (long)f->f_fh->fh_Type;
st->st_dev = (dev_t)st->st_handler; /* trunc to 16 bit */
st->st_ino = get_unique_id(NULL, f->f_fh);
st->st_atime =
st->st_ctime =
st->st_mtime = OFFSET_FROM_1970 * 24 * 3600 + ix_get_gmt_offset() +
fib->fib_Date.ds_Days * 24 * 60 * 60 +
fib->fib_Date.ds_Minute * 60 +
fib->fib_Date.ds_Tick/TICKS_PER_SECOND;
/* in a try to count the blocks used for filemanagement, we add one for
* the fileheader. Note, that this is wrong for large files, where there
* are some extension-blocks as well */
st->st_blocks = fib->fib_NumBlocks + 1;
}
else
{
/* ATTENTION: see lseek.c for Bugs in Seek() and ACTION_SEEK ! */
/* seek to EOF */
pos = (is_interactive ? -1 : Seek(CTOBPTR(f->f_fh), 0, OFFSET_END));
if (pos >= 0)
len = Seek(CTOBPTR(f->f_fh), pos, OFFSET_BEGINNING);
else
len = 0;
bzero (st, sizeof(struct stat));
if (!(f->f_stb_dirty & FSDF_OWNER))
{
st->st_uid = syscall(SYS_geteuid);
st->st_gid = syscall(SYS_getegid);
}
if (!(f->f_stb_dirty & FSDF_MODE))
{
st->st_mode = (len >= 0 && !is_interactive) ?
S_IFREG | (0666 & ~u.u_cmask) : S_IFCHR | 0777;
}
st->st_handler = (long)f->f_fh->fh_Type;
/* the following is a limited try to support programs, that assume that
* st_dev is always valid */
st->st_dev = (dev_t)(long)st->st_handler; /* truncate to 16 bit */
/* yet another kludge.. if we call this with different descriptors, we
* should get different inode numbers.. grmpf.. */
st->st_ino = (ino_t)~(long)(f->f_fh);
st->st_nlink = 1; /* for now no problem.. 2.0... */
/* len could be -1, if the device doesn't allow seeking.. */
st->st_size = len >= 0 ? len : 0;
st->st_atime =
st->st_mtime =
st->st_ctime = syscall (SYS_time, 0);
}
/* try to find out block size of device, hey postman, it's packet-time
* again:-)) */
/* clear the info-structure. Since this packet is used by the console
* handler to transmit the window pointer, it actually answers the
* request, but doesn't set the not used fields to 0.. this gives HUGE
* block lengths :-)) */
bzero (info, sizeof(*info));
res = 0;
bytesperblock = 0;
if (S_ISREG(st->st_mode))
{
lock = DupLockFromFH(CTOBPTR(f->f_fh));
if (lock)
{
res = Info(lock, (void *)info);
UnLock(lock);
}
if (res && info->id_BytesPerBlock)
bytesperblock = info->id_BytesPerBlock;
}
st->st_blksize = 0;
if (res && bytesperblock)
{
st->st_blksize = bytesperblock;
if (!is_interactive && S_ISREG(st->st_mode))
st->st_blksize *= ix.ix_fs_buf_factor;
if (!st->st_blocks)
st->st_blocks = ((st->st_size + bytesperblock - 1) / bytesperblock);
else
st->st_blocks = (st->st_blocks * bytesperblock) / 512;
}
if (!st->st_blksize)
{
st->st_blksize = 512;
st->st_blocks = (st->st_size + 511) >> 9;
}
end:
__release_file (f);
syscall (SYS_sigsetmask, omask);
return 0;
}