afsifs-20050615
authorEric Williams <ericjw@umich.edu>
Wed, 15 Jun 2005 17:51:44 +0000 (17:51 +0000)
committerJim Rees <rees@umich.edu>
Wed, 15 Jun 2005 17:51:44 +0000 (17:51 +0000)
Windows IFS client code and build option

25 files changed:
README-NT
src/WINNT/afsd/NTMakefile
src/WINNT/afsd/afsd.c
src/WINNT/afsd/afsd.h
src/WINNT/afsd/afsd_service.c
src/WINNT/afsd/afsdifs.c [new file with mode: 0644]
src/WINNT/afsd/afsdifs.h [new file with mode: 0644]
src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/rawops.c [new file with mode: 0644]
src/WINNT/afsrdr/afsrdr.c [new file with mode: 0644]
src/WINNT/afsrdr/afsrdr.h [new file with mode: 0644]
src/WINNT/afsrdr/ifs_rpc.c [new file with mode: 0644]
src/WINNT/afsrdr/ifs_rpc.h [new file with mode: 0644]
src/WINNT/afsrdr/kif.h [new file with mode: 0644]
src/WINNT/afsrdr/makefile [new file with mode: 0644]
src/WINNT/afsrdr/sources [new file with mode: 0644]
src/WINNT/client_config/drivemap.cpp
src/WINNT/install/NSIS/NTMakefile
src/WINNT/install/NSIS/OpenAFS.nsi
src/WINNT/install/NSIS/Service.cpp
src/config/NTMakefile.i386_nt40
src/ntbuild.bat
src/sys/pioctl_nt.c

index 7507062..522a5ad 100644 (file)
--- 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
index 8361c51..a4b9683 100644 (file)
@@ -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 \
index 2f10e2e..4a51af1 100644 (file)
@@ -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 <afs/param.h>
 #include <afs/stds.h>
 #include <crtdbg.h>
 #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;
 
index 112b202..d6fd398 100644 (file)
@@ -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);
index ad334c1..ad8614f 100644 (file)
@@ -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 <afs/param.h>
 #include <afs/stds.h>
@@ -31,6 +55,7 @@
 #ifdef _DEBUG
 #include <crtdbg.h>
 #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 <Enter> 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 (file)
index 0000000..4e1ef48
--- /dev/null
@@ -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 <osi.h>
+#include "afsd.h"
+#include <winioctl.h>
+#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 (file)
index 0000000..e18ef07
--- /dev/null
@@ -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);
index 4fa09dc..86826e8 100644 (file)
@@ -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);
     }
index d4e5ca5..29b83c9 100644 (file)
@@ -41,6 +41,8 @@
 
 #include "cm_rpc.h"
 #include <strsafe.h>
+#include <winioctl.h>
+#include <WINNT\afsrdr\kif.h>
 
 #ifdef _DEBUG
 #include <crtdbg.h>
@@ -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 */
index 13e735c..d031791 100644 (file)
@@ -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 (file)
index 0000000..928f243
--- /dev/null
@@ -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 <osi.h>
+#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 (file)
index 0000000..e5c01e9
--- /dev/null
@@ -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 <ntifs.h>
+#include <ntdddisk.h>
+#include <strsafe.h>
+#include <ksdebug.h>
+#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 <driveletter>:\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 (file)
index 0000000..79f9b14
--- /dev/null
@@ -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 <ntifs.h>
+
+#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 (file)
index 0000000..b7d924b
--- /dev/null
@@ -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 <ntifs.h>
+#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 (file)
index 0000000..b5784f7
--- /dev/null
@@ -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 <ntifs.h>
+#include <stdlib.h>
+#else
+#include <osi.h>
+#include <windows.h>
+#include <winioctl.h>
+#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 (file)
index 0000000..d1237f3
--- /dev/null
@@ -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 (file)
index 0000000..5acbbd2
--- /dev/null
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/src/WINNT/afsrdr/sources b/src/WINNT/afsrdr/sources
new file mode 100644 (file)
index 0000000..41abfe9
--- /dev/null
@@ -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
index 75e1bf9..88856ae 100644 (file)
@@ -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 <afs/param.h>
@@ -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)
       //           <AuthID>: Authentication ID, 16 char hex.
       //           <netbiosname>: 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
 }
index 4678823..52e8811 100644 (file)
@@ -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
index 3fd63f0..8bba6ef 100644 (file)
@@ -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
index 4833fc7..80b9481 100644 (file)
@@ -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 );
index f0e28b0..894fcb3 100644 (file)
@@ -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
index 2941835..2e0c1a1 100755 (executable)
@@ -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 #######################################################################
index 74ab762..333c3dc 100644 (file)
@@ -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 <afsconfig.h>
 #include <afs/param.h>
@@ -42,6 +66,7 @@ RCSID
 #include <pioctl_nt.h>
 #include <WINNT/afsreg.h>
 #include <lanahelper.h>
+#include <WINNT/afsrdr/kif.h>
 
 #include <loadfuncs-krb5.h>
 #include <krb5.h>
@@ -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);