From 3cc3cedba03827ba3796740a40f2f75bba85a44e Mon Sep 17 00:00:00 2001 From: Eric Williams Date: Wed, 15 Jun 2005 17:51:44 +0000 Subject: [PATCH] afsifs-20050615 Windows IFS client code and build option --- README-NT | 34 +- src/WINNT/afsd/NTMakefile | 8 + src/WINNT/afsd/afsd.c | 59 +- src/WINNT/afsd/afsd.h | 2 + src/WINNT/afsd/afsd_service.c | 88 +- src/WINNT/afsd/afsdifs.c | 1191 ++++++++++++++++ src/WINNT/afsd/afsdifs.h | 33 + src/WINNT/afsd/cm_callback.c | 15 + src/WINNT/afsd/cm_ioctl.c | 54 +- src/WINNT/afsd/cm_vnodeops.c | 15 +- src/WINNT/afsd/rawops.c | 364 +++++ src/WINNT/afsrdr/afsrdr.c | 2496 ++++++++++++++++++++++++++++++++++ src/WINNT/afsrdr/afsrdr.h | 68 + src/WINNT/afsrdr/ifs_rpc.c | 1407 +++++++++++++++++++ src/WINNT/afsrdr/ifs_rpc.h | 113 ++ src/WINNT/afsrdr/kif.h | 90 ++ src/WINNT/afsrdr/makefile | 1 + src/WINNT/afsrdr/sources | 31 + src/WINNT/client_config/drivemap.cpp | 109 +- src/WINNT/install/NSIS/NTMakefile | 3 + src/WINNT/install/NSIS/OpenAFS.nsi | 44 +- src/WINNT/install/NSIS/Service.cpp | 16 +- src/config/NTMakefile.i386_nt40 | 8 +- src/ntbuild.bat | 14 +- src/sys/pioctl_nt.c | 105 +- 25 files changed, 6345 insertions(+), 23 deletions(-) create mode 100644 src/WINNT/afsd/afsdifs.c create mode 100644 src/WINNT/afsd/afsdifs.h create mode 100644 src/WINNT/afsd/rawops.c create mode 100644 src/WINNT/afsrdr/afsrdr.c create mode 100644 src/WINNT/afsrdr/afsrdr.h create mode 100644 src/WINNT/afsrdr/ifs_rpc.c create mode 100644 src/WINNT/afsrdr/ifs_rpc.h create mode 100644 src/WINNT/afsrdr/kif.h create mode 100644 src/WINNT/afsrdr/makefile create mode 100644 src/WINNT/afsrdr/sources diff --git a/README-NT b/README-NT index 7507062..522a5ad 100644 --- a/README-NT +++ b/README-NT @@ -13,6 +13,18 @@ prior to Windows 2000 are not being supported. The InstallShield installer is still in the source tree but is no longer supported. A new open source installer based on NSIS 2.0 replaces it. +NOTE: +In this release, there are two clients offered: an SMB version (as was +included in all previous versions), and an IFS version (newly released). +To build the IFS version, follow the directions below, but note that +only the NSIS installer script can be correctly configured; the Wix +installer will not work correctly. Also, the kernel module associated +with the IFS version must be built separately, using the IFS kit or DDK +build environment. While in the DDK build environment, enter into the +afsrdr source directory, and execute 'build'. This will create the +module to be packaged by the installer. + + *********** Windows 2000/XP/2003 Build Process **************** Building OpenAFS for Windows requires configuring a Windows @@ -232,7 +244,7 @@ STEP F. Begin the build (3) Configure the environment variables: - For a release build: + For a release build (SMB version): (a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the Visual Studio environment you installed. @@ -241,7 +253,16 @@ STEP F. Begin the build (c) Execute the NTBUILD.BAT file with the parameter "free" - For a debug build: + For a release build (IFS version): + + (a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the + Visual Studio environment you installed. + + (b) Execute the SETENV.BAT file with the parameters "/2000 /RETAIL" + + (c) Execute the NTBUILD.BAT file with the parameter "free ifs" + + For a debug build (SMB version): (a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the Visual Studio environment you installed. @@ -250,6 +271,15 @@ STEP F. Begin the build (c) Execute the NTBUILD.BAT file with the parameter "checked" + For a debug build (IFS version): + + (a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the + Visual Studio environment you installed. + + (b) Execute the SETENV.BAT file with the parameters "/2000 /DEBUG" + + (c) Execute the NTBUILD.BAT file with the parameter "checked ifs" + (4) Clean the work area: nmake /f NTMakefile clean diff --git a/src/WINNT/afsd/NTMakefile b/src/WINNT/afsd/NTMakefile index 8361c51..a4b9683 100644 --- a/src/WINNT/afsd/NTMakefile +++ b/src/WINNT/afsd/NTMakefile @@ -88,7 +88,15 @@ $(RXOBJS): $(RX)\$$(@B).c $(IDLFILES):afsrpc.idl midl $(MIDL_FLAGS) /no_robust $(AFSDEV_AUXMIDLFLAGS) /app_config $? +RPCOBJS = $(OUT)\ifs_rpc.obj + +$(RPCOBJS):..\afsrdr\ifs_rpc.c + $(C2OBJ) ..\afsrdr\ifs_rpc.c + AFSDOBJS=\ + $(OUT)\ifs_rpc.obj \ + $(OUT)\rawops.obj \ + $(OUT)\afsdifs.obj \ $(OUT)\afsd_init.obj \ $(OUT)\cm_cell.obj \ $(OUT)\cm_server.obj \ diff --git a/src/WINNT/afsd/afsd.c b/src/WINNT/afsd/afsd.c index 2f10e2e..4a51af1 100644 --- a/src/WINNT/afsd/afsd.c +++ b/src/WINNT/afsd/afsd.c @@ -6,6 +6,30 @@ * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ #include #include @@ -25,12 +49,16 @@ #include #endif +#include "afsdifs.h" + HANDLE main_inst; HWND main_wnd; char main_statusText[100]; RECT main_rect; osi_log_t *afsd_logp; +HANDLE hAFSDWorkerThread[WORKER_THREADS], DoTerminate; + extern int traceOnPanic; extern void afsd_DbgBreakAllocInit(); @@ -77,6 +105,7 @@ int WINAPI WinMain( int nCmdShow) { MSG msg; + int i; afsd_SetUnhandledExceptionFilter(); @@ -104,6 +133,15 @@ int WINAPI WinMain( TranslateMessage(&msg); DispatchMessage(&msg); } + +#ifdef AFSIFS + WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE); + for (i = 0; i < WORKER_THREADS; i++) + CloseHandle(hAFSDWorkerThread[i]); + //CloseHandle(hAFSDMainThread); + RpcMgmtStopServerListening(NULL); +#endif + return (msg.wParam); } @@ -137,7 +175,7 @@ BOOL InitInstance( HDC hDC; TEXTMETRIC textmetric; INT nLineHeight; - long code; + long code, cnt; char *reason; /* remember this, since it is a useful thing for some of the Windows @@ -185,10 +223,23 @@ BOOL InitInstance( if (code != 0) osi_panic(reason, __FILE__, __LINE__); - code = afsd_InitSMB(&reason, MessageBox); +#ifndef AFSIFS + code = afsd_InitSMB(&reason, MessageBox); +#else + code = ifs_Init(&reason); +#endif + if (code != 0) osi_panic(reason, __FILE__, __LINE__); +#ifdef AFSIFS + DoTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_DoTerminate")); + if ( GetLastError() == ERROR_ALREADY_EXISTS ) + afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_DoTerminate")); + for (cnt = 0; cnt < WORKER_THREADS; cnt++) + hAFSDWorkerThread[cnt] = CreateThread(NULL, 0, ifs_MainLoop, 0, 0, NULL); +#endif + ShowWindow(hWnd, SW_SHOWMINNOACTIVE); UpdateWindow(hWnd); return (TRUE); @@ -225,7 +276,11 @@ LONG APIENTRY MainWndProc( break; case WM_DESTROY: +#ifndef AFSIFS RpcMgmtStopServerListening(NULL); +#else + SetEvent(DoTerminate); +#endif PostQuitMessage(0); break; diff --git a/src/WINNT/afsd/afsd.h b/src/WINNT/afsd/afsd.h index 112b202..d6fd398 100644 --- a/src/WINNT/afsd/afsd.h +++ b/src/WINNT/afsd/afsd.h @@ -132,6 +132,8 @@ extern HANDLE WaitToTerminate; #define LOG_PACKET 1 #undef NOTSERVICE +#define WORKER_THREADS 10 + #define AFSD_HOOK_DLL "afsdhook.dll" #define AFSD_INIT_HOOK "AfsdInitHook" typedef BOOL ( APIENTRY * AfsdInitHook )(void); diff --git a/src/WINNT/afsd/afsd_service.c b/src/WINNT/afsd/afsd_service.c index ad334c1..ad8614f 100644 --- a/src/WINNT/afsd/afsd_service.c +++ b/src/WINNT/afsd/afsd_service.c @@ -6,6 +6,30 @@ * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ #include #include @@ -31,6 +55,7 @@ #ifdef _DEBUG #include #endif +#include "afsdifs.h" //#define REGISTER_POWER_NOTIFICATIONS 1 #include "afsd_flushvol.h" @@ -41,8 +66,11 @@ static SERVICE_STATUS ServiceStatus; static SERVICE_STATUS_HANDLE StatusHandle; HANDLE hAFSDMainThread = NULL; +#ifdef AFSIFS +HANDLE hAFSDWorkerThread[WORKER_THREADS]; +#endif -HANDLE WaitToTerminate; +HANDLE WaitToTerminate, DoTerminate; int GlobalStatus; @@ -64,6 +92,7 @@ static void afsd_notifier(char *msgp, char *filep, long line) char tbuffer[512]; char *ptbuf[1]; HANDLE h; + int i; if (filep) sprintf(tbuffer, "Error at file %s, line %d: %s", @@ -96,7 +125,14 @@ static void afsd_notifier(char *msgp, char *filep, long line) DebugBreak(); #endif - SetEvent(WaitToTerminate); +#ifndef AFSIFS + SetEvent(WaitToTerminate); +#else + SetEvent(DoTerminate); + WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE); + for (i = 0; i < WORKER_THREADS; i++) + CloseHandle(hAFSDWorkerThread[i]); +#endif #ifdef JUMP if (GetCurrentThreadId() == MainThreadId) @@ -201,7 +237,11 @@ afsd_ServiceControlHandler(DWORD ctrlCode) } doneTrace: +#ifndef AFSIFS SetEvent(WaitToTerminate); +#else + SetEvent(DoTerminate); +#endif break; case SERVICE_CONTROL_INTERROGATE: @@ -269,7 +309,11 @@ afsd_ServiceControlHandlerEx( } doneTrace: +#ifndef AFSIFS SetEvent(WaitToTerminate); +#else + SetEvent(DoTerminate); +#endif dwRet = NO_ERROR; break; @@ -403,6 +447,7 @@ static void MountGlobalDrives(void) } } +#ifndef AFSIFS for ( ; dwRetry < MAX_RETRIES; dwRetry++) { NETRESOURCE nr; @@ -429,6 +474,9 @@ static void MountGlobalDrives(void) /* Disconnect any previous mappings */ dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE); } +#else + /* FIXFIX */ +#endif } RegCloseKey(hKey); @@ -453,7 +501,8 @@ static void DismountGlobalDrives() if (dwResult != ERROR_SUCCESS) return; - while (1) { +#ifndef AFSIFS + while (1) { dwDriveSize = sizeof(szDriveToMapTo); dwSubMountSize = sizeof(szSubMount); dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize); @@ -472,6 +521,9 @@ static void DismountGlobalDrives() afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed"); } +#else + /* FIXFIX */ +#endif RegCloseKey(hKey); } @@ -1015,6 +1067,7 @@ afsd_Main(DWORD argc, LPTSTR *argv) #endif /* JUMP */ HMODULE hHookDll; HMODULE hAdvApi32; + int cnt; #ifdef _DEBUG _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | @@ -1032,6 +1085,12 @@ afsd_Main(DWORD argc, LPTSTR *argv) if ( GetLastError() == ERROR_ALREADY_EXISTS ) afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate")); +#ifdef AFSIFS + DoTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_DoTerminate")); + if ( GetLastError() == ERROR_ALREADY_EXISTS ) + afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_DoTerminate")); +#endif + #ifndef NOTSERVICE hAdvApi32 = LoadLibrary("advapi32.dll"); if (hAdvApi32 == NULL) @@ -1207,11 +1266,22 @@ afsd_Main(DWORD argc, LPTSTR *argv) ServiceStatus.dwWaitHint -= 5000; SetServiceStatus(StatusHandle, &ServiceStatus); #endif + +#ifndef AFSIFS code = afsd_InitSMB(&reason, MessageBox); if (code != 0) { afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code); osi_panic(reason, __FILE__, __LINE__); } +#else + code = ifs_Init(&reason); + if (code != 0) { + afsi_log("ifs_Init failed: %s (code = %d)", reason, code); + osi_panic(reason, __FILE__, __LINE__); + } + for (cnt = 0; cnt < WORKER_THREADS; cnt++) + hAFSDWorkerThread[cnt] = CreateThread(NULL, 0, ifs_MainLoop, 0, 0, NULL); +#endif /* allow an exit to be called post smb initialization */ hHookDll = LoadLibrary(AFSD_HOOK_DLL); @@ -1288,7 +1358,13 @@ afsd_Main(DWORD argc, LPTSTR *argv) } } - WaitForSingleObject(WaitToTerminate, INFINITE); +#ifndef AFSIFS + WaitForSingleObject(WaitToTerminate, INFINITE); +#else + WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE); + for (cnt = 0; cnt < WORKER_THREADS; cnt++) + CloseHandle(hAFSDWorkerThread[cnt]); +#endif afsi_log("Received Termination Signal, Stopping Service"); @@ -1429,7 +1505,11 @@ main(int argc, char * argv[]) printf("Hit to terminate OpenAFS Client Service\n"); getchar(); +#ifndef AFSIFS SetEvent(WaitToTerminate); +#else + SetEvent(DoTerminate); +#endif } } diff --git a/src/WINNT/afsd/afsdifs.c b/src/WINNT/afsd/afsdifs.c new file mode 100644 index 0000000..4e1ef48 --- /dev/null +++ b/src/WINNT/afsd/afsdifs.c @@ -0,0 +1,1191 @@ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ + +#include +#include "afsd.h" +#include +#include "..\afsrdr\kif.h" +#include "..\afsrdr\ifs_rpc.h" + +#include "afsdifs.h" + + +/****************************/ +/* parameters, macros, etc. */ +/****************************/ +#define IFSL_SUCCEEDED(st) (!(st & IFSL_FAIL_BASE)) +#define MAP_RETURN(code) if (code) return ifs_MapCmError(code); + /* defined in multiple places (search source) */ +#define BUF_FILEHASH(fidp) ((((fidp)->vnode+((fidp)->unique << 13) + ((fidp)->unique >> (32-13)) \ + +(fidp)->volume+(fidp)->cell) \ + /*& 0xffffffff*/)) +#define ROOTPATH "\\" +//#define ROOTPATH "\\CITI.UMICH.EDU" +#define TRANSFER_BUF_SIZE (2*1024*1024) +#define SCPL_LOCK EnterCriticalSection(&scp_list_lock); +#define SCPL_UNLOCK LeaveCriticalSection(&scp_list_lock); +#define MAX_USERS 32 + +/****************************/ +/* structs */ +/****************************/ +struct user_map_entry /* how we keep users straight. total of MAX_USERS of these */ + { + LARGE_INTEGER id; /* internal id created by kernel */ + cm_user_t *creds; /* global (thread-specific) var userp is set to this */ + }; + +struct scp_status /* one for each unique file in afs */ + { + struct scp_status *next; /* stored in a global chain in a chain locked by SCPL_[UN]LOCK */ + cm_scache_t *scp; /* file handle used with cm_ fns */ + ULONG fid; /* internal id generated by BUF_FILEHASH from AFS's 128-bit FID */ + }; +typedef struct scp_status scp_status_t; + +struct readdir_context /* temporary struct, allocated as necessary, for cm_Apply callback */ + { + char *matchString; /* for matching against */ + char *buf, *buf_pos; /* filling buffer to length, currently at buf_pos */ + ULONG length; + ULONG count; /* number of entries packed so far */ + }; +typedef struct readdir_context readdir_context_t; + + +/****************************/ +/* global vars */ +/****************************/ +__declspec(thread) cm_user_t *userp; +struct user_map_entry user_map[MAX_USERS]; + +CRITICAL_SECTION mapLock, scp_list_lock; + +extern HANDLE DoTerminate; + +scp_status_t *scp_list_head = NULL; + + +/****************************/ +/* error functions */ +/****************************/ +char *IfslErrorToText(unsigned long ifsl) +{ +switch (ifsl) + { + case IFSL_SUCCESS: + return "success"; + case IFSL_DOES_NOT_EXIST: + return "does not exist"; + case IFSL_NOT_IMPLEMENTED: + return "not implemented"; + case IFSL_END_OF_ENUM: + return "end of enum"; + case IFSL_CANNOT_MAKE: + return "cannot make"; + case IFSL_END_OF_FILE: + return "end of file"; + case IFSL_NO_ACCESS: + return "no access"; + case IFSL_BUFFER_TOO_SMALL: + return "buffer too small"; + case IFSL_SHARING_VIOLATION: + return "sharing violation"; + case IFSL_BAD_INPUT: + return "bad input"; + case IFSL_GENERIC_FAILURE: + return "generic failure"; + case IFSL_OPEN_CREATED: + return "open created"; + case IFSL_OPEN_EXISTS: + return "open exists"; + case IFSL_OPEN_OPENED: + return "opened"; + case IFSL_OPEN_OVERWRITTEN: + return "overwritten"; + case IFSL_OPEN_SUPERSCEDED: + return "supersceded"; + case IFSL_BADFILENAME: + return "bad filename"; + case IFSL_READONLY: + return "read only"; + case IFSL_IS_A_DIR: + return "is a dir"; + case IFSL_PATH_DOES_NOT_EXIST: + return "path does not exist"; + case IFSL_IS_A_FILE: + return "is a file"; + case IFSL_NOT_EMPTY: + return "dir not empty"; + case IFSL_UNSPEC: + return "unspecified error"; + default: + return "NOT FOUND"; + } +} + +unsigned long ifs_MapCmError(unsigned long code) +{ +switch (code) + { + case CM_ERROR_STOPNOW: + case 0: + return IFSL_SUCCESS; + case CM_ERROR_NOSUCHCELL: + case CM_ERROR_NOSUCHVOLUME: + case CM_ERROR_NOSUCHFILE: // x + return IFSL_DOES_NOT_EXIST; + case CM_ERROR_NOSUCHPATH: // x + return IFSL_PATH_DOES_NOT_EXIST; + case CM_ERROR_BADNTFILENAME: + return IFSL_BADFILENAME; + case CM_ERROR_TIMEDOUT: + case CM_ERROR_ALLOFFLINE: + case CM_ERROR_CLOCKSKEW: + case CM_ERROR_REMOTECONN: + case CM_ERROR_ALLBUSY: + return IFSL_GENERIC_FAILURE; + case CM_ERROR_NOACCESS: + return IFSL_NO_ACCESS; + case CM_ERROR_RETRY: + case CM_ERROR_TOOBIG: + case CM_ERROR_BADFD: + case CM_ERROR_BADFDOP: + case CM_ERROR_CROSSDEVLINK: + return IFSL_GENERIC_FAILURE; + case CM_ERROR_EXISTS: + return IFSL_OPEN_EXISTS; + case CM_ERROR_BADOP: + case CM_ERROR_INVAL: + case CM_ERROR_UNKNOWN: + case CM_ERROR_BADSMB: + return IFSL_GENERIC_FAILURE;//TODO:? ERR - STATUS_NO_MORE_FILES; + case CM_ERROR_NOTDIR: + case CM_ERROR_ISDIR: + case CM_ERROR_READONLY: + return IFSL_BAD_INPUT; + case CM_ERROR_BUFFERTOOSMALL: + return IFSL_BUFFER_TOO_SMALL; + case CM_ERROR_WOULDBLOCK: + case CM_ERROR_BADSHARENAME: + case CM_ERROR_NOMORETOKENS: + case CM_ERROR_NOTEMPTY: + case CM_ERROR_USESTD: + case CM_ERROR_ATSYS: + return IFSL_GENERIC_FAILURE; + case CM_ERROR_NOFILES: + case CM_ERROR_BADTID: + return IFSL_END_OF_ENUM; + case CM_ERROR_PARTIALWRITE: + case CM_ERROR_NOIPC: + case CM_ERROR_RENAME_IDENTICAL: + case CM_ERROR_AMBIGUOUS_FILENAME: + return IFSL_GENERIC_FAILURE; + case IFSL_SHARING_VIOLATION: + return IFSL_SHARING_VIOLATION; + case IFSL_NOT_EMPTY: + return IFSL_NOT_EMPTY; + case CM_ERROR_SPACE: + case CM_ERROR_QUOTA: + return IFSL_OVERQUOTA; + } +return IFSL_GENERIC_FAILURE; +} + + +/****************************/ +/* support fns */ +/****************************/ +cm_scache_t *ifs_FindScp(ULONG fid) /* walk list to find scp<->fid mapping */ +{ +scp_status_t *curr; + +SCPL_LOCK; + +curr = scp_list_head; +while (curr) + { + if (curr->fid == fid) + { + SCPL_UNLOCK; + return curr->scp; + } + curr = curr->next; + } +SCPL_UNLOCK; +return NULL; +} + +/* must call with scp write-locked. will always return correct results + unless network fails (it loops properly). */ +ifs_CheckAcl(cm_scache_t *scp, ULONG access, ULONG *granted) +{ +long outRights, code; +cm_req_t req; + +cm_InitReq(&req); + +/* ripped from cm_scache.c */ +while (1) + { + if (cm_HaveAccessRights(scp, userp, access, granted)) + { + return 0; + } + else + { + /* we don't know the required access rights */ + code = cm_GetAccessRights(scp, userp, &req); + MAP_RETURN(code); + continue; + } + } + +return 0; +} + +/* extract data from scp. in ifs_ support function to centralize changes. */ +ifs_CopyInfo(cm_scache_t *scp, ULONG *attribs, LARGE_INTEGER *size, + LARGE_INTEGER *creation, LARGE_INTEGER *access, + LARGE_INTEGER *change, LARGE_INTEGER *written) +{ +access->QuadPart = 0; /* these mappings are not quite correct. we have the */ +change->QuadPart = scp->clientModTime; /* right to leave them zero, if necessary. */ +written->QuadPart = scp->clientModTime; +creation->QuadPart = scp->serverModTime; + +*attribs = 0; +if (scp->fileType == CM_SCACHETYPE_DIRECTORY || + scp->fileType == CM_SCACHETYPE_SYMLINK || + scp->fileType == CM_SCACHETYPE_MOUNTPOINT/* || + scp->fileType == 0*/) + *attribs |= FILE_ATTRIBUTE_DIRECTORY; + +/*if (!attribs && scp->fileType == CM_SCACHETYPE_FILE) + *attribs |= FILE_ATTRIBUTE_NORMAL;*/ + +if (*attribs == FILE_ATTRIBUTE_DIRECTORY) + size->QuadPart = 0; +else + *size = scp->length; + +return 0; +} + + +/* close and zero scp pointer. zeroing pointer should + help eliminate accessing discarded cache entries. */ +void ifs_InternalClose(cm_scache_t **scp) +{ +osi_assert(scp && *scp); +lock_ObtainMutex(&((*scp)->mx)); +cm_ReleaseSCache(*scp); +if ((*scp)->refCount == 0) /* we haven't held scache for external use yet */ + cm_DiscardSCache(*scp); +lock_ReleaseMutex(&((*scp)->mx)); +*scp = NULL; +} + +/* normalizes path by removing trailing slashes. separates last + path component with a null, so that *dirp points to parent path + and *filep points to filename. modifies string path. */ +BOOLEAN ifs_FindComponents(char *path, const char **dirp, const char **filep) +{ +char *lastSep; +BOOLEAN removed; +static char emptyPath[] = "\\"; /* if the path contains only one component, this is the parent. */ + +osi_assert(path); + +if (strlen(path)) + removed = (path[strlen(path)-1] == '\\'); +else + removed = 1; + +lastSep = strrchr(path, '\\'); +while (lastSep == path + strlen(path) - 1) + { + *lastSep = '\0'; + lastSep = strrchr(path, '\\'); + } + +if (lastSep) + { + *lastSep = '\0'; + + *dirp = path; + *filep = lastSep + 1; + } +else + { + lastSep = path + strlen(path); + + *dirp = emptyPath; + *filep = path; + } + +return removed; +} + +/* here to make maintenance easy */ +unsigned long ifs_ConvertFileName(wchar_t *in, unsigned int inchars, char *out, unsigned int outchars) +{ +unsigned long code; + +code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, in, inchars, out, outchars-1, NULL, NULL); +if (!code) + return IFSL_BADFILENAME; + +return 0; +} + +/* called by rpc_ library to let us initialize environment. + call with id of zero to clear current thread auth. */ +ifs_ImpersonateClient(LARGE_INTEGER user_id) +{ +int x, empty; + +if (!user_id.QuadPart) + { + userp = NULL; + return 0; + } + +empty = -1; +EnterCriticalSection(&mapLock); +for (x = 0; x < MAX_USERS; x++) + { + if (user_map[x].id.QuadPart == 0) + empty = x; + if (user_map[x].id.QuadPart == user_id.QuadPart) + goto done; + } +if (empty == -1) + { + LeaveCriticalSection(&mapLock); + return -1; + } +user_map[empty].id = user_id; +user_map[empty].creds = cm_NewUser(); +x = empty; + +done: + userp = user_map[x].creds; +LeaveCriticalSection(&mapLock); + +return 0; +} + + +/****************************/ +/* upcalls */ +/****************************/ +uc_namei(WCHAR *name, ULONG *fid) /* performs name<->fid mapping, and enters it into table */ +{ +char *buffer; /* we support semi-infinite path lengths */ +long code; +cm_scache_t *scp, *dscp; +char *dirp, *filep; +cm_req_t req; +scp_status_t *st; +short len; + +cm_InitReq(&req); + +len = wcslen(name)+20; /* characters *should* map 1<->1, but in case */ +buffer = malloc(len); +code = ifs_ConvertFileName(name, -1, buffer, len); +if (code) + { + free(buffer); + MAP_RETURN(code); + } +ifs_FindComponents(buffer, &dirp, &filep); + +code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp); +if (code) + { + free(buffer); + MAP_RETURN(code); + } +if (*filep) + code = cm_Lookup(dscp, filep, 0, userp, &req, &scp); +else + cm_HoldSCache(scp = dscp); +cm_ReleaseSCache(dscp); + +if (code) + { + free(buffer); + MAP_RETURN(code); + } + +SCPL_LOCK; +st = malloc(sizeof(scp_status_t)); +st->scp = scp; +st->fid = BUF_FILEHASH(&scp->fid); +st->next = scp_list_head; +scp_list_head = st; +SCPL_UNLOCK; + +*fid = st->fid; +free(buffer); + +return 0; +} + +/* this should only be called right after open, so we do not need to stat file. + * we only check the server's restrictions. sharing violations are handled in the + * kernel. the access mode we grant sticks with the file_object until its death. */ +uc_check_access(ULONG fid, ULONG access, ULONG *granted) +{ +ULONG afs_acc, afs_gr; +cm_scache_t *scp; +ULONG gr; +BOOLEAN file, dir; + +gr = 0; + +scp = ifs_FindScp(fid); +if (!scp) + return IFSL_BAD_INPUT; + +file = (scp->fileType == CM_SCACHETYPE_FILE); +dir = !file; + +/* access definitions from prs_fs.h */ +afs_acc = 0; +if (access & FILE_READ_DATA) + afs_acc |= PRSFS_READ; +if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA))) + afs_acc |= PRSFS_WRITE; +if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES) + afs_acc |= PRSFS_WRITE; +if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY))) + afs_acc |= PRSFS_INSERT; +if (dir && (access & FILE_LIST_DIRECTORY)) + afs_acc |= PRSFS_LOOKUP; +if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES) + afs_acc |= PRSFS_LOOKUP; +if (file && (access & FILE_EXECUTE)) /* look at making this require write access */ + afs_acc |= PRSFS_WRITE; +if (dir && (access & FILE_TRAVERSE)) + afs_acc |= PRSFS_READ; +if (dir && (access & FILE_DELETE_CHILD)) + afs_acc |= PRSFS_DELETE; +if (/*file && */(access & DELETE)) + afs_acc |= PRSFS_DELETE; + +/* check ACL with server */ +lock_ObtainMutex(&(scp->mx)); +ifs_CheckAcl(scp, afs_acc, &afs_gr); +lock_ReleaseMutex(&(scp->mx)); + +*granted = 0; +if (afs_gr & PRSFS_READ) + *granted |= FILE_READ_DATA | FILE_EXECUTE; +if (afs_gr & PRSFS_WRITE) + *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE; // last one hack +if (afs_gr & PRSFS_INSERT) + *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0); +if (afs_gr & PRSFS_LOOKUP) + *granted |= (dir ? FILE_LIST_DIRECTORY : 0) | FILE_READ_EA | FILE_READ_ATTRIBUTES; +if (afs_gr & PRSFS_DELETE) + *granted |= FILE_DELETE_CHILD | DELETE; +if (afs_gr & PRSFS_LOCK) + *granted |= 0; +if (afs_gr & PRSFS_ADMINISTER) + *granted |= 0; + +* granted |= SYNCHRONIZE | READ_CONTROL; + +return 0; +} + +uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid) +{ +char *buffer; /* we support semi-infinite path lengths */ +long code; +cm_scache_t *scp, *dscp; +char *dirp, *filep; +unsigned char removed; +cm_req_t req; +scp_status_t *st; +cm_attr_t attr; +short len; + +cm_InitReq(&req); + +len = wcslen(name)+20; /* characters *should* map 1<->1, but in case */ +buffer = malloc(len); +code = ifs_ConvertFileName(name, -1, buffer, len); +if (code) + { + free(buffer); + MAP_RETURN(code); + } +removed = ifs_FindComponents(buffer, &dirp, &filep); + +/* lookup the parent directory, which must exist */ +code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp); +if (code) + { + free(buffer); + MAP_RETURN(code); + } + +osi_assert(filep); +if (*filep) + { + attr.mask = CM_ATTRMASK_LENGTH; + attr.length = alloc; + + if (attribs & FILE_ATTRIBUTE_DIRECTORY) + { + code = cm_MakeDir(dscp, filep, 0, &attr, userp, &req); + if (!code) + code = cm_Lookup(dscp, filep, 0, userp, &req, &scp); + } + else + { + /* for debugging strange error */ + /*if (!strcmp(filep+strlen(filep)-3, "478") || + !strcmp(filep+strlen(filep)-3, "503")) + _asm int 3;*/ + code = cm_Create(dscp, filep, 0, &attr, &scp, userp, &req); + } + } +cm_ReleaseSCache(dscp); + +if (code) + { + free(buffer); + MAP_RETURN(code); + } + +SCPL_LOCK; +st = malloc(sizeof(scp_status_t)); +st->scp = scp; +st->fid = BUF_FILEHASH(&scp->fid); +st->next = scp_list_head; +scp_list_head = st; +SCPL_UNLOCK; + +*fid = st->fid; +*granted = access; + +return 0; +} + +/* this does not fill the attribs member completely. additional flags must + be added in the kernel, such as read-only. */ +uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation, + LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written) +{ +cm_scache_t *scp; +cm_req_t req; +ULONG code; + +scp = ifs_FindScp(fid); +if (!scp) + return IFSL_BAD_INPUT; + +/* stat file; don't want callback */ +cm_InitReq(&req); +lock_ObtainMutex(&(scp->mx)); +cm_HoldUser(userp); +code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS); +cm_ReleaseUser(userp); + +if (code) + lock_ReleaseMutex(&(scp->mx)); +MAP_RETURN(code); + +code = ifs_CopyInfo(scp, attribs, size, creation, access, change, written); +lock_ReleaseMutex(&(scp->mx)); +MAP_RETURN(code); + +return 0; +} + +/* set atime, mtime, etc. */ +uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access, + LARGE_INTEGER change, LARGE_INTEGER written) +{ +return IFSL_GENERIC_FAILURE; +} + +//FIX/quota errors +/* truncate or extend file, in cache and on server */ +uc_trunc(ULONG fid, LARGE_INTEGER size) +{ +ULONG code, gr; +cm_scache_t *scp; +cm_req_t req; +osi_hyper_t oldLen, writePos; +long written; + +scp = ifs_FindScp(fid); +if (!scp) + return IFSL_BAD_INPUT; + +/*code = ifs_CheckAcl(scp, FILE_WRITE_DATA, &gr); +if (code) + return code; +if (!(gr & FILE_WRITE_DATA)) + return IFSL_NO_ACCESS;*/ + +cm_InitReq(&req); +lock_ObtainMutex(&(scp->mx)); + +code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS); + +if (code) + lock_ReleaseMutex(&(scp->mx)); +MAP_RETURN(code); + +oldLen = scp->length; +lock_ReleaseMutex(&(scp->mx)); + +code = cm_SetLength(scp, &size, userp, &req); +MAP_RETURN(code); +/*code = cm_FSync(scp, userp, &req); +MAP_RETURN(code);*/ +/*code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS); +MAP_RETURN(code);*/ + +#if 0 +/* attempt to write last byte of file. fails to help because of delayed writing. */ +if (oldLen.QuadPart < size.QuadPart) + { + writePos.QuadPart = size.QuadPart - 1; + WriteData(scp, writePos, 1, &"\0\0\0", userp, &written); + MAP_RETURN(code); + if (written != 1) + return IFSL_UNSPEC; + } +#endif +/*cm_SyncOp(scp, NULL, +cm_Flush(*/ +//MAP_RETURN(code); + +return 0; +} + +/* read data from a file */ +uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data) +{ +ULONG code; +cm_scache_t *scp; +cm_req_t req; + +//_asm int 3; + +*read = 0; + +scp = ifs_FindScp(fid); +if (!scp) + return IFSL_BAD_INPUT; + +if (scp->fileType == CM_SCACHETYPE_DIRECTORY) + return IFSL_IS_A_DIR; + +code = ReadData(scp, offset, (unsigned long)length, data, userp, read); +MAP_RETURN(code); + +return 0; +} + +//FIX/ handle quota errors properly +/* write data to a file */ +uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data) +{ +ULONG code, gr; +cm_scache_t *scp; +cm_req_t req; + +scp = ifs_FindScp(fid); +if (!scp) + return IFSL_BAD_INPUT; + +/*code = ifs_CheckAcl(scp, FILE_WRITE_DATA, &gr); +if (code) + return code; +if (!(gr & FILE_WRITE_DATA)) + return IFSL_NO_ACCESS;*/ + +if (offset.QuadPart == -1) // perhaps re-stat here? + offset = scp->length; +code = WriteData(scp, offset, (unsigned long)length, data, userp, written); +MAP_RETURN(code); + +return 0; +} + +//need downcall for new length + +uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid) +{ +int code; +cm_req_t req; +//struct vnode *node; +cm_attr_t attr; +wchar_t *buf; +char *curdir, *curfile, *newdir, *newfile; +cm_scache_t *dscp1, *dscp2, *scp; +char b1[MAX_PATH], b2[MAX_PATH], b3[MAX_PATH]; +ULONG fid2; + + +code = !(scp = ifs_FindScp(fid)); +if (!code) + code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH); +if (!code) + code = ifs_ConvertFileName(new_name, -1, b2, MAX_PATH); +if (!code) + code = ifs_ConvertFileName(new_dir, -1, b3, MAX_PATH); +if (!code) + { + ifs_FindComponents(b1, &curdir, &curfile); + ifs_FindComponents(b2, &newdir, &newfile); + newdir = b3; + /*lock_ReleaseMutex(&scp->mx); + cm_FSync(scp, userp, &req); + if (scp->refCount != 1) + _asm int 3; + ifs_InternalClose(&scp);*/ + uc_close(fid); + code = cm_NameI(cm_data.rootSCachep, curdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp1); + } +if (!code) + { + if (!strcmp(curdir, newdir)) + { + dscp2 = dscp1; + dscp1->refCount++; + } + else + code = cm_NameI(cm_data.rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2); + if (!code) + { + code = cm_Rename(dscp1, curfile, dscp2, newfile, userp, &req); + //ifs_InternalClose(&dscp2); + //cm_InitReq(&req); + //code = cm_NameI(cm_rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2); + if (!code) + { + code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH); + code = uc_namei(b1, new_fid); + //if (fid != fid2) + // _asm int 3; + //code = cm_Lookup(dscp2, newfile, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &node->scp); + } + ifs_InternalClose(&dscp2); + } + else + { + //code = cm_Lookup(dscp1, curfile, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &node->scp); + code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH); + code = uc_namei(b1, new_fid); + //if (fid != fid2) + // _asm int 3; + } + ifs_InternalClose(&dscp1); + } + +return 0; +} + +ifs_ReaddirCallback(cm_scache_t *scp, cm_dirEntry_t *entry, void *param, osi_hyper_t *offset) +{ +readdir_context_t *context; +ULONG name_len, gr; +readdir_data_t *info; +char short_name[14], *endp; +ULONG code; +cm_req_t req; +cm_scache_t *child_scp; +cm_fid_t child_fid; +int t; + +context = param; + +name_len = strlen(entry->name); + +info = (readdir_data_t *)context->buf_pos; +if (context->length - (context->buf_pos - context->buf) < sizeof(readdir_data_t) + name_len * sizeof(WCHAR) + sizeof(LARGE_INTEGER)) + { + if (context->count == 0) + return CM_ERROR_BUFFERTOOSMALL; + info->cookie = *offset; + return CM_ERROR_STOPNOW; + } + +if ((context->matchString && context->matchString[0] && (!strcmp(context->matchString, entry->name) || context->matchString[0]=='*')) || + !(context->matchString && context->matchString[0])) + ; +else + return 0; + +cm_InitReq(&req); +cm_HoldUser(userp); +child_scp = NULL; + +child_fid.cell = scp->fid.cell; +child_fid.volume = scp->fid.volume; +child_fid.vnode = ntohl(entry->fid.vnode); +child_fid.unique = ntohl(entry->fid.unique); +code = cm_GetSCache(&child_fid, &child_scp, userp, &req); +//code = cm_Lookup(scp, entry->name, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &child_scp); +if (code || !child_scp) + { + cm_ReleaseUser(userp); + return 0; + } + +//if (child_scp->refCount == 1) + { + lock_ObtainMutex(&child_scp->mx); + code = cm_SyncOp(child_scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK); // do not need callback + lock_ReleaseMutex(&child_scp->mx); + } + +if (code) /* perhaps blank fields we do not know, and continue. bad filents should not prevent readdirs. */ + ; + +info->cookie = *offset; + +lock_ObtainMutex(&(child_scp->mx)); +code = ifs_CopyInfo(child_scp, &info->attribs, &info->size, &info->creation, &info->access, &info->change, &info->write); +//ifs_CheckAcl(child_scp, FILE_WRITE_DATA, &gr); /* perhaps add flag to not loop, to avoid network traffic if not found*/ +//if (gr & FILE_READ_DATA && !(gr & FILE_WRITE_DATA)) +// info->attribs |= FILE_ATTRIBUTE_READONLY; +lock_ReleaseMutex(&(child_scp->mx)); +ifs_InternalClose(&child_scp); +MAP_RETURN(code); + +cm_Gen8Dot3Name(entry, short_name, &endp); +*endp = '\0'; +info->short_name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, short_name, -1, info->short_name, 14))?t-1:0); +info->name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, entry->name, -1, info->name, 600))?t-1:0); + +context->buf_pos = ((char*)info) + sizeof(readdir_data_t) + info->name_length; +context->count++; + +info = (readdir_data_t *)context->buf_pos; +info->cookie.QuadPart = -1; + +return 0; +} + +uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len) +{ +ULONG code; +char buffer[2048]; +cm_req_t req; +cm_scache_t *scp, *child_scp; +readdir_context_t context; +LARGE_INTEGER cookie; + +if (cookie_in.QuadPart == -1) + { + *len = 0; + *count = 0; + return 0; + } + +scp = ifs_FindScp(fid); +if (!scp) + return IFSL_BAD_INPUT; +code = ifs_ConvertFileName(filter, -1, buffer, 2048); +if (code) + return code; + +cm_InitReq(&req); +cm_HoldUser(userp); + +cookie = cookie_in; +context.matchString = buffer; +context.buf_pos = context.buf = data; +context.length = *len; +context.count = 0; +*count = 0; + +//restart: + +((LARGE_INTEGER *)context.buf)->QuadPart = -1; + +code = cm_ApplyDir(scp, ifs_ReaddirCallback, &context, &cookie, userp, &req, NULL); + +context.buf_pos += sizeof(LARGE_INTEGER); + +if (code != CM_ERROR_STOPNOW) + goto done; + +//(*count)++; + +if (code) + goto done; + +//goto restart; + +code = 0; + +done: + +*count = context.count; + +cm_ReleaseUser(userp); +*len = context.buf_pos - context.buf; + +code = ifs_MapCmError(code); +return code; +} + +uc_close(ULONG fid) +{ +ULONG code; +cm_scache_t *scp; +cm_req_t req; +scp_status_t *prev, *curr; + +scp = ifs_FindScp(fid); +if (!scp) + return IFSL_BAD_INPUT; + +cm_InitReq(&req); +cm_FSync(scp, userp, &req); + +SCPL_LOCK; /* perhaps this should be earlier */ + +lock_ObtainMutex(&(scp->mx)); +cm_ReleaseSCache(scp); +if (!scp->refCount) + cm_DiscardSCache(scp); +lock_ReleaseMutex(&(scp->mx)); + +prev = NULL, curr = scp_list_head; + +while (curr) + { + if (curr->fid == fid) + { + if (prev) + prev->next = curr->next; + else + scp_list_head = curr->next; + free(curr); + break; + } + prev = curr; + curr = curr->next; + } + +SCPL_UNLOCK; + +return 0; +} + +uc_unlink(WCHAR *name) +{ +char buffer[2048]; +long code; +cm_scache_t *scp, *dscp; +char *dirp, *filep; +unsigned char removed; +cm_req_t req; +scp_status_t *st; + +cm_InitReq(&req); + +code = ifs_ConvertFileName(name, -1, buffer, 2048); +MAP_RETURN(code); +removed = ifs_FindComponents(buffer, &dirp, &filep); + +code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp); +MAP_RETURN(code); +if (*filep) + { + code = cm_Unlink(dscp, filep, userp, &req); + if (code) + code = cm_RemoveDir(dscp, filep, userp, &req); + } +else + ; /* problem */ +cm_ReleaseSCache(dscp); +MAP_RETURN(code); + +return 0; +} + + +int uc_ioctl_write(ULONG length, char *data, ULONG *key) +{ +int code; +cm_req_t req; +smb_ioctl_t *iop; + +iop = malloc(sizeof(smb_ioctl_t)); +memset(iop, 0, sizeof(smb_ioctl_t)); +smb_IoctlPrepareWrite(NULL, iop); + +memcpy(iop->inDatap + iop->inCopied, data, length); +iop->inCopied += length; +*key = (ULONG)iop; + +return 0; +} + +int uc_ioctl_read(ULONG key, ULONG *length, char *data) +{ +int code; +cm_req_t req; +smb_ioctl_t *iop; + +iop = key; +osi_assert(iop); + +cm_HoldUser(userp); +smb_IoctlPrepareRead(NULL, iop, userp); +cm_ReleaseUser(userp); + +*length = iop->outDatap - iop->outAllocp; +memcpy(data, iop->outAllocp, *length); +free(iop); + +return 0; +} + +int ifs_Init(char **reason) +{ +HANDLE kcom; + +//_asm int 3; +kcom = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + /*FILE_FLAG_OVERLAPPED*/0, NULL); +if (kcom == INVALID_HANDLE_VALUE) + { + *reason = "error creating communications file"; + return CM_ERROR_REMOTECONN; + } +CloseHandle(kcom); + +memset(user_map, 0, 32*sizeof(struct user_map_entry)); +InitializeCriticalSection(&mapLock); +InitializeCriticalSection(&scp_list_lock); + +return 0; +} + +ifs_TransactRpc(char *outbuf, int outlen, char *inbuf, int *inlen) +{ +HANDLE hf; +int ret; +DWORD err, read = 0; +DWORD inmax; + +if (!outbuf || !inbuf) + return IFSL_GENERIC_FAILURE; + +hf = CreateFile("\\\\.\\afscom\\downcall", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); +if (hf == INVALID_HANDLE_VALUE) + return 0; + +inmax = *inlen; +if (!DeviceIoControl(hf, IOCTL_AFSRDR_DOWNCALL, outbuf, outlen, inbuf, inmax, inlen, NULL)) + { + CloseHandle(hf); + return IFSL_GENERIC_FAILURE; + } + +CloseHandle(hf); +return inlen ? IFSL_SUCCESS : IFSL_GENERIC_FAILURE; +} + + +DWORD WINAPI ifs_MainLoop(LPVOID param) +{ +HANDLE pipe; +DWORD written; +unsigned char *bufIn, *bufOut; +DWORD lenIn, lenOut, status; +DWORD err; +OVERLAPPED olp; +rpc_t rpc; +BOOL st; + +bufIn = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE); +bufOut = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE); +if (!bufIn || !bufOut) + { + if (bufIn) VirtualFree(bufIn, 0, MEM_RELEASE); + if (bufOut) VirtualFree(bufOut, 0, MEM_RELEASE); + printf("could not allocate transfer bufs\n"); + PostMessage(NULL, WM_CLOSE, 0, 0); + return 1; + } + +//_asm int 3; +pipe = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + /*FILE_FLAG_OVERLAPPED*/0, NULL); +if (pipe == INVALID_HANDLE_VALUE) + { + VirtualFree(bufIn, 0, MEM_RELEASE); + VirtualFree(bufOut, 0, MEM_RELEASE); + printf("error creating communications file\n"); + PostMessage(NULL, WM_CLOSE, 0, 0); + return 1; + } + +//_asm int 3; +while (1) + { + if (WaitForSingleObject(DoTerminate, 0) == WAIT_OBJECT_0) + break; + st = ReadFile(pipe, bufIn, TRANSFER_BUF_SIZE, &lenIn, NULL); + if (!st) + if (GetLastError() == ERROR_INVALID_HANDLE) + break; + else + continue; + + ZeroMemory(&rpc, sizeof(rpc)); + rpc.in_buf = rpc.in_pos = bufIn; + rpc.out_buf = rpc.out_pos = bufOut; + + rpc_parse(&rpc); + + st = WriteFile(pipe, rpc.out_buf, rpc.out_pos - rpc.out_buf, &written, NULL); + if (!st) + if (GetLastError() == ERROR_INVALID_HANDLE) + break; + else + continue; + } + +return 1; +} diff --git a/src/WINNT/afsd/afsdifs.h b/src/WINNT/afsd/afsdifs.h new file mode 100644 index 0000000..e18ef07 --- /dev/null +++ b/src/WINNT/afsd/afsdifs.h @@ -0,0 +1,33 @@ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ + +int ifs_Init(char **reason); +DWORD WINAPI ifs_MainLoop(LPVOID); + + +long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op, + cm_user_t *userp, long *readp); +long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op, + cm_user_t *userp, long *readp); diff --git a/src/WINNT/afsd/cm_callback.c b/src/WINNT/afsd/cm_callback.c index 4fa09dc..86826e8 100644 --- a/src/WINNT/afsd/cm_callback.c +++ b/src/WINNT/afsd/cm_callback.c @@ -91,6 +91,12 @@ void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags) lock_ReleaseWrite(&cm_callbackLock); } +#ifdef AFSIFS +#define BUF_FILEHASH(fidp) ((((fidp)->vnode+((fidp)->unique << 13) + ((fidp)->unique >> (32-13)) \ + +(fidp)->volume+(fidp)->cell) \ + /*& 0xffffffff*/)) +#endif + /* * When we lose a callback, may have to send change notification replies. * Do not call with a lock on the scp. @@ -123,10 +129,14 @@ void cm_CallbackNotifyChange(cm_scache_t *scp) Sleep(dwDelay); if (scp->fileType == CM_SCACHETYPE_DIRECTORY) { +#ifndef AFSIFS if (scp->flags & CM_SCACHEFLAG_ANYWATCH) smb_NotifyChange(0, FILE_NOTIFY_GENERIC_DIRECTORY_FILTER, scp, NULL, NULL, TRUE); +#else + dc_break_callback(BUF_FILEHASH(&scp->fid)); +#endif } else { cm_fid_t tfid; cm_scache_t *dscp; @@ -136,11 +146,16 @@ void cm_CallbackNotifyChange(cm_scache_t *scp) tfid.vnode = scp->parentVnode; tfid.unique = scp->parentUnique; dscp = cm_FindSCache(&tfid); +#ifndef AFSIFS if ( dscp && dscp->flags & CM_SCACHEFLAG_ANYWATCH ) smb_NotifyChange( 0, FILE_NOTIFY_GENERIC_FILE_FILTER, dscp, NULL, NULL, TRUE); +#else + if (dscp) + dc_break_callback(BUF_FILEHASH(&dscp->fid)); +#endif if (dscp) cm_ReleaseSCache(dscp); } diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index d4e5ca5..29b83c9 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -41,6 +41,8 @@ #include "cm_rpc.h" #include +#include +#include #ifdef _DEBUG #include @@ -141,9 +143,11 @@ void TranslateExtendedChars(char *str) long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, cm_scache_t **scpp) { - long code; + long code, length; cm_scache_t *substRootp; - char * relativePath = ioctlp->inDatap; + char * relativePath = ioctlp->inDatap, absRoot[100]; + wchar_t absRoot_w[100]; + HANDLE rootDir; /* This is usually the file name, but for StatMountPoint it is the path. */ /* ioctlp->inDatap can be either of the form: @@ -154,7 +158,47 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, */ TranslateExtendedChars(relativePath); - if (relativePath[0] == relativePath[1] && +#ifdef AFSIFS + /* we have passed the whole path, including the afs prefix (pioctl_nt.c modified) */ + /*_asm int 3; + sprintf(absRoot, "%c:", relativePath[0]); + rootDir = CreateFile(absRoot, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, absRoot_w, 100*sizeof(wchar_t), &length, NULL)) + { + CloseHandle(rootDir); + return CM_ERROR_NOSUCHPATH; + } + CloseHandle(rootDir); + + ifs_ConvertFileName(absRoot_w, length/sizeof(wchar_t), absRoot, 100);*/ + +#if 0 + switch (relativePath[0]) /* FIXFIX */ + { + case 'y': + case 'Y': + absRoot = "\\ericjw\\test"; /* should use drivemap */ + } +#endif + code = cm_NameI(cm_data.rootSCachep, relativePath, + CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, + userp, ""/*absRoot*//*ioctlp->tidPathp*/, reqp, scpp); + + if (code) + return code; + + /* # of bytes of path */ + code = strlen(ioctlp->inDatap) + 1; + ioctlp->inDatap += code; + + /* This is usually nothing, but for StatMountPoint it is the file name. */ + TranslateExtendedChars(ioctlp->inDatap); + + return 0; +#endif + + if (relativePath[0] == relativePath[1] && relativePath[1] == '\\' && !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) { @@ -1787,7 +1831,8 @@ long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp) uname = tp; tp += strlen(tp) + 1; - if (flags & PIOCTL_LOGON) { +#ifndef AFSIFS /* no SMB username */ + if (flags & PIOCTL_LOGON) { /* SMB user name with which to associate tokens */ smbname = tp; osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]", @@ -1798,6 +1843,7 @@ long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp) osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]", osi_LogSaveString(smb_logp,uname)); } +#endif #ifndef DJGPP /* for win95, session key is back in pioctl */ /* uuid */ diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 13e735c..d031791 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -545,7 +545,20 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp, break; } - lock_ObtainMutex(&bufferp->mx); +#ifdef AFSIFS + lock_ObtainMutex(&scp->mx); + if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 + && (scp->bulkStatProgress.QuadPart <= thyper.QuadPart)) + { + scp->flags |= CM_SCACHEFLAG_BULKSTATTING; + cm_TryBulkStat(scp, &thyper, userp, reqp); + scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING; + scp->bulkStatProgress = thyper; + } + lock_ReleaseMutex(&scp->mx); +#endif + + lock_ObtainMutex(&bufferp->mx); bufferOffset = thyper; /* now get the data in the cache */ diff --git a/src/WINNT/afsd/rawops.c b/src/WINNT/afsd/rawops.c new file mode 100644 index 0000000..928f243 --- /dev/null +++ b/src/WINNT/afsd/rawops.c @@ -0,0 +1,364 @@ +/* + * Copyright 2000, International Business Machines Corporation and others. + * All Rights Reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + */ + +#include +#include "afsd.h" + +#include "afsdifs.h" + +#define CM_BUF_SIZE 4096 +long buf_bufferSize = CM_BUF_SIZE; + +long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op, + cm_user_t *userp, long *readp) +{ + //osi_hyper_t offset; + long code; + cm_buf_t *bufferp; + osi_hyper_t fileLength; + osi_hyper_t thyper; + osi_hyper_t lastByte; + osi_hyper_t bufferOffset; + long bufIndex, nbytes; + int sequential = 0; + cm_req_t req; + + cm_InitReq(&req); + + bufferp = NULL; + + lock_ObtainMutex(&scp->mx); + + /* start by looking up the file's end */ + code = cm_SyncOp(scp, NULL, userp, &req, 0, + CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + if (code) goto done; + + /* now we have the entry locked, look up the length */ + fileLength = scp->length; + + /* adjust count down so that it won't go past EOF */ + thyper.LowPart = count; + thyper.HighPart = 0; + thyper = LargeIntegerAdd(offset, thyper); /* where read should end */ + lastByte = thyper; + if (LargeIntegerGreaterThan(thyper, fileLength)) { + /* we'd read past EOF, so just stop at fileLength bytes. + * Start by computing how many bytes remain in the file. + */ + thyper = LargeIntegerSubtract(fileLength, offset); + + /* if we are past EOF, read 0 bytes */ + if (LargeIntegerLessThanZero(thyper)) + count = 0; + else + count = thyper.LowPart; + } + + *readp = count; + + /* now, copy the data one buffer at a time, + * until we've filled the request packet + */ + while (1) { + /* if we've copied all the data requested, we're done */ + if (count <= 0) break; + + /* otherwise, load up a buffer of data */ + thyper.HighPart = offset.HighPart; + thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1); + if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) { + /* wrong buffer */ + if (bufferp) { + buf_Release(bufferp); + bufferp = NULL; + } + lock_ReleaseMutex(&scp->mx); + + lock_ObtainRead(&scp->bufCreateLock); + code = buf_Get(scp, &thyper, &bufferp); + lock_ReleaseRead(&scp->bufCreateLock); + + lock_ObtainMutex(&scp->mx); + if (code) goto done; + bufferOffset = thyper; + + /* now get the data in the cache */ + while (1) { + code = cm_SyncOp(scp, bufferp, userp, &req, 0, + CM_SCACHESYNC_NEEDCALLBACK + | CM_SCACHESYNC_READ); + if (code) goto done; + + if (cm_HaveBuffer(scp, bufferp, 0)) break; + + /* otherwise, load the buffer and try again */ + code = cm_GetBuffer(scp, bufferp, NULL, userp, &req); + if (code) break; + } + if (code) { + buf_Release(bufferp); + bufferp = NULL; + goto done; + } + } /* if (wrong buffer) ... */ + + /* now we have the right buffer loaded. Copy out the + * data from here to the user's buffer. + */ + bufIndex = offset.LowPart & (buf_bufferSize - 1); + + /* and figure out how many bytes we want from this buffer */ + nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */ + if (nbytes > count) nbytes = count; /* don't go past EOF */ + + /* now copy the data */ + memcpy(op, bufferp->datap + bufIndex, nbytes); + + /* adjust counters, pointers, etc. */ + op += nbytes; + count -= nbytes; + thyper.LowPart = nbytes; + thyper.HighPart = 0; + offset = LargeIntegerAdd(thyper, offset); + } /* while 1 */ + +done: + lock_ReleaseMutex(&scp->mx); + //lock_ReleaseMutex(&fidp->mx); + if (bufferp) buf_Release(bufferp); + + if (code == 0 && sequential) + cm_ConsiderPrefetch(scp, &lastByte, userp, &req); + + return code; +} + + +long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op, + cm_user_t *userp, long *writtenp) +{ + long code = 0; + long written = 0; + //cm_scache_t *scp; + osi_hyper_t fileLength; /* file's length at start of write */ + osi_hyper_t minLength; /* don't read past this */ + long nbytes; /* # of bytes to transfer this iteration */ + cm_buf_t *bufferp; + osi_hyper_t thyper; /* hyper tmp variable */ + osi_hyper_t bufferOffset; + long bufIndex; /* index in buffer where our data is */ + int doWriteBack; + osi_hyper_t writeBackOffset; /* offset of region to write back when + * I/O is done */ + DWORD filter = 0; + cm_req_t req; + + cm_InitReq(&req); + + bufferp = NULL; + doWriteBack = 0; + + //scp = fidp->scp; + lock_ObtainMutex(&scp->mx); + + /* start by looking up the file's end */ + code = cm_SyncOp(scp, NULL, userp, &req, 0, + CM_SCACHESYNC_NEEDCALLBACK + | CM_SCACHESYNC_SETSTATUS + | CM_SCACHESYNC_GETSTATUS); + if (code) + goto done; + + /* make sure we have a writable FD */ + /*if (!(fidp->flags & SMB_FID_OPENWRITE)) { + code = CM_ERROR_BADFDOP; + goto done; + } */ + + /* now we have the entry locked, look up the length */ + fileLength = scp->length; + minLength = fileLength; + if (LargeIntegerGreaterThan(minLength, scp->serverLength)) + minLength = scp->serverLength; + + /* adjust file length if we extend past EOF */ + thyper.LowPart = count; + thyper.HighPart = 0; + thyper = LargeIntegerAdd(offset, thyper); /* where write should end */ + if (LargeIntegerGreaterThan(thyper, fileLength)) { + /* we'd write past EOF, so extend the file */ + scp->mask |= CM_SCACHEMASK_LENGTH; + scp->length = thyper; + filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE); + } else + filter |= FILE_NOTIFY_CHANGE_LAST_WRITE; + + /* now, if the new position (thyper) and the old (offset) are in + * different storeback windows, remember to store back the previous + * storeback window when we're done with the write. + */ + if ((thyper.LowPart & (-cm_chunkSize)) != + (offset.LowPart & (-cm_chunkSize))) { + /* they're different */ + doWriteBack = 1; + writeBackOffset.HighPart = offset.HighPart; + writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize); + } + + *writtenp = count; + + /* now, copy the data one buffer at a time, until we've filled the + * request packet */ + while (1) { + /* if we've copied all the data requested, we're done */ + if (count <= 0) break; + + /* handle over quota or out of space */ + if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) { + *writtenp = written; + break; + } + + /* otherwise, load up a buffer of data */ + thyper.HighPart = offset.HighPart; + thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1); + if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) { + /* wrong buffer */ + if (bufferp) { + lock_ReleaseMutex(&bufferp->mx); + buf_Release(bufferp); + bufferp = NULL; + } + lock_ReleaseMutex(&scp->mx); + + lock_ObtainRead(&scp->bufCreateLock); + code = buf_Get(scp, &thyper, &bufferp); + lock_ReleaseRead(&scp->bufCreateLock); + + lock_ObtainMutex(&bufferp->mx); + lock_ObtainMutex(&scp->mx); + if (code) goto done; + + bufferOffset = thyper; + + /* now get the data in the cache */ + while (1) { + code = cm_SyncOp(scp, bufferp, userp, &req, 0, + CM_SCACHESYNC_NEEDCALLBACK + | CM_SCACHESYNC_WRITE + | CM_SCACHESYNC_BUFLOCKED); + if (code) + goto done; + + /* If we're overwriting the entire buffer, or + * if we're writing at or past EOF, mark the + * buffer as current so we don't call + * cm_GetBuffer. This skips the fetch from the + * server in those cases where we're going to + * obliterate all the data in the buffer anyway, + * or in those cases where there is no useful + * data at the server to start with. + * + * Use minLength instead of scp->length, since + * the latter has already been updated by this + * call. + */ + if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength) || + LargeIntegerEqualTo(offset, bufferp->offset) && + (count >= buf_bufferSize || + LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset, ConvertLongToLargeInteger(count)), minLength))) { + if (count < buf_bufferSize + && bufferp->dataVersion == -1) + memset(bufferp->datap, 0, + buf_bufferSize); + bufferp->dataVersion = scp->dataVersion; + } + + if (cm_HaveBuffer(scp, bufferp, 1)) break; + + /* otherwise, load the buffer and try again */ + lock_ReleaseMutex(&bufferp->mx); + code = cm_GetBuffer(scp, bufferp, NULL, userp, + &req); + lock_ReleaseMutex(&scp->mx); + lock_ObtainMutex(&bufferp->mx); + lock_ObtainMutex(&scp->mx); + if (code) break; + } + if (code) { + lock_ReleaseMutex(&bufferp->mx); + buf_Release(bufferp); + bufferp = NULL; + goto done; + } + } /* if (wrong buffer) ... */ + + /* now we have the right buffer loaded. Copy out the + * data from here to the user's buffer. + */ + bufIndex = offset.LowPart & (buf_bufferSize - 1); + + /* and figure out how many bytes we want from this buffer */ + nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */ + if (nbytes > count) + nbytes = count; /* don't go past end of request */ + + /* now copy the data */ +#ifdef DJGPP + if (dosflag) + dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex); + else +#endif /* DJGPP */ + memcpy(bufferp->datap + bufIndex, op, nbytes); + buf_SetDirty(bufferp); + + /* and record the last writer */ + if (bufferp->userp != userp) { + cm_HoldUser(userp); + if (bufferp->userp) + cm_ReleaseUser(bufferp->userp); + bufferp->userp = userp; + } + + /* adjust counters, pointers, etc. */ + op += nbytes; + count -= nbytes; + written += nbytes; + thyper.LowPart = nbytes; + thyper.HighPart = 0; + offset = LargeIntegerAdd(thyper, offset); + } /* while 1 */ + + done: + lock_ReleaseMutex(&scp->mx); + if (bufferp) { + lock_ReleaseMutex(&bufferp->mx); + buf_Release(bufferp); + } + + if (code == 0 /* && filter != 0 && (fidp->flags & SMB_FID_NTOPEN) + && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)*/) { + /*smb_NotifyChange(FILE_ACTION_MODIFIED, filter, + fidp->NTopen_dscp, fidp->NTopen_pathp, + NULL, TRUE);*/ + } + + if (code == 0 && doWriteBack) { + lock_ObtainMutex(&scp->mx); + cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE); + lock_ReleaseMutex(&scp->mx); + cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart, + writeBackOffset.HighPart, cm_chunkSize, 0, userp); + } + + return code; +} + + diff --git a/src/WINNT/afsrdr/afsrdr.c b/src/WINNT/afsrdr/afsrdr.c new file mode 100644 index 0000000..e5c01e9 --- /dev/null +++ b/src/WINNT/afsrdr/afsrdr.c @@ -0,0 +1,2496 @@ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ + +/* versioning history + * + * 03-jun 2005 (eric williams) entered into versioning + */ + +/* developer: eric williams, + * center for information technology integration, + * university of michigan, ann arbor + * + * comments: nativeafs@citi.umich.edu + */ + +#define IRPMJFUNCDESC /* pull in text strings of the names of irp codes */ +#define RPC_SRV /* which half of the rpc library to use */ + +#include +#include +#include +#include +#include "ifs_rpc.h" +#include "afsrdr.h" +#include "kif.h" + + +/*** notes ***/ +/* flag pooltag Io(sp)(sp) to check queryinfo requests for buffer overrun */ + +NTKERNELAPI +NTSTATUS +IoAllocateDriverObjectExtension( + IN PDRIVER_OBJECT DriverObject, + IN PVOID ClientIdentificationAddress, + IN ULONG DriverObjectExtensionSize, + OUT PVOID *DriverObjectExtension + ); + +/*** local structs ***/ +/* represents a specific file */ +struct afs_fcb + { + FSRTL_COMMON_FCB_HEADER; /* needed to interface with cache manager, etc. */ + SECTION_OBJECT_POINTERS sectionPtrs; + ERESOURCE _resource; /* pointed to by fcb_header->Resource */ + ERESOURCE _pagingIoResource; + unsigned long fid; /* a courtesy from the userland daemon (a good hash function) */ + UCHAR delPending; /* 3 types: FIX */ + struct afs_ccb *ccb_list; /* list of open instances */ + SHARE_ACCESS share_access; /* common access control */ + }; +typedef struct afs_fcb afs_fcb_t; + +/* represents an open instance of a file */ +struct afs_ccb + { + struct afs_ccb *next; /* these are chained as siblings, non-circularly */ + ULONG access; /* how this instance is opened */ + wchar_t *name; /* ptr to name buffer */ + UNICODE_STRING str; /* full name struct, for notification fns */ + FILE_OBJECT *fo; /* can get parent fcb from this */ + LARGE_INTEGER cookie; /* on enum ops, where we are */ + wchar_t *filter; /* on enum ops, what we are filtering on */ + PACCESS_TOKEN token; /* security data of opening app */ + ULONG attribs; /* is dir, etc. */ + }; +typedef struct afs_ccb afs_ccb_t; + + +/*** globals ***/ +/* use wisely -- should be set by each thread in an arbitrary context */ +/* here mostly as a development convenience */ +DEVICE_OBJECT *RdrDevice, *ComDevice; +struct AfsRdrExtension *rdrExt; +struct ComExtension *comExt; + + +/*** error and return handling ***/ +/* current code is stable without, but these should wrap all operations */ +/*#define TRY try{ +#define EXCEPT(x, y) } except(EXCEPTION_EXECUTE_HANDLER) \ + { \ + KdBreakPoint(); \ + rpt4(("exception", "occurred")); \ + Irp->IoStatus.Status = x; \ + Irp->IoStatus.Information = y; \ + }*/ +#define TRY +#define EXCEPT(x, y) + +#define STATUS(st, in) Irp->IoStatus.Information = (in), Irp->IoStatus.Status = (st) +#define SYNC_FAIL(st) \ + { \ + STATUS(st, 0); \ + COMPLETE_NO_BOOST; \ + return st; \ + } +#define SYNC_FAIL2(st, in) \ + { \ + STATUS(st, in); \ + COMPLETE_NO_BOOST; \ + return st; \ + } +#define SYNC_RET(st) \ + { \ + STATUS(st, 0); \ + COMPLETE; \ + return st; \ + } +#define SYNC_RET2(st, in) \ + { \ + STATUS(st, in); \ + COMPLETE; \ + return st; \ + } +#define SYNC_FAIL_RPC_TIMEOUT SYNC_FAIL(STATUS_NETWORK_BUSY) + +#define LOCK_FCB_LIST FsRtlEnterFileSystem(); ExAcquireFastMutex(&rdrExt->fcbLock); +#define UNLOCK_FCB_LIST ExReleaseFastMutex(&rdrExt->fcbLock); FsRtlExitFileSystem(); + +#define LOCK_FCB ExAcquireResourceExclusiveLite(fcb->Resource, TRUE) +#define SLOCK_FCB ExAcquireResourceSharedLite(fcb->Resource, TRUE) +#define UNLOCK_FCB if (fcb) ExReleaseResourceLite(fcb->Resource) + +#define LOCK_PAGING_FCB ExAcquireResourceExclusiveLite(fcb->PagingIoResource, TRUE) +#define SLOCK_PAGING_FCB ExAcquireResourceSharedLite(fcb->PagingIoResource, TRUE) +#define UNLOCK_PAGING_FCB if (fcb) ExReleaseResourceLite(fcb->PagingIoResource) + +/*** constants ***/ +#define AFS_RDR_TAG (0x73666440)//@dfs//0x482ac230//0x3029a4f2 +#define MAX_PATH 700 +#define AFS_FS_NAME L"Andrew File System" + +#define COMM_IOCTL (void*)0x01 +#define COMM_DOWNCALL (void*)0x02 +#define COMM_UPCALLHOOK (void*)0x03 + +/*#define ACC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_LIST_DIRECTORY +#define ACC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA)* + + +/* dates from afs are time_t style -- seconds since 1970 */ /* 11644505691.6384 */ +#define AfsTimeToWindowsTime(x) (((x)+11644505692L)*10000000L) /*(1970L-1601L)*365.242199*24L*3600L)*/ +#define WindowsTimeToAfsTime(x) ((x)/10000000L-11644505692L) /*(1970L-1601L)*365.242199*24L*3600L)*/ +#define IsDeviceFile(fo) (!fo->FsContext) + + +/*** auxiliary functions ***/ +#define COMPLETE_NO_BOOST IoCompleteRequest(Irp, IO_NO_INCREMENT) +#define COMPLETE IoCompleteRequest(Irp, IO_NETWORK_INCREMENT) + +afs_fcb_t *FindFcb(FILE_OBJECT *fo) + { + if (fo) + return fo->FsContext; + return NULL; + } + +void *AfsFindBuffer(IRP *Irp) + { + void *outPtr; + if (Irp->MdlAddress) + { + outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + if (outPtr) + return outPtr; + } + outPtr = Irp->AssociatedIrp.SystemBuffer; + return outPtr; + } + +/* we do Resource locking because we don't want to figure out when to pull MainResource */ +BOOLEAN lazyWriteLock(PVOID context, BOOLEAN wait) +{ +afs_fcb_t *fcb = context; +ASSERT(fcb); +return ExAcquireResourceExclusiveLite(fcb->Resource, wait); +} + +void lazyWriteUnlock(PVOID context) +{ +afs_fcb_t *fcb = context; +ASSERT(fcb); +ExReleaseResourceLite(fcb->Resource); +} + +BOOLEAN readAheadLock(PVOID context, BOOLEAN wait) +{ +afs_fcb_t *fcb = context; +ASSERT(fcb); +return ExAcquireResourceSharedLite(fcb->Resource, wait); +} + +void readAheadUnlock(PVOID context) +{ +afs_fcb_t *fcb = context; +ASSERT(fcb); +ExReleaseResourceLite(fcb->Resource); +} + +afs_fcb_t *find_fcb(ULONG fid) +{ +afs_fcb_t compare, *compare_ptr, **fcbp; + +compare.fid = fid; +compare_ptr = &compare; +fcbp = RtlLookupElementGenericTable(&rdrExt->fcbTable, (void*)&compare_ptr); + +if (fcbp) + return (*fcbp); +return NULL; +} + + +/********************************************************** + * AfsRdrCreate + * - handle open and create requests + * - on success + * - FsContext of file object points to FCB + * - FsContext2 of file object is usermode handle of file instance + * - beginning failure codes and conditions came from ifstest + **********************************************************/ +NTSTATUS AfsRdrCreate(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *_fcb) +{ +afs_fcb_t *pfcb, *fcb, **fcbp; +afs_ccb_t *ccb, *pccb; +ULONG len, x, y; +wchar_t *str, *ptr; +ULONG fid, access, granted, disp; +LARGE_INTEGER size, creation, accesst, change, written, zero; +ULONG attribs; +ULONG share; +CC_FILE_SIZES sizes; +NTSTATUS status; +char created; +PACCESS_TOKEN acc_token; + +/* set rpc security context for current thread */ +acc_token = SeQuerySubjectContextToken(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); +ASSERT(acc_token); +rpc_set_context(acc_token); + +/* attempt to open afs volume directly */ +if (IrpSp->FileObject->FileName.Length == 0) + SYNC_FAIL(STATUS_SHARING_VIOLATION); + +if (IrpSp->FileObject->FileName.Length > MAX_PATH*sizeof(wchar_t)) + SYNC_FAIL(STATUS_OBJECT_NAME_INVALID); + +if (IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY && + IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) + SYNC_FAIL(STATUS_INVALID_PARAMETER); + +/* relative opens cannot start with \ */ +if (IrpSp->FileObject->RelatedFileObject && + IrpSp->FileObject->FileName.Length && + IrpSp->FileObject->FileName.Buffer[0] == L'\\') + SYNC_FAIL(STATUS_INVALID_PARAMETER);/*STATUS_OBJECT_PATH_SYNTAX_BAD);*/ + +/* a create request can be relative to a prior file. build filename here */ +pccb = NULL; +if (IrpSp->FileObject->RelatedFileObject) + pccb = IrpSp->FileObject->RelatedFileObject->FsContext2; +len = IrpSp->FileObject->FileName.Length + (pccb?wcslen(pccb->name):0)*sizeof(wchar_t) + 6; +str = ExAllocatePoolWithTag(NonPagedPool, len, AFS_RDR_TAG); +RtlZeroMemory(str, len); +if (pccb) + { + StringCbCatN(str, len, IrpSp->FileObject->RelatedFileObject->FileName.Buffer, IrpSp->FileObject->RelatedFileObject->FileName.Length); + StringCbCat(str, len, L"\\"); + } +StringCbCatN(str, len, IrpSp->FileObject->FileName.Buffer, IrpSp->FileObject->FileName.Length); + +/* request to open heirarchical parent of specified path */ +/* remove last path component */ +if (IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY) + { + y = x = wcslen(str); + if (x) + x--, y--; + for (x; x >= 0; x--) + { + if (str[x] == L'\\') + { + if (y == x && x != 0) + str[x] = L'\0'; + else if (x != 0) + { + str[x] = L'\0'; + break; + } + else + { + str[x+1] = L'\0'; + break; + } + } + } + } + +/* first two characters are \%01d . %d is number of path components immediately + following that should not be returned in file name queries. + EX: \3\mount\path\start\fname.ext is mapped to :\fname.ext */ +if (wcslen(str) <= 2) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_OBJECT_NAME_INVALID); + } + +fid = 0; +disp = (unsigned char)((IrpSp->Parameters.Create.Options >> 24) & 0xff); +access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; +share = IrpSp->Parameters.Create.ShareAccess; +size.QuadPart = 0; +created = 0; + +/* check for file existance. we jump to creating it if needed */ +if (disp == FILE_OPEN || disp == FILE_OPEN_IF || disp == FILE_OVERWRITE || + disp == FILE_OVERWRITE_IF || disp == FILE_SUPERSEDE) + { + /* chop our internal mount flagging from the beginning */ + status = uc_namei(str+2, &fid); + if (status == IFSL_DOES_NOT_EXIST && + (disp == FILE_OPEN_IF || + disp == FILE_OVERWRITE_IF || + disp == FILE_SUPERSEDE)) + goto create; + + if (status != IFSL_SUCCESS) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_NO_ACCESS: SYNC_FAIL(STATUS_ACCESS_DENIED); + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + case IFSL_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_NAME_NOT_FOUND, FILE_DOES_NOT_EXIST); + case IFSL_PATH_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_PATH_NOT_FOUND, FILE_DOES_NOT_EXIST); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + } + + /* make upcall to get ACL in afs. we specify our requested level to + keep it from hitting the network on a public volume. */ + status = uc_check_access(fid, access, &granted); + if (status != IFSL_SUCCESS) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + } + + /* make sure daemon approved access */ + if ((access & granted) != access) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_ACCESS_DENIED); + } + + /* we depend on this information for caching, etc. */ + status = uc_stat(fid, &attribs, &size, &creation, &accesst, &change, &written); + if (status != IFSL_SUCCESS) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + } + + /* afsd does not maintain instance-specific data, so we adjust here */ + if (granted & FILE_READ_DATA && !(granted & FILE_WRITE_DATA)) + attribs |= FILE_ATTRIBUTE_READONLY; + + if (IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE && + !(attribs & FILE_ATTRIBUTE_DIRECTORY)) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_NOT_A_DIRECTORY); + } + if (IrpSp->Parameters.Create.Options & FILE_NON_DIRECTORY_FILE && + attribs & FILE_ATTRIBUTE_DIRECTORY) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_FILE_IS_A_DIRECTORY); + } + + /* check for previous open instance(s) of file. it will be in the fcb chain. + when we have this locked, we cannot make upcalls -- running at APC_LEVEL. + lock here (not later) to prevent possible truncation races. */ + LOCK_FCB_LIST; + fcb = find_fcb(fid); + if (fcb) + { + LOCK_PAGING_FCB; + LOCK_FCB; + } + + /* if we found it, check to make sure open disposition and sharing + are not in conflict with previous opens. then, make new file + instance entry and, if necessary, file entry. */ + if (fcb) + { + /* file contents cannot be cached for a successful delete */ + if (access & FILE_WRITE_DATA) + if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForWrite)) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_SHARING_VIOLATION); + } + if (access & DELETE) + if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForWrite))//Delete)) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_SHARING_VIOLATION); + } + + /* check common sharing flags, but do not change */ + if (IoCheckShareAccess(access, share, IrpSp->FileObject, &fcb->share_access, FALSE) != STATUS_SUCCESS) + { + rpt0(("create", "sharing violation for %ws", str)); + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_SHARING_VIOLATION); + } + + zero.QuadPart = 0; + if (access & DELETE) + if (!MmCanFileBeTruncated(&(fcb->sectionPtrs), &zero)) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_SHARING_VIOLATION); + } + } + + /* do overwrite/supersede tasks */ + if (disp == FILE_OVERWRITE || + disp == FILE_OVERWRITE_IF || + disp == FILE_SUPERSEDE) + { + zero.QuadPart = 0; + if (fcb && !MmCanFileBeTruncated(&(fcb->sectionPtrs), &zero)) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_SHARING_VIOLATION); + } + if (size.QuadPart != 0) + { + size.QuadPart = 0; + status = uc_trunc(fid, size); + if (status != IFSL_SUCCESS) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_ACCESS_DENIED); + } + if (fcb) + { + fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size; + CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize); + } + } + if (Irp->Overlay.AllocationSize.QuadPart) + { + status = uc_trunc(fid, Irp->Overlay.AllocationSize); + size = Irp->Overlay.AllocationSize; + if (status != IFSL_SUCCESS) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_DISK_FULL); + } + if (fcb) + { + fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size; + CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize); + } + } + } + + if (fcb) + { + /* make actual change in common sharing flags */ + IoUpdateShareAccess(IrpSp->FileObject, &fcb->share_access); + goto makeccb; + } + + goto makefcb; + } + + +/* if disposition was to create the file, or its non-existance necessitates this */ +create: +if (disp == FILE_CREATE || + status == IFSL_DOES_NOT_EXIST && (disp == FILE_OPEN_IF || disp == FILE_OVERWRITE_IF || disp == FILE_SUPERSEDE)) + { + attribs = IrpSp->Parameters.Create.FileAttributes; + if (IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) + attribs |= FILE_ATTRIBUTE_DIRECTORY; + if (IrpSp->Parameters.Create.Options & FILE_NON_DIRECTORY_FILE) + attribs &= ~FILE_ATTRIBUTE_DIRECTORY; + status = uc_create(str+2, attribs, Irp->Overlay.AllocationSize, access, &granted, &fid); + if (status != IFSL_SUCCESS) + { + ExFreePoolWithTag(str, AFS_RDR_TAG); + switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_NO_ACCESS: SYNC_FAIL(STATUS_ACCESS_DENIED); + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + case IFSL_PATH_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_PATH_NOT_FOUND, FILE_DOES_NOT_EXIST); + case IFSL_OPEN_EXISTS: SYNC_FAIL2(STATUS_OBJECT_NAME_COLLISION, FILE_EXISTS); + case IFSL_OVERQUOTA: SYNC_FAIL(STATUS_DISK_FULL);//STATUS_QUOTA_EXCEEDED); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + } + + /* lock list like above. check again just to make sure it isn't in the list. + if it is, we should process like above. depending on how we follow symlinks + (same fid for multiple files), we cannot expect serialized create requests. */ + LOCK_FCB_LIST; + fcb = find_fcb(fid); + if (fcb) + _asm int 3; + + if (size.QuadPart != 0) + { + size.QuadPart = 0; + uc_trunc(fid, size); + if (status != IFSL_SUCCESS) + { + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_DISK_FULL); + } + } + if (Irp->Overlay.AllocationSize.QuadPart) + { + uc_trunc(fid, Irp->Overlay.AllocationSize); + size = Irp->Overlay.AllocationSize; + if (status != IFSL_SUCCESS) + { + UNLOCK_FCB_LIST; + ExFreePoolWithTag(str, AFS_RDR_TAG); + SYNC_FAIL(STATUS_ACCESS_DENIED); + } + } + + created = 1; + goto makefcb; + } + +/* OS passed unexpected disposition */ +ExFreePoolWithTag(str, AFS_RDR_TAG); +SYNC_FAIL(STATUS_NOT_IMPLEMENTED); +/*SYNC_FAIL2(STATUS_OBJECT_NAME_NOT_FOUND, FILE_DOES_NOT_EXIST);*/ + + +/* allocate nonpaged struct to track this file and all open instances */ +makefcb: + fcb = ExAllocateFromNPagedLookasideList(&rdrExt->fcbMemList); + ASSERT(fcb); + RtlZeroMemory(fcb, sizeof(afs_fcb_t)); + + fcb->fid = fid; + /*fcb->refs = 0;*/ + fcb->ccb_list = NULL; + fcb->IsFastIoPossible = FastIoIsNotPossible; + + ExInitializeResourceLite(&fcb->_resource); + ExInitializeResourceLite(&fcb->_pagingIoResource); + fcb->Resource = &fcb->_resource; + fcb->PagingIoResource = &fcb->_pagingIoResource; + LOCK_PAGING_FCB; + LOCK_FCB; + + fcb->sectionPtrs.DataSectionObject = NULL; + fcb->sectionPtrs.SharedCacheMap = NULL; + fcb->sectionPtrs.ImageSectionObject = NULL; + fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size; + + IoSetShareAccess(access, share, IrpSp->FileObject, &fcb->share_access); + + /* we store a pointer to the fcb. the table would want to store a copy otherwise. */ + fcbp = &fcb; + RtlInsertElementGenericTable(&rdrExt->fcbTable, fcbp, sizeof(fcbp), NULL); + + sizes.AllocationSize = sizes.FileSize = sizes.ValidDataLength = size; + rpt1(("create", "created size %d name %ws", size.LowPart, str)); + +/* allocate nonpaged struct tracking information specific to (file, open instance) pair, + and link from parent. is put at head of parent's list. */ +makeccb: + /* there are two different types of pending deletes. we return different + errors in places depending on a) delete specified on call to open, + or b) file specifically deleted */ + /* need to check for DELETE perms too? */ + if (IrpSp->Parameters.Create.Options & FILE_DELETE_ON_CLOSE) + fcb->delPending = 2; + + ccb = ExAllocateFromNPagedLookasideList(&rdrExt->ccbMemList); + ccb->name = str; + ccb->access = granted; + ccb->fo = IrpSp->FileObject; + ccb->cookie.QuadPart = 0; + ccb->filter = NULL; + ccb->attribs = attribs; + + /* save security context information. we never change this ccb attribute. */ + ObReferenceObjectByPointer(acc_token, TOKEN_QUERY, NULL, KernelMode); + ccb->token = acc_token; + /*ObOpenObjectByPointer(acc_token, OBJ_KERNEL_HANDLE, NULL, TOKEN_QUERY, NULL, KernelMode, &ccb->token);*/ + + /*fcb->refs++;*/ + if (!fcb->ccb_list) + { + ccb->next = NULL; + fcb->ccb_list = ccb; + } + else + { + ccb->next = fcb->ccb_list; + fcb->ccb_list = ccb; + } + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + UNLOCK_FCB_LIST; + + /* how we pack (as it is expected): a) fscontext same for all open instances of a file, + b) fscontext2 unique among each instance, c) private cache map pointer set by cache + manager upon caching, d) so pointers are per-file, as in (a). */ + IrpSp->FileObject->FsContext = fcb; + IrpSp->FileObject->FsContext2 = ccb; + IrpSp->FileObject->PrivateCacheMap = NULL; + IrpSp->FileObject->SectionObjectPointer = &(fcb->sectionPtrs); + + /* explicitly start caching on a data file. caching will still happen upon + paging i/o even if commented out below. the other option is to cache upon + the first read/write operation. that code is also in place. */ + if (!(attribs & FILE_ATTRIBUTE_DIRECTORY)) + { + /*CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1);*/ + /*CcSetAdditionalCacheAttributes(IrpSp->FileObject, TRUE, TRUE);*/ + } + + /* customize returns; semantics largely derived from output of ifstest.exe */ + switch (disp) + { + case FILE_OPEN: + SYNC_FAIL2(STATUS_SUCCESS, FILE_OPENED) + + case FILE_OPEN_IF: + if (created) + SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED) + else + SYNC_FAIL2(STATUS_SUCCESS, FILE_OPENED) + + case FILE_OVERWRITE: + SYNC_FAIL2(STATUS_SUCCESS, FILE_OVERWRITTEN) + + case FILE_OVERWRITE_IF: + if (created) + SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED) + else + SYNC_FAIL2(STATUS_SUCCESS, FILE_OVERWRITTEN) + + case FILE_SUPERSEDE: + if (created) + SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED) + else + SYNC_FAIL2(STATUS_SUCCESS, FILE_SUPERSEDED) + + case FILE_CREATE: + SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED) + } +_asm int 3; +return 0; +} + +/* experimental; does not work. need to handle filesizes + and cache invalidation in more places. */ +#define EXPLICIT_CACHING + +/********************************************************** + * AfsRdrRead + * - handle reads + **********************************************************/ +NTSTATUS AfsRdrRead(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +struct ReadKOut *p; +void *ptr; +LARGE_INTEGER offset, curroff; +ULONG length, read; +void *outPtr; +NTSTATUS status; +afs_ccb_t *ccb; +MDL m; +ULONG currpos, ttlread, toread; + +ccb = IrpSp->FileObject->FsContext2; +if (IsDeviceFile(IrpSp->FileObject) || (ccb->attribs & FILE_ATTRIBUTE_DIRECTORY)) + SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST); + +/* the second line disables read ahead and write behind. since our data is + already cached in userland, and there are read-ahead parameters there, + we do not use this service. */ +#ifdef EXPLICIT_CACHING +if (!IrpSp->FileObject->PrivateCacheMap) + { + CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1); + CcSetAdditionalCacheAttributes(IrpSp->FileObject, FALSE, TRUE); + //CcSetReadAheadGranularity + } +#endif + +if (!(ccb->access & FILE_READ_DATA) && !(Irp->Flags & IRP_PAGING_IO)) + SYNC_FAIL(STATUS_ACCESS_DENIED); + +if (!IrpSp->Parameters.Read.Length) + SYNC_FAIL(STATUS_SUCCESS); + +offset = IrpSp->Parameters.Read.ByteOffset; +length = IrpSp->Parameters.Read.Length; + +/* FIX: lock here, before finding end-of-file */ + +/* fast out for reads starting beyond eof */ +if (offset.QuadPart > fcb->ValidDataLength.QuadPart) + SYNC_FAIL(STATUS_END_OF_FILE); +/* pre-truncate reads */ +if (offset.QuadPart + length > fcb->ValidDataLength.QuadPart) + length = (ULONG)(fcb->ValidDataLength.QuadPart - offset.QuadPart); + +outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); +if (!outPtr) + SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES); + +#ifdef EXPLICIT_CACHING +if (!(Irp->Flags & (IRP_NOCACHE | IRP_PAGING_IO))) + { + FsRtlEnterFileSystem(); + SLOCK_PAGING_FCB; + ttlread = 0; + try + { + if (!CcCopyRead(IrpSp->FileObject, &offset, length, TRUE, outPtr, &Irp->IoStatus)) + { + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + SYNC_FAIL(STATUS_UNSUCCESSFUL); + } +// KdPrint(("read %x at %x cache done %x\n", length, (ULONG)offset.QuadPart, Irp->IoStatus.Information)); + ttlread = Irp->IoStatus.Information; + } + except (EXCEPTION_EXECUTE_HANDLER) + { + STATUS(STATUS_UNSUCCESSFUL, 0); + } + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + if (Irp->IoStatus.Status == STATUS_UNSUCCESSFUL) + SYNC_FAIL(STATUS_UNSUCCESSFUL); + } +else +#endif + { + FsRtlEnterFileSystem(); + SLOCK_FCB; + for (currpos = ttlread = 0; ttlread < length; ) + { + toread = length - currpos; + toread = (toread > TRANSFER_CHUNK_SIZE) ? TRANSFER_CHUNK_SIZE : toread; + curroff.QuadPart = offset.QuadPart + currpos; + status = uc_read(fcb->fid, curroff, toread, &read, outPtr); +// KdPrint(("read %x at %x done %x\n", length, (ULONG)offset.QuadPart, read)); + if (status == 0) + { + ttlread += read; + currpos += read; + if (read < toread) + goto end; + continue; + } + UNLOCK_FCB; + FsRtlExitFileSystem(); + switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_IS_A_DIR: SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST); + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + } +end: ; + UNLOCK_FCB; + FsRtlExitFileSystem(); + } + +/* update byteoffset when this is not a paging or async request */ +if (IoIsOperationSynchronous(Irp) && !(Irp->Flags & IRP_PAGING_IO)) + IrpSp->FileObject->CurrentByteOffset.QuadPart += ttlread; + +if (ttlread == 0)//< length) + SYNC_FAIL2(STATUS_END_OF_FILE, ttlread) +else + SYNC_FAIL2(STATUS_SUCCESS, ttlread) +} + + + +/********************************************************** + * AfsRdrWrite + * - handle writes + **********************************************************/ +NTSTATUS AfsRdrWrite(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +struct WriteKOut *p; +void *ptr, *outPtr; +ULONG length, written; +LARGE_INTEGER offset, end; +NTSTATUS status; +afs_ccb_t *ccb; +CC_FILE_SIZES sizes, oldSizes; +ULONG towrite, ttlwritten, currpos; +LARGE_INTEGER curroff; +BOOLEAN change, paging_lock; + +ccb = IrpSp->FileObject->FsContext2; +if (IsDeviceFile(IrpSp->FileObject) || (ccb->attribs & FILE_ATTRIBUTE_DIRECTORY)) + SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST); + +/* since we will be performing io on this instance, start caching. */ +#ifdef EXPLICIT_CACHING +if (!IrpSp->FileObject->PrivateCacheMap) + { + CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1); + CcSetAdditionalCacheAttributes(IrpSp->FileObject, FALSE, TRUE); + } +#endif + +if (!(ccb->access & FILE_WRITE_DATA) && !(Irp->Flags & IRP_PAGING_IO)) + SYNC_FAIL(STATUS_ACCESS_DENIED); + +/* fast-out for zero-length i/o */ +if (!IrpSp->Parameters.Write.Length) + SYNC_FAIL(STATUS_SUCCESS); + +if (IrpSp->Parameters.Write.ByteOffset.HighPart == 0xffffffff && + IrpSp->Parameters.Write.ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) + offset.QuadPart = fcb->FileSize.QuadPart; +else + offset = IrpSp->Parameters.Write.ByteOffset; +length = IrpSp->Parameters.Write.Length; + +if (!(outPtr = AfsFindBuffer(Irp))) + SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES); + +#ifdef EXPLICIT_CACHING +if (!(Irp->Flags & (IRP_NOCACHE | IRP_PAGING_IO))) + { + /* extend file for cached writes */ + FsRtlEnterFileSystem(); + LOCK_PAGING_FCB; + if (offset.QuadPart + length > fcb->FileSize.QuadPart) + { + end.QuadPart = offset.QuadPart + length; + fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = end; + LOCK_FCB; + CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize); + UNLOCK_FCB; + /*ret = *//*CcZeroData(IrpSp->FileObject, &oldSizes.FileSize, &end, FALSE);*/ /* should wait? */ + } + try + { + if (!CcCopyWrite(IrpSp->FileObject, &offset, length, TRUE, outPtr)) + SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + except (EXCEPTION_EXECUTE_HANDLER) + { + STATUS(STATUS_UNSUCCESSFUL, 0); + } +// KdPrint(("write %x at %x cache done\n", length, (ULONG)offset.QuadPart)); + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + ttlwritten = written = length; + if (Irp->IoStatus.Status == STATUS_UNSUCCESSFUL) + SYNC_FAIL(STATUS_UNSUCCESSFUL); + } +else +#endif + { + FsRtlEnterFileSystem(); + while (1) + { + if (offset.QuadPart + length > fcb->FileSize.QuadPart) + change = 1; + else + change = 0; + if (change && !(Irp->Flags & IRP_PAGING_IO)) + paging_lock = 1; + else + paging_lock = 0; + if (paging_lock) + LOCK_PAGING_FCB; + LOCK_FCB; + if (offset.QuadPart + length > fcb->FileSize.QuadPart) + { + if (Irp->Flags & IRP_PAGING_IO) + { + /* the input buffer and length is for a full page. ignore this. */ + if (offset.QuadPart > fcb->FileSize.QuadPart) + { + if (paging_lock) + { + _asm int 3; + UNLOCK_PAGING_FCB; + } + UNLOCK_FCB; + FsRtlExitFileSystem(); + SYNC_FAIL2(STATUS_SUCCESS, length); + } + length = (ULONG)(fcb->FileSize.QuadPart - offset.QuadPart); + if (paging_lock) + { + _asm int 3; + UNLOCK_PAGING_FCB; + } + break; + } + else + { + if (!change) + { + if (paging_lock) + { + _asm int 3; + UNLOCK_PAGING_FCB; + } + UNLOCK_FCB; + continue; + } + end.QuadPart = offset.QuadPart + length; + fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = end; + CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize); + if (paging_lock) + UNLOCK_PAGING_FCB; + break; + } + } + else + { + //UNLOCK_FCB; + if (paging_lock) + UNLOCK_PAGING_FCB; + break; + } + } + + for (currpos = ttlwritten = 0; ttlwritten < length; ) + { + towrite = length - currpos; + towrite = (towrite > TRANSFER_CHUNK_SIZE) ? TRANSFER_CHUNK_SIZE : towrite; + curroff.QuadPart = offset.QuadPart + currpos; + status = uc_write(fcb->fid, curroff, towrite, &written, outPtr); +// KdPrint(("write %x at %x done\n", length, (ULONG)offset.QuadPart)); + if (status == 0) + { + ttlwritten += written; + currpos += written; + if (written < towrite) + goto end; + continue; + } + UNLOCK_FCB; + FsRtlExitFileSystem(); + switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + case IFSL_OVERQUOTA: SYNC_FAIL(STATUS_DISK_FULL); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + } +end: ; + UNLOCK_FCB; + FsRtlExitFileSystem(); + } + +if (IoIsOperationSynchronous(Irp) && !(Irp->Flags & IRP_PAGING_IO)) + IrpSp->FileObject->CurrentByteOffset.QuadPart += ttlwritten; + +/* if we failed a write, we would not be here. so, we must + tell the vmm that all data was written. */ +if (Irp->Flags & IRP_PAGING_IO) + SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.Write.Length) +SYNC_FAIL2(STATUS_SUCCESS, ttlwritten) +} + + +wchar_t *SEARCH_MATCH_ALL = L"**"; + +/********************************************************** + * AfsRdrDirCtrl + * - handle directory notification callbacks + * - handle directory enumeration + **********************************************************/ +NTSTATUS AfsRdrDirCtrl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +struct EnumDirKOut *p; +LARGE_INTEGER size, creation, access, change, written; +ULONG attribs, count; +char buf[2048]; +afs_ccb_t *ccb; +void *outPtr, *info, *pre_adj_info; +FILE_BOTH_DIR_INFORMATION *info_both, *info_both_prev; +FILE_DIRECTORY_INFORMATION *info_dir, *info_dir_prev; +FILE_NAMES_INFORMATION *info_names, *info_names_prev; +int info_size; +readdir_data_t *ii; +ULONG x, buf_size; +LARGE_INTEGER last_cookie; +BOOLEAN overflow; +NTSTATUS status; +FILE_NOTIFY_INFORMATION *notify; + +if (IsDeviceFile(IrpSp->FileObject)) + SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST); + +if (IrpSp->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) + { + ccb = IrpSp->FileObject->FsContext2; + ccb->str.Length = wcslen(ccb->name)*sizeof(wchar_t); + ccb->str.MaximumLength = ccb->str.Length + sizeof(wchar_t); + ccb->str.Buffer = ccb->name; + + FsRtlEnterFileSystem(); + LOCK_FCB; /* FIX: shared lock? */ + FsRtlNotifyFullChangeDirectory(rdrExt->notifyList, &rdrExt->listHead, + ccb, + (STRING*)&ccb->str, + IrpSp->Flags & SL_WATCH_TREE, + FALSE, + /*FILE_NOTIFY_CHANGE_FILE_NAME,*/IrpSp->Parameters.NotifyDirectory.CompletionFilter, + Irp, NULL, NULL); + UNLOCK_FCB; + FsRtlExitFileSystem(); + /* do NOT complete request; that will be done by fsrtlnotify functions */ + return STATUS_PENDING; + } + +if (IrpSp->MinorFunction != IRP_MN_QUERY_DIRECTORY) + SYNC_FAIL(STATUS_NOT_IMPLEMENTED); + +if (IrpSp->Parameters.QueryDirectory.FileInformationClass != FileBothDirectoryInformation && + IrpSp->Parameters.QueryDirectory.FileInformationClass != FileDirectoryInformation && + IrpSp->Parameters.QueryDirectory.FileInformationClass != FileNamesInformation) + { + _asm int 3; + rpt0(("enum", "enum class %d not supported", IrpSp->Parameters.QueryDirectory.FileInformationClass)); + SYNC_FAIL(STATUS_NOT_IMPLEMENTED); + } + +ccb = IrpSp->FileObject->FsContext2; + +if (!(outPtr = AfsFindBuffer(Irp))) + SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES); + +if (IrpSp->Flags & SL_INDEX_SPECIFIED) + { + /* we were told where to start our search; afsd should scrub this input */ + ccb->cookie.QuadPart = IrpSp->Parameters.QueryDirectory.FileIndex; + if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL) + ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG); + ccb->filter = SEARCH_MATCH_ALL; + } +else if (IrpSp->Flags & SL_RESTART_SCAN || + ((IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) && ccb->cookie.QuadPart == 0)) + { + /* copy new filter string into nonpaged memory */ + ccb->cookie.QuadPart = 0; + if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL) + ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG); + buf_size = IrpSp->Parameters.QueryDirectory.FileName->Length+6; + ccb->filter = ExAllocatePoolWithTag(NonPagedPool, buf_size, AFS_RDR_TAG); + RtlCopyMemory(ccb->filter, IrpSp->Parameters.QueryDirectory.FileName->Buffer, buf_size); + ccb->filter[IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR)] = L'\0'; + } + +if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) + count = 1; +buf_size = 2040; + +status = uc_readdir(fcb->fid, ccb->cookie, ccb->filter, &count, buf, &buf_size); + +switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + case 0: break; + } + +switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) + { + case FileBothDirectoryInformation: + info_size = sizeof(FILE_BOTH_DIR_INFORMATION); + break; + case FileDirectoryInformation: + info_size = sizeof(FILE_DIRECTORY_INFORMATION); + break; + case FileNamesInformation: + info_size = sizeof(FILE_NAMES_INFORMATION); + break; + default: + KeBugCheckEx(0x12345, 0x98, 0x0, 0x0, 0x0); + } + +info = (FILE_BOTH_DIR_INFORMATION *)outPtr; +ii = (readdir_data_t *)buf; +Irp->IoStatus.Information = 0; +if (!count) + { + if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY && ccb->cookie.QuadPart == 0) + SYNC_FAIL(STATUS_NO_SUCH_FILE); + SYNC_FAIL(STATUS_NO_MORE_FILES); + } + +info_both_prev = NULL; +info_dir_prev = NULL; +info_names_prev = NULL; +if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) + count = 1; + +for (x = 0; x < count; x++) + { + pre_adj_info = info; + + /* must explicitly align second and subsequent entries on 8-byte boundaries */ + if (((ULONG)info & 0x7) && x) + info = (void*)(((ULONG)info) + (8-((ULONG)info & 0x7))); + + overflow = ((long)info + info_size + (long)ii->name_length > + (long)outPtr + (long)IrpSp->Parameters.QueryDirectory.Length); + if (overflow && x != 0) + { + ccb->cookie = ii->cookie; + SYNC_FAIL2(STATUS_SUCCESS, (long)pre_adj_info - (long)outPtr); + } + + memset(info, 0, info_size); + switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) + { + case FileBothDirectoryInformation: + info_both = info; + if (info_both_prev) + info_both_prev->NextEntryOffset = (char*)info_both - (char*)info_both_prev; + + info_both->NextEntryOffset = 0; + info_both->FileIndex = (ULONG)ii->cookie.QuadPart; + info_both->CreationTime.QuadPart = AfsTimeToWindowsTime(ii->creation.QuadPart); + info_both->LastAccessTime.QuadPart = AfsTimeToWindowsTime(ii->access.QuadPart); + info_both->LastWriteTime.QuadPart = AfsTimeToWindowsTime(ii->write.QuadPart); + info_both->ChangeTime.QuadPart = AfsTimeToWindowsTime(ii->change.QuadPart); + info_both->EndOfFile = info_both->AllocationSize = ii->size; + info_both->FileAttributes = ii->attribs;/*| FILE_ATTRIBUTE_READONLY*/; + info_both->EaSize = 0; + info_both->ShortNameLength = ii->short_name_length; + info_both->FileNameLength = ii->name_length; + RtlCopyMemory(info_both->ShortName, ii->short_name, ii->short_name_length*sizeof(WCHAR)); + + if (overflow) + { + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + info_both->FileNameLength = 0; + info_both->FileName[0] = L'\0'; + goto done; + } + + RtlCopyMemory(info_both->FileName, ii->name, ii->name_length*sizeof(WCHAR)); + info_both_prev = info_both; + break; + + case FileDirectoryInformation: + info_dir = info; + if (info_dir_prev) + info_dir_prev->NextEntryOffset = (char*)info_dir - (char*)info_dir_prev; + + info_dir->NextEntryOffset = 0; + info_dir->FileIndex = (ULONG)ii->cookie.QuadPart; + info_dir->CreationTime.QuadPart = AfsTimeToWindowsTime(ii->creation.QuadPart); + info_dir->LastAccessTime.QuadPart = AfsTimeToWindowsTime(ii->access.QuadPart); + info_dir->LastWriteTime.QuadPart = AfsTimeToWindowsTime(ii->write.QuadPart); + info_dir->ChangeTime.QuadPart = AfsTimeToWindowsTime(ii->change.QuadPart); + info_dir->EndOfFile = info_dir->AllocationSize = ii->size; + info_dir->FileAttributes = ii->attribs /*| FILE_ATTRIBUTE_READONLY*/; + info_dir->FileNameLength = ii->name_length; + + if (overflow) + { + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + info_dir->FileNameLength = 0; + info_dir->FileName[0] = L'\0'; + goto done; + } + + RtlCopyMemory(info_dir->FileName, ii->name, ii->name_length*sizeof(WCHAR)); + info_dir_prev = info_dir; + break; + + case FileNamesInformation: + info_names = info; + if (info_names_prev) + info_names_prev->NextEntryOffset = (char*)info_names - (char*)info_names_prev; + + info_names->NextEntryOffset = 0; + info_names->FileIndex = (ULONG)ii->cookie.QuadPart; + info_names->FileNameLength = ii->name_length; + + if (overflow) + { + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + info_names->FileNameLength = 0; + info_names->FileName[0] = L'\0'; + goto done; + } + + RtlCopyMemory(info_names->FileName, ii->name, ii->name_length*sizeof(WCHAR)); + info_names_prev = info_names; + break; + } + + info = (void*)(((ULONG)info) + info_size + (ULONG)ii->name_length*sizeof(WCHAR)); + ii = (readdir_data_t *)(((unsigned char *)ii) + sizeof(readdir_data_t) + ii->name_length); + last_cookie = ii->cookie; + } + +Irp->IoStatus.Status = STATUS_SUCCESS; +done: + ccb->cookie = last_cookie; + +SYNC_FAIL2(Irp->IoStatus.Status, (long)info - (long)outPtr); +} + + + + +/********************************************************** + * AfsRdrQueryInfo + * - handle stat calls + **********************************************************/ +NTSTATUS AfsRdrQueryInfo(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +FILE_BASIC_INFORMATION *infoBasic; +FILE_NAME_INFORMATION *infoName; +FILE_STANDARD_INFORMATION *infoStandard; +FILE_POSITION_INFORMATION *infoPosition; +FILE_ALL_INFORMATION *infoAll; +FILE_INTERNAL_INFORMATION *infoInternal; +LARGE_INTEGER size, creation, access, change, written; +ULONG attribs; +long count; +afs_ccb_t *ccb; +char *outPtr; +NTSTATUS status; +wchar_t *start; + +if (IsDeviceFile(IrpSp->FileObject)) + SYNC_FAIL(STATUS_UNSUCCESSFUL); // what should happen? + +if (!(outPtr = AfsFindBuffer(Irp))) + SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES); + +ccb = IrpSp->FileObject->FsContext2; + +status = uc_stat(fcb->fid, &attribs, &size, &creation, &access, &change, &written); +switch (status) + { + case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT; + case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER); + default: SYNC_FAIL(STATUS_UNSUCCESSFUL); + case 0: break; + } + +/* afsd does not maintain instance-specific data, so we adjust here */ +if (ccb->access & FILE_READ_DATA && !(ccb->access & FILE_WRITE_DATA)) + attribs |= FILE_ATTRIBUTE_READONLY; + +(void*)infoBasic = (void*)infoName = (void*)infoPosition = (void*)infoStandard = (void*)infoInternal = NULL; +switch (IrpSp->Parameters.QueryFile.FileInformationClass) + { + case FileBasicInformation: + infoBasic = (FILE_BASIC_INFORMATION*)outPtr; + break; + case FileNameInformation: + infoName = (FILE_NAME_INFORMATION*)outPtr; + break; + case FileStandardInformation: + infoStandard = (FILE_STANDARD_INFORMATION*)outPtr; + break; + case FilePositionInformation: + infoPosition = (FILE_POSITION_INFORMATION*)outPtr; + break; + case FileAllInformation: + infoAll = (FILE_ALL_INFORMATION*)outPtr; + infoBasic = &infoAll->BasicInformation; + infoName = &infoAll->NameInformation; + infoStandard = &infoAll->StandardInformation; + infoPosition = &infoAll->PositionInformation; + break; + case FileInternalInformation: + infoInternal = (FILE_INTERNAL_INFORMATION*)outPtr; + break; + default: + STATUS(STATUS_NOT_IMPLEMENTED, 0); + break; + } + +if (infoBasic) + { + memset(infoBasic, 0, sizeof(FILE_BASIC_INFORMATION)); + infoBasic->FileAttributes = attribs; + infoBasic->CreationTime.QuadPart = AfsTimeToWindowsTime(creation.QuadPart); + infoBasic->LastAccessTime.QuadPart = AfsTimeToWindowsTime(access.QuadPart); + infoBasic->LastWriteTime.QuadPart = AfsTimeToWindowsTime(written.QuadPart); + infoBasic->ChangeTime.QuadPart = AfsTimeToWindowsTime(change.QuadPart); + STATUS(STATUS_SUCCESS, sizeof(FILE_BASIC_INFORMATION)); + //KdPrint(("query basicinfo %d,%d %x,%I64d,%I64d\n", fcb->fid, (ULONG)IrpSp->FileObject->FsContext2, infoBasic->FileAttributes, infoBasic->CreationTime.QuadPart, infoBasic->ChangeTime.QuadPart)); + } + +if (infoName) + { + memset(infoName, 0, sizeof(FILE_NAME_INFORMATION)); + start = ccb->name; + count = (long)(*(start+1) - L'0'); + if (count > 9 || count < 0) + SYNC_FAIL(STATUS_OBJECT_NAME_INVALID); + if (count || *start == L'0') + { + for ( ; count >= 0 && start; count--) + start = wcschr(start+1, L'\\'); + if (!start) + SYNC_FAIL(STATUS_OBJECT_NAME_INVALID); + } + infoName->FileNameLength = wcslen(start)*sizeof(WCHAR); + if (((IrpSp->Parameters.QueryFile.FileInformationClass == FileAllInformation) ? sizeof(*infoAll) : sizeof(*infoName)) + + infoName->FileNameLength > IrpSp->Parameters.QueryFile.Length) + { + infoName->FileNameLength = 0; + infoName->FileName[0] = L'\0'; + STATUS(STATUS_BUFFER_OVERFLOW, sizeof(FILE_NAME_INFORMATION)); + //KdPrint(("query overflowing buffer %d\n", IrpSp->Parameters.QueryFile.Length)); + } + else + { //TODO:check filename is correct/correct format + StringCbCopy(infoName->FileName, IrpSp->Parameters.QueryFile.Length - sizeof(*infoName), start); + STATUS(STATUS_SUCCESS, sizeof(FILE_NAME_INFORMATION) + (infoName->FileNameLength - sizeof(WCHAR))); + } + //KdPrint(("query nameinfo %ws from %ws\n", infoName->FileName, ccb->name)); + } + +if (infoStandard) + { + memset(infoStandard, 0, sizeof(FILE_STANDARD_INFORMATION)); + infoStandard->AllocationSize.QuadPart = size.QuadPart; + infoStandard->EndOfFile.QuadPart = size.QuadPart; + infoStandard->NumberOfLinks = 1; + infoStandard->DeletePending = (fcb->delPending == 1); + infoStandard->Directory = (attribs & FILE_ATTRIBUTE_DIRECTORY)?TRUE:FALSE; //TODO:check if flag is valid at this point + STATUS(STATUS_SUCCESS, sizeof(FILE_STANDARD_INFORMATION)); + //KdPrint(("query stdinfo %d,%d %I64d,%s\n", fcb->fid, (ULONG)IrpSp->FileObject->FsContext2, infoStandard->EndOfFile.QuadPart, infoStandard->Directory?"dir":"file")); + } + +if (infoPosition) + { + infoPosition->CurrentByteOffset = IrpSp->FileObject->CurrentByteOffset; + STATUS(STATUS_SUCCESS, sizeof(FILE_POSITION_INFORMATION)); + //KdPrint(("query position %d,%d %I64d\n", fcb, (ULONG)IrpSp->FileObject->FsContext2, infoPosition->CurrentByteOffset.QuadPart)); + } + +if (IrpSp->Parameters.QueryFile.FileInformationClass == FileAllInformation) + { + if (!infoName->FileNameLength) + STATUS(STATUS_BUFFER_OVERFLOW, sizeof(FILE_ALL_INFORMATION)); + else + STATUS(STATUS_SUCCESS, sizeof(FILE_ALL_INFORMATION) + (infoName->FileNameLength - sizeof(WCHAR))); + } + +if (infoInternal) + { + infoInternal->IndexNumber.QuadPart = fcb->fid; + STATUS(STATUS_SUCCESS, sizeof(FILE_INTERNAL_INFORMATION)); + } + +status = Irp->IoStatus.Status; +COMPLETE; +return status; +} + + + + +/********************************************************** + * AfsRdrSetInfo + * - handle setting mod time + * - handle deleting + * - handle truncation/extension + * - handle renaming + **********************************************************/ +NTSTATUS AfsRdrSetInfo(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +struct SetInfoKOut *p; +afs_fcb_t *fcbt; +afs_ccb_t *ccb; +FILE_DISPOSITION_INFORMATION *infoDisp; +FILE_BASIC_INFORMATION *infoBasic; +FILE_END_OF_FILE_INFORMATION *infoLength; +FILE_RENAME_INFORMATION *infoRename; +FILE_POSITION_INFORMATION *infoPosition; +NTSTATUS ret; +wchar_t *buf, *part, *ptr; +ULONG size, new_fid; +NTSTATUS status; + +if (IrpSp->FileObject->FileName.Length == 0) + SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST); + +ccb = IrpSp->FileObject->FsContext2; + +switch (IrpSp->Parameters.SetFile.FileInformationClass) + { + /* delete disposition */ + case FileDispositionInformation: + infoDisp = Irp->AssociatedIrp.SystemBuffer; + + FsRtlEnterFileSystem(); + LOCK_FCB; + + if (infoDisp->DeleteFile) + { + if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForDelete)) + SYNC_FAIL(STATUS_ACCESS_DENIED); + fcb->delPending |= 0x1; + } + else + fcb->delPending &= ~0x1; + UNLOCK_FCB; + FsRtlExitFileSystem(); + SYNC_RET(STATUS_SUCCESS); + + /*case FileAllocationInformation:*/ + case FileEndOfFileInformation: + /* ignore extensions caused by paging requests*/ + if (Irp->Flags & IRP_PAGING_IO) + SYNC_FAIL(STATUS_SUCCESS); + + infoLength = Irp->AssociatedIrp.SystemBuffer; + + FsRtlEnterFileSystem(); + LOCK_PAGING_FCB; + LOCK_FCB; + if (IrpSp->Parameters.SetFile.AdvanceOnly && (infoLength->EndOfFile.QuadPart > fcb->FileSize.QuadPart) || + !IrpSp->Parameters.SetFile.AdvanceOnly && (infoLength->EndOfFile.QuadPart < fcb->FileSize.QuadPart)) + { + status = uc_trunc(fcb->fid, infoLength->EndOfFile); + /* because it is not written to the server immediately, this error will not always happen */ + if (status == IFSL_OVERQUOTA) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + SYNC_FAIL(STATUS_DISK_FULL); + } + } + fcb->FileSize = fcb->AllocationSize = fcb->ValidDataLength = infoLength->EndOfFile; + CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize); + //CcPurgeCacheSection(IrpSp->FileObject->SectionObjectPointer, &fcb->AllocationSize, 0, FALSE); + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + SYNC_FAIL(STATUS_SUCCESS); + + case FileBasicInformation: + infoBasic = Irp->AssociatedIrp.SystemBuffer; + status = uc_setinfo(fcb->fid, infoBasic->FileAttributes, infoBasic->CreationTime, infoBasic->LastAccessTime, infoBasic->ChangeTime, infoBasic->LastWriteTime); + SYNC_FAIL(STATUS_SUCCESS); + + case FileRenameInformation: + //KdPrint(("set rename %d\n", fcb->fid)); + infoRename = Irp->AssociatedIrp.SystemBuffer; + new_fid = fcb->fid; + //rpt1(("setinfo", "rename %d,%d %d,%ws", ExtractFid(fcb), (ULONG)IrpSp->FileObject->FsContext2, infoRename->ReplaceIfExists, infoRename->FileName)); + + if (IrpSp->Parameters.SetFile.FileObject) + fcbt = FindFcb(IrpSp->Parameters.SetFile.FileObject); + + //null-terminate all strings into uc_rename? + //FIX/one rename case not working + + if (IrpSp->Parameters.SetFile.FileObject == NULL && + infoRename->RootDirectory == NULL) + { + WCHAR fname[300]; /* FIX: uc_rename needs null-terminated string */ + StringCchCopyNW(fname, 300-1, infoRename->FileName, infoRename->FileNameLength/sizeof(WCHAR)); + uc_rename(fcb->fid, ccb->name+2, NULL, fname, &new_fid); + fcb->fid = new_fid; + } + else if (IrpSp->Parameters.SetFile.FileObject != NULL && + infoRename->RootDirectory == NULL) + { + WCHAR fname[300]; + StringCchCopyNW(fname, 300-1, infoRename->FileName, infoRename->FileNameLength/sizeof(WCHAR)); + uc_rename(fcb->fid, ccb->name+2, fcbt->ccb_list->name+2, fname, &new_fid); + fcb->fid = new_fid; + } + else + { + _asm int 3; + /*fcbt = FindFcb(IrpSp->Parameters.SetFile.FileObject); + + p->CurrNameOff = 0; + StringCbCopyW(buf, size, fcb->name); + p->NewNameOff = wcslen(buf)+1; + StringCbCopyNW(buf + p->NewNameOff, + size - p->NewNameOff, + infoRename->FileName, + infoRename->FileNameLength*sizeof(wchar_t)); + buf[p->NewNameOff+infoRename->FileNameLength] = L'\0'; + p->NewDirOff = p->NewNameOff + wcslen(buf + p->NewNameOff)+1; + StringCbCopyW(buf + p->NewDirOff, + size - p->NewDirOff, + fcbt->name);*/ + } + SYNC_RET(STATUS_SUCCESS); + break; + + case FilePositionInformation: + infoPosition = Irp->AssociatedIrp.SystemBuffer; + IrpSp->FileObject->CurrentByteOffset = infoPosition->CurrentByteOffset; + SYNC_FAIL(STATUS_SUCCESS); + + default: + KdPrint(("set unsupp %d type %d\n", fcb->fid, IrpSp->Parameters.SetFile.FileInformationClass)); + SYNC_FAIL(STATUS_NOT_IMPLEMENTED); + } + +SYNC_FAIL(STATUS_UNSUCCESSFUL); +} + +dc_break_callback(ULONG fid) +{ +afs_fcb_t *fcb; +int pos; +USHORT len; +UNICODE_STRING *s; + +LOCK_FCB_LIST; + +fcb = find_fcb(fid); +if (!fcb) + { + UNLOCK_FCB_LIST; + return 1; /* we are done with this file */ + } + +ASSERT(fcb->ccb_list); +/*pos = wcslen(fcb->ccb_list->name); +if (fcb->ccb_list->name[pos-1] == L'\\') + pos--; +ASSERT(pos); +while (pos > 0) + { + if (fcb->ccb_list->name[pos-1] == L'\\') + break; + pos--; + }*/ + +len = (wcslen(fcb->ccb_list->name) + 10) * sizeof(wchar_t); +s = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)+len+sizeof(wchar_t)); +s->Length = len; +s->MaximumLength = len + sizeof(wchar_t); +s->Buffer = (PWSTR)(s+1); + +StringCbCopyW((PWSTR)(s+1), len, fcb->ccb_list->name); +if (s->Buffer[wcslen(s->Buffer) - 1] != L'\\') + StringCbCatW(s->Buffer, len, L"\\"); +pos = wcslen(s->Buffer); +StringCbCatW(s->Buffer, len, L"jj"); /* FIX: make bogus change notification */ + +KdPrint(("break callback on %d %ws %ws\n", fid, fcb->ccb_list->name, fcb->ccb_list->name+pos)); + +FsRtlNotifyFullReportChange(rdrExt->notifyList, &rdrExt->listHead, + (PSTRING)s, (USHORT)pos*sizeof(wchar_t), NULL, NULL, + FILE_NOTIFY_CHANGE_FILE_NAME/*FILE_NOTIFY_VALID_MASK/*FILE_NOTIFY_CHANGE_FILE_NAME*/, FILE_ACTION_ADDED, NULL); + +ExFreePool(s); +UNLOCK_FCB_LIST; +return 0; +} + +/********************************************************** + * AfsRdrDeviceControl + * - handle communication requests from fs, etc. + * - handle ioctls + **********************************************************/ +NTSTATUS AfsRdrDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +struct KOutEntry *entry; +NTSTATUS ret; +struct CbKIn *kin; +USHORT offset; +UNICODE_STRING nm; +void *outPtr; +ULONG key, code, length; + +/* utility ioctls */ +if (DeviceObject == ComDevice && + IrpSp->FileObject->FsContext2 == COMM_IOCTL && + IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_IOCTL) + { + outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + if (!outPtr) + _asm int 3; + + rpc_set_context(IrpSp->FileObject->FsContext); + code = uc_ioctl_write(IrpSp->Parameters.DeviceIoControl.InputBufferLength, + Irp->AssociatedIrp.SystemBuffer, + (ULONG*)&key); + length = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + if (!code) + code = uc_ioctl_read(key, &length, outPtr); + rpc_remove_context(); + + switch (code) + { + case IFSL_SUCCESS: + STATUS(STATUS_SUCCESS, length); + break; + default: + STATUS(STATUS_UNSUCCESSFUL, 0); + break; + } + } +/* downcalls by afsd */ +else if (DeviceObject == ComDevice && + IrpSp->FileObject->FsContext2 == COMM_DOWNCALL && + IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_DOWNCALL) + { + outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + if (!outPtr) + _asm int 3; + + rpc_set_context(IrpSp->FileObject->FsContext); + code = rpc_call(IrpSp->Parameters.DeviceIoControl.InputBufferLength, + Irp->AssociatedIrp.SystemBuffer, + IrpSp->Parameters.DeviceIoControl.OutputBufferLength, + outPtr, + &length); + rpc_remove_context(); + switch (code) + { + case IFSL_SUCCESS: + STATUS(STATUS_SUCCESS, length); + break; + default: + STATUS(STATUS_UNSUCCESSFUL, 0); + break; + } + } +else if (DeviceObject == RdrDevice && + IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_GET_PATH) + { + outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + if (!outPtr) + _asm int 3; + + StringCbCopyW(outPtr, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, fcb->ccb_list->name+2); + + STATUS(STATUS_SUCCESS, (wcslen(outPtr)+1)*sizeof(wchar_t)); + } +else + { + rpt0(("devctl", "devctl %d rejected", IrpSp->Parameters.DeviceIoControl.IoControlCode)); + SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST); + } + +ret = Irp->IoStatus.Status; +COMPLETE; +return ret; +} + + + +/********************************************************** + * AfsRdrCleanup + * - called when usermode handle count reaches zero + **********************************************************/ +NTSTATUS AfsRdrCleanup(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +NTSTATUS ret; +struct AfsRdrExtension *ext; + +//try { +IrpSp = IoGetCurrentIrpStackLocation(Irp); + +if (IrpSp->FileObject->FileName.Length == 0) + SYNC_FAIL(STATUS_SUCCESS); + +ext = ((struct AfsRdrExtension*)RdrDevice->DeviceExtension); + +LOCK_FCB_LIST; +LOCK_PAGING_FCB; +LOCK_FCB; + +FsRtlNotifyCleanup(ext->notifyList, &ext->listHead, IrpSp->FileObject->FsContext2); + +CcFlushCache(IrpSp->FileObject->SectionObjectPointer, NULL, 0, NULL); + +if (fcb->delPending && !MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForDelete)) + /* yes, moot at this point */ + STATUS(STATUS_ACCESS_DENIED, 0); +else + STATUS(STATUS_SUCCESS, 0); + +MmFlushImageSection(IrpSp->FileObject->SectionObjectPointer, MmFlushForWrite); +CcPurgeCacheSection(IrpSp->FileObject->SectionObjectPointer, NULL, 0, TRUE); +CcUninitializeCacheMap(IrpSp->FileObject, NULL, NULL); + +UNLOCK_FCB; +UNLOCK_PAGING_FCB; +UNLOCK_FCB_LIST; + +/*} except(EXCEPTION_EXECUTE_HANDLER) + { + _asm int 3; + STATUS(STATUS_UNSUCCESSFUL, 0); + ExReleaseResourceLite(&ext->fcbLock); + FsRtlExitFileSystem(); + }*/ + +ret = Irp->IoStatus.Status; +COMPLETE; +return ret; +} + + +/********************************************************** + * AfsRdrClose + * - handle actual unlinking + * - handle closing + **********************************************************/ +NTSTATUS AfsRdrClose(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +ULONG length; +wchar_t *name; +char kill; +KEVENT ev; +LARGE_INTEGER timeout; +afs_ccb_t *ccb, *curr; + +if (IrpSp->FileObject->FileName.Length == 0) + SYNC_FAIL(STATUS_SUCCESS); + +ccb = IrpSp->FileObject->FsContext2; +LOCK_FCB_LIST; + +/* set share correctly so future opens can succeed */ +IoRemoveShareAccess(IrpSp->FileObject, &fcb->share_access); +ObDereferenceObject(ccb->token); + +curr = fcb->ccb_list; +if (fcb->ccb_list == ccb) + fcb->ccb_list = fcb->ccb_list->next; +else + while (curr->next) + { + if (curr->next == ccb) + { + curr->next = curr->next->next; + break; + } + curr = curr->next; + } + +if (!fcb->ccb_list) + { + uc_close(fcb->fid); + if (fcb->delPending) + { + uc_unlink(ccb->name+2); + } + ExDeleteResourceLite(&fcb->_resource); + ExDeleteResourceLite(&fcb->_pagingIoResource); + RtlDeleteElementGenericTable(&rdrExt->fcbTable, &fcb); + ExFreeToNPagedLookasideList(&rdrExt->fcbMemList, fcb); + } + +ExFreePoolWithTag(ccb->name, AFS_RDR_TAG); +if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL) + ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG); +ExFreeToNPagedLookasideList(&rdrExt->ccbMemList, ccb); + +UNLOCK_FCB_LIST; + +SYNC_FAIL(STATUS_SUCCESS); +} + + +/********************************************************** + * AfsRdrShutdown + * - should flush all data + **********************************************************/ +NTSTATUS AfsRdrShutdown(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp) +{ +_asm int 3; +STATUS(STATUS_SUCCESS, 0); +COMPLETE; +} + + +/********************************************************** + * AfsRdrFlushFile + * - flushes specified file to userspace and then disk + **********************************************************/ +NTSTATUS AfsRdrFlushFile(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +NTSTATUS ret; +afs_ccb_t *ccb; + +/*TRY*/ +IrpSp = IoGetCurrentIrpStackLocation(Irp); + +if (IrpSp->FileObject->FileName.Length == 0) + SYNC_RET(STATUS_INVALID_DEVICE_REQUEST); + +ccb = IrpSp->FileObject->FsContext2; + +CcFlushCache(&fcb->sectionPtrs, NULL, 0, &Irp->IoStatus); + +//SYNC_FAIL2(/*STATUS_LOCK_NOT_GRANTED*//*STATUS_NOT_IMPLEMENTED*/STATUS_SUCCESS, 0); + +/*EXCEPT(STATUS_UNSUCCESSFUL, 0);*/ +COMPLETE; +return Irp->IoStatus.Status; +} + + +/********************************************************** + * AfsRdrLockCtrl + * - should handle lock requests + **********************************************************/ +NTSTATUS AfsRdrLockCtrl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb) +{ +NTSTATUS ret; + +/*TRY*/ +IrpSp = IoGetCurrentIrpStackLocation(Irp); + +/* complete lock on control device object without processing, as directed */ +if (IrpSp->FileObject->FileName.Length == 0) + { + rpt0(("lock", "lock granted on root device obj")); + SYNC_FAIL(STATUS_SUCCESS); + } + +SYNC_FAIL2(/*STATUS_LOCK_NOT_GRANTED*//*STATUS_NOT_IMPLEMENTED*/STATUS_SUCCESS, 0); + +/*EXCEPT(STATUS_UNSUCCESSFUL, 0);*/ +} + + +/********************************************************** + * AfsRdrQueryVol + * - handle volume information requests + **********************************************************/ +NTSTATUS AfsRdrQueryVol(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp) +{ +FILE_FS_ATTRIBUTE_INFORMATION *infoAttr; +FILE_FS_DEVICE_INFORMATION *infoDevice; +FILE_FS_SIZE_INFORMATION * infoSize; +FILE_FS_VOLUME_INFORMATION *infoVolume; +NTSTATUS ret; + +TRY + +switch (IrpSp->Parameters.QueryVolume.FsInformationClass) + { + case FileFsAttributeInformation: + infoAttr = (FILE_FS_ATTRIBUTE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer; + memset(infoAttr, 0, sizeof(FILE_FS_ATTRIBUTE_INFORMATION)); + infoAttr->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH; //TODOTODO:? + infoAttr->MaximumComponentNameLength = 255; // should this be 255? + ///RtlCopyMemory(infoAttr->FileSystemName, L"AFS", 2); + ///infoAttr->FileSystemNameLength = 2; + //StringCbCopyLen(infoAttr->FileSystemName, IrpSp->Parameters.QueryVolume.Length-sizeof(*infoAttr)-2, L"AFS", &infoAttr->FileSystemNameLength); + //IrpSp->Parameters.QueryVolume.Length = 0; + //Irp->IoStatus.Information = sizeof(*infoAttr) + (infoAttr->FileSystemNameLength - sizeof(WCHAR)); + if (sizeof(*infoAttr) + wcslen(AFS_FS_NAME)*sizeof(wchar_t) > IrpSp->Parameters.QueryVolume.Length) + { + infoAttr->FileSystemNameLength = 0; + rpt0(("vol", "overflowing attr buffer %d", IrpSp->Parameters.QueryVolume.Length)); + SYNC_FAIL2(STATUS_BUFFER_OVERFLOW, sizeof(*infoAttr)); + } + else + { + infoAttr->FileSystemNameLength = wcslen(AFS_FS_NAME)*sizeof(wchar_t); + StringCbCopyW(infoAttr->FileSystemName, IrpSp->Parameters.QueryVolume.Length - sizeof(*infoAttr) + sizeof(WCHAR), AFS_FS_NAME); + SYNC_FAIL2(STATUS_SUCCESS, sizeof(*infoAttr) + (infoAttr->FileSystemNameLength - sizeof(WCHAR))); + } + break; + + case FileFsDeviceInformation: + infoDevice = (FILE_FS_DEVICE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer; + memset(infoDevice, 0, sizeof(FILE_FS_DEVICE_INFORMATION)); + infoDevice->DeviceType = FILE_DEVICE_DISK;//DeviceObject->DeviceType;// FILE_DEVICE_NETWORK_FILE_SYSTEM; + infoDevice->Characteristics = DeviceObject->Characteristics;//FILE_DEVICE_IS_MOUNTED /*| FILE_REMOTE_DEVICE*/; // remote device? + IrpSp->Parameters.QueryVolume.Length = sizeof(*infoDevice); + SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.QueryVolume.Length); + break; + + case FileFsSizeInformation: + infoSize = (FILE_FS_SIZE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer; + memset(infoSize, 0, sizeof(FILE_FS_SIZE_INFORMATION)); + infoSize->TotalAllocationUnits.QuadPart = 0x00000000F0000000; //FIX + infoSize->AvailableAllocationUnits.QuadPart = 0x00000000E0000000; + infoSize->SectorsPerAllocationUnit = 1; + infoSize->BytesPerSector = 1; + IrpSp->Parameters.QueryVolume.Length = sizeof(*infoSize); + SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.QueryVolume.Length); + break; + + case FileFsVolumeInformation: + infoVolume = (FILE_FS_VOLUME_INFORMATION*)Irp->AssociatedIrp.SystemBuffer; + memset(infoVolume, 0, sizeof(FILE_FS_VOLUME_INFORMATION)); + infoVolume->VolumeCreationTime.QuadPart = AfsTimeToWindowsTime(1080000000);//0x43218765); //TODO:fix + infoVolume->VolumeSerialNumber = 0x12345678; //TODO:fix + infoVolume->SupportsObjects = FALSE; + //StringCbCopyLen(infoVolume->VolumeLabel, IrpSp->Parameters.QueryVolume.Length-sizeof(*infoVolume)-2, L"AfsRed", &infoVolume->VolumeLabelLength); + //IrpSp->Parameters.QueryVolume.Length = 0; + if (sizeof(*infoVolume) + 12 > IrpSp->Parameters.QueryVolume.Length) + { + infoVolume->VolumeLabelLength = 0; + rpt0(("vol", "overflowing buffer %d", IrpSp->Parameters.QueryVolume.Length)); + SYNC_FAIL2(STATUS_BUFFER_OVERFLOW, sizeof(*infoVolume)); + } + else + { + infoVolume->VolumeLabelLength = 12; + RtlCopyMemory(infoVolume->VolumeLabel, L"AfsRed", 12); + SYNC_FAIL2(STATUS_SUCCESS, sizeof(*infoVolume) + (infoVolume->VolumeLabelLength - sizeof(WCHAR))); + } + break; + //case FileFsFullSizeInformation: + //TODO: + } + +EXCEPT(STATUS_UNSUCCESSFUL, 0); + +rpt0(("vol", "vol class %d unknown", IrpSp->Parameters.QueryVolume.FsInformationClass)); +SYNC_FAIL(STATUS_NOT_IMPLEMENTED); +} + +VOID AfsRdrUnload(DRIVER_OBJECT *DriverObject) +{ +UNICODE_STRING userModeName; + +FsRtlNotifyUninitializeSync(&rdrExt->notifyList); + +RtlInitUnicodeString(&userModeName, L"\\DosDevices\\afscom"); +IoDeleteSymbolicLink(&userModeName); + +/*RtlInitUnicodeString(&userModeName, L"\\DosDevices\\T:"); +IoDeleteSymbolicLink(&userModeName);*/ + +ExDeleteNPagedLookasideList(&rdrExt->fcbMemList); +ExDeleteNPagedLookasideList(&rdrExt->ccbMemList); + +rpc_shutdown(); + +IoDeleteDevice(ComDevice); +IoDeleteDevice(RdrDevice); + +#ifdef RPT_ENA +rptCliClose(REPORT); +#endif + +KdPrint(("RdrUnload exiting.\n")); +} + + +// handles all non-handled irp's synchronously +NTSTATUS AfsRdrNull(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp) +{ +NTSTATUS ret; + +/*TRY +rpt0(("kunhand", IrpMjFuncDesc[IrpSp->MajorFunction]));*/ + +SYNC_FAIL(STATUS_NOT_IMPLEMENTED); + +/*EXCEPT(STATUS_UNSUCCESSFUL, 0); + +ret = Irp->IoStatus.Status; +COMPLETE_NO_BOOST; +return ret;*/ +} + +NTSTATUS ComDispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp) +{ +IO_STACK_LOCATION *IrpSp, *IrpSpClient; +NTSTATUS ret; +struct ComExtension *ext; +void *ptr, *ptr2; +rpc_t find, *find_ptr; +LARGE_INTEGER timeout; +struct afsFcb *fcb; +rpc_t *rpc, **rpcp; +ULONG len; +ULONG code, read; +PACCESS_TOKEN acc_token; + +ext = (struct ComExtension *)DeviceObject->DeviceExtension; +IrpSp = IoGetCurrentIrpStackLocation(Irp); + +switch (IrpSp->MajorFunction) + { + case IRP_MJ_CREATE: + IrpSp->FileObject->FsContext = 0; + IrpSp->FileObject->FsContext2 = 0; + if (IrpSp->FileObject->FileName.Length) + { + /* ioctls come from fs, vos, bos, etc. using a pre-existing interface */ + /* downcalls come from afsd, using a new interface */ + /* upcall hooks come from afsd */ + if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\ioctl")) + IrpSp->FileObject->FsContext2 = COMM_IOCTL; + else if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\downcall")) + IrpSp->FileObject->FsContext2 = COMM_DOWNCALL; + else if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\upcallhook")) + IrpSp->FileObject->FsContext2 = COMM_UPCALLHOOK; + } + if (!IrpSp->FileObject->FsContext2) + SYNC_FAIL2(STATUS_INVALID_DEVICE_REQUEST, 0); + + acc_token = SeQuerySubjectContextToken(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); + ASSERT(acc_token); + /* SeQueryAuthenticationIdToken */ + IrpSp->FileObject->FsContext = acc_token; + STATUS(STATUS_SUCCESS, FILE_OPENED); + break; + + case IRP_MJ_CLEANUP: + /* acc_token does not have to be released */ + case IRP_MJ_CLOSE: + STATUS(STATUS_SUCCESS, 0); + break; + + case IRP_MJ_WRITE: + /* we only process MDL writes */ + //_asm int 3; + if (!Irp->MdlAddress || + !(ptr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))) /* should be LowPagePriority */ + SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES); + + if (!IrpSp->FileObject->FsContext || + !IrpSp->FileObject->FsContext2) + SYNC_FAIL(STATUS_INVALID_HANDLE); + + if (IrpSp->FileObject->FsContext2 == COMM_UPCALLHOOK) + { + rpc_recv(ptr, IrpSp->Parameters.Write.Length); + STATUS(STATUS_SUCCESS, IrpSp->Parameters.Write.Length); + } + else + STATUS(STATUS_INVALID_DEVICE_REQUEST, 0); + break; + case IRP_MJ_READ: + if (!Irp->MdlAddress || !(ptr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))) // should be LowPagePriority + _asm int 3; + + if (IrpSp->FileObject->FsContext2 == COMM_UPCALLHOOK) + { + /*timeout.QuadPart = -10000000L;*/ + timeout.QuadPart = -100000000L; + KeWaitForSingleObject(&comExt->outEvent, Executive, KernelMode, FALSE, &timeout); + + if (!rpc_send(ptr, IrpSp->Parameters.Read.Length, &read)) + { + KeClearEvent(&comExt->outEvent); + KeWaitForSingleObject(&comExt->outEvent, Executive, KernelMode/*UserMode*/, FALSE, &timeout); + if (!rpc_send(ptr, IrpSp->Parameters.Read.Length, &read)) + { + KeClearEvent(&comExt->outEvent); + SYNC_FAIL(STATUS_UNSUCCESSFUL); + } + } + SYNC_FAIL2(STATUS_SUCCESS, read); + } + else + STATUS(STATUS_INVALID_DEVICE_REQUEST, 0); + break; + case IRP_MJ_DEVICE_CONTROL: + return AfsRdrDeviceControl(DeviceObject, Irp, IrpSp, NULL); + default: + STATUS(STATUS_INVALID_DEVICE_REQUEST, 0); + break; + } + +ret = Irp->IoStatus.Status; +COMPLETE; +return ret; +} + + +// handles all irp's for primary (fs) device +NTSTATUS Dispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp) +{ +IO_STACK_LOCATION *IrpSp; +NTSTATUS ret; +afs_fcb_t *fcb; +afs_ccb_t *ccb; + +if (DeviceObject->DeviceType == FILE_DEVICE_DATALINK) + return ComDispatch(DeviceObject, Irp); + +IrpSp = IoGetCurrentIrpStackLocation(Irp); + +rpt4(("irp", "%s min %d on %d (%ws) %x %x", IrpMjFuncDesc[IrpSp->MajorFunction], IrpSp->MinorFunction, 0/*ExtractFid(IrpSp->FileObject->FsContext)*/, IrpSp->FileObject->FileName.Buffer, IrpSp->Flags, IrpSp->Parameters.Create.Options)); + +fcb = IrpSp->FileObject->FsContext;//FindFcb(IrpSp->FileObject); +if (IrpSp->MajorFunction != IRP_MJ_CREATE) + ASSERT(fcb); + +if (IrpSp->FileObject && IrpSp->FileObject->FsContext2) + { + ccb = IrpSp->FileObject->FsContext2; + rpc_set_context(ccb->token); + } + +switch (IrpSp->MajorFunction) + { + case IRP_MJ_CREATE: + ret = AfsRdrCreate(DeviceObject, Irp, IrpSp, NULL); break; + case IRP_MJ_DIRECTORY_CONTROL: + ret = AfsRdrDirCtrl(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_READ: + ret = AfsRdrRead(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_WRITE: + ret = AfsRdrWrite(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_CLOSE: + ret = AfsRdrClose(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_QUERY_INFORMATION: + ret = AfsRdrQueryInfo(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_DEVICE_CONTROL: + ret = AfsRdrDeviceControl(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_CLEANUP: + ret = AfsRdrCleanup(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_LOCK_CONTROL: + ret = AfsRdrLockCtrl(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_QUERY_VOLUME_INFORMATION: + ret = AfsRdrQueryVol(DeviceObject, Irp, IrpSp); break; + case IRP_MJ_SHUTDOWN: + ret = AfsRdrShutdown(DeviceObject, Irp, IrpSp); break; + case IRP_MJ_FILE_SYSTEM_CONTROL: + if (IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST && + (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1 || + IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2 || + IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK || + IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK)) + STATUS(STATUS_OPLOCK_NOT_GRANTED, 0); + else + STATUS(STATUS_INVALID_DEVICE_REQUEST/*STATUS_NOT_IMPLEMENTED*//*STATUS_INVALID_PARAMETER*/, 0); + ret = Irp->IoStatus.Status; + goto complete; + case IRP_MJ_SET_INFORMATION: + ret = AfsRdrSetInfo(DeviceObject, Irp, IrpSp, fcb); break; + case IRP_MJ_FLUSH_BUFFERS: + ret = AfsRdrFlushFile(DeviceObject, Irp, IrpSp, fcb); break; + default: + ret = AfsRdrNull(DeviceObject, Irp, IrpSp); break; + } +rpc_remove_context(); +return ret; + +complete: +rpc_remove_context(); +COMPLETE; +return ret; +} + +BOOLEAN +fastIoRead ( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject + ) +{ +BOOLEAN ret; +ULONG adj_len; +afs_fcb_t *fcb; + +fcb = FileObject->FsContext; +ASSERT(fcb); + +FsRtlEnterFileSystem(); +LOCK_PAGING_FCB; +adj_len = Length; +if (FileOffset->QuadPart > fcb->FileSize.QuadPart) + { + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + IoStatus->Status = STATUS_END_OF_FILE; + IoStatus->Information = 0; + return TRUE; + } +if (FileOffset->QuadPart + Length > fcb->FileSize.QuadPart) + adj_len = (ULONG)(fcb->FileSize.QuadPart - FileOffset->QuadPart); + +try + { + ret = CcCopyRead(FileObject, FileOffset, adj_len, Wait, Buffer, IoStatus); + /*if (IoStatus->Status == STATUS_SUCCESS && + (adj_len < Length)) + IoStatus->Status = STATUS_END_OF_FILE;*/ +// KdPrint(("read %x at %x fast done %x\n", Length, (ULONG)FileOffset->QuadPart, IoStatus->Information)); + FileObject->CurrentByteOffset.QuadPart += IoStatus->Information; + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + } +except (EXCEPTION_EXECUTE_HANDLER) + { + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + return FALSE; + } +return ret; +} + +BOOLEAN +fastIoWrite ( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject + ) +{ +BOOLEAN ret; +LARGE_INTEGER adj_end; +afs_fcb_t *fcb; + +fcb = FileObject->FsContext; +ASSERT(fcb); + +FsRtlEnterFileSystem(); +LOCK_PAGING_FCB; + +if (FileOffset->QuadPart + Length > fcb->FileSize.QuadPart) + { + adj_end.QuadPart = fcb->FileSize.QuadPart + Length; + fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = adj_end; + LOCK_FCB; + try + { + CcSetFileSizes(FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize); + } + except (EXCEPTION_EXECUTE_HANDLER) + { + UNLOCK_FCB; + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + return FALSE; + } + UNLOCK_FCB; + } + +try + { + ret = CcCopyWrite(FileObject, FileOffset, Length, Wait, Buffer); + IoStatus->Status = ret?STATUS_SUCCESS:STATUS_UNSUCCESSFUL; + IoStatus->Information = ret?Length:0; +// KdPrint(("write %x at %x fast done\n", Length, (ULONG)FileOffset->QuadPart)); + FileObject->CurrentByteOffset.QuadPart += IoStatus->Information; + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + } +except (EXCEPTION_EXECUTE_HANDLER) + { + UNLOCK_PAGING_FCB; + FsRtlExitFileSystem(); + return FALSE; + } +return ret; +} + +RTL_GENERIC_COMPARE_RESULTS FcbCompareRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID FirstStruct, PVOID SecondStruct) + { + afs_fcb_t *p1, *p2; + + p1 = (void*)*(afs_fcb_t**)FirstStruct; p2 = (void*)*(afs_fcb_t**)SecondStruct; + if (p1->fid < p2->fid) + return GenericLessThan; + if (p1->fid > p2->fid) + return GenericGreaterThan; + return GenericEqual; + } + +RTL_GENERIC_COMPARE_RESULTS ReqCompareRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID FirstStruct, PVOID SecondStruct) + { + rpc_t *p1, *p2; + + p1 = *(rpc_t**)FirstStruct; p2 = *(rpc_t**)SecondStruct; + if (p1->key < p2->key) + return GenericLessThan; + if (p1->key > p2->key) + return GenericGreaterThan; + return GenericEqual; + } + +PVOID AllocateRoutine(struct _RTL_GENERIC_TABLE *Table, CLONG ByteSize) + { + PVOID ret; + ret = ExAllocatePoolWithTag(NonPagedPool, ByteSize, AFS_RDR_TAG); + ASSERT(ret); + RtlZeroMemory(ret, ByteSize); + return ret; + } + +VOID FreeRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID Buffer) + { + ExFreePoolWithTag(Buffer, AFS_RDR_TAG); + } + +//KSPIN_LOCK rpc_lock; +//KIRQL irql; +FAST_MUTEX rpc_lock; + +void ifs_lock_rpcs() +{ +ExAcquireFastMutex(&rpc_lock); +//KeAcquireSpinLock(&rpc_lock, &irql); +} + +void ifs_unlock_rpcs() +{ +ExReleaseFastMutex(&rpc_lock); +//KeReleaseSpinLock(&rpc_lock, irql); +} + +NTSTATUS DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath) +{ +NTSTATUS err; +UNICODE_STRING rdrName, comName, userModeName, userModeCom; +int x; +IO_STATUS_BLOCK status; +FAST_IO_DISPATCH *fastIoDispatch; + +//_asm int 3; + +//try { +#ifdef RPT_ENA +REPORT = rptOpen(NULL, "afskern"); +#endif +rpt0(("init", "rpt initialized at %x", REPORT)); + +RtlInitUnicodeString(&rdrName, L"\\Device\\afsrdr"); +RtlInitUnicodeString(&comName, L"\\Device\\afscom"); + +rpt0(("init", "kern initializing")); +//KeInitializeSpinLock(&rpc_lock); +ExInitializeFastMutex(&rpc_lock); + +IoAllocateDriverObjectExtension(DriverObject, (void *)0x394389f7, sizeof(FAST_IO_DISPATCH), &fastIoDispatch); +RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH)); +fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); +fastIoDispatch->FastIoRead = fastIoRead; +fastIoDispatch->FastIoWrite = fastIoWrite; +DriverObject->FastIoDispatch = fastIoDispatch; + +for (x = 0; x < IRP_MJ_MAXIMUM_FUNCTION; x++) + DriverObject->MajorFunction[x] = Dispatch; +DriverObject->DriverUnload = AfsRdrUnload; + +err = IoCreateDevice(DriverObject, sizeof(struct AfsRdrExtension)*2, &rdrName, FILE_DEVICE_NETWORK_FILE_SYSTEM, /*FILE_REMOTE_DEVICE*/0, FALSE, &RdrDevice); +if (!NT_SUCCESS(STATUS_SUCCESS)) + return STATUS_UNSUCCESSFUL; +err = IoCreateDevice(DriverObject, sizeof(struct ComExtension)*2, &comName, FILE_DEVICE_DATALINK, 0, FALSE, &ComDevice); +if (!NT_SUCCESS(STATUS_SUCCESS)) + return STATUS_UNSUCCESSFUL; + +RdrDevice->Flags |= DO_DIRECT_IO; +RdrDevice->StackSize = 5; /* could this be zero? */ +rdrExt = ((struct AfsRdrExtension*)RdrDevice->DeviceExtension); +RtlZeroMemory(rdrExt, sizeof(struct AfsRdrExtension)); + +/* could raise exception */ +FsRtlNotifyInitializeSync(&rdrExt->notifyList); +InitializeListHead(&rdrExt->listHead); + +rdrExt->callbacks.AcquireForLazyWrite = lazyWriteLock; +rdrExt->callbacks.ReleaseFromLazyWrite = lazyWriteUnlock; +rdrExt->callbacks.AcquireForReadAhead = readAheadLock; +rdrExt->callbacks.ReleaseFromReadAhead = readAheadUnlock; +ExInitializeNPagedLookasideList(&rdrExt->fcbMemList, NULL, NULL, 0, sizeof(afs_fcb_t), AFS_RDR_TAG, 0); +ExInitializeNPagedLookasideList(&rdrExt->ccbMemList, NULL, NULL, 0, sizeof(afs_ccb_t), AFS_RDR_TAG, 0); +ExInitializeFastMutex(&rdrExt->fcbLock); +RtlInitializeGenericTable(&rdrExt->fcbTable, FcbCompareRoutine, AllocateRoutine, FreeRoutine, NULL); + + +ComDevice->Flags |= DO_DIRECT_IO; +ComDevice->StackSize = 5; // ?? +comExt = ((struct ComExtension*)ComDevice->DeviceExtension); +RtlZeroMemory(comExt, sizeof(struct ComExtension)); + +//ExInitializeNPagedLookasideList(&comExt->outMemList, NULL, NULL, 0, sizeof(struct KOutEntry)+100, AFS_RDR_TAG, 0); +InitializeListHead(&comExt->outReqList); +KeInitializeSpinLock(&comExt->outLock); +ExInitializeFastMutex(&comExt->inLock); +RtlInitializeGenericTable(&comExt->inTable, ReqCompareRoutine, AllocateRoutine, FreeRoutine, NULL); +KeInitializeEvent(&comExt->outEvent, NotificationEvent, TRUE); +KeInitializeEvent(&comExt->cancelEvent, NotificationEvent, TRUE); + +comExt->rdr = rdrExt; +rdrExt->com = comExt; + +RtlInitUnicodeString(&userModeCom, L"\\DosDevices\\afscom"); +err = IoCreateSymbolicLink(&userModeCom, &comName); + +/*RtlInitUnicodeString(&rdrName, L"\\Device\\afsrdr\\1\\CITI.UMICH.EDU"); +RtlInitUnicodeString(&userModeName, L"\\DosDevices\\W:"); +err = IoCreateSymbolicLink(&userModeName, &rdrName);*/ + +/*} except(EXCEPTION_EXECUTE_HANDLER) + { + _asm int 3; + //logerror(); + return -1; + }*/ + +KdPrint(("DriverEntry exiting.\n")); +return STATUS_SUCCESS; +} diff --git a/src/WINNT/afsrdr/afsrdr.h b/src/WINNT/afsrdr/afsrdr.h new file mode 100644 index 0000000..79f9b14 --- /dev/null +++ b/src/WINNT/afsrdr/afsrdr.h @@ -0,0 +1,68 @@ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ + +/* versioning history + * + * 03-jun 2005 (eric williams) entered into versioning + */ + +#include + +#define rpt0(args) +#define rpt1(args) +#define rpt2(args) +#define rpt3(args) +#define rpt4(args) +#define rpt5(args) + +struct AfsRdrExtension +{ +struct ComExtension *com; +KMUTEX protectMutex; +PNOTIFY_SYNC notifyList; +LIST_ENTRY listHead; +NPAGED_LOOKASIDE_LIST fcbMemList; +FAST_MUTEX fcbLock; +NPAGED_LOOKASIDE_LIST ccbMemList; +RTL_GENERIC_TABLE fcbTable; +CACHE_MANAGER_CALLBACKS callbacks; +}; + +struct ComExtension +{ +struct AfsRdrExtension *rdr; +LIST_ENTRY outReqList; +KSPIN_LOCK outLock; +RTL_GENERIC_TABLE inTable; +FAST_MUTEX inLock; +KEVENT outEvent, cancelEvent; +}; + +extern struct AfsRdrExtension *rdrExt; +extern struct ComExtension *comExt; + + +void ifs_lock_rpcs(); +void ifs_unlock_rpcs(); diff --git a/src/WINNT/afsrdr/ifs_rpc.c b/src/WINNT/afsrdr/ifs_rpc.c new file mode 100644 index 0000000..b7d924b --- /dev/null +++ b/src/WINNT/afsrdr/ifs_rpc.c @@ -0,0 +1,1407 @@ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ + +/* versioning history + * + * 03-jun 2005 (eric williams) entered into versioning + */ + +#ifdef RPC_KERN +#include +#include "ifs_rpc.h" +#include "afsrdr.h" +#else +#include "ifs_rpc.h" +#endif +#include "kif.h" + +/* general internal functions */ +rpc_t *rpc_create(int size_hint); +void rpc_destroy(rpc_t *rpc); +int rpc_marshal_long(rpc_t *rpc, ULONG data); +int rpc_marshal_longlong(rpc_t *rpc, LARGE_INTEGER data); +int rpc_marshal_wstr(rpc_t *rpc, WCHAR *str); +int rpc_unmarshal_long(rpc_t *rpc, ULONG *data); +int rpc_unmarshal_longlong(rpc_t *rpc, LARGE_INTEGER *data); +int rpc_unmarshal_wstr(rpc_t *rpc, WCHAR *str); + +/* kernel-queue specific internal functions */ +#ifdef RPC_KERN +int rpc_queue(rpc_t *rpc); +rpc_queue_bulk(rpc_t *rpc, char *out_bulk, ULONG out_len, char *in_bulk, ULONG in_len); +rpc_cancel(rpc_t *rpc); +rpc_send_reg(rpc_t *rpc, char *out_buf); +rpc_queue_bulk_mdl(rpc_t *rpc, MDL *mdl); +rpc_t *rpc_find(int id); +rpc_t *rpc_upgrade(rpc_t *rpc, int old_status, int new_status); +rpc_wait(rpc_t *rpc, BOOLEAN long_op); +rpc_send_mdl(rpc_t *rpc, char *out_buf); +#endif + +/* internal timing functions (not used) */ +#ifdef RPC_KERN +#define TIMING_START() LARGE_INTEGER start, stop; \ + start.QuadPart = KeQueryInterruptTime(); +#define TIMING_END(name) stop.QuadPart = KeQueryInterruptTime(); \ + rpt5((name, "%s %d", name, (ULONG)(stop.QuadPart - start.QuadPart))); +#endif + + +/* rpc security kernel functions */ +#ifdef RPC_KERN +struct rpc_cred_map_entry + { + void *token; + PETHREAD thread; + }; + +struct rpc_cred_map_entry cred_map[20]; +rpc_t *rpc_list_head = NULL; + +rpc_set_context(void *context) + { + int x, empty, ret; + PETHREAD thd; + + thd = PsGetCurrentThread(); + empty = -1; + ret = 0; + + // LOCKLOCK + for (x = 0; x < 20; x++) + { + if (cred_map[x].thread == NULL) + empty = x; + if (cred_map[x].thread == thd) + { + cred_map[x].token = context; + goto done; + } + } + if (empty != -1) + { + cred_map[empty].thread = thd; + cred_map[empty].token = context; + } + else + ret = -1; + + done: + // UNLOCKUNLOCK + return ret; + } + +void *rpc_get_context() + { + int x; + PETHREAD thd; + + thd = PsGetCurrentThread(); + + // no lock + for (x = 0; x < 20; x++) + if (cred_map[x].thread == thd) + return cred_map[x].token; + // no unlock + return NULL; + } + +rpc_remove_context() + { + int x; + PETHREAD thd; + + thd = PsGetCurrentThread(); + // no lock + for (x = 0; x < 20; x++) + if (cred_map[x].thread == thd) + { + cred_map[x].token = NULL; + cred_map[x].thread = NULL; + return 0; + } + + // no unlock + return -1; + } +#endif + + +/* rpc internal functions for kernel */ +#ifdef RPC_KERN +rpc_t *rpc_create(int size_hint) + { + ULONG size; + rpc_t *rpc; + SECURITY_SUBJECT_CONTEXT subj_context; + PACCESS_TOKEN acc_token; + LUID auth_id; + LARGE_INTEGER user_id; + NTSTATUS status; + HANDLE token; + + token = rpc_get_context(); + ASSERT(token); + status = SeQueryAuthenticationIdToken(token, &auth_id); + + user_id.LowPart = auth_id.LowPart; + user_id.HighPart = auth_id.HighPart; + + ifs_lock_rpcs(); + + if (!(rpc = rpc_upgrade(NULL, 0, 1))) + { + size = sizeof(rpc_t) + 4096*10; + rpc = ExAllocatePoolWithTag(NonPagedPool, size, 0x1234); + if (!rpc) + _asm int 3; + memset(rpc, 0, size); + rpc->next = rpc_list_head; + rpc_list_head = rpc; + rpc_upgrade(rpc, 0, 1); + } + + rpc->out_buf = rpc->out_pos = (char*)(rpc+1); + rpc->in_buf = rpc->in_pos = ((char*)(rpc+1))+2048*10; + + rpc->key = rand() + 10; + rpc_marshal_long(rpc, rpc->key); + rpc->bulk_out_len = (ULONG*)rpc->out_pos; + rpc_marshal_long(rpc, 0); + + /*SeCaptureSubjectContext(&subj_context); + acc_token = SeQuerySubjectContextToken(&subj_context); + status = SeQueryAuthenticationIdToken(acc_token, &auth_id);*/ + /**token = rpc_get_context(); + ASSERT(token); + status = SeQueryAuthenticationIdToken(token, &auth_id); + + user_id.LowPart = auth_id.LowPart; + user_id.HighPart = auth_id.HighPart; + SeReleaseSubjectContext(&subj_context);*/ + + rpc_marshal_longlong(rpc, user_id); + + ifs_unlock_rpcs(); + + return rpc; + } + +void rpc_destroy(rpc_t *rpc) + { + rpc_t *curr; + int count; + + /*ExFreePoolWithTag(rpc, 0x1234);*/ + ifs_lock_rpcs(); + + if (rpc_upgrade(rpc, -1, 0)) + ; + + ifs_unlock_rpcs(); + } +#endif + + +/* rpc internal functions for usermode */ +#ifndef RPC_KERN +rpc_t *rpc_create(int size_hint) + { + ULONG size; + rpc_t *rpc; + ULONG status; + + size = sizeof(rpc_t) + 4096; + rpc = malloc(size); + if (!rpc) + _asm int 3; + memset(rpc, 0, size); + + rpc->out_buf = rpc->out_pos = (char*)(rpc+1); + rpc->in_buf = rpc->in_pos = ((char*)(rpc+1))+2048; + + rpc->key = rand() + 10; + rpc_marshal_long(rpc, rpc->key); + + return rpc; + } + +void rpc_destroy(rpc_t *rpc) + { + if (!rpc) + return; + //_asm int 3; + + free(rpc); + } + +rpc_transact(rpc_t *rpc) + { + HANDLE hf; + int ret; + ULONG header_len; + DWORD err, read = 0; + + if (!rpc) + return IFSL_GENERIC_FAILURE; + + header_len = rpc->out_pos - rpc->out_buf; + + read = 2048; + return ifs_TransactRpc(rpc->out_buf, header_len, rpc->in_buf, &read); + } +#endif + + +/* upcall stubs */ +#ifdef RPC_KERN +uc_namei(WCHAR *name, ULONG *fid) + { + rpc_t *rpc; + ULONG status; + MDL *mdl; + TIMING_START(); + /* put namei cache here */ + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_NAMEI); + rpc_marshal_long(rpc, wcslen(name)); + + rpc_queue_bulk(rpc, (void*)name, (wcslen(name)+1)*sizeof(wchar_t), NULL, 0); + + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel namei")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, fid); + + rpc_destroy(rpc); + TIMING_END("namei"); + return status; + } + +uc_check_access(ULONG fid, ULONG access, ULONG *granted) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_CHECK_ACCESS); + rpc_marshal_long(rpc, fid); + rpc_marshal_long(rpc, access); + + rpc_queue(rpc); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel access")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, granted); + + rpc_destroy(rpc); + TIMING_END("access"); + return status; + } + +uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_CREATE); + rpc_marshal_long(rpc, attribs); + rpc_marshal_longlong(rpc, alloc); + rpc_marshal_long(rpc, access); + + rpc_queue_bulk(rpc, (void*)name, (wcslen(name)+1)*sizeof(wchar_t), NULL, 0); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel create")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, granted); + rpc_unmarshal_long(rpc, fid); + + rpc_destroy(rpc); + TIMING_END("create"); + return status; + } + +uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation, LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_STAT); + rpc_marshal_long(rpc, fid); + + rpc_queue(rpc); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel stat")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, attribs); + rpc_unmarshal_longlong(rpc, size); + rpc_unmarshal_longlong(rpc, creation); + rpc_unmarshal_longlong(rpc, access); + rpc_unmarshal_longlong(rpc, change); + rpc_unmarshal_longlong(rpc, written); + + rpc_destroy(rpc); + TIMING_END("stat"); + return status; + } + +uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access, LARGE_INTEGER change, LARGE_INTEGER written) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_SETINFO); + rpc_marshal_long(rpc, fid); + rpc_marshal_long(rpc, attribs); + rpc_marshal_longlong(rpc, creation); + rpc_marshal_longlong(rpc, access); + rpc_marshal_longlong(rpc, change); + rpc_marshal_longlong(rpc, written); + + + rpc_queue(rpc); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel setinfo")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + + rpc_destroy(rpc); + TIMING_END("setinfo"); + return status; + } + +uc_trunc(ULONG fid, LARGE_INTEGER size) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_TRUNC); + rpc_marshal_long(rpc, fid); + rpc_marshal_longlong(rpc, size); + + rpc_queue(rpc); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel trunc")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + + rpc_destroy(rpc); + TIMING_END("trunc"); + return status; + } + +uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_READ); + rpc_marshal_long(rpc, fid); + rpc_marshal_longlong(rpc, offset); + rpc_marshal_long(rpc, length); + + rpc_queue_bulk(rpc, NULL, 0, data, length); + if (!rpc_wait(rpc, RPC_TIMEOUT_LONG)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel read")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, read); + + rpc_destroy(rpc); + TIMING_END("read"); + return status; + } + +/*uc_read_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, MDL *data) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_READ_BULK); + rpc_marshal_long(rpc, fid); + rpc_marshal_longlong(rpc, offset); + rpc_marshal_long(rpc, length); + + rpc_queue_bulk_mdl(rpc, data); + if (!rpc_wait(rpc, 1)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel read mdl")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, read); + + rpc_destroy(rpc); + TIMING_END("read_mdl"); + return status; + }*/ + +uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_WRITE); + rpc_marshal_long(rpc, fid); + rpc_marshal_longlong(rpc, offset); + rpc_marshal_long(rpc, length); + + rpc_queue_bulk(rpc, data, length, NULL, 0); + if (!rpc_wait(rpc, RPC_TIMEOUT_LONG)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel write")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, written); + + rpc_destroy(rpc); + TIMING_END("write"); + return status; + } + +/*uc_write_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, MDL *data) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_WRITE_BULK); + rpc_marshal_long(rpc, fid); + rpc_marshal_longlong(rpc, offset); + rpc_marshal_long(rpc, length); + + rpc_queue_bulk_mdl(rpc, data); + if (!rpc_wait(rpc, 1)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel write mdl")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, written); + + rpc_destroy(rpc); + TIMING_END("write_mdl"); + return status; + }*/ + +uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_READDIR); + rpc_marshal_long(rpc, fid); + rpc_marshal_longlong(rpc, cookie_in); + rpc_marshal_wstr(rpc, filter); + rpc_marshal_long(rpc, *len); + + rpc_queue_bulk(rpc, NULL, 0, data, *len); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel readdir")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, count); + rpc_unmarshal_long(rpc, len); + + rpc_destroy(rpc); + TIMING_END("readdir"); + return status; + } + +uc_close(ULONG fid) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_CLOSE); + rpc_marshal_long(rpc, fid); + + rpc_queue(rpc); + if (!rpc_wait(rpc, RPC_TIMEOUT_LONG)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel close")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + + rpc_destroy(rpc); + TIMING_END("close"); + return status; + } + +uc_unlink(WCHAR *name) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_UNLINK); + rpc_marshal_wstr(rpc, name); + + rpc_queue(rpc); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel unlink")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + + rpc_destroy(rpc); + TIMING_END("unlink"); + return status; + } + +uc_ioctl_write(ULONG length, char *data, ULONG *key) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_IOCTL_WRITE); + rpc_marshal_long(rpc, length); + + rpc_queue_bulk(rpc, data, length, NULL, 0); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel ioctl write")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, key); + + rpc_destroy(rpc); + TIMING_END("ioctl_write"); + return status; + } + +uc_ioctl_read(ULONG key, ULONG *length, char *data) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_IOCTL_READ); + rpc_marshal_long(rpc, key); + + rpc_queue_bulk(rpc, NULL, 0, data, *length); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel ioctl read")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, length); + + rpc_destroy(rpc); + TIMING_END("ioctl_read"); + return status; + } + +uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid) + { + rpc_t *rpc; + ULONG status; + TIMING_START(); + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_RENAME); + rpc_marshal_long(rpc, fid); + rpc_marshal_wstr(rpc, curr); + rpc_marshal_wstr(rpc, new_dir); + rpc_marshal_wstr(rpc, new_name); + + rpc_queue(rpc); + if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT)) + { + rpc_cancel(rpc); + rpt0(("cancel", "cancel rename")); + return IFSL_RPC_TIMEOUT; + } + + rpc_unmarshal_long(rpc, &status); + rpc_unmarshal_long(rpc, new_fid); + + rpc_destroy(rpc); + TIMING_END("rename"); + return status; + } +#endif + + +/* downcall stubs */ +#ifndef RPC_KERN +dc_break_callback(ULONG fid) + { + rpc_t *rpc; + ULONG status; + + rpc = rpc_create(0); + + rpc_marshal_long(rpc, RPC_BREAK_CALLBACK); + rpc_marshal_long(rpc, fid); + if (!rpc_transact(rpc)) + { + rpc_destroy(rpc); + return IFSL_GENERIC_FAILURE; + } + rpc_unmarshal_long(rpc, &status); + rpc_destroy(rpc); + return status; + } +#endif + + +/* rpc packing function */ +rpc_marshal_long(rpc_t *rpc, ULONG data) + { + memcpy(rpc->out_pos, &data, sizeof(ULONG)); + rpc->out_pos += sizeof(ULONG); + return 0; + } + +rpc_marshal_longlong(rpc_t *rpc, LARGE_INTEGER data) + { + memcpy(rpc->out_pos, &data, sizeof(LARGE_INTEGER)); + rpc->out_pos += sizeof(LARGE_INTEGER); + return 0; + } + +rpc_marshal_wstr(rpc_t *rpc, WCHAR *str) + { + long len; + len = wcslen(str); + rpc_marshal_long(rpc, len); + memcpy(rpc->out_pos, str, len*sizeof(WCHAR)); + rpc->out_pos += len*sizeof(WCHAR); + return 0; + } + + +rpc_unmarshal_long(rpc_t *rpc, ULONG *data) + { + memcpy(data, rpc->in_pos, sizeof(ULONG)); + rpc->in_pos += sizeof(ULONG); + return 0; + } + +rpc_unmarshal_longlong(rpc_t *rpc, LARGE_INTEGER *data) + { + memcpy(data, rpc->in_pos, sizeof(LARGE_INTEGER)); + rpc->in_pos += sizeof(LARGE_INTEGER); + return 0; + } + +rpc_unmarshal_wstr(rpc_t *rpc, WCHAR *str)//, int len) + { + long len; + rpc_unmarshal_long(rpc, &len); + memcpy(str, rpc->in_pos, len*sizeof(WCHAR)); + rpc->in_pos += len*sizeof(WCHAR); + str[len] = L'\0'; + return 0; + } + + +/* kernel-queue management functions */ +#ifdef RPC_KERN +rpc_t *rpc_find(int id) + { + rpc_t *curr; + + curr = rpc_list_head; + while (curr) + { + if (curr->key == id && curr->status != 0) + return curr; + curr = curr->next; + } + return NULL; + } + +rpc_t *rpc_upgrade(rpc_t *rpc, int old_status, int new_status) + { + rpc_t *curr; + + if (rpc) + { + ASSERT(!old_status || rpc_find(rpc->key)); + if (old_status != -1 && rpc->status != old_status) + return NULL; + curr = rpc; + } + else + { + curr = rpc_list_head; + while (curr) + { + if (old_status == -1 || curr->status == old_status) + break; + curr = curr->next; + } + } + + if (!curr) + return NULL; + + ASSERT(old_status == -1 || curr->status == old_status); + curr->status = new_status; + + return curr; + } + +rpc_queue(rpc_t *rpc) + { + int ret; + + ifs_lock_rpcs(); + + KeInitializeEvent(&rpc->ev, NotificationEvent, FALSE); + ret = (rpc_upgrade(rpc, 1, 2) != NULL); + KeSetEvent(&comExt->outEvent, 0, FALSE); + + ifs_unlock_rpcs(); + + return ret; + } + +rpc_cancel(rpc_t *rpc) + { + rpc_destroy(rpc); + //ExAcquireFastMutex(&ext->inLock); + /*ifs_lock_rpcs(); + if (rpc_upgrade(rpc, -1, 0)) + rpc_destroy(rpc); + ifs_unlock_rpcs();*/ + //RtlDeleteElementGenericTable(&ext->inTable, (void*)&rpc); + //ExReleaseFastMutex(&ext->inLock); + } + +rpc_shutdown() + { + rpc_t *curr, *next; + + ifs_lock_rpcs(); + + curr = rpc_list_head; + while (curr) + { + next = curr->next; + ExFreePoolWithTag(curr, 0x1234); + curr = next; + } + rpc_list_head = NULL; + + ifs_unlock_rpcs(); + } + +rpc_wait(rpc_t *rpc, BOOLEAN long_op) + { + NTSTATUS ret; + LARGE_INTEGER timeout; + //p->FsContext = (ULONG)&ev; + + if (long_op) + timeout.QuadPart = -600000000L; /* 60 seconds 60L*1000000L */ + else + timeout.QuadPart = -200000000L; /* 20 seconds 20L*1000000L */ + + do + ret = KeWaitForSingleObject(&rpc->ev, Executive, KernelMode, FALSE, &timeout); + while (ret != STATUS_SUCCESS);// && ret != STATUS_TIMEOUT); + + /*if (KeReadStateEvent(&rpc->ev) == 0) + _asm int 3;*/ + if (rpc->status == 5) + return 0; + + if (ret == STATUS_SUCCESS) + return 1; + _asm int 3; + return 0; + } + +rpc_queue_bulk(rpc_t *rpc, char *out_bulk, ULONG out_len, char *in_bulk, ULONG in_len) + { + rpc->bulk_out = out_bulk; + *rpc->bulk_out_len = out_len; + rpc->bulk_in = in_bulk; + rpc->bulk_in_max = in_len; + return rpc_queue(rpc); + } + +/*rpc_queue_bulk_mdl(rpc_t *rpc, MDL *bulk) + { + rpc->bulk_mdl = bulk; + *rpc->bulk_out_len = 0xFFFFFFFC; + rpc->bulk_in = 0; + return rpc_queue(rpc); + }*/ + +rpc_get_len(rpc_t *rpc) + { + if (*rpc->bulk_out_len != 0xFFFFFFFC) + return rpc->out_pos - rpc->out_buf + *rpc->bulk_out_len + sizeof(ULONG); + else + return rpc->out_pos - rpc->out_buf + sizeof(ULONG); + } + +rpc_send(char *out_buf, int out_len, int *out_written) + { + rpc_t *rpc; + int ret, mdl; + ULONG header_len; + + restart: + + ifs_lock_rpcs(); + rpc = rpc_upgrade(NULL, 2, 3); + + if (!rpc) + { + ifs_unlock_rpcs(); + return 0; + } + + if (rpc_get_len(rpc) > out_len) + { + //_asm int 3; + ifs_unlock_rpcs(); + rpt0(("cancel", "cancel on send")); + rpc_upgrade(rpc, -1, 5); + KeSetEvent(&rpc->ev, IO_NO_INCREMENT, FALSE); /* move to rpc_ fn */ + //rpc_cancel(rpc); + goto restart;//return 0; + } + + + + /*mdl = (*rpc->bulk_out_len == 0xFFFFFFFC); + + if (mdl) + *rpc->bulk_out_len = 0;*/ + + header_len = rpc->out_pos - rpc->out_buf; + RtlCopyMemory(out_buf, rpc->out_buf, header_len); + + //if (!mdl) + { + if (*rpc->bulk_out_len && rpc->bulk_out) + RtlCopyMemory(out_buf + header_len, rpc->bulk_out, *rpc->bulk_out_len); + *out_written = header_len + *rpc->bulk_out_len; + } + #if 0 + else + { + if (rpc->bulk_mdl) + { + void *ptr; + //_asm int 3; + #if 0 + try + { + _asm int 3; + MmProbeAndLockPages(rpc->bulk_mdl, UserMode, IoModifyAccess); + } + except (EXCEPTION_EXECUTE_HANDLER) + { + _asm int 3; + } + #endif + try + { + rpc->bulk_out = MmMapLockedPagesSpecifyCache(rpc->bulk_mdl, UserMode, MmNonCached, NULL, FALSE, NormalPagePriority); + } + except (EXCEPTION_EXECUTE_HANDLER) + { + PMDL remap; + void *ptr; + _asm int 3; + ptr = ExAllocatePool(PagedPool, MmGetMdlByteCount(rpc->bulk_mdl)); + remap = IoAllocateMdl(ptr, MmGetMdlByteCount(rpc->bulk_mdl), FALSE, TRUE, NULL); + MmProbeAndLockPages(remap, UserMode, IoModifyAccess); + rpc->bulk_out = MmMapLockedPagesSpecifyCache(remap, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority); + _asm int 3; + rpc->bulk_out = MmGetSystemAddressForMdlSafe(rpc->bulk_mdl, NormalPagePriority); + MmUnmapLockedPages(rpc->bulk_out, rpc->bulk_mdl); + rpc->bulk_out = MmMapLockedPagesSpecifyCache(rpc->bulk_mdl, UserMode, MmNonCached, NULL, FALSE, NormalPagePriority); + + remap = IoAllocateMdl(rpc->bulk_out, MmGetMdlByteCount(rpc->bulk_mdl), FALSE, TRUE, NULL); + remap->Process = (void*)PsGetCurrentProcess(); + MmBuildMdlForNonPagedPool(remap); + //MmProbeAndLockPages(remap, UserMode, IoModifyAccess); + rpc->bulk_out = MmMapLockedPagesSpecifyCache(remap, UserMode, MmNonCached, (void*)0x01111111, FALSE, NormalPagePriority); + /*ifs_unlock_rpcs(); + rpc_upgrade(rpc, -1, 5); + KeSetEvent(&rpc->ev, IO_NO_INCREMENT, FALSE); + //rpc_cancel(rpc); + goto restart;//return 0;*/ + } + ptr = rpc->bulk_out; + RtlCopyMemory(out_buf + header_len, &ptr, sizeof(ptr)); + } + + *rpc->bulk_out_len = 0xFFFFFFFC; + *out_written = header_len + sizeof(void*); + } + #endif + + ifs_unlock_rpcs(); + return (*out_written != 0); + } + +#if 0 +rpc_send_reg(rpc_t *rpc, char *out_buf) + { + ULONG header_len; + + header_len = rpc->out_pos - rpc->out_buf; + RtlCopyMemory(out_buf, rpc->out_buf, header_len); + + if (rpc->bulk_out_len && rpc->bulk_out) + RtlCopyMemory(out_buf + header_len, rpc->bulk_out, *rpc->bulk_out_len); + return header_len + *rpc->bulk_out_len; + } +#endif +#endif + + +/* rpc library api */ +#ifdef RPC_KERN +rpc_recv(char *in_buf, ULONG len) + { + ULONG key, header_size; + char *alloc; + rpc_t *rpc; + + ifs_lock_rpcs(); + + rpc = rpc_find(*(ULONG*)in_buf); + if (!rpc) + { + //_asm int 3; + ifs_unlock_rpcs(); + return -1; + } + + //_asm int 3; + /*if (*rpc->bulk_out_len == 0xFFFFFFFC) + { + ASSERT(rpc->bulk_out); + MmUnmapLockedPages(rpc->bulk_out, rpc->bulk_mdl); + // MmUnlockPages(rpc->bulk_mdl); + }*/ + + alloc = rpc->in_buf; + rpc->in_buf = rpc->in_pos = in_buf; + rpc_unmarshal_long(rpc, &key); + ASSERT(key == rpc->key); + rpc_unmarshal_long(rpc, &rpc->bulk_in_len); + + rpc->in_buf = rpc->in_pos = alloc; + header_size = len - rpc->bulk_in_len; + ASSERT(header_size < 4096); + RtlCopyMemory(rpc->in_buf, in_buf + 2*sizeof(ULONG), header_size - 2*sizeof(ULONG)); + //if (*rpc->bulk_out_len != 0xFFFFFFFC) + { + if (rpc->bulk_in_len && rpc->bulk_in) + { + ASSERT(rpc->bulk_in_len <= rpc->bulk_in_max); + //_asm int 3; + RtlCopyMemory(rpc->bulk_in, in_buf + header_size, rpc->bulk_in_len);//len - header_size - 2*sizeof(ULONG)); + } + } + + KeSetEvent(&rpc->ev, IO_NO_INCREMENT, FALSE); + ifs_unlock_rpcs(); + return 0; + } + +rpc_call(ULONG in_len, char *in_buf, ULONG out_max, char *out_buf, ULONG *out_len) + { + long rpc_code; + ULONG status; + WCHAR name[1024]; + ULONG key, fid; + LARGE_INTEGER user_id; + rpc_t rpc; + + rpc.in_buf = rpc.in_pos = in_buf; + rpc.out_buf = rpc.out_pos = out_buf; + + rpc_unmarshal_long(&rpc, &key); + rpc_unmarshal_long(&rpc, &rpc_code); + + switch (rpc_code) + { + case RPC_BREAK_CALLBACK: + rpc_unmarshal_long(&rpc, &fid); + status = dc_break_callback(fid); + rpc_marshal_long(&rpc, status); + break; + } + *out_len = rpc.out_pos - rpc.out_buf; + return 0; + //ifs_ImpersonateClient(user_id); + } +#endif + +#ifndef RPC_KERN +rpc_parse(rpc_t *rpc) + { + long rpc_code; + ULONG status; + WCHAR name[1024]; + ULONG key; + LARGE_INTEGER user_id; + + rpc_unmarshal_long(rpc, &key); + rpc_unmarshal_long(rpc, &rpc->bulk_in_len); + rpc_unmarshal_longlong(rpc, &user_id); + rpc_unmarshal_long(rpc, &rpc_code); + + ifs_ImpersonateClient(user_id); + + rpc_marshal_long(rpc, key); + rpc->bulk_out_len = (ULONG*)rpc->out_pos; + rpc_marshal_long(rpc, 0); + + switch (rpc_code) + { + case RPC_NAMEI: + { + ULONG fid, length; + char *data; + //rpc_unmarshal_wstr(rpc, name); + rpc_unmarshal_long(rpc, &length); + //data = *((char**)rpc->in_pos); + data = rpc->in_pos; + status = uc_namei((WCHAR*)data, &fid); + //status = uc_namei(name, &fid); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, fid); + } + break; + case RPC_CHECK_ACCESS: + { + ULONG fid, access, granted; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_long(rpc, &access); + status = uc_check_access(fid, access, &granted); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, granted); + } + break; + case RPC_CREATE: + { + LARGE_INTEGER alloc; + ULONG access, granted, fid, attribs; + char *data; + + rpc_unmarshal_long(rpc, &attribs); + rpc_unmarshal_longlong(rpc, &alloc); + rpc_unmarshal_long(rpc, &access); + //rpc_unmarshal_wstr(rpc, name); + data = rpc->in_pos; + status = uc_create((WCHAR*)data, attribs, alloc, access, &granted, &fid); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, granted); + rpc_marshal_long(rpc, fid); + } + break; + case RPC_STAT: + { + ULONG fid, attribs; + LARGE_INTEGER size, creation, access, change, written; + rpc_unmarshal_long(rpc, &fid); + status = uc_stat(fid, &attribs, &size, &creation, &access, &change, &written); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, attribs); + rpc_marshal_longlong(rpc, size); + rpc_marshal_longlong(rpc, creation); + rpc_marshal_longlong(rpc, access); + rpc_marshal_longlong(rpc, change); + rpc_marshal_longlong(rpc, written); + } + break; + case RPC_READ: + { + ULONG fid, length, read; + LARGE_INTEGER offset; + char *data, *save; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_longlong(rpc, &offset); + rpc_unmarshal_long(rpc, &length); + save = rpc->out_pos; + rpc_marshal_long(rpc, 0); + rpc_marshal_long(rpc, 0); + data = rpc->out_pos; + rpc->out_pos = save; + status = uc_read(fid, offset, length, &read, data); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, read); + rpc->out_pos += read; + *rpc->bulk_out_len = read; + } + break; + /* case RPC_READ_BULK: + { + ULONG fid, length, read; + LARGE_INTEGER offset; + char *data, *save; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_longlong(rpc, &offset); + rpc_unmarshal_long(rpc, &length); + data = *((char**)rpc->in_pos); + status = uc_read(fid, offset, length, &read, data); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, read); + *rpc->bulk_out_len = 0; + } + break;*/ + case RPC_WRITE: + { + ULONG fid, length, written; + LARGE_INTEGER offset; + char *data; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_longlong(rpc, &offset); + rpc_unmarshal_long(rpc, &length); + data = rpc->in_pos; + status = uc_write(fid, offset, length, &written, data); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, written); + } + break; + /* case RPC_WRITE_BULK: + { + ULONG fid, length, written; + LARGE_INTEGER offset; + char *data; + //_asm int 3; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_longlong(rpc, &offset); + rpc_unmarshal_long(rpc, &length); + data = *((char**)rpc->in_pos); + status = uc_write(fid, offset, length, &written, data); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, written); + } + break;*/ + case RPC_TRUNC: + { + ULONG fid; + LARGE_INTEGER size; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_longlong(rpc, &size); + status = uc_trunc(fid, size); + rpc_marshal_long(rpc, status); + } + break; + case RPC_SETINFO: + { + ULONG fid, attribs; + LARGE_INTEGER creation, access, change, written; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_long(rpc, &attribs); + rpc_unmarshal_longlong(rpc, &creation); + rpc_unmarshal_longlong(rpc, &access); + rpc_unmarshal_longlong(rpc, &change); + rpc_unmarshal_longlong(rpc, &written); + status = uc_setinfo(fid, attribs, creation, access, change, written); + rpc_marshal_long(rpc, status); + } + break; + case RPC_READDIR: + { + ULONG fid, count, len; + LARGE_INTEGER cookie_in; + char *data, *save; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_longlong(rpc, &cookie_in); + rpc_unmarshal_wstr(rpc, name); + rpc_unmarshal_long(rpc, &len); + save = rpc->out_pos; + rpc_marshal_long(rpc, 0); + rpc_marshal_long(rpc, 0); + rpc_marshal_long(rpc, 0); + data = rpc->out_pos; + rpc->out_pos = save; + status = uc_readdir(fid, cookie_in, name, &count, data, &len); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, count); + rpc_marshal_long(rpc, len); + rpc->out_pos += len; + *rpc->bulk_out_len = len; + } + break; + case RPC_CLOSE: + { + ULONG fid; + rpc_unmarshal_long(rpc, &fid); + status = uc_close(fid); + rpc_marshal_long(rpc, status); + } + break; + case RPC_UNLINK: + { + ULONG fid, unlink; + rpc_unmarshal_wstr(rpc, name); + status = uc_unlink(name); + rpc_marshal_long(rpc, status); + } + break; + case RPC_IOCTL_WRITE: + { + ULONG length, key; + rpc_unmarshal_long(rpc, &length); + status = uc_ioctl_write(length, rpc->in_pos, &key); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, key); + } + break; + case RPC_IOCTL_READ: + { + ULONG key, length; + char *save, *data; + rpc_unmarshal_long(rpc, &key); + save = rpc->out_pos; + rpc_marshal_long(rpc, 0); + rpc_marshal_long(rpc, 0); + data = rpc->out_pos; + rpc->out_pos = save; + status = uc_ioctl_read(key, &length, data); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, length); + rpc->out_pos += length; + *rpc->bulk_out_len = length; + } + break; + case RPC_RENAME: + { + ULONG fid, new_fid; + WCHAR curr[1024], new_dir[1024], new_name[1024]; + rpc_unmarshal_long(rpc, &fid); + rpc_unmarshal_wstr(rpc, curr); + rpc_unmarshal_wstr(rpc, new_dir); + rpc_unmarshal_wstr(rpc, new_name); + status = uc_rename(fid, curr, new_dir, new_name, &new_fid); + rpc_marshal_long(rpc, status); + rpc_marshal_long(rpc, new_fid); + } + break; + } + } +#endif diff --git a/src/WINNT/afsrdr/ifs_rpc.h b/src/WINNT/afsrdr/ifs_rpc.h new file mode 100644 index 0000000..b5784f7 --- /dev/null +++ b/src/WINNT/afsrdr/ifs_rpc.h @@ -0,0 +1,113 @@ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ + +/* versioning history + * + * 03-jun 2005 (eric williams) entered into versioning + */ + +#ifdef RPC_KERN +#include +#include +#else +#include +#include +#include +#endif + +/* upcalls */ +#define RPC_NAMEI 0x10 +#define RPC_CHECK_ACCESS 0x11 +#define RPC_CREATE 0x12 +#define RPC_STAT 0x13 +#define RPC_READ 0x14 +#define RPC_WRITE 0x15 +#define RPC_TRUNC 0x16 +#define RPC_SETINFO 0x17 +#define RPC_READDIR 0x18 +#define RPC_CLOSE 0x19 +#define RPC_UNLINK 0x1A +#define RPC_IOCTL_WRITE 0x1B +#define RPC_IOCTL_READ 0x1C +#define RPC_RENAME 0x1D +#define RPC_READ_BULK 0x1E +#define RPC_WRITE_BULK 0x1F + +/* downcalls */ +#define RPC_BREAK_CALLBACK 0x80 + +#define TRANSFER_CHUNK_SIZE (1024*1024) +#define RPC_TIMEOUT_SHORT 0 +#define RPC_TIMEOUT_LONG 1 + +/* internal data struct for both client and server */ +struct rpc + { +#ifdef RPC_KERN + struct rpc *next; + int size; + KEVENT ev; + MDL *bulk_mdl; +#endif + char *bulk_out; + ULONG *bulk_out_len; + char *bulk_in; + ULONG bulk_in_len, bulk_in_max; + ULONG key; + char *out_buf, *out_pos; + char *in_buf, *in_pos; + int status; + }; +typedef struct rpc rpc_t; + + +/* application interface into rpc library */ +#ifdef RPC_KERN +rpc_call(ULONG in_len, char *in_buf, ULONG out_max, char *out_buf, ULONG *out_len); +rpc_set_context(void *context); +rpc_remove_context(); +rpc_get_len(rpc_t *rpc); +rpc_send(char *out_buf, int out_len, int *out_written); +rpc_recv(char *in_buf, ULONG len); +rpc_shutdown(); + +#else + +rpc_parse(rpc_t *rpc); +#endif + + +/* extended information */ +struct readdir_data + { + LARGE_INTEGER cookie; + long offset; + LARGE_INTEGER creation, access, write, change, size; + ULONG attribs, name_length; /* chars */ + CCHAR short_name_length; /* chars */ + WCHAR short_name[14]; + WCHAR name[]; + }; +typedef struct readdir_data readdir_data_t; diff --git a/src/WINNT/afsrdr/kif.h b/src/WINNT/afsrdr/kif.h new file mode 100644 index 0000000..d1237f3 --- /dev/null +++ b/src/WINNT/afsrdr/kif.h @@ -0,0 +1,90 @@ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ + +/* versioning history + * + * 03-jun 2005 (eric williams) entered into versioning + */ + +/* error codes */ +#define IFSL_SUCCESS_BASE 0x00000000 +#define IFSL_FAIL_BASE 0x80000000 + +#define IFSL_SUCCESS (IFSL_SUCCESS_BASE + 0) +#define IFSL_DOES_NOT_EXIST (IFSL_FAIL_BASE + 1) +#define IFSL_NOT_IMPLEMENTED (IFSL_FAIL_BASE + 2) +#define IFSL_END_OF_ENUM (IFSL_SUCCESS_BASE + 3) +#define IFSL_CANNOT_MAKE (IFSL_FAIL_BASE + 4) +#define IFSL_END_OF_FILE (IFSL_SUCCESS_BASE + 5) +#define IFSL_NO_ACCESS (IFSL_FAIL_BASE + 6) +#define IFSL_BUFFER_TOO_SMALL (IFSL_FAIL_BASE + 7) +#define IFSL_SHARING_VIOLATION (IFSL_FAIL_BASE + 8) +#define IFSL_BAD_INPUT (IFSL_FAIL_BASE + 9) +#define IFSL_GENERIC_FAILURE (IFSL_FAIL_BASE + 10) +#define IFSL_OPEN_CREATED (IFSL_SUCCESS_BASE + 11) +#define IFSL_OPEN_EXISTS (IFSL_FAIL_BASE + 12) +#define IFSL_OPEN_OPENED (IFSL_SUCCESS_BASE + 13) +#define IFSL_OPEN_OVERWRITTEN (IFSL_SUCCESS_BASE + 14) +#define IFSL_OPEN_SUPERSCEDED (IFSL_SUCCESS_BASE + 15) +#define IFSL_BADFILENAME (IFSL_FAIL_BASE + 16) +#define IFSL_READONLY (IFSL_FAIL_BASE + 17) +#define IFSL_IS_A_DIR (IFSL_FAIL_BASE + 18) +#define IFSL_PATH_DOES_NOT_EXIST (IFSL_FAIL_BASE + 19) +#define IFSL_IS_A_FILE (IFSL_FAIL_BASE + 20) +#define IFSL_NO_FILE (IFSL_FAIL_BASE + 21) +#define IFSL_NOT_EMPTY (IFSL_FAIL_BASE + 22) +#define IFSL_RPC_TIMEOUT (IFSL_FAIL_BASE + 23) +#define IFSL_OVERQUOTA (IFSL_FAIL_BASE + 24) +#define IFSL_UNSPEC (IFSL_FAIL_BASE + 25) + + +/* ioctl codes */ +#define IOCTL_AFSRDR_IOCTL CTL_CODE(IOCTL_DISK_BASE, 0x007, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_AFSRDR_DOWNCALL CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_AFSRDR_GET_PATH CTL_CODE(IOCTL_DISK_BASE, 0x009, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + + +/* upcalls */ +uc_namei(WCHAR *name, ULONG *fid); +uc_check_access(ULONG fid, ULONG access, ULONG *granted); +uc_create(WCHAR *str, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid); +uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation, LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written); +uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access, LARGE_INTEGER change, LARGE_INTEGER written); +uc_trunc(ULONG fid, LARGE_INTEGER size); +uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data); +uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data); +/*#ifdef RPC_KERN +uc_read_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, MDL *data); +uc_write_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, MDL *mdl); +#endif*/ +uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len); +uc_close(ULONG fid); +uc_unlink(WCHAR *name); +uc_ioctl_write(ULONG length, char *data, ULONG *key); +uc_ioctl_read(ULONG key, ULONG *length, char *data); +uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid); + +/* downcalls */ +dc_break_callback(ULONG fid); diff --git a/src/WINNT/afsrdr/makefile b/src/WINNT/afsrdr/makefile new file mode 100644 index 0000000..5acbbd2 --- /dev/null +++ b/src/WINNT/afsrdr/makefile @@ -0,0 +1 @@ +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/src/WINNT/afsrdr/sources b/src/WINNT/afsrdr/sources new file mode 100644 index 0000000..41abfe9 --- /dev/null +++ b/src/WINNT/afsrdr/sources @@ -0,0 +1,31 @@ +#/* copyright (c) 2005 +# * the regents of the university of michigan +# * all rights reserved +# * +# * permission is granted to use, copy, create derivative works and +# * redistribute this software and such derivative works for any purpose, +# * so long as the name of the university of michigan is not used in +# * any advertising or publicity pertaining to the use or distribution +# * of this software without specific, written prior authorization. if +# * the above copyright notice or any other identification of the +# * university of michigan is included in any copy of any portion of +# * this software, then the disclaimer below must also be included. +# * +# * this software is provided as is, without representation from the +# * university of michigan as to its fitness for any purpose, and without +# * warranty by the university of michigan of any kind, either express +# * or implied, including without limitation the implied warranties of +# * merchantability and fitness for a particular purpose. the regents +# * of the university of michigan shall not be liable for any damages, +# * including special, indirect, incidental, or consequential damages, +# * with respect to any claim arising out or in connection with the use +# * of the software, even if it has been or is hereafter advised of the +# * possibility of such damages. +# */ + +SOURCES= afsrdr.c ifs_rpc.c +TARGETNAME=afsrdr +TARGETPATH=obj +TARGETTYPE=DRIVER +DRIVERTYPE=FS +C_DEFINES=-DUNICODE -DRPT_CLI -DRPC_KERN diff --git a/src/WINNT/client_config/drivemap.cpp b/src/WINNT/client_config/drivemap.cpp index 75e1bf9..88856ae 100644 --- a/src/WINNT/client_config/drivemap.cpp +++ b/src/WINNT/client_config/drivemap.cpp @@ -6,6 +6,30 @@ * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as no fee is charged, and so long as the copyright notice + * above, this grant of permission, and the disclaimer below appear + * in all copies made; and so long as the name of the university of + * michigan is not used in any advertising or publicity pertaining + * to the use or distribution of this software without specific, written + * prior authorization. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for nay damages, + * including special, indirect, incidental, or consequential damages, + * with respect to ant claim arising out of or in connection with the + * use of the software, even if it has been or is hereafter advised + * of the possibility of such damages. + */ extern "C" { #include @@ -314,9 +338,16 @@ BOOL SubmountToPath (PDRIVEMAPLIST pList, LPTSTR pszPath, LPTSTR pszSubmount, BO // Otherwise, look up our list of submounts. // +#ifdef AFSIFS + AdjustAfsPath (pszPath, pszSubmount, TRUE, TRUE); +#endif for (size_t ii = 0; ii < pList->cSubmounts; ++ii) { +#ifndef AFSIFS if (!lstrcmpi (pList->aSubmounts[ii].szSubmount, pszSubmount)) +#else + if (!lstrcmpi (pList->aSubmounts[ii].szMapping, pszPath)) +#endif { if (fMarkInUse) pList->aSubmounts[ii].fInUse = TRUE; @@ -815,7 +846,11 @@ BOOL ActivateDriveMap (TCHAR chDrive, LPTSTR pszMapping, LPTSTR pszSubmountReq, } // We now have a submount name and drive letter--map the network drive. +#ifndef AFSIFS DWORD rc=MountDOSDrive(chDrive,szSubmount,fPersistent,NULL); +#else + DWORD rc=MountDOSDrive(chDrive,/*szSubmount*/pszMapping,fPersistent,NULL); +#endif if (rc == NO_ERROR) return TRUE; @@ -931,10 +966,25 @@ BOOL GetDriveSubmount (TCHAR chDrive, LPTSTR pszSubmountNow) // : Authentication ID, 16 char hex. // : Netbios name of server // +#ifndef AFSIFS if (_tcsnicmp(szMapping, cszLANMANDEVICE, _tcslen(cszLANMANDEVICE))) +#else + const TCHAR ker_sub_path[] = "\\Device\\afsrdr\\"; + if (_tcsnicmp(szMapping, ker_sub_path, _tcslen(ker_sub_path))) +#endif return FALSE; +#ifndef AFSIFS pszSubmount = &szMapping[ _tcslen(cszLANMANDEVICE) ]; +#else + pszSubmount = &szMapping[ _tcslen(ker_sub_path) ]; +#endif +#ifdef AFSIFS + if (*(pszSubmount) < '0' || + *(pszSubmount) > '9') + return FALSE; + ++pszSubmount; +#else if (IsWindows2000()) { if (*(pszSubmount) != TEXT(';')) @@ -970,6 +1020,7 @@ BOOL GetDriveSubmount (TCHAR chDrive, LPTSTR pszSubmountNow) return FALSE; pszSubmount += _tcslen(szNetBiosName); +#endif } else // (!IsWindowsNT()) { @@ -991,7 +1042,12 @@ BOOL GetDriveSubmount (TCHAR chDrive, LPTSTR pszSubmountNow) if (!pszSubmount || !*pszSubmount) return FALSE; +#ifndef AFSIFS lstrcpy (pszSubmountNow, pszSubmount); +#else + lstrcpy (pszSubmountNow, "\\afs"); + lstrcat (pszSubmountNow, pszSubmount); +#endif return TRUE; } @@ -1358,9 +1414,43 @@ BOOL GlobalMountDrive() DWORD MountDOSDrive(char chDrive,const char *szSubmount,BOOL bPersistent,const char * pUsername) { - TCHAR szPath[MAX_PATH]; + DWORD err; + BOOL succ; + TCHAR szPath[MAX_PATH], szTokens[MAX_PATH], *tok; TCHAR szClient[MAX_PATH]; TCHAR szDrive[3] = TEXT("?:"); + +#ifdef AFSIFS + int pathCount, currPos, lastPos, x; + + pathCount = 0; + + pathCount = 0; + strcpy(szTokens, szSubmount); + tok = strtok(szTokens, "/\\"); + strcpy(szPath, ""); + while (tok) + { + if (pathCount || stricmp(tok, "afs")) + { + strcat(szPath, "\\"); + strcat(szPath, tok); + pathCount++; + } + tok = strtok(NULL, "/\\"); + } + + sprintf(szDrive,"%c:",chDrive); + strcpy(szTokens, szPath); + sprintf(szPath,"\\Device\\afsrdr\\%d%s",pathCount,szTokens); + //succ = DefineDosDevice(DDD_RAW_TARGET_PATH, "J:", "\\Device\\afsrdr\\2\\ericjw\\test"); + succ = DefineDosDevice(DDD_RAW_TARGET_PATH, szDrive, szPath); + err = GetLastError(); + + return succ ? NO_ERROR : ERROR_DEVICE_IN_USE; + +#else + sprintf(szDrive,"%c:",chDrive); GetClientNetbiosName (szClient); sprintf(szPath,"\\\\%s\\%s",szClient,szSubmount); @@ -1375,11 +1465,19 @@ DWORD MountDOSDrive(char chDrive,const char *szSubmount,BOOL bPersistent,const c (bPersistent)?"Persistant" : "NonPresistant", szDrive,szPath,pUsername?pUsername:"NULL",res); return res; +#endif } DWORD DisMountDOSDriveFull(const char *szPath,BOOL bForce) { +#ifndef AFSIFS DWORD res=WNetCancelConnection(szPath,bForce); +#else + DWORD res; + res = ERROR_DEVICE_IN_USE; + // must handle drive letters and afs paths + //DDD_REMOVE_DEFINITION +#endif DEBUG_EVENT3("AFS DriveMap","%sDismount Remote[%s]=%x", bForce ? "Forced " : "",szPath,res); return (res==ERROR_NOT_CONNECTED)?NO_ERROR:res; @@ -1398,6 +1496,13 @@ DWORD DisMountDOSDrive(const char *pSubmount,BOOL bForce) DWORD DisMountDOSDrive(const char chDrive,BOOL bForce) { TCHAR szPath[MAX_PATH]; - sprintf(szPath,"%c:",chDrive); + DWORD succ; + + sprintf(szPath,"%c:",chDrive); +#ifdef AFSIFS + succ = DefineDosDevice(DDD_REMOVE_DEFINITION, szPath, NULL); + return (!succ) ? GetLastError() : 0; +#else return DisMountDOSDriveFull(szPath,bForce); +#endif } diff --git a/src/WINNT/install/NSIS/NTMakefile b/src/WINNT/install/NSIS/NTMakefile index 4678823..52e8811 100644 --- a/src/WINNT/install/NSIS/NTMakefile +++ b/src/WINNT/install/NSIS/NTMakefile @@ -89,6 +89,9 @@ prebuild: !else if ("$(AFSVER_CL)" == "1300") echo !define CL_1300 1 >> $(OUT)\nsi-includes.nsi !endif +!if ("$(AFSIFS)" == "TRUE") + echo !define AFSIFS 1 >> $(OUT)\nsi-includes.nsi +!endif !if ("$(AFSDEV_BUILDTYPE)" == "CHECKED") echo !define DEBUG 1 >>$(OUT)\nsi-includes.nsi !endif diff --git a/src/WINNT/install/NSIS/OpenAFS.nsi b/src/WINNT/install/NSIS/OpenAFS.nsi index 3fd63f0..8bba6ef 100644 --- a/src/WINNT/install/NSIS/OpenAFS.nsi +++ b/src/WINNT/install/NSIS/OpenAFS.nsi @@ -49,7 +49,7 @@ VIAddVersionKey "CompanyName" "OpenAFS.org" VIAddVersionKey "ProductVersion" ${AFS_VERSION} VIAddVersionKey "FileVersion" ${AFS_VERSION} VIAddVersionKey "FileDescription" "OpenAFS for Windows Installer" -VIAddVersionKey "LegalCopyright" "(C)2000-2004" +VIAddVersionKey "LegalCopyright" "(C)2000-2005" !ifdef DEBUG VIAddVersionKey "PrivateBuild" "Checked/Debug" !endif ; End DEBUG @@ -64,11 +64,19 @@ VIAddVersionKey "PrivateBuild" "Checked/Debug" !define REPLACEDLL_NOREGISTER ;General +!ifndef AFSIFS !ifndef DEBUG OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows.exe" !else OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows-DEBUG.exe" !endif +!else +!ifndef DEBUG + OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows-IFS.exe" +!else + OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows-IFS-DEBUG.exe" +!endif +!endif SilentInstall normal SetCompressor lzma !define MUI_ICON "..\..\client_config\afs_config.ico" @@ -483,6 +491,7 @@ var REG_VALUE var REG_DATA_1 var REG_DATA_2 var REG_DATA_3 +var REG_DATA_4 ;-------------------------------- @@ -547,6 +556,13 @@ Section "AFS Client" secClient SetOutPath "$SYSDIR" !insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afslogon.dll" "$SYSDIR\afslogon.dll" "$INSTDIR" File "${AFS_CLIENT_BUILDDIR}\afscpcc.exe" +!ifdef AFSIFS +!ifndef DEBUG + !insertmacro ReplaceDLL "..\..\afsrdr\objfre_w2K_x86\i386\afsrdr.sys" "$SYSDIR\DRIVERS\afsrdr.sys" "$INSTDIR" +!else + !insertmacro ReplaceDLL "..\..\afsrdr\objchk_w2K_x86\i386\afsrdr.sys" "$SYSDIR\DRIVERS\afsrdr.sys" "$INSTDIR" +!endif +!endif Call AFSLangFiles @@ -660,6 +676,7 @@ Section "AFS Client" secClient SetOutPath "$INSTDIR\Common" File "${AFS_WININSTALL_DIR}\Service.exe" nsExec::Exec "net stop TransarcAFSDaemon" + nsExec::Exec "net stop AfsRdr" ;IMPORTANT! If we are not refreshing the config files, do NOT remove the service ;Don't re-install because it must be present or we wouldn't have passed the Reg check @@ -667,6 +684,10 @@ Section "AFS Client" secClient StrCmp $R2 "" +1 skipremove nsExec::Exec '$INSTDIR\Common\Service.exe u TransarcAFSDaemon' nsExec::Exec '$INSTDIR\Common\Service.exe TransarcAFSDaemon "$INSTDIR\Client\Program\afsd_service.exe" "OpenAFS Client Service"' + nsExec::Exec '$INSTDIR\Common\Service.exe u AfsRdr' +!ifdef AFSIFS + nsExec::Exec '$INSTDIR\Common\Service.exe AfsRdr "$SYSDIR\DRIVERS\afsrdr.sys" "AFS Redirector"' +!endif skipremove: Delete "$INSTDIR\Common\service.exe" @@ -711,13 +732,28 @@ skipremove: strcpy $REG_DATA_1 "PNP_TDI" strcpy $REG_DATA_2 "" strcpy $REG_DATA_3 "" + strcpy $REG_DATA_4 "" Call RegWriteMultiStr strcpy $REG_SUB_KEY "SYSTEM\CurrentControlSet\Services\TransarcAFSDaemon" strcpy $REG_VALUE "DependOnService" strcpy $REG_DATA_1 "Tcpip" strcpy $REG_DATA_2 "NETBIOS" strcpy $REG_DATA_3 "RpcSs" +!ifdef AFSIFS + strcpy $REG_DATA_4 "AfsRdr" +!else + strcpy $REG_DATA_4 "" +!endif + Call RegWriteMultiStr +!ifdef AFSIFS + strcpy $REG_SUB_KEY "SYSTEM\CurrentControlSet\Services\AfsRdr" + strcpy $REG_VALUE "DependOnService" + strcpy $REG_DATA_1 "Tcpip" + strcpy $REG_DATA_2 "" + strcpy $REG_DATA_3 "" + strcpy $REG_DATA_4 "" Call RegWriteMultiStr +!endif ; WinLogon Event Notification WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\AfsLogon" "Asynchronous" 0 @@ -3774,6 +3810,12 @@ Function RegWriteMultiStr System::Call "*$2(&t$9 '$REG_DATA_3')" ; Place the string IntOp $2 $2 + $9 ; Advance to the next position + StrCmp '$REG_DATA_4' "" terminate + StrLen $9 '$REG_DATA_4' ; Length of third string + IntOp $9 $9 + 1 ; Plus null + System::Call "*$2(&t$9 '$REG_DATA_4')" ; Place the string + IntOp $2 $2 + $9 ; Advance to the next position + terminate: System::Call "*$2(&t1 '')" ; Place the terminating null IntOp $2 $2 + 1 ; Advance to the next position diff --git a/src/WINNT/install/NSIS/Service.cpp b/src/WINNT/install/NSIS/Service.cpp index 4833fc7..80b9481 100644 --- a/src/WINNT/install/NSIS/Service.cpp +++ b/src/WINNT/install/NSIS/Service.cpp @@ -13,6 +13,8 @@ int main(int argc, char *argv[]) { + DWORD type, start; + if(argc<3) { printf("Insufficient arguments: Service ServiceName ServicePath DisplayName.\n"); @@ -31,11 +33,21 @@ int main(int argc, char *argv[]) if(*argv[1]!='u' && *argv[1]!='U') { + if (!stricmp(argv[2] + strlen(argv[2]) - 3, "sys")) + { + type = SERVICE_FILE_SYSTEM_DRIVER; + start = SERVICE_DEMAND_START; + } + else + { + type = SERVICE_WIN32_OWN_PROCESS; + start = SERVICE_AUTO_START; + } hService = CreateService(hSCM, argv[1], _T(argv[3]), SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, + type, + start, SERVICE_ERROR_IGNORE, argv[2], NULL,NULL,NULL, NULL, NULL ); diff --git a/src/config/NTMakefile.i386_nt40 b/src/config/NTMakefile.i386_nt40 index f0e28b0..894fcb3 100644 --- a/src/config/NTMakefile.i386_nt40 +++ b/src/config/NTMakefile.i386_nt40 @@ -256,6 +256,12 @@ afscdefs = $(afscdefs) /G7 !ENDIF !ENDIF +!IF ("$(AFSIFS)" == "TRUE") +dafsifs = "-DAFSIFS" +!ELSE +dafsifs = "" +!ENDIF + !IF ("$(AFSDEV_BUILDTYPE)" == "FREE") afscflags = $(afscflags) /Ox /Zi @@ -296,7 +302,7 @@ AFSDEV_WARNLEVEL = 3 afscflags = $(afscflags) /W$(AFSDEV_WARNLEVEL) # C/C++ compilation macros -C2OBJ = $(cc) /Fo$@ /Fd$*.pdb $(cflags) $(cdebug) $(cvarsdll) $(afscflags) $(afscdefs) /c +C2OBJ = $(cc) /Fo$@ /Fd$*.pdb $(cflags) $(cdebug) $(dafsifs) $(cvarsdll) $(afscflags) $(afscdefs) /c CPP2OBJ = $(C2OBJ) # Inference rules for building and installing targets # Compile .c files, from current directory to defined by OUT diff --git a/src/ntbuild.bat b/src/ntbuild.bat index 2941835..2e0c1a1 100755 --- a/src/ntbuild.bat +++ b/src/ntbuild.bat @@ -83,13 +83,25 @@ goto usage :checked set AFSBLD_TYPE=CHECKED set AFSDEV_CRTDEBUG=1 -goto args_done +goto ifs_arg :free set AFSBLD_TYPE=FREE set AFSDEV_CRTDEBUG=0 +goto ifs_arg + +:ifs_arg + +set AFSIFS= +if "%2"=="ifs" goto is_ifs +if "%2"=="IFS" goto is_ifs + goto args_done +:is_ifs + +set AFSIFS=TRUE + :args_done REM ####################################################################### diff --git a/src/sys/pioctl_nt.c b/src/sys/pioctl_nt.c index 74ab762..333c3dc 100644 --- a/src/sys/pioctl_nt.c +++ b/src/sys/pioctl_nt.c @@ -6,6 +6,30 @@ * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ +/* copyright (c) 2005 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any purpose, + * so long as the name of the university of michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. if + * the above copyright notice or any other identification of the + * university of michigan is included in any copy of any portion of + * this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the + * university of michigan as to its fitness for any purpose, and without + * warranty by the university of michigan of any kind, either express + * or implied, including without limitation the implied warranties of + * merchantability and fitness for a particular purpose. the regents + * of the university of michigan shall not be liable for any damages, + * including special, indirect, incidental, or consequential damages, + * with respect to any claim arising out or in connection with the use + * of the software, even if it has been or is hereafter advised of the + * possibility of such damages. + */ #include #include @@ -42,6 +66,7 @@ RCSID #include #include #include +#include #include #include @@ -315,6 +340,7 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep) DWORD gle; DWORD dwSize = sizeof(szUser); +#ifndef AFSIFS if (fileNamep) { drivep = strchr(fileNamep, ':'); if (drivep && (drivep - fileNamep) >= 1) { @@ -365,14 +391,25 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep) lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL); sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME); } +#else + sprintf(tbuffer,"\\\\.\\afscom\\ioctl"); +#endif fflush(stdout); /* now open the file */ fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); - fflush(stdout); - if (fh == INVALID_HANDLE_VALUE) { + + fflush(stdout); + +#ifdef AFSIFS + if (fh == INVALID_HANDLE_VALUE) { + return -1; + } +#endif + + if (fh == INVALID_HANDLE_VALUE) { int gonext = 0; gle = GetLastError(); @@ -593,6 +630,7 @@ Transceive(HANDLE handle, fs_ioctlRequest_t * reqp) long rcount; long ioCount; DWORD gle; + char *data; rcount = reqp->mp - reqp->data; if (rcount <= 0) { @@ -601,7 +639,8 @@ Transceive(HANDLE handle, fs_ioctlRequest_t * reqp) return EINVAL; /* not supposed to happen */ } - if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) { +#ifndef AFSIFS + if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) { /* failed to write */ gle = GetLastError(); @@ -618,6 +657,17 @@ Transceive(HANDLE handle, fs_ioctlRequest_t * reqp) fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle); return gle; } +#else + /* ioctl completes as one operation, so copy input to a new buffer, and use as output buffer */ + data = malloc(rcount); + memcpy(data, reqp->data, rcount); + if (!DeviceIoControl(handle, IOCTL_AFSRDR_IOCTL, data, rcount, reqp->data, sizeof(reqp->data), &ioCount, NULL)) + { + free(data); + return GetLastError(); + } + free(data); +#endif reqp->nbytes = ioCount; /* set # of bytes available */ reqp->mp = reqp->data; /* restart marshalling */ @@ -691,6 +741,34 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize) int pathHasDrive; int doSwitch; char newPath[3]; + HANDLE rootDir; + wchar_t *wpath; + unsigned long length; + +#ifdef AFSIFS + if (!pathp) + return CM_ERROR_NOSUCHPATH; + + //sprintf(tpath, "%c:\\", pathp[0]); + rootDir = CreateFile(pathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (rootDir == INVALID_HANDLE_VALUE) + return CM_ERROR_NOSUCHPATH; + + wpath = tpath; + length = 0; + if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, wpath, 1000, &length, NULL)) + { + CloseHandle(rootDir); + return CM_ERROR_NOSUCHPATH; + } + CloseHandle(rootDir); + + code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, wpath, length/sizeof(wchar_t), outPathp, outSize/sizeof(wchar_t), NULL, NULL); + +// strcpy(outPathp, tpath); + return 0; +#endif + if (pathp[0] != 0 && pathp[1] == ':') { /* there's a drive letter there */ @@ -746,6 +824,7 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize) /* now get the absolute path to the current wdir in this drive */ GetCurrentDirectory(sizeof(tpath), tpath); if (tpath[1] == ':') +#ifndef AFSIFS strcpy(outPathp, tpath + 2); /* skip drive letter */ else if ( tpath[0] == '\\' && tpath[1] == '\\') { /* UNC path - strip off the server and sharename */ @@ -760,6 +839,26 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize) } else { strcpy(outPathp,&tpath[--i]); } +#else + { + HANDLE rootDir; + + strcpy(outPathp, tpath); + + sprintf(outPathp, "%c:\\", tpath[0]); + rootDir = CreateFile(outPathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, absRoot_w, 100*sizeof(wchar_t), &length, NULL)) + { + CloseHandle(rootDir); + return CM_ERROR_NOSUCHPATH; + } + CloseHandle(rootDir); + + ifs_ConvertFileName(absRoot_w, length/sizeof(wchar_t), absRoot, 100); + + } +#endif } else { /* this should never happen */ strcpy(outPathp, tpath); -- 1.9.4