#include <9pm/windows.h> #include <9pm/u.h> #include <9pm/libc.h> #include <9pm/ctype.h> #include <9pm/fcall.h> #include "dat.h" #include "fns.h" #include "syscall.h" #pragma comment(lib, "mpr.lib") #define DPRINT if(1)print typedef struct Uchan Uchan; struct Uchan { HANDLE h; Cname* syspath; int type; int eof; Dir dir; Rune rtmp[128]; WIN32_FIND_DATA finddata; uchar *buf; int nbuf; int havedir; int rootoff; char rootent[10]; QLock qlk; }; enum { Trootdir, Tmntdir, Tserver, Tdir, Tvolume, /* root of drive (like c:\) */ Tfile, Tpipe, Tconsole, Tstdin, /* do we need this? */ }; static int pathqid(int, char*); static long unixtime(FILETIME ft); static FILETIME wintime(ulong); static long consolewrite(Uchan*, void*, long); static long consoleread(Uchan*, void*, long); static long serverread(Uchan*, void*, long, vlong); static void serveropen(Uchan*, int); static void serverclose(Uchan*); static long directoryread(Uchan*, uchar*, long, vlong); static void data2dir(WIN32_FIND_DATA*, Dir*, char*); static long rootdirread(Uchan*, uchar*, long, vlong); static void rootdiropen(Uchan*); /* * Convert between real Windows paths and the paths we present. * We map x:\ to /x, \\server to /mnt/server, and \\. to /mnt/local * (BUG not yet) */ static struct { Rune *r; char *s; } pathtab[] = { L"X:\\", "/X", L"\\\\.\\", "/mnt/local", L"\\\\", "/mnt", }; static Rune* towin(char *s) { char *ss; Rune *r, *rr; int drive, i, match, len; drive = '?'; if(s[0]=='/' && islower(s[1]) && (s[2]=='/' || s[2]=='\0')){ drive = s[1]; match = 0; }else{ match = -1; for(i=0; iname = newcname(buf); c->mode = mode; c->flag |= COPEN; c->type = devno('U', 1); c->qid = qid; uc = smalloc(sizeof *uc); uc->syspath = newcname(buf); uc->type = pathtype(buf); uc->h = h; c->aux = uc; return c; } static Chan* syspath2chan(Qid qid, char *buf) { Chan *c; Uchan *uc; c = newchan(); c->name = newcname(buf); c->type = devno('U', 1); c->qid = qid; uc = smalloc(sizeof *uc); uc->syspath = newcname(buf); uc->type = pathtype(buf); c->aux = uc; return c; } int issysfd(Chan *c) { Uchan *uc; if(devtab[c->type]->dc != 'U') return 0; uc = c->aux; return uc->h != nil && uc->h != INVALID_HANDLE_VALUE && uc->type >= Tfile; } static void fsreset(void) { char *s; for(s="\\:?*;"; *s; s++) isfrog[*s] = 1; } static Chan* fsattach(char *spec) { Chan *c; Qid q; Uchan *uc; static Lock lk; static int devno; if(spec && spec[0]) error(Ebadspec); mkqid(&q, pathqid(0, "/"), 0, QTDIR); c = devattach('U', ""); c->qid = q; uc = smalloc(sizeof *uc); uc->syspath = newcname("/"); c->aux = uc; lock(&lk); c->dev = devno++; unlock(&lk); return c; } Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int i, type; int volatile alloc; Cname *p, *oname; Uchan *uc; Walkqid *wq; if(nname > MAXWELEM) error("devfs: too many name elements"); alloc = 0; wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); if(waserror()){ if(alloc && wq->clone!=nil) cclose(wq->clone); free(wq); return nil; } if(nc == nil){ nc = devclone(c); uc = smalloc(sizeof *uc); *uc = *(Uchan*)c->aux; nc->aux = uc; incref(&uc->syspath->ref); alloc = 1; } wq->clone = nc; uc = nc->aux; oname = uc->syspath; incref(&oname->ref); type = uc->type; for(i = 0; i < nname; i++){ p = addelem(uc->syspath, name[i]); if(strcmp(name[i], "..") == 0) cleancname(p); uc->syspath = p; if((type = pathtype(p->s)) < 0){ //print("cannot find %s\n", p->s); cnameclose(uc->syspath); uc->syspath = oname; if(alloc) cclose(nc); wq->clone = nil; if(i == 0){ free(wq); poperror(); return nil; } break; } mkqid(&wq->qid[i], pathqid(0, uc->syspath->s), 0, 0); if(type < Tfile) wq->qid[i].type |= QTDIR; } poperror(); if(i == nname){ cnameclose(oname); uc->type = type; } if(i > 0 && wq->clone != nil) wq->clone->qid = wq->qid[i-1]; wq->nqid = i; return wq; } static Chan* fsopen(Chan *c, int mode) { int acc, aflag, cflag, share; HANDLE h; Rune *wpath; Uchan *uc; uc = c->aux; switch(uc->type){ case Tserver: serveropen(uc, mode); break; case Trootdir: rootdiropen(uc); case Tdir: uc->h = INVALID_HANDLE_VALUE; break; case Tfile: switch(mode&3){ default: acc = 0; break; case OREAD: case OEXEC: acc = GENERIC_READ; break; case OWRITE: acc = GENERIC_WRITE; break; case ORDWR: acc = GENERIC_READ|GENERIC_WRITE; break; } cflag = OPEN_EXISTING; if(mode&OTRUNC) cflag = TRUNCATE_EXISTING; aflag = 0; if(mode&ORCLOSE) aflag |= FILE_FLAG_DELETE_ON_CLOSE; share = FILE_SHARE_READ|FILE_SHARE_WRITE; wpath = towin(uc->syspath->s); h = CreateFile(wpath, acc, share, 0, cflag, aflag, 0); free(wpath); if(h == INVALID_HANDLE_VALUE){ oserror(); //print("open %S: %r\n", wpath); nexterror(); } uc->h = h; break; } c->mode = openmode(mode); c->offset = 0; c->flag |= COPEN; return c; } static void fscreate(Chan *c, char *name, int mode, ulong perm) { int acc, cflag, aflag, share; Rune *path; Uchan *uc; uc = c->aux; switch(uc->type){ case Tserver: case Tvolume: case Tfile: error(Eperm); case Tdir: path = fspath(uc->syspath->s, name); if(perm&DMDIR){ if(mode != OREAD) error(Ebadarg); if(!CreateDirectory(path, 0)){ oserror(); free(path); nexterror(); } free(path); uc->h = INVALID_HANDLE_VALUE; }else{ switch(mode&3){ default: acc = 0; break; case OREAD: case OEXEC: acc = GENERIC_READ; break; case OWRITE: acc = GENERIC_WRITE; break; case ORDWR: acc = GENERIC_READ|GENERIC_WRITE; break; } /*BUG: OEXCL, OTRUNC? */ cflag = CREATE_ALWAYS; aflag = 0; if(mode&ORCLOSE) aflag |= FILE_FLAG_DELETE_ON_CLOSE; share = FILE_SHARE_READ|FILE_SHARE_WRITE; uc->h = CreateFile(path, acc, share, 0, cflag, aflag, 0); free(path); if(uc->h == INVALID_HANDLE_VALUE){ oserror(); nexterror(); } uc->type = Tfile; c->qid.type = 0; } uc->syspath = addelem(uc->syspath, name); c->qid.path = pathqid(0, uc->syspath->s); break; } c->mode = openmode(mode); c->offset = 0; c->flag |= COPEN; } static void fsremove(Chan*); static void fsclose(Chan *c) { Uchan *uc; uc = c->aux; if(c->flag & COPEN){ switch(uc->type){ case Tconsole: case Tpipe: case Tfile: case Tstdin: if(uc->h != INVALID_HANDLE_VALUE) CloseHandle(uc->h); break; case Tdir: FindClose(uc->h); if(uc->havedir){ free(uc->dir.name); free(uc->dir.uid); free(uc->dir.gid); } break; case Tserver: WNetCloseEnum(uc->h); break; } } cnameclose(uc->syspath); free(uc); } static long fsread(Chan *c, void *a, long n, vlong vo) { int r; Uchan *uc; OVERLAPPED o; DWORD m; uc = c->aux; if(uc->eof) return 0; DPRINT("fsread\n"); memset(&o, 0, sizeof o); o.Offset = vo; o.OffsetHigh = vo>>32; switch(uc->type){ case Tfile: r = ReadFile(uc->h, a, n, &m, &o); if(r == 0){ if(uc->type==Tpipe || GetLastError() == ERROR_HANDLE_EOF) m = 0; else{ oserror(); nexterror(); } } break; case Tmntdir: m = 0; break; case Trootdir: m = rootdirread(uc, a, n, vo); break; case Tconsole: m = consoleread(uc, a, n); break; case Tvolume: case Tdir: m = directoryread(uc, a, n, vo); break; case Tserver: m = serverread(uc, a, n, vo); break; } return m; } static long fswrite(Chan *c, void *a, long n, vlong vo) { Uchan *uc; OVERLAPPED o; DWORD m; memset(&o, 0, sizeof o); o.Offset = vo; o.OffsetHigh = vo>>32; uc = c->aux; switch(uc->type){ case Tpipe: if(!WriteFile(uc->h, a, n, &m, nil)){ oserror(); print("pipewrite: %r\n"); nexterror(); } break; case Tfile: if(!WriteFile(uc->h, a, n, &m, &o)){ oserror(); print("writefile: %r\n"); nexterror(); } break; case Tconsole: m = consolewrite(uc, a, n); break; case Tdir: error(Ebadusefd); break; } return m; } static void fsremove(Chan *c) { int err; Rune *path; Uchan *uc; uc = c->aux; path = towin(uc->syspath->s); if(path == nil) error(Eperm); if(c->qid.type&QTDIR) err = !RemoveDirectory(path); else err = !DeleteFile(path); free(path); if(err) oserror(); if(c->flag & COPEN){ CloseHandle(uc->h); uc->h = INVALID_HANDLE_VALUE; } cnameclose(uc->syspath); free(uc); if(err) nexterror(); } static int fsstat(Chan *c, uchar *buf, int n) { Dir d; HANDLE h; char *dpath, *s; Rune *path, *p; Uchan *uc; WIN32_FIND_DATA data; uc = c->aux; switch(uc->type){ case Tpipe: case Tconsole: case Tstdin: error("cannot stat pipe, console, stdin"); } dpath = strdup(uc->syspath->s); if(dpath == nil) error("out of memory"); s = strrchr(dpath, '/'); if(s == dpath) *(s+1) = '\0'; else *s = '\0'; path = towin(uc->syspath->s); if(waserror()){ free(dpath); free(path); nexterror(); } memset(&d, 0, sizeof d); switch(uc->type){ default: error("windows fsstat bug"); case Trootdir: d.name = strdup("/"); goto Fakedir; case Tmntdir: d.name = strdup("mnt"); goto Fakedir; case Tserver: p = runestrrchr(path, '\\'); p++; memset(&d, 0, sizeof d); d.name = win_wstr2utf(p); Fakedir: d.uid = strdup("sys"); d.gid = strdup("sys"); d.mtime = d.atime = seconds(); d.type = 'U'; d.dev = 0; d.qid = c->qid; d.mode = DMDIR|0777; break; case Tvolume: memset(&data, 0, sizeof data); data.dwFileAttributes = GetFileAttributes(path); if(data.dwFileAttributes == (DWORD)-1){ oserror(); nexterror(); } data.ftCreationTime = data.ftLastAccessTime = data.ftLastWriteTime = wintime(seconds()); data.nFileSizeHigh = 0; data.nFileSizeLow = 0; p = runestrrchr(path, '\\'); p++; runestrecpy(data.cFileName, data.cFileName+nelem(data.cFileName), p); data2dir(&data, &d, uc->syspath->s); break; case Tdir: case Tfile: memset(&data, 0, sizeof data); h = FindFirstFile(path, &data); if(h == INVALID_HANDLE_VALUE){ oserror(); nexterror(); } FindClose(h); data2dir(&data, &d, dpath); break; } n = convD2M(&d, buf, n); free(dpath); free(d.uid); free(d.gid); free(d.name); free(path); poperror(); return n; } static int fswstat(Chan *c, uchar *edir, int nedir) { char *strs; int attr, n; Dir dir; FILETIME *pat, at, *pmt, mt; HANDLE h; Rune *path, *newpath, *p; Uchan *uc; WIN32_FIND_DATA *data; uc = c->aux; path = towin(uc->syspath->s); strs = smalloc(nedir); data = smalloc(sizeof(*data)); if(waserror()){ free(path); free(strs); free(data); nexterror(); } if((nedir=convM2D(edir, nedir, &dir, strs)) == 0) error("convM2D failed"); switch(uc->type){ case Trootdir: case Tmntdir: case Tserver: error(Eperm); case Tvolume: if(!win_usesecurity) error("cannot wstat volume: no security"); if(win_secwperm(path, &dir, 1) < 0) nexterror(); break; case Tdir: case Tfile: h = FindFirstFile(path, data); if(h == INVALID_HANDLE_VALUE) { oserror(); nexterror(); } FindClose(h); pat = pmt = NULL; if(~dir.atime != 0){ at = wintime(dir.atime); pat = &at; } if(~dir.mtime != 0){ mt = wintime(dir.mtime); pmt = &mt; } if(pat || pmt){ h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(h == INVALID_HANDLE_VALUE){ oserror(); nexterror(); } if(!SetFileTime(h, 0, pat, pmt)){ oserror(); CloseHandle(h); nexterror(); } CloseHandle(h); } attr = data->dwFileAttributes; if(~dir.mode != 0){ if(dir.mode & 0222) attr &= ~FILE_ATTRIBUTE_READONLY; else attr |= FILE_ATTRIBUTE_READONLY; if(attr&FILE_ATTRIBUTE_READONLY) SetFileAttributes(path, attr); } //print("win_usesecurity %d\n", win_usesecurity); if(win_usesecurity && win_secwperm(path, &dir, attr&FILE_ATTRIBUTE_DIRECTORY) < 0) nexterror(); if(~dir.mode != 0 && !(attr & FILE_ATTRIBUTE_READONLY)) SetFileAttributes(path, attr); /* do last so path is valid throughout */ if(dir.name != nil && dir.name[0]){ p = runestrrchr(path, '\\'); n = p-path+1; newpath = smalloc(sizeof(Rune)*(n+utflen(dir.name)+1)); memmove(newpath, path, n*sizeof(Rune)); win_utf2wstrn(newpath+n, utflen(dir.name)+1, dir.name); if(runestrcmp(path, newpath) != 0 && !MoveFile(path, newpath)){ free(newpath); oserror(); nexterror(); } free(newpath); } break; case Tpipe: error("cannot wstat pipe"); case Tstdin: error("cannot wstat stdin"); case Tconsole: error("cannot wstat console"); } free(path); free(strs); free(data); poperror(); return nedir; } static void fschdir(Chan *c) { Rune *path; Uchan *uc; uc = c->aux; switch(uc->type){ default: error("unKnown path type (BUG)"); case Tserver: error("can't chdir to server yet"); case Tvolume: case Tfile: path = towin(uc->syspath->s); if(path == nil) error("can't chdir there"); if(!SetCurrentDirectory(path)){ free(path); oserror(); nexterror(); } free(path); break; } } Dev devfs = { (Rune)'U', "fs", fsreset, fsattach, fswalk, fsstat, fsopen, fscreate, fsclose, fsread, devbread, fswrite, devbwrite, fsremove, fswstat, }; static int pathqid(int oh, char *path) { uint h; char *p; h = oh; h = (h*1000003 + '\\'); for(p=path; *p; p++) h = (h*1000003 + *p); return h; } static long unixtime(FILETIME ft) { vlong t; t = (vlong)ft.dwLowDateTime + ((vlong)ft.dwHighDateTime<<32); t -= (vlong)10000000*134774*24*60*60; return (long)(t/10000000); } static FILETIME wintime(ulong t) { FILETIME ft; vlong vt; vt = (vlong)t*10000000+(vlong)10000000*134774*24*60*60; ft.dwLowDateTime = vt; ft.dwHighDateTime = vt>>32; return ft; } static long consolewrite(Uchan *uc, void *buf, long n) { char *p; Rune buf2[1000], *q; int i, n2, on; static Lock lk; static int tmpconsole; qlock(&uc->qlk); if(uc->h == INVALID_HANDLE_VALUE) { lock(&lk); if(!tmpconsole) tmpconsole = AllocConsole(); unlock(&lk); uc->h = GetStdHandle(STD_OUTPUT_HANDLE); } p = buf; on = n; /* handle partial runes */ if(uc->nbuf) { i = uc->nbuf; assert(i < UTFmax); while(i < UTFmax && n>0) { uc->buf[i] = *p; i++; p++; n--; if(fullrune(uc->buf, i)) { uc->nbuf = 0; chartorune(buf2, uc->buf); if(!WriteConsole(uc->h, buf2, 1, &n, 0)) { qunlock(&uc->qlk); oserror(); nexterror(); } break; } } } while(n >= UTFmax || fullrune(p, n)) { n2 = nelem(buf2); q = buf2; while(n2) { if(n < UTFmax && !fullrune(p, n)) break; i = chartorune(q, p); p += i; n -= i; n2--; q++; } if(!WriteConsole(uc->h, buf2, q-buf2, &n2, 0)) { qunlock(&uc->qlk); oserror(); nexterror(); } } if(n != 0) { if(uc->buf == 0) uc->buf = mallocz(UTFmax, 1); assert(n+uc->nbuf < UTFmax); memcpy(uc->buf+uc->nbuf, p, n); uc->nbuf += n; } qunlock(&uc->qlk); return on; } /* * It appears that win NT 4.0 has a bug in ReadConsole * If ReadConsole is called with a buffer that is smaller than * the input that is buffered, it appears that readconsoles buffer * can get corrupted by WriteConsole * i.e * char buf[3]; * int n2; * * for(;;) { * if(!ReadConsole(h, buf, sizeof(buf), &n2, 0)) * exit(0); * if(!WriteConsole(h2, buf, n2, &n2, 0)) * exit(0); * * Sleep(100); * } * */ static long consoleread(Uchan *uc, void *a, long n) { int n2, i; Rune r, rbuf[200]; char *p; uchar *buf; buf = a; qlock(&uc->qlk); if(n == 0 || uc->h == INVALID_HANDLE_VALUE){ qunlock(&uc->qlk); return 0; } while(uc->nbuf==0 && uc->eof==0) { if(!ReadConsole(uc->h, rbuf, nelem(rbuf), &n2, 0)){ qunlock(&uc->qlk); oserror(); nexterror(); return -1; } if(n2 == 0) continue; if(uc->buf == 0) uc->buf = mallocz(sizeof(rbuf)*UTFmax, 1); for(i=0,p=uc->buf; ieof = 1; break; } p += runetochar(p, &r); } uc->nbuf = p-uc->buf; } if(n > uc->nbuf) n = uc->nbuf; memmove(buf, uc->buf, n); memmove(uc->buf, uc->buf+n, uc->nbuf-n); uc->nbuf -= n; qunlock(&uc->qlk); return n; } static void serveropen(Uchan *uc, int mode) { NETRESOURCE res; HANDLE h; res.dwScope = RESOURCE_GLOBALNET; res.dwType = RESOURCETYPE_DISK; res.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC; res.dwUsage = RESOURCEUSAGE_CONTAINER; res.lpLocalName = 0; res.lpRemoteName = towin(uc->syspath->s); res.lpComment = 0; res.lpProvider = 0; if (WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &res, &h) != NO_ERROR) { free(res.lpRemoteName); uc->h = INVALID_HANDLE_VALUE; oserror(); nexterror(); } free(res.lpRemoteName); uc->h = h; } static int serverentry(Uchan *uc, int t) { int count, n; uchar buf[1000]; Dir *dir; Rune *p; NETRESOURCE *res; n = sizeof(buf); count = 1; if(WNetEnumResource(uc->h, &count, buf, &n) != NO_ERROR) return 0; res = (NETRESOURCE*)buf; dir = &uc->dir; memset(dir, 0, sizeof(Dir)); p = runestrrchr(res->lpRemoteName, (Rune)'\\'); dir->name = win_wstr2utf(p+1); dir->mode = DMDIR | 0777; dir->qid.path = DMDIR; /* BUG */ dir->qid.vers = t; dir->atime = t; dir->mtime = t; uc->havedir = 1; return 1; } static long serverread(Uchan *uc, void *a, long n, vlong off) { int i, m, t; uchar *buf; qlock(&uc->qlk); if(waserror()){ /* serveropen can error */ qunlock(&uc->qlk); nexterror(); } if(off == 0){ if(uc->havedir){ uc->havedir = 0; free(uc->dir.name); } if(uc->h != INVALID_HANDLE_VALUE){ WNetCloseEnum(uc->h); uc->h = INVALID_HANDLE_VALUE; } serveropen(uc, OREAD); } buf = a; t = seconds(); for(i=0; ihavedir && !serverentry(uc, t)) break; if((m=convD2M(&uc->dir, buf+i, n-i)) <= BIT16SZ) break; uc->havedir = 0; free(uc->dir.name); } qunlock(&uc->qlk); poperror(); return i; } static void serverclose(Uchan *uc) { if(uc->havedir){ uc->havedir = 0; free(uc->dir.name); } if(uc->h != INVALID_HANDLE_VALUE){ WNetCloseEnum(uc->h); uc->h = INVALID_HANDLE_VALUE; } } static void data2dir(WIN32_FIND_DATA *dat, Dir *dir, char *dirpath) { int ret; Rune *p; char *ext; dir->name = win_wstr2utf(dat->cFileName); dir->qid.type = 0; dir->qid.path = pathqid(pathqid(0, dirpath), dir->name); dir->atime = unixtime(dat->ftLastAccessTime); dir->mtime = unixtime(dat->ftLastWriteTime); dir->qid.vers = dir->mtime; dir->length = dat->nFileSizeLow | (dat->nFileSizeHigh<<32); dir->type = 'U'; dir->dev = 0; if(!win_usesecurity){ //print("win_usesecurity = 0\n"); goto Nosec; } p = fspath(dirpath, dir->name); ret = win_secperm(dir, p); //print("win_secperm %S = %d\n", p, ret); free(p); if(ret < 0){ Nosec: /* no NT security so make something up */ dir->uid = strdup(eve); dir->gid = strdup(eve); dir->mode = 0666; ext = strrchr(dir->name, '.'); if(ext != 0 && (cistrcmp(ext, ".exe") == 0 || cistrcmp(ext, ".rsh") == 0)) dir->mode |= 0111; if(dat->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) dir->mode |= 0111; } if(dat->dwFileAttributes & FILE_ATTRIBUTE_READONLY) dir->mode &= ~0222; if(dat->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){ dir->qid.type |= QTDIR; dir->mode |= DMDIR; } } static void udata2dir(Uchan *uc) { Rune *s; s = uc->finddata.cFileName; if(s[0] == 0) return; if(s[0]=='.' && (s[1]==0 || (s[1]=='.' && s[2]==0))) return; data2dir(&uc->finddata, &uc->dir, uc->syspath->s); uc->havedir = 1; } int dirbadentry(WIN32_FIND_DATA *data) { Rune *s; s = data->cFileName; if(s[0] == 0) return 1; if(s[0] == '.' && (s[1] == 0 || s[1] == '.' && s[2] == 0)) return 1; return 0; } static int dirnext(Uchan *uc) { while(!uc->havedir){ if(!FindNextFile(uc->h, &uc->finddata)) return 0; udata2dir(uc); } return 1; } static long directoryread(Uchan *uc, uchar *buf, long n, vlong off) { int i, m; Rune *path; qlock(&uc->qlk); if(off == 0){ DPRINT("\toffset zero\n"); if(uc->h != INVALID_HANDLE_VALUE && uc->h != nil){ DPRINT("FindClose %p\n", uc->h); FindClose(uc->h); } if(uc->havedir){ DPRINT("Havedir\n"); uc->havedir = 0; free(uc->dir.name); free(uc->dir.uid); free(uc->dir.gid); } path = fspath(uc->syspath->s, "*.*"); uc->h = FindFirstFile(path, &uc->finddata); free(path); if(uc->h == INVALID_HANDLE_VALUE){ qunlock(&uc->qlk); DPRINT("\tfindfirst failed; ret 0\n"); return 0; } udata2dir(uc); } for(i=0; ihavedir && !dirnext(uc)){ break; } if((m=convD2M(&uc->dir, buf+i, n-i)) <= BIT16SZ){ DPRINT("\tconvD2M returns %d; ret %d\n", m, i); break; } uc->havedir = 0; free(uc->dir.name); free(uc->dir.uid); free(uc->dir.gid); } qunlock(&uc->qlk); return i; } static void rootdiropen(Uchan *uc) { uc->dir.name = uc->rootent; uc->dir.uid = eve; uc->dir.gid = eve; uc->dir.mode = DMDIR|0777; uc->dir.qid.type = QTDIR; uc->dir.qid.vers = 0; uc->dir.length = 0; uc->rootoff = 0; } static long rootdirread(Uchan *uc, uchar *buf, long n, vlong off) { int i, m; qlock(&uc->qlk); if(off==0){ uc->rootoff = 0; uc->havedir = 0; } for(i=0; ihavedir){ if(uc->rootoff>26) break; else if(uc->rootoff==26) strcpy(uc->rootent, "mnt"); else{ uc->rootent[0] = 'a'+uc->rootoff; uc->rootent[1] = '\0'; } uc->dir.qid.path = pathqid(pathqid(0, "/"), uc->dir.name); uc->havedir = 1; uc->rootoff++; } if((m=convD2M(&uc->dir, buf+i, n-i)) <= BIT16SZ){ DPRINT("\tconvD2M returns %d; ret %d\n", m, i); break; } uc->havedir = 0; } qunlock(&uc->qlk); return i; } long syspassfd(ulong *arg) { int j, fd; char buf[ERRMAX]; Chan *c; HANDLE h, nh; Qid qid; Syscallmem *scm; Uchan *uc; if(waserror()){ print("up %p syspassfd: %s\n", up, up->errstr); nexterror(); } fd = arg[0]; if(fd < 0 || fd > 2) error(Ebadarg); h = (HANDLE)arg[1]; if(h==nil || h==INVALID_HANDLE_VALUE) error(Ebadarg); scm = up->sysaux; if(!DuplicateHandle(scm->hs.hclientproc, h, GetCurrentProcess(), &nh, 0, 0, DUPLICATE_SAME_ACCESS)){ osrerrstr(buf, sizeof buf); snprint(up->errstr, ERRMAX, "DuplicateHandle: %s", buf); nexterror(); } uc = smalloc(sizeof(Uchan)); uc->h = nh; if(waserror()){ free(uc); CloseHandle(nh); nexterror(); } /* * This won't happen, since * we can't pass console handles * between processes. Idiots. */ if(GetConsoleMode(nh, &j)) uc->type = Tconsole; else{ j = GetFileType(nh); switch(j){ default: error("unknown handle type"); case FILE_TYPE_UNKNOWN: case FILE_TYPE_DISK: case FILE_TYPE_CHAR: uc->type = Tfile; break; case FILE_TYPE_PIPE: uc->type = Tpipe; break; } } c = newchan(); if(waserror()){ cclose(c); nexterror(); } sprint(up->genbuf, "/fd/%d", fd); c->name = newcname(up->genbuf); c->type = devno('U', 1); mkqid(&qid, fd, 0, 0); c->qid = qid; c->aux = uc; c->flag |= COPEN; c->mode = fd==0 ? OREAD: OWRITE; print("up %p newfd chan %p fd %d\n", up, c, fd); if(newfdx(c, fd) < 0){ print("failed %s\n", up->errstr); nexterror(); } poperror(); poperror(); poperror(); return 0; } long syspassdir(ulong *arg) { USED(arg); error(Ebadarg); return -1; }