#include #include #include #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); }