#include <u.h>
#include <libc.h>
#include <ureg.h>
#include "linuxsys.h"
#include "linux.h"
struct __old_kernel_stat {
ushort st_dev;
ushort st_ino;
ushort st_mode;
ushort st_nlink;
ushort st_uid;
ushort st_gid;
ushort st_rdev;
ulong st_size;
ulong st_atime;
ulong st_mtime;
ulong st_ctime;
};
struct stat {
ushort st_dev;
ushort __pad1;
ulong st_ino;
ushort st_mode;
ushort st_nlink;
ushort st_uid;
ushort st_gid;
ushort st_rdev;
ushort __pad2;
ulong st_size;
ulong st_blksize;
ulong st_blocks;
ulong st_atime;
ulong __unused1;
ulong st_mtime;
ulong __unused2;
ulong st_ctime;
ulong __unused3;
ulong __unused4;
ulong __unused5;
};
struct stat64 {
uvlong lst_dev;
uint __pad1;
uint __lst_ino;
uint lst_mode;
uint lst_nlink;
uint lst_uid;
uint lst_gid;
uvlong lst_rdev;
uint __pad2;
vlong lst_size;
uint lst_blksize;
uvlong lst_blocks;
uint lst_atime;
uint lst_atime_nsec;
uint lst_mtime;
uint lst_mtime_nsec;
uint lst_ctime;
uint lst_ctime_nsec;
uvlong lst_ino;
};
struct dirent {
long d_ino;
long d_off;
ushort d_reclen;
char d_name[];
};
#define S_IFMT 0170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFIFO 0010000
#define S_ISUID 0004000
#define S_ISGID 0002000
#define S_ISVTX 0001000
static void
dir2nstat(struct stat *st, Dir *d)
{
st->st_dev = d->type;
st->st_ino = d->qid.path;
st->st_mode = d->mode & 0777;
/* BUG handle more file types. */
//print("stat on #%C: %s\n", d->type, d->name);
if(d->mode & DMDIR)
st->st_mode |= S_IFDIR;
else if(strcmp(d->name, "cons") == 0) // bug, surely.
st->st_mode |= S_IFCHR;
else if(d->type == '|')
st->st_mode |= S_IFIFO;
else if(d->type == 'H')
st->st_mode |= S_IFBLK;
else if(d->type == 'M')
st->st_mode |= S_IFREG;
st->st_nlink = 1;
st->st_uid = 0; // BUG get uid
st->st_gid = 0; // BUG get gid
st->st_size = d->length;
st->st_rdev = 0;
st->st_blksize = 4096; // good as any
st->st_blocks = (d->length+st->st_blksize-1) / st->st_blksize;
st->st_atime = d->atime;
st->st_mtime = d->mtime;
st->st_ctime = d->mtime;
}
static void
dir2nstat64(struct stat64 *st, Dir *d)
{
memset(st, 0, sizeof(*st));
st->lst_dev = d->type;
st->lst_ino = d->qid.path;
st->__lst_ino = d->qid.path & 0xFFFFFF;
st->lst_mode = d->mode & 0777;
/* BUG handle more file types. */
//print("stat on #%C: %s\n", d->type, d->name);
if(d->mode & DMDIR)
st->lst_mode |= S_IFDIR;
else if(strcmp(d->name, "cons") == 0) // bug, surely.
st->lst_mode |= S_IFCHR;
else if(d->type == '|')
st->lst_mode |= S_IFIFO;
else if(d->type == 'H')
st->lst_mode |= S_IFBLK;
else if(d->type == 'M')
st->lst_mode |= S_IFREG;
st->lst_nlink = 1;
st->lst_uid = 0; // BUG get uid
st->lst_gid = 0; // BUG get gid
st->lst_size = d->length;
st->lst_rdev = 0;
st->lst_blksize = 4096; // good as any
st->lst_blocks = (d->length+512-1) / 512;
st->lst_atime = d->atime;
st->lst_mtime = d->mtime;
st->lst_ctime = d->mtime;
}
SYSCALL(sys_newfstat)
{
ulong fd = ARG1;
struct stat *sbuf = (struct stat *) ARG2;
Dir *d;
DPRINT("newfstat(%lud, %p)...", fd, sbuf);
if((d = dirfstat(fd)) == nil)
RETURN(-EBADF);
dir2nstat(sbuf, d);
free(d);
RETURN(0);
}
SYSCALL(sys_fstat64)
{
ulong fd = ARG1;
struct stat64 *sbuf = (struct stat64*)ARG2;
Dir *d;
DPRINT("fstat64(%lud, %p)...", fd, sbuf);
if((d = dirfstat(fd)) == nil)
RETURN(-EBADF);
dir2nstat64(sbuf, d);
free(d);
RETURN(0);
}
SYSCALL(sys_newstat)
{
char *file = (char*) ARG1;
struct stat *sbuf = (struct stat *) ARG2;
Dir *d;
DPRINT("newstat(%s, %p)...", file, sbuf);
if((d = dirstat(file)) == nil)
RETURN(mkerror());
dir2nstat(sbuf, d);
free(d);
RETURN(0);
}
SYSCALL(sys_newstat64)
{
char *file = (char*)ARG1;
struct stat64 *sbuf = (struct stat64*)ARG2;
Dir *d;
DPRINT("newstat64(%s, %p)...", file, sbuf);
if((d = dirstat(file)) == nil)
RETURN(mkerror());
dir2nstat64(sbuf, d);
free(d);
RETURN(0);
}
/*
* same as stat except when called on a
* link, which we don't support.
*/
SYSCALL(sys_newlstat)
{
char *file = (char*) ARG1;
struct stat *sbuf = (struct stat *) ARG2;
Dir *d;
DPRINT("newlstat(%s, %p)...", file, sbuf);
if((d = dirstat(file)) == nil)
RETURN(mkerror());
dir2nstat(sbuf, d);
free(d);
RETURN(0);
}
SYSCALL(sys_newlstat64)
{
char *file = (char*) ARG1;
struct stat64 *sbuf = (struct stat64 *) ARG2;
Dir *d;
DPRINT("newlstat64(%s, %p)...", file, sbuf);
if((d = dirstat(file)) == nil)
RETURN(mkerror());
dir2nstat64(sbuf, d);
free(d);
RETURN(0);
}
struct utimbuf {
long actime;
long modtime;
};
SYSCALL(sys_utime)
{
char *file = (char*)ARG1;
struct utimbuf *times = (struct utimbuf*)ARG2;
Dir *d;
if((d = dirstat(file)) == nil)
RETURN(mkerror());
times->actime = d->atime;
times->modtime = d->mtime;
free(d);
RETURN(0);
}
SYSCALL(sys_newfchown)
{
// BUG
RETURN(0);
}
SYSCALL(sys_fchmod)
{
int fd = ARG1;
uint mod = ARG2;
Dir *d;
DPRINT("fchmod(%d, %o)...", fd, mod);
if((d = dirfstat(fd)) == nil)
RETURN(mkerror());
d->mode = mod & 0777;
if(dirfwstat(fd, d) < 0){
free(d);
RETURN(mkerror());
}
free(d);
RETURN(0);
}
typedef struct dirent64 dirent64;
struct dirent64 {
uvlong d_ino;
vlong d_off;
ushort d_reclen;
uchar d_type;
char d_name[];
};
typedef struct DirReader DirReader;
struct DirReader
{
int i; /* current dir */
int n; /* count of dirs */
Dir *dir;
};
static void
destroydirreadertag(void *tag)
{
DirReader *dr;
DPRINT("destroydirreadertag()...");
dr = *fdtagp(tag);
*fdtagp(tag) = nil;
if(dr->dir)
free(dr->dir);
free(dr);
}
SYSCALL(sys_getdents64)
{
int fd = ARG1;
ulong buf = ARG2;
int nbuf = ARG3;
DirReader *dr;
ulong off;
dirent64 *prev;
void *tag;
DPRINT("sys_getdents64(%d, %p, %d)...", fd, (void*)buf, nbuf);
tag = openfdtag(fd, TAG_READDIR, 1);
if((dr = (DirReader*)*fdtagp(tag)) == nil){
dr = malloc(sizeof(DirReader));
*fdtagp(tag) = dr;
atdestroyfdtag(tag, destroydirreadertag);
dr->i = 0;
dr->n = 0;
dr->dir = nil;
if((dr->n = dirreadall(fd, &dr->dir)) < 0){
destroyfdtag(tag);
closefdtag(tag);
RETURN(mkerror());
}
}
off = 0;
prev = nil;
for(;dr->i < dr->n; dr->i++){
int l;
dirent64 *e;
Dir *d;
d = &(dr->dir[dr->i]);
l = sizeof(dirent64) + strlen(d->name) + 1;
if(off + l > nbuf) {
closefdtag(tag);
RETURN(off);
}
e = (dirent64*)(buf + off);
e->d_ino = d->qid.path;
e->d_off = 0;
e->d_reclen = l;
e->d_type = d->type;
strcpy(e->d_name, d->name);
if(prev) prev->d_off = off;
prev = e;
off += l;
}
destroyfdtag(tag);
RETURN(off);
}
SYSCALL(sys_getxattr)
{
RETURN(-ENOATTR);
}
|