#include <windows.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h> #include "u.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "error.h" #include <libsec.h> /* for sha1 in pathhash() */ typedef struct DIR DIR;typedef struct Ufsinfo Ufsinfo; enum{ TPATH_ROOT = 0, // "" TPATH_VOLUME = 1, // "C:" TPATH_FILE = 2, // "C:\bla"}; struct DIR{ // for FindFileFirst() HANDLE handle; WIN32_FIND_DATA wfd; // for GetLogicalDriveStrings() wchar_t *drivebuf; wchar_t *drivep; // dont move to the next item int keep;}; struct Ufsinfo{ int mode; HANDLE fh; DIR* dir; vlong offset; QLock oq; wchar_t *path;}; static wchar_t *catpath(wchar_t *, char *, wchar_t *);static ulong fsdirread(Chan*, uchar*, int, vlong);static ulong fsaccess(int);static ulong pathtype(wchar_t *);static int checkvolume(wchar_t *); static ulongunixtime(FILETIME *ft){ vlong t; t = ((vlong)ft->dwHighDateTime << 32)|((vlong)ft->dwLowDateTime); t -= 116444736000000000LL; return ((t<0)?(-1 - (-t - 1)) : t)/10000000;} static FILETIMEfiletime(ulong ut){ FILETIME ft; vlong t = (vlong)ut * 10000000LL; t += 116444736000000000LL; ft.dwLowDateTime = t; ft.dwHighDateTime = t >> 32; return ft;} static uvlongpathhash(wchar_t *p){ uchar digest[SHA1dlen]; sha1((uchar*)p, wcslen(p)*sizeof(wchar_t), digest, nil); return *(uvlong*)digest;} static ulongwfdtodmode(WIN32_FIND_DATA *wfd){ int m; m = DMREAD|DMWRITE|DMEXEC; if(wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) m |= DMDIR; if(wfd->dwFileAttributes & FILE_ATTRIBUTE_READONLY) m &= ~DMWRITE; m |= (m & 07)<<3; m |= (m & 07)<<6; return m;} static Qidwfdtoqid(wchar_t *path, WIN32_FIND_DATA *wfd){ ulong t; WIN32_FIND_DATA f; Qid q; t = pathtype(path); switch(t){ case TPATH_VOLUME: case TPATH_ROOT: q.type = QTDIR; q.path = pathhash(path); q.vers = 0; break; case TPATH_FILE: if(!wfd){ HANDLE h; if((h = FindFirstFile(path, &f))==INVALID_HANDLE_VALUE) oserror(); FindClose(h); wfd = &f; } q.type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? QTDIR : QTFILE; q.path = pathhash(path); q.vers = unixtime(&wfd->ftLastWriteTime); break; } return q;} static voidwfdtodir(wchar_t *path, Dir *d, WIN32_FIND_DATA *wfd){ extern ulong kerndate; WIN32_FIND_DATA f; switch(pathtype(path)){ case TPATH_VOLUME: case TPATH_ROOT: wfd = nil; d->mode = 0777 | DMDIR; d->atime = seconds(); d->mtime = kerndate; d->length = 0; break; case TPATH_FILE: if(wfd == nil){ HANDLE h; if((h = FindFirstFile(path, &f))==INVALID_HANDLE_VALUE) oserror(); FindClose(h); wfd = &f; } d->mode = wfdtodmode(wfd); d->atime = unixtime(&wfd->ftLastAccessTime); d->mtime = unixtime(&wfd->ftLastWriteTime); d->length = ((uvlong)wfd->nFileSizeHigh << 32)|((uvlong)wfd->nFileSizeLow); break; } d->qid = wfdtoqid(path, wfd); d->uid = eve; d->gid = eve; d->muid = eve;} static char*lastelem(Chan *c){ char *s, *t; s = chanpath(c); if((t = strrchr(s, '/')) == nil) return s; if(t[1] == 0) return t; return t+1;} static ulongpathtype(wchar_t *path){ if(path[0] == 0 || path[1] == 0) return TPATH_ROOT; if(path[1] == ':' && path[2] == 0) return TPATH_VOLUME; return TPATH_FILE;} static intcheckvolume(wchar_t *path){ wchar_t vol[MAX_PATH]; wchar_t volname[MAX_PATH]; wchar_t fsysname[MAX_PATH]; DWORD complen; DWORD flags; wcscpy(vol, path); wcscat(vol, L"\\"); if(!GetVolumeInformation( vol, volname, MAX_PATH, NULL, &complen, &flags, fsysname, MAX_PATH)) return 0; return 1; } static wchar_t*wstrdup(wchar_t *s){ wchar_t *d; long n; n = (wcslen(s)+1)*sizeof(wchar_t); d = mallocz(n, 0); memmove(d, s, n); return d;} static Chan*fsattach(char *spec){ static int devno; Ufsinfo *uif; Chan *c; uif = mallocz(sizeof(Ufsinfo), 1); uif->path = wstrdup(L""); c = devattach('U', spec); c->aux = uif; c->dev = devno++; c->qid.type = QTDIR; return c;} static Chan*fsclone(Chan *c, Chan *nc){ Ufsinfo *uif; uif = mallocz(sizeof(Ufsinfo), 1); *uif = *(Ufsinfo*)c->aux; uif->path = wstrdup(uif->path); nc->aux = uif; return nc;} static intfswalk1(Chan *c, char *name){ WIN32_FIND_DATA wfd; HANDLE h; wchar_t *p; Ufsinfo *uif; uif = c->aux; p = catpath(uif->path, name, nil); switch(pathtype(p)){ case TPATH_VOLUME: if(!checkvolume(p)){ free(p); return 0; } case TPATH_ROOT: c->qid = wfdtoqid(p, nil); break; case TPATH_FILE: if((h = FindFirstFile(p, &wfd)) == INVALID_HANDLE_VALUE){ free(p); return 0; } FindClose(h); c->qid = wfdtoqid(p, &wfd); break; } free(uif->path); uif->path = p; return 1;} static Walkqid*fswalk(Chan *c, Chan *nc, char **name, int nname){ int i; Walkqid *wq; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); fsclone(c, nc); wq->clone = nc; for(i=0; i<nname; i++){ if(fswalk1(nc, name[i]) == 0) break; wq->qid[i] = nc->qid; } if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq;} static intfsstat(Chan *c, uchar *buf, int n){ Dir d; Ufsinfo *uif; if(n < BIT16SZ) error(Eshortstat); uif = c->aux; d.name = lastelem(c); wfdtodir(uif->path, &d, nil); d.type = 'U'; d.dev = c->dev; return convD2M(&d, buf, n);} static Chan*fsopen(Chan *c, int mode){ wchar_t *p; Ufsinfo *uif; int omode; omode = openmode(mode); uif = c->aux; if(c->qid.type & QTDIR){ DIR *d; if(omode != OREAD) error(Eperm); d = malloc(sizeof(*d)); if(waserror()){ free(d); nexterror(); } switch(pathtype(uif->path)){ case TPATH_ROOT: d->drivebuf = malloc(sizeof(wchar_t)*MAX_PATH); if(GetLogicalDriveStrings(MAX_PATH-1, d->drivebuf) == 0){ free(d->drivebuf); d->drivebuf = nil; oserror(); } d->drivep = d->drivebuf; break; case TPATH_VOLUME: case TPATH_FILE: p = catpath(uif->path, "*.*", nil); if((d->handle = FindFirstFile(p, &d->wfd)) == INVALID_HANDLE_VALUE){ free(p); oserror(); } free(p); break; } d->keep = 1; uif->dir = d; poperror(); } else { uif->dir = NULL; if((uif->fh = CreateFile( uif->path, fsaccess(omode & 3), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, (mode & OTRUNC) ? TRUNCATE_EXISTING : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) oserror(); } uif->offset = 0; c->offset = 0; c->mode = omode; c->flag |= COPEN; return c;} static Chan*fscreate(Chan *c, char *name, int mode, ulong perm){ wchar_t *newpath; Ufsinfo *uif; DIR *d; HANDLE h; int omode; omode = openmode(mode & ~OEXCL); uif = c->aux; newpath = catpath(uif->path, name, nil); if(waserror()){ free(newpath); nexterror(); } d = NULL; h = INVALID_HANDLE_VALUE; if(perm & DMDIR) { wchar_t *p; if(omode != OREAD || pathtype(uif->path) == TPATH_ROOT) error(Eperm); if(!CreateDirectory(newpath, NULL)){ if(GetLastError() != ERROR_ALREADY_EXISTS || mode & OEXCL) oserror(); } d = malloc(sizeof(*d)); p = catpath(newpath, "*.*", nil); if((d->handle = FindFirstFile(p, &d->wfd)) == INVALID_HANDLE_VALUE){ free(p); free(d); oserror(); } free(p); if(waserror()){ FindClose(d->handle); free(d); nexterror(); } d->keep = 1; } else { if((h = CreateFile( newpath, fsaccess(omode & 3), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, (mode & OEXCL) ? CREATE_NEW : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) oserror(); if(waserror()){ CloseHandle(h); nexterror(); } } c->qid = wfdtoqid(newpath, nil); uif->dir = d; uif->fh = h; poperror(); free(uif->path); uif->path = newpath; uif->offset = 0; poperror(); c->offset = 0; c->mode = omode; c->flag |= COPEN; return c;} static voidfsclose(Chan *c){ Ufsinfo *uif; uif = c->aux; if(c->flag & COPEN) { if(uif->dir != nil){ if(uif->dir->drivebuf != nil){ free(uif->dir->drivebuf); uif->dir->drivebuf = nil; } else { FindClose(uif->dir->handle); free(uif->dir); } } else { CloseHandle(uif->fh); } c->flag &= ~COPEN; if(c->flag & CRCLOSE) { devtab[c->type]->remove(c); return; } } free(uif->path); free(uif);} static longfsread(Chan *c, void *va, long n, vlong offset){ HANDLE fh; DWORD r; Ufsinfo *uif; Lines 1–500 of 820. Load more
#include <windows.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include <libsec.h> /* for sha1 in pathhash() */ typedef struct DIR DIR; typedef struct Ufsinfo Ufsinfo; enum { TPATH_ROOT = 0, // "" TPATH_VOLUME = 1, // "C:" TPATH_FILE = 2, // "C:\bla" }; struct DIR { // for FindFileFirst() HANDLE handle; WIN32_FIND_DATA wfd; // for GetLogicalDriveStrings() wchar_t *drivebuf; wchar_t *drivep; // dont move to the next item int keep; }; struct Ufsinfo { int mode; HANDLE fh; DIR* dir; vlong offset; QLock oq; wchar_t *path; }; static wchar_t *catpath(wchar_t *, char *, wchar_t *); static ulong fsdirread(Chan*, uchar*, int, vlong); static ulong fsaccess(int); static ulong pathtype(wchar_t *); static int checkvolume(wchar_t *); static ulong unixtime(FILETIME *ft) { vlong t; t = ((vlong)ft->dwHighDateTime << 32)|((vlong)ft->dwLowDateTime); t -= 116444736000000000LL; return ((t<0)?(-1 - (-t - 1)) : t)/10000000; } static FILETIME filetime(ulong ut) { FILETIME ft; vlong t = (vlong)ut * 10000000LL; t += 116444736000000000LL; ft.dwLowDateTime = t; ft.dwHighDateTime = t >> 32; return ft; } static uvlong pathhash(wchar_t *p) { uchar digest[SHA1dlen]; sha1((uchar*)p, wcslen(p)*sizeof(wchar_t), digest, nil); return *(uvlong*)digest; } static ulong wfdtodmode(WIN32_FIND_DATA *wfd) { int m; m = DMREAD|DMWRITE|DMEXEC; if(wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) m |= DMDIR; if(wfd->dwFileAttributes & FILE_ATTRIBUTE_READONLY) m &= ~DMWRITE; m |= (m & 07)<<3; m |= (m & 07)<<6; return m; } static Qid wfdtoqid(wchar_t *path, WIN32_FIND_DATA *wfd) { ulong t; WIN32_FIND_DATA f; Qid q; t = pathtype(path); switch(t){ case TPATH_VOLUME: case TPATH_ROOT: q.type = QTDIR; q.path = pathhash(path); q.vers = 0; break; case TPATH_FILE: if(!wfd){ HANDLE h; if((h = FindFirstFile(path, &f))==INVALID_HANDLE_VALUE) oserror(); FindClose(h); wfd = &f; } q.type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? QTDIR : QTFILE; q.path = pathhash(path); q.vers = unixtime(&wfd->ftLastWriteTime); break; } return q; } static void wfdtodir(wchar_t *path, Dir *d, WIN32_FIND_DATA *wfd) { extern ulong kerndate; WIN32_FIND_DATA f; switch(pathtype(path)){ case TPATH_VOLUME: case TPATH_ROOT: wfd = nil; d->mode = 0777 | DMDIR; d->atime = seconds(); d->mtime = kerndate; d->length = 0; break; case TPATH_FILE: if(wfd == nil){ HANDLE h; if((h = FindFirstFile(path, &f))==INVALID_HANDLE_VALUE) oserror(); FindClose(h); wfd = &f; } d->mode = wfdtodmode(wfd); d->atime = unixtime(&wfd->ftLastAccessTime); d->mtime = unixtime(&wfd->ftLastWriteTime); d->length = ((uvlong)wfd->nFileSizeHigh << 32)|((uvlong)wfd->nFileSizeLow); break; } d->qid = wfdtoqid(path, wfd); d->uid = eve; d->gid = eve; d->muid = eve; } static char* lastelem(Chan *c) { char *s, *t; s = chanpath(c); if((t = strrchr(s, '/')) == nil) return s; if(t[1] == 0) return t; return t+1; } static ulong pathtype(wchar_t *path) { if(path[0] == 0 || path[1] == 0) return TPATH_ROOT; if(path[1] == ':' && path[2] == 0) return TPATH_VOLUME; return TPATH_FILE; } static int checkvolume(wchar_t *path) { wchar_t vol[MAX_PATH]; wchar_t volname[MAX_PATH]; wchar_t fsysname[MAX_PATH]; DWORD complen; DWORD flags; wcscpy(vol, path); wcscat(vol, L"\\"); if(!GetVolumeInformation( vol, volname, MAX_PATH, NULL, &complen, &flags, fsysname, MAX_PATH)) return 0; return 1; } static wchar_t* wstrdup(wchar_t *s) { wchar_t *d; long n; n = (wcslen(s)+1)*sizeof(wchar_t); d = mallocz(n, 0); memmove(d, s, n); return d; } static Chan* fsattach(char *spec) { static int devno; Ufsinfo *uif; Chan *c; uif = mallocz(sizeof(Ufsinfo), 1); uif->path = wstrdup(L""); c = devattach('U', spec); c->aux = uif; c->dev = devno++; c->qid.type = QTDIR; return c; } static Chan* fsclone(Chan *c, Chan *nc) { Ufsinfo *uif; uif = mallocz(sizeof(Ufsinfo), 1); *uif = *(Ufsinfo*)c->aux; uif->path = wstrdup(uif->path); nc->aux = uif; return nc; } static int fswalk1(Chan *c, char *name) { WIN32_FIND_DATA wfd; HANDLE h; wchar_t *p; Ufsinfo *uif; uif = c->aux; p = catpath(uif->path, name, nil); switch(pathtype(p)){ case TPATH_VOLUME: if(!checkvolume(p)){ free(p); return 0; } case TPATH_ROOT: c->qid = wfdtoqid(p, nil); break; case TPATH_FILE: if((h = FindFirstFile(p, &wfd)) == INVALID_HANDLE_VALUE){ free(p); return 0; } FindClose(h); c->qid = wfdtoqid(p, &wfd); break; } free(uif->path); uif->path = p; return 1; } static Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int i; Walkqid *wq; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); fsclone(c, nc); wq->clone = nc; for(i=0; i<nname; i++){ if(fswalk1(nc, name[i]) == 0) break; wq->qid[i] = nc->qid; } if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq; } static int fsstat(Chan *c, uchar *buf, int n) { Dir d; Ufsinfo *uif; if(n < BIT16SZ) error(Eshortstat); uif = c->aux; d.name = lastelem(c); wfdtodir(uif->path, &d, nil); d.type = 'U'; d.dev = c->dev; return convD2M(&d, buf, n); } static Chan* fsopen(Chan *c, int mode) { wchar_t *p; Ufsinfo *uif; int omode; omode = openmode(mode); uif = c->aux; if(c->qid.type & QTDIR){ DIR *d; if(omode != OREAD) error(Eperm); d = malloc(sizeof(*d)); if(waserror()){ free(d); nexterror(); } switch(pathtype(uif->path)){ case TPATH_ROOT: d->drivebuf = malloc(sizeof(wchar_t)*MAX_PATH); if(GetLogicalDriveStrings(MAX_PATH-1, d->drivebuf) == 0){ free(d->drivebuf); d->drivebuf = nil; oserror(); } d->drivep = d->drivebuf; break; case TPATH_VOLUME: case TPATH_FILE: p = catpath(uif->path, "*.*", nil); if((d->handle = FindFirstFile(p, &d->wfd)) == INVALID_HANDLE_VALUE){ free(p); oserror(); } free(p); break; } d->keep = 1; uif->dir = d; poperror(); } else { uif->dir = NULL; if((uif->fh = CreateFile( uif->path, fsaccess(omode & 3), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, (mode & OTRUNC) ? TRUNCATE_EXISTING : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) oserror(); } uif->offset = 0; c->offset = 0; c->mode = omode; c->flag |= COPEN; return c; } static Chan* fscreate(Chan *c, char *name, int mode, ulong perm) { wchar_t *newpath; Ufsinfo *uif; DIR *d; HANDLE h; int omode; omode = openmode(mode & ~OEXCL); uif = c->aux; newpath = catpath(uif->path, name, nil); if(waserror()){ free(newpath); nexterror(); } d = NULL; h = INVALID_HANDLE_VALUE; if(perm & DMDIR) { wchar_t *p; if(omode != OREAD || pathtype(uif->path) == TPATH_ROOT) error(Eperm); if(!CreateDirectory(newpath, NULL)){ if(GetLastError() != ERROR_ALREADY_EXISTS || mode & OEXCL) oserror(); } d = malloc(sizeof(*d)); p = catpath(newpath, "*.*", nil); if((d->handle = FindFirstFile(p, &d->wfd)) == INVALID_HANDLE_VALUE){ free(p); free(d); oserror(); } free(p); if(waserror()){ FindClose(d->handle); free(d); nexterror(); } d->keep = 1; } else { if((h = CreateFile( newpath, fsaccess(omode & 3), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, (mode & OEXCL) ? CREATE_NEW : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) oserror(); if(waserror()){ CloseHandle(h); nexterror(); } } c->qid = wfdtoqid(newpath, nil); uif->dir = d; uif->fh = h; poperror(); free(uif->path); uif->path = newpath; uif->offset = 0; poperror(); c->offset = 0; c->mode = omode; c->flag |= COPEN; return c; } static void fsclose(Chan *c) { Ufsinfo *uif; uif = c->aux; if(c->flag & COPEN) { if(uif->dir != nil){ if(uif->dir->drivebuf != nil){ free(uif->dir->drivebuf); uif->dir->drivebuf = nil; } else { FindClose(uif->dir->handle); free(uif->dir); } } else { CloseHandle(uif->fh); } c->flag &= ~COPEN; if(c->flag & CRCLOSE) { devtab[c->type]->remove(c); return; } } free(uif->path); free(uif); } static long fsread(Chan *c, void *va, long n, vlong offset) { HANDLE fh; DWORD r; Ufsinfo *uif;