]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Windows: Redirector interface for afsd_service.exe
authorJeffrey Altman <jaltman@your-file-system.com>
Thu, 15 Sep 2011 05:11:15 +0000 (01:11 -0400)
committerJeffrey Altman <jaltman@openafs.org>
Thu, 15 Sep 2011 18:25:13 +0000 (11:25 -0700)
Over the last three years the afsd_service sources have been
gradually separated into distinct layers for the SMB server
and the AFS cache.  The eventual goal of this work was to
permit the addition of alternative interfaces to the cache
manager in parallel.

This patchset implements the first alternative interface,
a reverse ioctl model that communicates with a native IFS
redirector driver.  The driver will be submitted in a
subsequent patchset.

Although it is possible to run afsd_service with both the
SMB and RDR interfaces active at the same time.  In practice
it is somewhat impractical because it destroys the uniformity
of the \\AFS name space.  The RDR loads at boot time and claims
all of \\AFS.  The SMB interface if active at the same time
must use the old \\%HOSTNAME%-AFS.  As implemented, if the RDR
interface is functional the SMB interface is not started.  Only
if the RDR interface fails will the SMB interface be activated.

The afsd_service.exe maintains all of its primary responsibilities
for communicating with the AFS servers, processing callbacks,
enforcing permissions, handling afs path ioctls, Windows RPC
service simulation, and object management.  The biggest change
is in the cm_buf_t management.  Data is exchanged with the
RDR by passing control over cm_buf_t->data buffers in the form
of Windows File Extents.  This avoids data copies across a
communication channel which significantly improves performance
at a substantial complexity cost.

Credential management is switched from a Windows username binding
to a GUID binding where the GUIDs represent authentication groups
that are managed by the RDR.

This patchset includes additional changes to support integrated
logon in conjunction with the RDR.  In particular, adding support
for authentication groups.

Change-Id: I7135489421c67a429ec3b2acd4c8ae08b8329f6d
Reviewed-on: http://gerrit.openafs.org/5432
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Tested-by: Rod Widdowson <rdw@steadingsoftware.com>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>
42 files changed:
src/WINNT/afsd/NTMakefile
src/WINNT/afsd/afsd.h
src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/afsd_service.c
src/WINNT/afsd/afslogon.c
src/WINNT/afsd/afslogon.h
src/WINNT/afsd/cm.h
src/WINNT/afsd/cm_aclent.c
src/WINNT/afsd/cm_buf.c
src/WINNT/afsd/cm_buf.h
src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_callback.h
src/WINNT/afsd/cm_conn.c
src/WINNT/afsd/cm_conn.h
src/WINNT/afsd/cm_daemon.c
src/WINNT/afsd/cm_dcache.c
src/WINNT/afsd/cm_freelance.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_ioctl.h
src/WINNT/afsd/cm_memmap.c
src/WINNT/afsd/cm_memmap.h
src/WINNT/afsd/cm_performance.c
src/WINNT/afsd/cm_rdr.h [new file with mode: 0644]
src/WINNT/afsd/cm_scache.c
src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_server.c
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_vnodeops.h
src/WINNT/afsd/cm_volstat.c
src/WINNT/afsd/cm_volstat.h
src/WINNT/afsd/cm_volume.c
src/WINNT/afsd/fs.c
src/WINNT/afsd/logon_ad.cpp
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c
src/WINNT/afsrdr/user/RDRFunction.c [new file with mode: 0644]
src/WINNT/afsrdr/user/RDRInit.cpp [new file with mode: 0644]
src/WINNT/afsrdr/user/RDRIoctl.c [new file with mode: 0644]
src/WINNT/afsrdr/user/RDRIoctl.h [new file with mode: 0644]
src/WINNT/afsrdr/user/RDRPipe.c [new file with mode: 0644]
src/WINNT/afsrdr/user/RDRPipe.h [new file with mode: 0644]
src/WINNT/afsrdr/user/RDRPrototypes.h [new file with mode: 0644]

index 77b0a0c654c84dc3578ebd44b4d99cbca06222b2..525fcbb7100da1805886af28779df8e70ecac942 100644 (file)
@@ -7,7 +7,7 @@
 
 AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL" /DSMB_UNICODE -I..\kfw\inc\loadfuncs \
         -I..\kfw\inc\krb5 -I..\kfw\inc\leash -I$(DESTDIR)\include\afs \
-        -I$(DESTDIR)\include\rx
+        -I$(DESTDIR)\include\rx -I..\afsrdr\common -I..\afsrdr\user
 AFSDEV_NETGUI = 1
 RELDIR=WINNT\afsd
 !INCLUDE ..\..\config\NTMakefile.$(SYS_NAME)
@@ -153,10 +153,26 @@ AFSDOBJS=\
        $(OUT)\ms-wkssvc_s.obj \
        $(OUT)\rpc_wkssvc.obj \
        $(OUT)\rpc_srvsvc.obj \
-        $(OUT)\AFS_component_version_number.obj
+        $(OUT)\AFS_component_version_number.obj \
+       $(OUT)\RDRInit.obj \
+       $(OUT)\RDRFunction.obj \
+        $(OUT)\RDRIoctl.obj \
+        $(OUT)\RDRPipe.obj
 
 $(AFSDOBJS):
 
+$(OUT)\RDRInit.obj: ..\afsrdr\user\RDRInit.cpp ..\afsrdr\user\RDRPrototypes.h ..\afsrdr\user\RDRIoctl.h
+       $(CPP2OBJ) ..\afsrdr\user\RDRInit.cpp
+
+$(OUT)\RDRFunction.obj: ..\afsrdr\user\RDRFunction.c ..\afsrdr\user\RDRPrototypes.h ..\afsrdr\user\RDRIoctl.h
+       $(C2OBJ)  ..\afsrdr\user\RDRFunction.c
+
+$(OUT)\RDRIoctl.obj: ..\afsrdr\user\RDRIoctl.c ..\afsrdr\user\RDRIoctl.h
+       $(C2OBJ)  ..\afsrdr\user\RDRIoctl.c
+
+$(OUT)\RDRPipe.obj: ..\afsrdr\user\RDRPipe.c ..\afsrdr\user\RDRPipe.h
+       $(C2OBJ)  ..\afsrdr\user\RDRPipe.c
+
 $(OUT)\cm_conn.obj: cm_conn.c
        $(C2OBJ) -DAFS_PTHREAD_ENV /Fo$@ $**
 
@@ -317,7 +333,8 @@ LOGON_DLLSDKLIBS =\
        activeds.lib \
        user32.lib \
         userenv.lib \
-        shell32.lib
+        shell32.lib \
+        rpcrt4.lib
 
 $(LOGON_DLLFILE): $(LOGON_DLLOBJS) $(LOGON_DLLLIBS)
        $(DLLGUILINK) $(LOGONLINKFLAGS) -def:afslogon.def $(LOGON_DLLSDKLIBS)
@@ -450,12 +467,14 @@ AFSD_EXELIBS =\
        $(DESTDIR)\lib\afs\mtafsvldb.lib \
        $(DESTDIR)\lib\afs\mtafsint.lib \
        $(DESTDIR)\lib\afsrpc.lib \
+        $(DESTDIR)\lib\afsrxkad.lib \
        $(DESTDIR)\lib\afs\mtafsutil.lib \
        $(DESTDIR)\lib\afsauthent.lib \
        $(DESTDIR)\lib\libafsconf.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afspthread.lib \
        $(DESTDIR)\lib\afsroken.lib \
+        $(DESTDIR)\lib\afshcrypto.lib \
         $(LANAHELPERLIB)
 
 $(AFSD_EXEFILE): $(OUT)\afsd.obj $(AFSDOBJS) $(OUT)\afsd.res  $(RXOBJS) $(AFSD_EXELIBS)
index 00ffa12dda34160f124c65ad1165d35fb9ec182e..516e22c8c2e95472c5e590b9012395535e1e9587 100644 (file)
@@ -60,6 +60,7 @@ BOOL APIENTRY About(HWND, unsigned int, unsigned int, long);
 #include "cm_memmap.h"
 #include "cm_freelance.h"
 #include "cm_performance.h"
+#include "cm_rdr.h"
 #include "afsd_init.h"
 #include "afsd_eventlog.h"
 
index 3db3f32e805336326b66d6891def43c8b408b241..dcf1004ffeac77cea51792477b5367c7a2ca344e 100644 (file)
@@ -103,9 +103,10 @@ BOOL reportSessionStartups = FALSE;
 
 cm_initparams_v1 cm_initParams;
 
-clientchar_t *cm_sysName = 0;
 unsigned int  cm_sysNameCount = 0;
 clientchar_t *cm_sysNameList[MAXNUMSYSNAMES];
+unsigned int  cm_sysName64Count = 0;
+clientchar_t *cm_sysName64List[MAXNUMSYSNAMES];
 
 DWORD TraceOption = 0;
 
@@ -917,12 +918,15 @@ afsd_InitCM(char **reasonP)
     for ( i=0; i < MAXNUMSYSNAMES; i++ ) {
         cm_sysNameList[i] = osi_Alloc(MAXSYSNAME * sizeof(clientchar_t));
         cm_sysNameList[i][0] = '\0';
+        cm_sysName64List[i] = osi_Alloc(MAXSYSNAME * sizeof(clientchar_t));
+        cm_sysName64List[i][0] = '\0';
     }
-    cm_sysName = cm_sysNameList[0];
 
+    /* Process SysName lists from the registry */
     {
         clientchar_t *p, *q;
         clientchar_t * cbuf = (clientchar_t *) buf;
+
         dummyLen = sizeof(buf);
         code = RegQueryValueExW(parmKey, L"SysName", NULL, NULL, (LPBYTE) cbuf, &dummyLen);
         if (code != ERROR_SUCCESS || !cbuf[0]) {
@@ -934,7 +938,7 @@ afsd_InitCM(char **reasonP)
             cm_ClientStrCpy(cbuf, lengthof(buf), _C("x86_win32 i386_w2k i386_nt40"));
 #endif
         }
-        afsi_log("Sys name %S", cbuf);
+        afsi_log("Sys name list: %S", cbuf);
 
         /* breakup buf into individual search string entries */
         for (p = q = cbuf; p < cbuf + dummyLen; p++) {
@@ -944,16 +948,49 @@ afsd_InitCM(char **reasonP)
                 cm_sysNameCount++;
                 do {
                     if (*p == '\0')
-                        goto done_sysname;
+                        goto done_sysname32;
                     p++;
                 } while (*p == '\0' || isspace(*p));
                 q = p;
                 p--;
             }
         }
+      done_sysname32:
+        ;
+
+#ifdef _WIN64
+        /*
+         * If there is a 64-bit list, process it.  Otherwise, we will leave
+         * it undefined which implies that the 32-bit list be used for both.
+         * The 64-bit list is only used for the native file system driver.
+         * The SMB redirector interface does not provide any means of indicating
+         * the source of the request.
+         */
+        dummyLen = sizeof(buf);
+        code = RegQueryValueExW(parmKey, L"SysName64", NULL, NULL, (LPBYTE) cbuf, &dummyLen);
+        if (code == ERROR_SUCCESS && cbuf[0]) {
+            afsi_log("Sys name 64 list: %S", cbuf);
+
+            /* breakup buf into individual search string entries */
+            for (p = q = cbuf; p < cbuf + dummyLen; p++) {
+                if (*p == '\0' || iswspace(*p)) {
+                    memcpy(cm_sysName64List[cm_sysName64Count],q,(p-q) * sizeof(clientchar_t));
+                    cm_sysName64List[cm_sysName64Count][p-q] = '\0';
+                    cm_sysName64Count++;
+                    do {
+                        if (*p == '\0')
+                            goto done_sysname64;
+                        p++;
+                    } while (*p == '\0' || isspace(*p));
+                    q = p;
+                    p--;
+                }
+            }
+        }
+      done_sysname64:
+        ;
+#endif
     }
-  done_sysname:
-    cm_ClientStrCpy(cm_sysName, MAXSYSNAME, cm_sysNameList[0]);
 
     dummyLen = sizeof(cryptall);
     code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
@@ -1527,11 +1564,11 @@ int afsd_InitSMB(char **reasonP, void *aMBfunc)
     }
 
     if ( smb_Enabled ) {
-    /* Do this last so that we don't handle requests before init is done.
-     * Here we initialize the SMB listener.
-     */
-    smb_Init(afsd_logp, smb_UseV3, numSvThreads, aMBfunc);
-    afsi_log("smb_Init complete");
+        /* Do this last so that we don't handle requests before init is done.
+         * Here we initialize the SMB listener.
+         */
+        smb_Init(afsd_logp, smb_UseV3, numSvThreads, aMBfunc);
+        afsi_log("smb_Init complete");
     } else {
         afsi_log("smb_Init skipped");
     }
index 873e6d0211697bf6b98f0031d480e048907aa688..532f9567d94fa5077b62f4068bfabef6e51b5597 100644 (file)
@@ -1327,6 +1327,21 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         /* Notify any volume status handlers that the cache manager has started */
         cm_VolStatus_Service_Started();
 
+        code = RDR_Initialize();
+        RDR_Initialized = !code;
+        afsi_log("RDR_Initialize returned: (code = %d)", code);
+
+        if (RDR_Initialized) {
+            if (cm_sysNameCount)
+                RDR_SysName( AFS_SYSNAME_ARCH_32BIT, cm_sysNameCount, cm_sysNameList );
+#ifdef _WIN64
+            if (cm_sysName64Count)
+                RDR_SysName( AFS_SYSNAME_ARCH_64BIT, cm_sysName64Count, cm_sysName64List );
+            else if (cm_sysNameCount)
+                RDR_SysName( AFS_SYSNAME_ARCH_64BIT, cm_sysNameCount, cm_sysNameList );
+#endif
+        }
+
         /*
          * Set the default for the SMB interface based upon the state of the
          * Redirector interface.
@@ -1464,11 +1479,15 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     DismountGlobalDrives();
     afsi_log("Global Drives dismounted");
 
+    if (RDR_Initialized) {
+        RDR_ShutdownNotify();
+        cm_VolStatus_SetRDRNotifications(FALSE);
+        afsi_log("RDR notified of shutdown");
+    }
+
     smb_Shutdown();
     afsi_log("smb shutdown complete");
 
-    RpcShutdown();
-
     cm_ReleaseAllLocks();
 
     cm_DaemonShutdown();
@@ -1479,8 +1498,15 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
     afsd_ShutdownCM();
 
+    RpcShutdown();
+
     cm_ShutdownMappedMemory();
 
+    if (RDR_Initialized) {
+        RDR_ShutdownFinal();
+        afsi_log("RDR shutdown complete");
+    }
+
     rx_Finalize();
     afsi_log("rx finalization complete");
 
index ccac524d28ba01901e401f4f19e4a9b994d3a476..38f74997d5f05a42181d53455046c96e78f59ea1 100644 (file)
 #include <afs/param.h>
 #include <roken.h>
 
-#include "afslogon.h"
-
 #include <io.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <fcntl.h>
 
 #include <winsock2.h>
+#include <winioctl.h>
+#define SECURITY_WIN32
+#include <sspi.h>
 #include <lm.h>
 #include <nb30.h>
+#include <sddl.h>
+
+#include "afslogon.h"
 
 #include <afs/stds.h>
 #include <afs/pioctl_nt.h>
@@ -810,7 +814,8 @@ UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOu
     return FALSE;
 }  // UnicodeStringToANSI
 
-DWORD APIENTRY NPLogonNotify(
+DWORD APIENTRY
+NPLogonNotify(
        PLUID lpLogonId,
        LPCWSTR lpAuthentInfoType,
        LPVOID lpAuthentInfo,
@@ -850,6 +855,8 @@ DWORD APIENTRY NPLogonNotify(
     int retryInterval;
     int sleepInterval;
 
+    CtxtHandle LogonContext;
+
     /* Are we interactive? */
     interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
 
@@ -952,7 +959,7 @@ DWORD APIENTRY NPLogonNotify(
         /* Get cell name if doing integrated logon.
            We might overwrite this if we are logging into an AD realm and we find out that
            the user's home dir is in some other cell. */
-        DebugEvent("About to call cm_GetRootCellName()");
+        DebugEvent0("About to call cm_GetRootCellName()");
         code = cm_GetRootCellName(cell);
         if (code < 0) {
             DebugEvent0("Unable to obtain Root Cell");
@@ -972,7 +979,8 @@ DWORD APIENTRY NPLogonNotify(
         }
     }
 
-    /* loop until AFS is started. */
+    AFSCreatePAG(lpLogonId);
+
     if (afsWillAutoStart) {
         /*
          * If the service is configured for auto start but hasn't started yet,
@@ -981,12 +989,12 @@ DWORD APIENTRY NPLogonNotify(
         if (!(IsServiceRunning() || IsServiceStartPending()))
             StartTheService();
 
+        /* loop until AFS is started or fails. */
         while ( IsServiceStartPending() ) {
             Sleep(10);
         }
 
         while (IsServiceRunning() && code != KTC_NOCM && code != KTC_NOCMRPC && code != KTC_NOCELL) {
-
             DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
                        opt.LogonOption,afsWillAutoStart);
 
@@ -1004,6 +1012,9 @@ DWORD APIENTRY NPLogonNotify(
            /* if Integrated Logon  */
            if (ISLOGONINTEGRATED(opt.LogonOption))
            {
+                LogonSSP(lpLogonId, &LogonContext);
+                ImpersonateSecurityContext(&LogonContext);
+
                if ( KFW_is_available() ) {
                    SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
                     if (opt.realm) {
@@ -1077,6 +1088,10 @@ DWORD APIENTRY NPLogonNotify(
                    DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
                                code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
                }
+
+                RevertSecurityContext(&LogonContext);
+                DeleteSecurityContext(&LogonContext);
+
                if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
                    for ( ctemp = uname; *ctemp ; ctemp++) {
                        *ctemp = tolower(*ctemp);
@@ -1128,8 +1143,8 @@ DWORD APIENTRY NPLogonNotify(
            Sleep(sleepInterval * 1000);
            retryInterval -= sleepInterval;
        }
+        DebugEvent0("while loop exited");
     }
-    DebugEvent0("while loop exited");
 
     /* remove any kerberos 5 tickets currently held by the SYSTEM account
      * for this user
index 44a0baec537aa869f3749407ab01af2f39bd9e3a..bbac07d0a784b5230eb91e30a3ab0d3c0a72268f 100644 (file)
@@ -26,7 +26,6 @@ SOFTWARE.
 /* We only support VC 1200 and above anyway */
 #pragma once
 
-#include <windows.h>
 #include <objbase.h>
 #include <npapi.h>
 #if (_WIN32_WINNT < 0x0501)
@@ -132,6 +131,10 @@ DWORD GetAdHomePath(char * homePath, size_t homePathLen, PLUID lpLogonId, LogonO
 DWORD QueryAdHomePathFromSid(char * homePath, size_t homePathLen, PSID psid, PWSTR domain);
 BOOL GetLocalShortDomain(PWSTR Domain, DWORD cbDomain);
 
+void AFSCreatePAG(PLUID lpLogonId);
+
+DWORD LogonSSP(PLUID lpLogonId, PCtxtHandle outCtx);
+
 #ifdef __cplusplus
 }
 #endif
index e80848c925399f8fff8663775d9045a41ce36f78..c55c19a8300958c3f95d7892445731bec193fb97 100644 (file)
@@ -45,6 +45,7 @@
 
 #define LOCK_HIERARCHY_IGNORE                    0
 
+#define LOCK_HIERARCHY_RDR_GLOBAL               10
 #define LOCK_HIERARCHY_SMB_STARTED              20
 #define LOCK_HIERARCHY_SMB_LISTENER             30
 #define LOCK_HIERARCHY_SMB_DIRWATCH             40
@@ -87,5 +88,8 @@
 #define LOCK_HIERARCHY_AFSDBSBMT_GLOBAL       1000
 #define LOCK_HIERARCHY_TOKEN_EVENT_GLOBAL     2000
 #define LOCK_HIERARCHY_SYSCFG_GLOBAL          3000
+
+#define LOCK_HIERARCHY_RDR_EXTENTS               0
 #endif /*  OPENAFS_WINNT_AFSD_CM_H */
 
+
index 65e356359c1267be9401ab8a78a8c5e63a66b709..88f882918d5aa8c8e2cb18383e9f9363e6cb60d0 100644 (file)
@@ -338,6 +338,9 @@ void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp)
             aclp->userp = NULL;
             aclp->backp = (struct cm_scache *) 0;
             found = 1;
+            if (RDR_Initialized && cm_HaveCallback(scp))
+                RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                     scp->fid.hash, scp->fileType, AFS_INVALIDATE_CREDS);
             break;
         }
     }
@@ -351,6 +354,7 @@ void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp)
 void
 cm_ResetACLCache(cm_cell_t *cellp, cm_user_t *userp)
 {
+    cm_volume_t *volp, *nextVolp;
     cm_scache_t *scp, *nextScp;
     afs_uint32 hash;
 
@@ -369,6 +373,40 @@ cm_ResetACLCache(cm_cell_t *cellp, cm_user_t *userp)
         }
     }
     lock_ReleaseRead(&cm_scacheLock);
+
+    if (RDR_Initialized) {
+        lock_ObtainRead(&cm_volumeLock);
+        for (hash = 0; hash < cm_data.volumeHashTableSize; hash++) {
+            for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = nextVolp) {
+                nextVolp = volp->vol[RWVOL].nextp;
+                if ((cellp == NULL || cellp->cellID == volp->cellp->cellID) &&
+                    volp->vol[RWVOL].ID) {
+                    lock_ReleaseRead(&cm_volumeLock);
+                    RDR_InvalidateVolume(volp->cellp->cellID, volp->vol[RWVOL].ID, AFS_INVALIDATE_CREDS);
+                    lock_ObtainRead(&cm_volumeLock);
+                }
+            }
+            for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = nextVolp) {
+                nextVolp = volp->vol[ROVOL].nextp;
+                if ((cellp == NULL || cellp->cellID == volp->cellp->cellID) &&
+                    volp->vol[ROVOL].ID) {
+                    lock_ReleaseRead(&cm_volumeLock);
+                    RDR_InvalidateVolume(volp->cellp->cellID, volp->vol[ROVOL].ID, AFS_INVALIDATE_CREDS);
+                    lock_ObtainRead(&cm_volumeLock);
+                }
+            }
+            for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = nextVolp) {
+                nextVolp = volp->vol[BACKVOL].nextp;
+                if ((cellp == NULL || cellp->cellID == volp->cellp->cellID) &&
+                    volp->vol[BACKVOL].ID) {
+                    lock_ReleaseRead(&cm_volumeLock);
+                    RDR_InvalidateVolume(volp->cellp->cellID, volp->vol[BACKVOL].ID, AFS_INVALIDATE_CREDS);
+                    lock_ObtainRead(&cm_volumeLock);
+                }
+            }
+        }
+        lock_ReleaseRead(&cm_volumeLock);
+    }
 }
 
 
index 73d64f8e5fb6429a6a495335b75e004f1568b9f8..d34281e5c79d177dac1ccc93b3d99cfdaf63e893 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <strsafe.h>
 #include <math.h>
+#include <hcrypto\md5.h>
 
 #include "afsd.h"
 #include "cm_memmap.h"
@@ -60,6 +61,10 @@ osi_log_t *buf_logp = NULL;
 /* Global lock protecting hash tables and free lists */
 osi_rwlock_t buf_globalLock;
 
+/* Global lock used to limit the number of RDR Release
+ * Extents requests to one. */
+osi_mutex_t buf_rdrReleaseExtentsLock;
+
 /* ptr to head of the free list (most recently used) and the
  * tail (the guy to remove first).  We use osi_Q* functions
  * to put stuff in buf_freeListp, and maintain the end
@@ -163,11 +168,12 @@ void buf_ReleaseLocked(cm_buf_t *bp, afs_uint32 writeLocked)
             lock_ConvertRToW(&buf_globalLock);
 
         if (bp->refCount == 0 &&
-            !(bp->qFlags & CM_BUF_QINLRU)) {
+            !(bp->qFlags & (CM_BUF_QINLRU|CM_BUF_QREDIR))) {
             osi_QAddH( (osi_queue_t **) &cm_data.buf_freeListp,
                        (osi_queue_t **) &cm_data.buf_freeListEndp,
                        &bp->q);
             _InterlockedOr(&bp->qFlags, CM_BUF_QINLRU);
+            buf_IncrementFreeCount();
         }
 
         if (!writeLocked)
@@ -201,11 +207,12 @@ void buf_Release(cm_buf_t *bp)
     if (refCount == 0) {
         lock_ObtainWrite(&buf_globalLock);
         if (bp->refCount == 0 &&
-            !(bp->qFlags & CM_BUF_QINLRU)) {
+            !(bp->qFlags & (CM_BUF_QINLRU|CM_BUF_QREDIR))) {
             osi_QAddH( (osi_queue_t **) &cm_data.buf_freeListp,
                        (osi_queue_t **) &cm_data.buf_freeListEndp,
                        &bp->q);
             _InterlockedOr(&bp->qFlags, CM_BUF_QINLRU);
+            buf_IncrementFreeCount();
         }
         lock_ReleaseWrite(&buf_globalLock);
     }
@@ -224,13 +231,26 @@ buf_Sync(int quitOnShutdown)
         if (quitOnShutdown && buf_ShutdownFlag)
             break;
 
+        /*
+         * If the buffer is held be the redirector we must fetch
+         * it back in order to determine whether or not it is in
+         * fact dirty.
+         */
+        if (bp->qFlags & CM_BUF_QREDIR) {
+            osi_Log1(buf_logp,"buf_Sync buffer held by redirector bp 0x%p", bp);
+
+            /* Request single buffer from the redirector */
+            buf_RDRShakeAnExtentFree(bp, &req);
+        }
+
         lock_ReleaseRead(&buf_globalLock);
-        /* all dirty buffers are held when they are added to the
-        * dirty list.  No need for an additional hold.
-        */
+        /*
+         * all dirty buffers are held when they are added to the
+         * dirty list.  No need for an additional hold.
+         */
         lock_ObtainMutex(&bp->mx);
 
-        if (bp->flags & CM_BUF_DIRTY && !(bp->qFlags & CM_BUF_QREDIR)) {
+        if ((bp->flags & CM_BUF_DIRTY)) {
             /* start cleaning the buffer; don't touch log pages since
              * the log code counts on knowing exactly who is writing
              * a log page at any given instant.
@@ -339,7 +359,7 @@ long
 buf_ValidateBuffers(void)
 {
     cm_buf_t * bp, *bpf, *bpa, *bpb;
-    afs_uint64 countb = 0, countf = 0, counta = 0;
+    afs_uint64 countb = 0, countf = 0, counta = 0, countr = 0;
 
     if (cm_data.buf_freeListp == NULL && cm_data.buf_freeListEndp != NULL ||
          cm_data.buf_freeListp != NULL && cm_data.buf_freeListEndp == NULL) {
@@ -380,6 +400,20 @@ buf_ValidateBuffers(void)
         }
     }
 
+    for ( bp = cm_data.buf_redirListp; bp; bp = (cm_buf_t *) osi_QNext(&bp->q)) {
+        if (!(bp->qFlags & CM_BUF_QREDIR)) {
+            afsi_log("CM_BUF_QREDIR not set on cm_buf_t in buf_redirListp");
+            fprintf(stderr, "CM_BUF_QREDIR not set on cm_buf_t in buf_redirListp");
+            return -9;
+        }
+        countr++;
+        if (countr > cm_data.buf_nbuffers) {
+            afsi_log("cm_ValidateBuffers failure: countr > cm_data.buf_nbuffers");
+            fprintf(stderr, "cm_ValidateBuffers failure: countr > cm_data.buf_nbuffers\n");
+            return -10;
+        }
+    }
+
     for (bp = cm_data.buf_allp; bp; bp=bp->allp) {
         if (bp->magic != CM_BUF_MAGIC) {
             afsi_log("cm_ValidateBuffers failure: bp->magic != CM_BUF_MAGIC");
@@ -447,6 +481,7 @@ long buf_Init(int newFile, cm_buf_ops_t *opsp, afs_uint64 nbuffers)
     if (osi_Once(&once)) {
         /* initialize global locks */
         lock_InitializeRWLock(&buf_globalLock, "Global buffer lock", LOCK_HIERARCHY_BUF_GLOBAL);
+        lock_InitializeMutex(&buf_rdrReleaseExtentsLock, "RDR Release Extents lock", LOCK_HIERARCHY_RDR_EXTENTS);
 
         if ( newFile ) {
             /* remember this for those who want to reset it */
@@ -483,6 +518,7 @@ long buf_Init(int newFile, cm_buf_ops_t *opsp, afs_uint64 nbuffers)
                            (osi_queue_t **) &cm_data.buf_freeListEndp,
                            &bp->q);
                 _InterlockedOr(&bp->qFlags, CM_BUF_QINLRU);
+                buf_IncrementFreeCount();
                 lock_InitializeMutex(&bp->mx, "Buffer mutex", LOCK_HIERARCHY_BUFFER);
 
                 /* grab appropriate number of bytes from aligned zone */
@@ -508,8 +544,49 @@ long buf_Init(int newFile, cm_buf_ops_t *opsp, afs_uint64 nbuffers)
                 bp->waitCount = 0;
                 bp->waitRequests = 0;
                 _InterlockedAnd(&bp->flags, ~CM_BUF_WAITING);
+                bp->error = 0;
+                if (bp->qFlags & CM_BUF_QREDIR) {
+                    /*
+                     * extent was not returned by the file system driver.
+                     * clean up the mess.
+                     */
+                    bp->dataVersion = CM_BUF_VERSION_BAD;
+                    _InterlockedAnd(&bp->qFlags, ~CM_BUF_QREDIR);
+                    osi_QRemoveHT( (osi_queue_t **) &cm_data.buf_redirListp,
+                                   (osi_queue_t **) &cm_data.buf_redirListEndp,
+                                   &bp->q);
+                    buf_DecrementRedirCount();
+                    bp->redirq.nextp = bp->redirq.prevp = NULL;
+                    bp->redirLastAccess = 0;
+                    bp->redirReleaseRequested = 0;
+                    buf_Release(bp);
+                }
                 bp++;
             }
+
+            /*
+             * There should be nothing left in cm_data.buf_redirListp
+             * but double check just to be sure.
+             */
+            for ( bp = cm_data.buf_redirListp;
+                  bp;
+                  bp = cm_data.buf_redirListp)
+            {
+                /*
+                 * extent was not returned by the file system driver.
+                 * clean up the mess.
+                 */
+                bp->dataVersion = CM_BUF_VERSION_BAD;
+                _InterlockedAnd(&bp->qFlags, ~CM_BUF_QREDIR);
+                osi_QRemoveHT( (osi_queue_t **) &cm_data.buf_redirListp,
+                               (osi_queue_t **) &cm_data.buf_redirListEndp,
+                               &bp->q);
+                buf_DecrementRedirCount();
+                bp->redirq.nextp = bp->redirq.prevp = NULL;
+                bp->redirLastAccess = 0;
+                bp->redirReleaseRequested = 0;
+                buf_Release(bp);
+            }
         }
 
 #ifdef TESTING
@@ -868,6 +945,8 @@ void buf_Recycle(cm_buf_t *bp)
 
     osi_assertx(bp->magic == CM_BUF_MAGIC, "invalid cm_buf_t magic");
 
+    osi_assertx(!(bp->qFlags & CM_BUF_QREDIR), "can't recycle redir held buffers");
+
     /* if we get here, we know that the buffer still has a 0 ref count,
      * and that it is clean and has no currently pending I/O.  This is
      * the dude to return.
@@ -924,6 +1003,253 @@ void buf_Recycle(cm_buf_t *bp)
     bp->dataVersion = CM_BUF_VERSION_BAD;      /* unknown so far */
 }
 
+
+/*
+ * buf_RDRShakeAnExtentFree
+ * called with buf_globalLock read locked
+ */
+afs_uint32
+buf_RDRShakeAnExtentFree(cm_buf_t *rbp, cm_req_t *reqp)
+{
+    afs_uint32 code = 0;
+    LARGE_INTEGER heldExtents = {0,0};
+    AFSFileExtentCB extentList[1];
+    DWORD extentCount = 0;
+    BOOL locked = FALSE;
+
+    if (!(rbp->qFlags & CM_BUF_QREDIR))
+        return 0;
+
+    lock_ReleaseRead(&buf_globalLock);
+
+    if (!lock_TryMutex(&buf_rdrReleaseExtentsLock)) {
+        osi_Log0(afsd_logp, "Waiting for prior RDR_RequestExtentRelease request to complete");
+        if (reqp->flags & CM_REQ_NORETRY) {
+            code = CM_ERROR_WOULDBLOCK;
+            goto done;
+        }
+
+        lock_ObtainMutex(&buf_rdrReleaseExtentsLock);
+    }
+
+    extentList[0].Flags = 0;
+    extentList[0].Length = cm_data.blockSize;
+    extentList[0].FileOffset.QuadPart = rbp->offset.QuadPart;
+    extentList[0].CacheOffset.QuadPart = rbp->datap - cm_data.baseAddress;
+    extentCount = 1;
+
+    code = RDR_RequestExtentRelease(&rbp->fid, heldExtents, extentCount, extentList);
+
+    lock_ReleaseMutex(&buf_rdrReleaseExtentsLock);
+
+  done:
+    lock_ObtainRead(&buf_globalLock);
+    return code;
+}
+
+/*
+ * buf_RDRShakeFileExtentsFree
+ * requests all extents held by the redirector to be returned for
+ * the specified cm_scache_t.  This function is called with no
+ * locks held.
+ */
+afs_uint32
+buf_RDRShakeFileExtentsFree(cm_scache_t *rscp, cm_req_t *reqp)
+{
+    afs_uint32 code = 0;
+    afs_uint64 n_redir = 0;
+
+    if (!lock_TryMutex(&buf_rdrReleaseExtentsLock)) {
+        osi_Log0(afsd_logp, "Waiting for prior RDR_RequestExtentRelease request to complete");
+        if (reqp->flags & CM_REQ_NORETRY)
+            return CM_ERROR_WOULDBLOCK;
+
+        lock_ObtainMutex(&buf_rdrReleaseExtentsLock);
+    }
+
+    for ( code = CM_ERROR_RETRY; code == CM_ERROR_RETRY; ) {
+        LARGE_INTEGER heldExtents = {0,0};
+        AFSFileExtentCB extentList[1024];
+        DWORD extentCount = 0;
+        cm_buf_t *srbp;
+        time_t now;
+
+        /* only retry if a call to RDR_RequestExtentRelease says to */
+        code = 0;
+        lock_ObtainWrite(&buf_globalLock);
+
+        if (rscp->redirBufCount == 0)
+        {
+            lock_ReleaseWrite(&buf_globalLock);
+            break;
+        }
+
+        time(&now);
+        for ( srbp = redirq_to_cm_buf_t(rscp->redirQueueT);
+              srbp;
+              srbp = ((code == 0 && extentCount == 0) ? redirq_to_cm_buf_t(rscp->redirQueueT) :
+                       redirq_to_cm_buf_t(osi_QPrev(&srbp->redirq))))
+        {
+            extentList[extentCount].Flags = 0;
+            extentList[extentCount].Length = cm_data.blockSize;
+            extentList[extentCount].FileOffset.QuadPart = srbp->offset.QuadPart;
+            extentList[extentCount].CacheOffset.QuadPart = srbp->datap - cm_data.baseAddress;
+            srbp->redirReleaseRequested = now;
+            extentCount++;
+
+            if (extentCount == 1024) {
+                lock_ReleaseWrite(&buf_globalLock);
+                heldExtents.QuadPart = cm_data.buf_redirCount;
+                code = RDR_RequestExtentRelease(&rscp->fid, heldExtents, extentCount, extentList);
+                if (code) {
+                    if (code == CM_ERROR_RETRY) {
+                        /*
+                         * The redirector either is not holding the extents or cannot let them
+                         * go because they are otherwise in use.  At the moment, do nothing.
+                         */
+                    } else
+                        break;
+                }
+                extentCount = 0;
+                lock_ObtainWrite(&buf_globalLock);
+            }
+        }
+        lock_ReleaseWrite(&buf_globalLock);
+
+        if (code == 0 && extentCount > 0) {
+            heldExtents.QuadPart = cm_data.buf_redirCount;
+            code = RDR_RequestExtentRelease(&rscp->fid, heldExtents, extentCount, extentList);
+        }
+
+        if ((code == CM_ERROR_RETRY) && (reqp->flags & CM_REQ_NORETRY)) {
+            code = CM_ERROR_WOULDBLOCK;
+            break;
+        }
+    }
+    lock_ReleaseMutex(&buf_rdrReleaseExtentsLock);
+    return code;
+}
+
+afs_uint32
+buf_RDRShakeSomeExtentsFree(cm_req_t *reqp, afs_uint32 oneFid, afs_uint32 minage)
+{
+    afs_uint32 code = 0;
+
+    if (!lock_TryMutex(&buf_rdrReleaseExtentsLock)) {
+        if (reqp->flags & CM_REQ_NORETRY)
+            return CM_ERROR_WOULDBLOCK;
+
+        osi_Log0(afsd_logp, "Waiting for prior RDR_RequestExtentRelease request to complete");
+        lock_ObtainMutex(&buf_rdrReleaseExtentsLock);
+    }
+
+    for ( code = CM_ERROR_RETRY; code == CM_ERROR_RETRY; ) {
+        LARGE_INTEGER heldExtents;
+        AFSFileExtentCB extentList[1024];
+        DWORD extentCount = 0;
+        cm_buf_t *rbp, *srbp;
+        cm_scache_t *rscp;
+        time_t now;
+        BOOL locked = FALSE;
+
+        /* only retry if a call to RDR_RequestExtentRelease says to */
+        code = 0;
+        lock_ObtainWrite(&buf_globalLock);
+        locked = TRUE;
+
+        for ( rbp = cm_data.buf_redirListEndp;
+              code == 0 && rbp && (!oneFid || extentCount == 0);
+              rbp = (cm_buf_t *) osi_QPrev(&rbp->q))
+        {
+            if (!oneFid)
+                extentCount = 0;
+
+            if (rbp->redirLastAccess >= rbp->redirReleaseRequested) {
+                rscp = cm_FindSCache(&rbp->fid);
+                if (!rscp)
+                    continue;
+
+                time(&now);
+                for ( srbp = redirq_to_cm_buf_t(rscp->redirQueueT);
+                      srbp && extentCount < 1024;
+                      srbp = redirq_to_cm_buf_t(osi_QPrev(&srbp->redirq)))
+                {
+                    /*
+                     * Do not request a release if we have already done so
+                     * or if the extent was delivered to windows less than
+                     * 'minage' seconds ago.
+                     */
+                    if (srbp->redirLastAccess >= srbp->redirReleaseRequested &&
+                         srbp->redirLastAccess < now - minage) {
+                        extentList[extentCount].Flags = 0;
+                        extentList[extentCount].Length = cm_data.blockSize;
+                        extentList[extentCount].FileOffset.QuadPart = srbp->offset.QuadPart;
+                        extentList[extentCount].CacheOffset.QuadPart = srbp->datap - cm_data.baseAddress;
+                        srbp->redirReleaseRequested = now;
+                        extentCount++;
+                    }
+                }
+                cm_ReleaseSCache(rscp);
+            }
+
+            if ( !oneFid && extentCount > 0) {
+                if (locked) {
+                    lock_ReleaseWrite(&buf_globalLock);
+                    locked = FALSE;
+                }
+                heldExtents.QuadPart = cm_data.buf_redirCount;
+                code = RDR_RequestExtentRelease(&rbp->fid, heldExtents, extentCount, extentList);
+            }
+            if (!locked) {
+                lock_ObtainWrite(&buf_globalLock);
+                locked = TRUE;
+            }
+        }
+        if (locked)
+            lock_ReleaseWrite(&buf_globalLock);
+        if (code == 0) {
+            if (oneFid) {
+                heldExtents.QuadPart = cm_data.buf_redirCount;
+                if (rbp && extentCount)
+                    code = RDR_RequestExtentRelease(&rbp->fid, heldExtents, extentCount, extentList);
+                else
+                    code = RDR_RequestExtentRelease(NULL, heldExtents, 1024, NULL);
+            } else {
+                code = 0;
+            }
+        }
+
+        if ((code == CM_ERROR_RETRY) && (reqp->flags & CM_REQ_NORETRY)) {
+            code = CM_ERROR_WOULDBLOCK;
+            break;
+        }
+    }
+    lock_ReleaseMutex(&buf_rdrReleaseExtentsLock);
+    return code;
+}
+
+/* returns 0 if the buffer does not exist, and non-0 if it does */
+static long
+buf_ExistsLocked(struct cm_scache *scp, osi_hyper_t *offsetp)
+{
+    cm_buf_t *bp;
+
+    if (bp = buf_FindLocked(&scp->fid, offsetp)) {
+        /* Do not call buf_ReleaseLocked() because we
+         * do not want to allow the buffer to be added
+         * to the free list.
+         */
+        afs_int32 refCount = InterlockedDecrement(&bp->refCount);
+#ifdef DEBUG_REFCOUNT
+        osi_Log2(afsd_logp,"buf_ExistsLocked bp 0x%p ref %d", bp, refCount);
+        afsi_log("%s:%d buf_ExistsLocked bp 0x%p, ref %d", __FILE__, __LINE__, bp, refCount);
+#endif
+        return CM_BUF_EXISTS;
+    }
+
+    return 0;
+}
+
 /* recycle a buffer, removing it from the free list, hashing in its new identity
  * and returning it write-locked so that no one can use it.  Called without
  * any locks held, and can return an error if it loses the race condition and
@@ -940,6 +1266,7 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
     cm_buf_t *bp;      /* buffer we're dealing with */
     cm_buf_t *nextBp;  /* next buffer in file hash chain */
     afs_uint32 i;      /* temp */
+    afs_uint64 n_bufs, n_nonzero, n_busy, n_dirty, n_own;
 
 #ifdef TESTING
     buf_ValidateBufQueues();
@@ -947,24 +1274,19 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
 
     while(1) {
       retry:
+        n_bufs = 0;
+        n_nonzero = 0;
+        n_own = 0;
+        n_busy = 0;
+        n_dirty = 0;
+
         lock_ObtainRead(&scp->bufCreateLock);
         lock_ObtainWrite(&buf_globalLock);
         /* check to see if we lost the race */
-        if (scp) {
-            if (bp = buf_FindLocked(&scp->fid, offsetp)) {
-               /* Do not call buf_ReleaseLocked() because we
-                * do not want to allow the buffer to be added
-                * to the free list.
-                */
-                afs_int32 refCount = InterlockedDecrement(&bp->refCount);
-#ifdef DEBUG_REFCOUNT
-                osi_Log2(afsd_logp,"buf_GetNewLocked bp 0x%p ref %d", bp, refCount);
-                afsi_log("%s:%d buf_GetNewLocked bp 0x%p, ref %d", __FILE__, __LINE__, bp, refCount);
-#endif
-                lock_ReleaseWrite(&buf_globalLock);
-                lock_ReleaseRead(&scp->bufCreateLock);
-                return CM_BUF_EXISTS;
-            }
+        if (buf_ExistsLocked(scp, offsetp)) {
+            lock_ReleaseWrite(&buf_globalLock);
+            lock_ReleaseRead(&scp->bufCreateLock);
+            return CM_BUF_EXISTS;
         }
 
        /* does this fix the problem below?  it's a simple solution. */
@@ -972,6 +1294,10 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
        {
            lock_ReleaseWrite(&buf_globalLock);
             lock_ReleaseRead(&scp->bufCreateLock);
+
+            if ( RDR_Initialized )
+                goto rdr_release;
+
            osi_Log0(afsd_logp, "buf_GetNewLocked: Free Buffer List is empty - sleeping 200ms");
            Sleep(200);
            goto retry;
@@ -989,28 +1315,30 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
          * starting cleaning I/O for those which are dirty.  If we find
          * a clean buffer, we rehash it, lock it and return it.
          */
-        for(bp = cm_data.buf_freeListEndp; bp; bp=(cm_buf_t *) osi_QPrev(&bp->q)) {
+        for (bp = cm_data.buf_freeListEndp; bp; bp=(cm_buf_t *) osi_QPrev(&bp->q)) {
+            n_bufs++;
+
             /* check to see if it really has zero ref count.  This
              * code can bump refcounts, at least, so it may not be
              * zero.
              */
-            if (bp->refCount > 0)
+            if (bp->refCount > 0) {
+                n_nonzero++;
                 continue;
+            }
 
             /* we don't have to lock buffer itself, since the ref
              * count is 0 and we know it will stay zero as long as
              * we hold the global lock.
              */
 
-            /* Don't recycle a buffer held by the redirector. */
-            if (bp->qFlags & CM_BUF_QREDIR)
-                continue;
-
             /* don't recycle someone in our own chunk */
             if (!cm_FidCmp(&bp->fid, &scp->fid)
                  && (bp->offset.LowPart & (-cm_chunkSize))
-                 == (offsetp->LowPart & (-cm_chunkSize)))
+                 == (offsetp->LowPart & (-cm_chunkSize))) {
+                n_own++;
                 continue;
+            }
 
             /* if this page is being filled (!) or cleaned, see if
              * the I/O has completed.  If not, skip it, otherwise
@@ -1021,10 +1349,17 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
                  * holding the big lock?  Watch for contention
                  * here.
                  */
+                n_busy++;
                 continue;
             }
 
             if (bp->flags & CM_BUF_DIRTY) {
+                n_dirty++;
+
+                /* leave the buffer alone if held by the redirector */
+                if (bp->qFlags & CM_BUF_QREDIR)
+                    continue;
+
                 /* if the buffer is dirty, start cleaning it and
                  * move on to the next buffer.  We do this with
                  * just the lock required to minimize contention
@@ -1047,9 +1382,28 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
 
                 /* now put it back and go around again */
                 buf_Release(bp);
-                goto retry;
+
+                /* but first obtain the locks we gave up
+                 * before the buf_CleanAsync() call */
+                lock_ObtainRead(&scp->bufCreateLock);
+                lock_ObtainWrite(&buf_globalLock);
+
+                /*
+                 * Since we dropped the locks we need to verify that
+                 * another thread has not allocated the buffer for us.
+                 */
+                if (buf_ExistsLocked(scp, offsetp)) {
+                    lock_ReleaseWrite(&buf_globalLock);
+                    lock_ReleaseRead(&scp->bufCreateLock);
+                    return CM_BUF_EXISTS;
+                }
+                continue;
             }
 
+            osi_Log3(afsd_logp, "buf_GetNewLocked: scp 0x%p examined %u buffers before recycling bufp 0x%p",
+                     scp, n_bufs, bp);
+            osi_Log4(afsd_logp, "... nonzero %u; own %u; busy %u; dirty %u", n_nonzero, n_own, n_busy, n_dirty);
+
             /* if we get here, we know that the buffer still has a 0
              * ref count, and that it is clean and has no currently
              * pending I/O.  This is the dude to return.
@@ -1093,6 +1447,7 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
                            (osi_queue_t **) &cm_data.buf_freeListEndp,
                            &bp->q);
             _InterlockedAnd(&bp->qFlags, ~CM_BUF_QINLRU);
+            buf_DecrementFreeCount();
 
             /* prepare to return it.  Give it a refcount */
             bp->refCount = 1;
@@ -1122,7 +1477,23 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req
         } /* for all buffers in lru queue */
         lock_ReleaseWrite(&buf_globalLock);
         lock_ReleaseRead(&scp->bufCreateLock);
-       osi_Log0(afsd_logp, "buf_GetNewLocked: Free Buffer List has no buffers with a zero refcount - sleeping 100ms");
+
+       osi_Log1(afsd_logp, "buf_GetNewLocked: Free Buffer List has %u buffers none free", n_bufs);
+        osi_Log4(afsd_logp, "... nonzero %u; own %u; busy %u; dirty %u", n_nonzero, n_own, n_busy, n_dirty);
+
+        if (RDR_Initialized) {
+            afs_uint32 code;
+          rdr_release:
+            code = buf_RDRShakeSomeExtentsFree(reqp, TRUE, 2 /* seconds */);
+            switch (code) {
+            case CM_ERROR_RETRY:
+            case 0:
+                goto retry;
+            case CM_ERROR_WOULDBLOCK:
+                return CM_ERROR_WOULDBLOCK;
+            }
+        }
+
        Sleep(100);             /* give some time for a buffer to be freed */
     }  /* while loop over everything */
     /* not reached */
@@ -1215,6 +1586,8 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *reqp, cm_buf
 
         if (code != 0) {
             /* failure or queued */
+
+            /* unless cm_BufRead() is altered, this path cannot be hit */
             if (code != ERROR_IO_PENDING) {
                 bp->error = code;
                 _InterlockedOr(&bp->flags, CM_BUF_ERROR);
@@ -1269,6 +1642,7 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *reqp, cm_buf
                        (osi_queue_t **) &cm_data.buf_freeListEndp,
                        &bp->q);
         _InterlockedAnd(&bp->qFlags, ~CM_BUF_QINLRU);
+        buf_DecrementFreeCount();
     }
     lock_ReleaseWrite(&buf_globalLock);
 
@@ -1280,30 +1654,6 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *reqp, cm_buf
     return 0;
 }
 
-/* count # of elements in the free list;
- * we don't bother doing the proper locking for accessing dataVersion or flags
- * since it is a pain, and this is really just an advisory call.  If you need
- * to do better at some point, rewrite this function.
- */
-long buf_CountFreeList(void)
-{
-    long count;
-    cm_buf_t *bufp;
-
-    count = 0;
-    lock_ObtainRead(&buf_globalLock);
-    for(bufp = cm_data.buf_freeListp; bufp; bufp = (cm_buf_t *) osi_QNext(&bufp->q)) {
-        /* if the buffer doesn't have an identity, or if the buffer
-         * has been invalidate (by having its DV stomped upon), then
-         * count it as free, since it isn't really being utilized.
-         */
-        if (!(bufp->qFlags & CM_BUF_QINHASH) || bufp->dataVersion == CM_BUF_VERSION_BAD)
-            count++;
-    }
-    lock_ReleaseRead(&buf_globalLock);
-    return count;
-}
-
 /* clean a buffer synchronously */
 afs_uint32 buf_CleanAsync(cm_scache_t *scp, cm_buf_t *bp, cm_req_t *reqp, afs_uint32 flags, afs_uint32 *pisdirty)
 {
@@ -1375,7 +1725,14 @@ void buf_SetDirty(cm_buf_t *bp, cm_req_t *reqp, afs_uint32 offset, afs_uint32 le
         bp->dirty_offset = offset;
         bp->dirty_length = length;
 
-        /* and add to the dirty list.
+        /*
+         * if the request is not from the afs redirector,
+         * add to the dirty list.  The redirector interface ensures
+         * that a background store operation is queued for each and
+         * every dirty extent that is released.  Therefore, the
+         * buf_IncrSyncer thread is not required to ensure that
+         * dirty buffers are written to the file server.
+         *
          * we obtain a hold on the buffer for as long as it remains
          * in the list.  buffers are only removed from the list by
          * the buf_IncrSyncer function regardless of when else the
@@ -1385,19 +1742,21 @@ void buf_SetDirty(cm_buf_t *bp, cm_req_t *reqp, afs_uint32 offset, afs_uint32 le
          * elsewhere, never add to the dirty list if the buffer is
          * already there.
          */
-        lock_ObtainWrite(&buf_globalLock);
-        if (!(bp->qFlags & CM_BUF_QINDL)) {
-            buf_HoldLocked(bp);
-            if (!cm_data.buf_dirtyListp) {
-                cm_data.buf_dirtyListp = cm_data.buf_dirtyListEndp = bp;
-            } else {
-                cm_data.buf_dirtyListEndp->dirtyp = bp;
-                cm_data.buf_dirtyListEndp = bp;
+        if (!(reqp->flags & CM_REQ_SOURCE_REDIR)) {
+            lock_ObtainWrite(&buf_globalLock);
+            if (!(bp->qFlags & CM_BUF_QINDL)) {
+                buf_HoldLocked(bp);
+                if (!cm_data.buf_dirtyListp) {
+                    cm_data.buf_dirtyListp = cm_data.buf_dirtyListEndp = bp;
+                } else {
+                    cm_data.buf_dirtyListEndp->dirtyp = bp;
+                    cm_data.buf_dirtyListEndp = bp;
+                }
+                bp->dirtyp = NULL;
+                _InterlockedOr(&bp->qFlags, CM_BUF_QINDL);
             }
-            bp->dirtyp = NULL;
-            _InterlockedOr(&bp->qFlags, CM_BUF_QINDL);
+            lock_ReleaseWrite(&buf_globalLock);
         }
-        lock_ReleaseWrite(&buf_globalLock);
     }
 
     /* and record the last writer */
@@ -1438,6 +1797,13 @@ long buf_CleanAndReset(void)
     lock_ObtainRead(&buf_globalLock);
     for(i=0; i<cm_data.buf_hashSize; i++) {
         for(bp = cm_data.buf_scacheHashTablepp[i]; bp; bp = bp->hashp) {
+            if (bp->qFlags & CM_BUF_QREDIR) {
+                osi_Log1(buf_logp,"buf_CleanAndReset buffer held by redirector bp 0x%p", bp);
+
+                /* Request single extent from the redirector */
+                buf_RDRShakeAnExtentFree(bp, &req);
+            }
+
             if ((bp->flags & CM_BUF_DIRTY) == CM_BUF_DIRTY) {
                 buf_HoldLocked(bp);
                 lock_ReleaseRead(&buf_globalLock);
@@ -1547,6 +1913,7 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
 
     buf_HoldLocked(bufp);
     lock_ReleaseRead(&buf_globalLock);
+
     while (bufp) {
         lock_ObtainMutex(&bufp->mx);
 
@@ -1585,7 +1952,29 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
              */
             if (LargeIntegerLessThanOrEqualTo(*sizep, bufp->offset)) {
                 /* truncating the entire page */
+                if (reqp->flags & CM_REQ_SOURCE_REDIR) {
+                    /*
+                     * Implicitly clear the redirector flag
+                     * and release the matching hold.
+                     */
+                    if (bufp->qFlags & CM_BUF_QREDIR) {
+                        osi_Log4(buf_logp,"buf_Truncate taking from file system bufp 0x%p vno 0x%x foffset 0x%x:%x",
+                                 bufp, bufp->fid.vnode, bufp->offset.HighPart, bufp->offset.LowPart);
+                        lock_ObtainWrite(&buf_globalLock);
+                        if (bufp->qFlags & CM_BUF_QREDIR) {
+                            buf_RemoveFromRedirQueue(scp, bufp);
+                            buf_ReleaseLocked(bufp, TRUE);
+                        }
+                        lock_ReleaseWrite(&buf_globalLock);
+                    }
+                } else {
+                    if (RDR_Initialized)
+                        RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+                                             scp->fid.unique, scp->fid.hash,
+                                             scp->fileType, AFS_INVALIDATE_SMB);
+                }
                 _InterlockedAnd(&bufp->flags, ~CM_BUF_DIRTY);
+                bufp->error = 0;
                 bufp->dirty_offset = 0;
                 bufp->dirty_length = 0;
                 bufp->dataVersion = CM_BUF_VERSION_BAD;        /* known bad */
@@ -1701,15 +2090,17 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
             /* actually, we only know that buffer is clean if ref
              * count is 1, since we don't have buffer itself locked.
              */
-            if (!(bp->flags & CM_BUF_DIRTY)) {
+            if (!(bp->flags & CM_BUF_DIRTY) && !(bp->qFlags & CM_BUF_QREDIR)) {
                 lock_ObtainWrite(&buf_globalLock);
-                if (bp->refCount == 1) {       /* bp is held above */
-                    nbp = bp->fileHashp;
-                    if (nbp)
-                        buf_HoldLocked(nbp);
-                    buf_ReleaseLocked(bp, TRUE);
-                    didRelease = 1;
-                    buf_Recycle(bp);
+                if (!(bp->flags & CM_BUF_DIRTY) && !(bp->qFlags & CM_BUF_QREDIR)) {
+                    if (bp->refCount == 1) {   /* bp is held above */
+                        nbp = bp->fileHashp;
+                        if (nbp)
+                            buf_HoldLocked(nbp);
+                        buf_ReleaseLocked(bp, TRUE);
+                        didRelease = 1;
+                        buf_Recycle(bp);
+                    }
                 }
                 lock_ReleaseWrite(&buf_globalLock);
             }
@@ -1774,6 +2165,11 @@ long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
     cm_buf_t *nbp;             /* next one */
     afs_uint32 i;
 
+    if (RDR_Initialized && scp->redirBufCount > 0) {
+        /* Retrieve all extents for this file from the redirector */
+        buf_RDRShakeFileExtentsFree(scp, reqp);
+    }
+
     i = BUF_FILEHASH(&scp->fid);
 
     lock_ObtainRead(&buf_globalLock);
@@ -1784,8 +2180,22 @@ long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
     for (; bp; bp = nbp) {
         /* clean buffer synchronously */
         if (cm_FidCmp(&bp->fid, &scp->fid) == 0) {
+            /*
+             * If the buffer is held by the redirector we must fetch
+             * it back in order to determine whether or not it is in
+             * fact dirty.
+             */
+            lock_ObtainRead(&buf_globalLock);
+            if (bp->qFlags & CM_BUF_QREDIR) {
+                osi_Log1(buf_logp,"buf_CleanVnode buffer held by redirector bp 0x%p", bp);
+
+                /* Retrieve single extent from the redirector */
+                buf_RDRShakeAnExtentFree(bp, reqp);
+            }
+            lock_ReleaseRead(&buf_globalLock);
+
             lock_ObtainMutex(&bp->mx);
-            if (bp->flags & CM_BUF_DIRTY) {
+            if ((bp->flags & CM_BUF_DIRTY)) {
                 if (userp && userp != bp->userp) {
                     cm_HoldUser(userp);
                     if (bp->userp)
@@ -1992,13 +2402,84 @@ long buf_DirtyBuffersExist(cm_fid_t *fidp)
     cm_buf_t *bp;
     afs_uint32 bcount = 0;
     afs_uint32 i;
+    long found = 0;
 
     i = BUF_FILEHASH(fidp);
 
+    lock_ObtainRead(&buf_globalLock);
     for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp=bp->fileHashp, bcount++) {
-       if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY))
-           return 1;
+       if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY)) {
+           found = 1;
+            break;
+        }
     }
+    lock_ReleaseRead(&buf_globalLock);
+    return 0;
+}
+
+long buf_RDRBuffersExist(cm_fid_t *fidp)
+{
+    cm_buf_t *bp;
+    afs_uint32 bcount = 0;
+    afs_uint32 i;
+    long found = 0;
+
+    if (!RDR_Initialized)
+        return 0;
+
+    i = BUF_FILEHASH(fidp);
+
+    lock_ObtainRead(&buf_globalLock);
+    for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp=bp->fileHashp, bcount++) {
+       if (!cm_FidCmp(fidp, &bp->fid) && (bp->qFlags & CM_BUF_QREDIR)) {
+           found = 1;
+            break;
+        }
+    }
+    lock_ReleaseRead(&buf_globalLock);
+    return 0;
+}
+
+long buf_ClearRDRFlag(cm_scache_t *scp, char *reason)
+{
+    cm_fid_t *fidp = &scp->fid;
+    cm_buf_t *bp;
+    afs_uint32 bcount = 0;
+    afs_uint32 i;
+
+    i = BUF_FILEHASH(fidp);
+
+    lock_ObtainWrite(&scp->rw);
+    lock_ObtainRead(&buf_globalLock);
+    for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp=bp->fileHashp, bcount++) {
+       if (!cm_FidCmp(fidp, &bp->fid) && (bp->qFlags & CM_BUF_QREDIR)) {
+            lock_ConvertRToW(&buf_globalLock);
+            if (bp->qFlags & CM_BUF_QREDIR) {
+                osi_Log4(buf_logp,"buf_ClearRDRFlag taking from file system bp 0x%p vno 0x%x foffset 0x%x:%x",
+                          bp, bp->fid.vnode, bp->offset.HighPart, bp->offset.LowPart);
+                buf_RemoveFromRedirQueue(scp, bp);
+                buf_ReleaseLocked(bp, TRUE);
+            }
+            lock_ConvertWToR(&buf_globalLock);
+        }
+    }
+
+    /* Confirm that there are none left */
+    lock_ConvertRToW(&buf_globalLock);
+    for ( bp = redirq_to_cm_buf_t(scp->redirQueueT);
+          bp;
+          bp = redirq_to_cm_buf_t(scp->redirQueueT))
+    {
+        if (bp->qFlags & CM_BUF_QREDIR) {
+            osi_Log4(buf_logp,"buf_ClearRDRFlag taking from file system bufp 0x%p vno 0x%x foffset 0x%x:%x",
+                      bp, bp->fid.vnode, bp->offset.HighPart, bp->offset.LowPart);
+            buf_RemoveFromRedirQueue(scp, bp);
+            buf_ReleaseLocked(bp, TRUE);
+        }
+
+    }
+    lock_ReleaseWrite(&buf_globalLock);
+    lock_ReleaseWrite(&scp->rw);
     return 0;
 }
 
@@ -2032,3 +2513,132 @@ long buf_CleanDirtyBuffers(cm_scache_t *scp)
     return 0;
 }
 #endif
+
+/*
+ * The following routines will not be used on a
+ * regular basis but are very useful in a variety
+ * of scenarios when debugging data corruption.
+ */
+const char *
+buf_HexCheckSum(cm_buf_t * bp)
+{
+    int i, k;
+    static char buf[33];
+    static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+    for (i=0;i<16;i++) {
+        k = bp->md5cksum[i];
+
+        buf[i*2] = tr[k / 16];
+        buf[i*2+1] = tr[k % 16];
+    }
+    buf[32] = '\0';
+
+    return buf;
+}
+
+void
+buf_ComputeCheckSum(cm_buf_t * bp)
+{
+    MD5_CTX md5;
+
+    MD5_Init(&md5);
+    MD5_Update(&md5, bp->datap, cm_data.blockSize);
+    MD5_Final(bp->md5cksum, &md5);
+
+    osi_Log4(buf_logp, "CheckSum bp 0x%p md5 %s, dirty: offset %u length %u",
+             bp, osi_LogSaveString(buf_logp, buf_HexCheckSum(bp)),
+             bp->dirty_offset, bp->dirty_length);
+}
+
+int
+buf_ValidateCheckSum(cm_buf_t * bp)
+{
+    MD5_CTX md5;
+    unsigned char tmp[16];
+
+    MD5_Init(&md5);
+    MD5_Update(&md5, bp->datap, cm_data.blockSize);
+    MD5_Final(tmp, &md5);
+
+    if (memcmp(tmp, bp->md5cksum, 16) == 0)
+        return 1;
+    return 0;
+}
+
+void
+buf_InsertToRedirQueue(cm_scache_t *scp, cm_buf_t *bufp)
+{
+    lock_AssertWrite(&buf_globalLock);
+    if (scp)
+        lock_AssertWrite(&scp->rw);
+
+    if (bufp->qFlags & CM_BUF_QINLRU) {
+        _InterlockedAnd(&bufp->qFlags, ~CM_BUF_QINLRU);
+        osi_QRemoveHT( (osi_queue_t **) &cm_data.buf_freeListp,
+                       (osi_queue_t **) &cm_data.buf_freeListEndp,
+                       &bufp->q);
+        buf_DecrementFreeCount();
+    }
+    _InterlockedOr(&bufp->qFlags, CM_BUF_QREDIR);
+    osi_QAddH( (osi_queue_t **) &cm_data.buf_redirListp,
+               (osi_queue_t **) &cm_data.buf_redirListEndp,
+               &bufp->q);
+    buf_IncrementRedirCount();
+    bufp->redirLastAccess = time(NULL);
+    if (scp) {
+        osi_QAddH( (osi_queue_t **) &scp->redirQueueH,
+                   (osi_queue_t **) &scp->redirQueueT,
+                   &bufp->redirq);
+        scp->redirLastAccess = bufp->redirLastAccess;
+        InterlockedIncrement(&scp->redirBufCount);
+    }
+}
+
+void
+buf_RemoveFromRedirQueue(cm_scache_t *scp, cm_buf_t *bufp)
+{
+    lock_AssertWrite(&buf_globalLock);
+    if (scp)
+        lock_AssertWrite(&scp->rw);
+
+    _InterlockedAnd(&bufp->qFlags, ~CM_BUF_QREDIR);
+    osi_QRemoveHT( (osi_queue_t **) &cm_data.buf_redirListp,
+                   (osi_queue_t **) &cm_data.buf_redirListEndp,
+                   &bufp->q);
+    buf_DecrementRedirCount();
+    if (scp) {
+        osi_QRemoveHT( (osi_queue_t **) &scp->redirQueueH,
+                       (osi_queue_t **) &scp->redirQueueT,
+                       &bufp->redirq);
+        InterlockedDecrement(&scp->redirBufCount);
+    }
+}
+
+void
+buf_MoveToHeadOfRedirQueue(cm_scache_t *scp, cm_buf_t *bufp)
+{
+    lock_AssertWrite(&buf_globalLock);
+    osi_assertx(bufp->qFlags & CM_BUF_QREDIR,
+                 "buf_MoveToHeadOfRedirQueue buffer not held by redirector");
+
+    if (scp)
+        lock_AssertWrite(&scp->rw);
+
+    osi_QRemoveHT( (osi_queue_t **) &cm_data.buf_redirListp,
+                   (osi_queue_t **) &cm_data.buf_redirListEndp,
+                   &bufp->q);
+    osi_QAddH( (osi_queue_t **) &cm_data.buf_redirListp,
+               (osi_queue_t **) &cm_data.buf_redirListEndp,
+               &bufp->q);
+    bufp->redirLastAccess = time(NULL);
+    if (scp) {
+        osi_QRemoveHT( (osi_queue_t **) &scp->redirQueueH,
+                       (osi_queue_t **) &scp->redirQueueT,
+                       &bufp->redirq);
+        osi_QAddH( (osi_queue_t **) &scp->redirQueueH,
+                   (osi_queue_t **) &scp->redirQueueT,
+                   &bufp->redirq);
+        scp->redirLastAccess = bufp->redirLastAccess;
+    }
+}
index 0c57905eb76815f8b2548ead255d52f289cbdb78..3c5e293cead5a2983d9f6d7c18db0343ee4734c8 100644 (file)
@@ -42,8 +42,8 @@ extern int buf_cacheType;
 
 /* represents a single buffer */
 typedef struct cm_buf {
-    osi_queue_t q;             /* queue of all zero-refcount buffers */
-    afs_uint32 qFlags;         /* queue/hash state flags - buf_globalLock */
+    osi_queue_t    q;          /* queue: buf_freeList and buf_redirList */
+    afs_uint32     qFlags;     /* queue/hash state flags - buf_globalLock */
     afs_uint32     magic;
     struct cm_buf *allp;       /* next in all list */
     struct cm_buf *hashp;      /* hash bucket pointer */
@@ -77,7 +77,7 @@ typedef struct cm_buf {
     afs_uint32 waitRequests;    /* num of thread wait requests */
 
     afs_uint32 dirty_offset;    /* offset from beginning of buffer containing dirty bytes */
-    afs_uint32 dirty_length;      /* number of dirty bytes within the buffer */
+    afs_uint32 dirty_length;    /* number of dirty bytes within the buffer */
 
 #ifdef DISKCACHE95
     cm_diskcache_t *dcp;        /* diskcache structure */
@@ -88,8 +88,17 @@ typedef struct cm_buf {
 #else
     void * dummy;
 #endif
+
+    /* redirector state - protected by buf_globalLock */
+    osi_queue_t redirq;         /* queue: cm_scache_t redirList */
+    time_t      redirLastAccess;/* last time redir accessed the buffer */
+    time_t      redirReleaseRequested;
+
+    unsigned char md5cksum[16]; /* md5 checksum of the block pointed to by datap */
 } cm_buf_t;
 
+#define redirq_to_cm_buf_t(q) ((q) ? (cm_buf_t *)((char *) (q) - offsetof(cm_buf_t, redirq)) : NULL)
+
 /* values for cmFlags */
 #define CM_BUF_CMFETCHING      1       /* fetching this buffer */
 #define CM_BUF_CMSTORING       2       /* storing this buffer */
@@ -132,8 +141,6 @@ extern long buf_Init(int newFile, cm_buf_ops_t *, afs_uint64 nbuffers);
 
 extern void buf_Shutdown(void);
 
-extern long buf_CountFreeList(void);
-
 #ifdef DEBUG_REFCOUNT
 extern void buf_ReleaseDbg(cm_buf_t *, char *, long);
 
@@ -212,10 +219,51 @@ extern long buf_DirtyBuffersExist(cm_fid_t * fidp);
 
 extern long buf_CleanDirtyBuffers(cm_scache_t *scp);
 
+extern long buf_RDRBuffersExist(cm_fid_t *fidp);
+
+extern long buf_ClearRDRFlag(cm_scache_t *scp, char * reason);
+
 extern long buf_ForceDataVersion(cm_scache_t * scp, afs_uint64 fromVersion, afs_uint64 toVersion);
 
 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
 
+extern void buf_ComputeCheckSum(cm_buf_t *bp);
+
+extern int  buf_ValidateCheckSum(cm_buf_t *bp);
+
+extern const char *buf_HexCheckSum(cm_buf_t * bp);
+
+extern afs_uint32
+buf_RDRShakeSomeExtentsFree(cm_req_t *reqp, afs_uint32 oneFid, afs_uint32 minage);
+
+extern afs_uint32
+buf_RDRShakeAnExtentFree(cm_buf_t *bufp, cm_req_t *reqp);
+
+extern afs_uint32
+buf_RDRShakeFileExtentsFree(cm_scache_t *scp, cm_req_t *reqp);
+
+extern void
+buf_InsertToRedirQueue(cm_scache_t *scp, cm_buf_t *bufp);
+
+extern void
+buf_RemoveFromRedirQueue(cm_scache_t *scp, cm_buf_t *bufp);
+
+extern void
+buf_MoveToHeadOfRedirQueue(cm_scache_t *scp, cm_buf_t *bufp);
+
+#ifdef _M_IX86
+#define buf_IncrementRedirCount()  InterlockedIncrement(&cm_data.buf_redirCount)
+#define buf_DecrementRedirCount()  InterlockedDecrement(&cm_data.buf_redirCount)
+#define buf_IncrementFreeCount()   InterlockedIncrement(&cm_data.buf_freeCount)
+#define buf_DecrementFreeCount()   InterlockedDecrement(&cm_data.buf_freeCount)
+#else
+#define buf_IncrementRedirCount()  InterlockedIncrement64(&cm_data.buf_redirCount)
+#define buf_DecrementRedirCount()  InterlockedDecrement64(&cm_data.buf_redirCount)
+#define buf_IncrementFreeCount()   InterlockedIncrement64(&cm_data.buf_freeCount)
+#define buf_DecrementFreeCount()   InterlockedDecrement64(&cm_data.buf_freeCount)
+#endif
+
 /* error codes */
 #define CM_BUF_EXISTS  1       /* buffer exists, and shouldn't */
+
 #endif /* OPENAFS_WINNT_AFSD_BUF_H */
index 9b56a0d79a69b3abd0ed14a3a9ff83cbb70af0ea..b85b4f8a7b3e6fb61c6f98b4aba47e231ebeeb2f 100644 (file)
@@ -197,6 +197,10 @@ void cm_RevokeCallback(struct rx_call *callp, cm_cell_t * cellp, AFSFid *fidp)
             osi_Log4(afsd_logp, "RevokeCallback Discarding SCache scp 0x%p vol %u vn %u uniq %u",
                      scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
 
+            if (RDR_Initialized)
+                RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                     scp->fid.hash, scp->fileType, AFS_INVALIDATE_CALLBACK);
+
             lock_ObtainWrite(&scp->rw);
             cm_DiscardSCache(scp);
             lock_ReleaseWrite(&scp->rw);
@@ -241,7 +245,7 @@ void cm_RevokeVolumeCallback(struct rx_call *callp, cm_cell_t *cellp, AFSFid *fi
     cm_scache_t *scp;
     cm_fid_t tfid;
 
-    osi_Log1(afsd_logp, "RevokeVolumeCallback vol %d", fidp->Volume);
+    osi_Log1(afsd_logp, "RevokeVolumeCallback vol %u", fidp->Volume);
 
     /* do this first, so that if we're executing a callback granting call
      * at this moment, we kill it before it can be merged in.  Otherwise,
@@ -251,7 +255,6 @@ void cm_RevokeVolumeCallback(struct rx_call *callp, cm_cell_t *cellp, AFSFid *fi
     tfid.cell = cellp ? cellp->cellID : 0;
     tfid.volume = fidp->Volume;
     tfid.vnode = tfid.unique = 0;
-
     cm_RecordRacingRevoke(&tfid, CM_RACINGFLAG_CANCELVOL);
 
     lock_ObtainWrite(&cm_scacheLock);
@@ -265,11 +268,19 @@ void cm_RevokeVolumeCallback(struct rx_call *callp, cm_cell_t *cellp, AFSFid *fi
                 lock_ReleaseWrite(&cm_scacheLock);
 
                 lock_ObtainWrite(&scp->rw);
-                osi_Log4(afsd_logp, "RevokeVolumeCallback Discarding SCache scp 0x%p vol %u vn %u uniq %u",
-                          scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
+                osi_Log5(afsd_logp, "RevokeVolumeCallback Discarding SCache scp 0x%p vol %u vn %u uniq %u",
+                          scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
+                osi_Log2(afsd_logp, ".... dv 0x%x:%x",
+                          (afs_uint32)((scp->dataVersion >> 32) & 0xFFFFFFFF),
+                          (afs_uint32)(scp->dataVersion & 0xFFFFFFFF));
+
                 cm_DiscardSCache(scp);
                 lock_ReleaseWrite(&scp->rw);
 
+                if (RDR_Initialized)
+                    RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                         scp->fid.hash, scp->fileType, AFS_INVALIDATE_CALLBACK);
+
                 cm_CallbackNotifyChange(scp);
                 lock_ObtainWrite(&cm_scacheLock);
                 cm_ReleaseSCacheNoLock(scp);
@@ -281,6 +292,9 @@ void cm_RevokeVolumeCallback(struct rx_call *callp, cm_cell_t *cellp, AFSFid *fi
 
     lock_ReleaseWrite(&cm_scacheLock);
 
+    if (cellp && RDR_Initialized)
+        RDR_InvalidateVolume(cellp->cellID, fidp->Volume, AFS_INVALIDATE_CALLBACK);
+
     osi_Log1(afsd_logp, "RevokeVolumeCallback Complete vol %d", fidp->Volume);
 }
 
@@ -1063,8 +1077,12 @@ SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid)
                     }
                 }
                 lock_ReleaseWrite(&scp->rw);
-                if (discarded)
+                if (discarded) {
                     cm_CallbackNotifyChange(scp);
+                    if (RDR_Initialized)
+                        RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                              scp->fid.hash, scp->fileType, AFS_INVALIDATE_EXPIRED);
+                }
                 lock_ObtainWrite(&cm_scacheLock);
                 cm_ReleaseSCacheNoLock(scp);
 
@@ -1557,7 +1575,8 @@ int cm_HaveCallback(cm_scache_t *scp)
                     break;
                 }
             }
-            if (!haveCB &&
+            if (cm_readonlyVolumeVersioning &&
+                !haveCB &&
                 volp->creationDateRO == scp->volumeCreationDate &&
                 volp->cbServerpRO != NULL) {
                 haveCB = 1;
@@ -1699,6 +1718,9 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
         cm_DiscardSCache(scp);
         lock_ReleaseWrite(&scp->rw);
         cm_CallbackNotifyChange(scp);
+        if (RDR_Initialized)
+            RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                 scp->fid.hash, scp->fileType, AFS_INVALIDATE_CALLBACK);
         lock_ObtainWrite(&scp->rw);
     } else {
         if (scp && scp->flags & CM_SCACHEFLAG_PURERO) {
@@ -1993,6 +2015,10 @@ void cm_CheckCBExpiration(void)
             cm_DiscardSCache(scp);
             lock_ReleaseWrite(&scp->rw);
 
+            if (RDR_Initialized)
+                RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                      scp->fid.hash, scp->fileType, AFS_INVALIDATE_EXPIRED);
+
             cm_CallbackNotifyChange(scp);
 
           scp_complete:
index bfb6119c8d9f089779ee2162620a40abad2832b8..ebc4c24ef47d22f88161ff6f986a3da71cb8e335 100644 (file)
@@ -79,4 +79,5 @@ extern afs_int32 cm_OfflineROIsValid;
 extern afs_int32 cm_giveUpAllCBs;
 
 extern afs_int32 cm_shutdown;
+
 #endif /*  OPENAFS_WINNT_AFSD_CM_CALLBACK_H */
index 958f8fdfca02845f935fdde777dda15977c59f75..c737b2030a7c3cf67a40787fbe8b742fce31e36f 100644 (file)
@@ -156,7 +156,7 @@ void cm_InitConn(void)
             if (HardDeadtimeout == 0) {
                 HardDeadtimeout = (unsigned short) (RDRtimeout > 125 ? 120 : (RDRtimeout - 5));
                 afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
-            }       
+            }
             if (IdleDeadtimeout == 0) {
                 IdleDeadtimeout = (unsigned short) ConnDeadtimeout;
                 afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout);
@@ -696,15 +696,23 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
                lock_ReleaseWrite(&cm_scacheLock);
                 cm_LockMarkSCacheLost(scp);
                lock_ReleaseWrite(&scp->rw);
+                if (RDR_Initialized)
+                    RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                          scp->fid.hash, scp->fileType, AFS_INVALIDATE_DELETED);
                cm_ReleaseSCache(scp);
 
                if (pscp) {
                    if (cm_HaveCallback(pscp)) {
                        lock_ObtainWrite(&pscp->rw);
                        cm_DiscardSCache(pscp);
-                       lock_ReleaseWrite(&pscp->rw);
-                   }
-                   cm_ReleaseSCache(pscp);
+                       lock_ReleaseWrite(&pscp->rw);
+
+                        if (RDR_Initialized)
+                            RDR_InvalidateObject(pscp->fid.cell, pscp->fid.volume, pscp->fid.vnode, pscp->fid.unique,
+                                                 pscp->fid.hash, pscp->fileType, AFS_INVALIDATE_EXPIRED);
+
+                   }
+                   cm_ReleaseSCache(pscp);
                }
            }
        } else {
index ab6031ba112ae98a2e680e949132944ec828e676..a1ddb1af8d4e60d7e78abf66f8a81e53a1183f0d 100644 (file)
@@ -53,8 +53,8 @@ typedef struct cm_conn {
  * to the cache manager functions.
  */
 typedef struct cm_req {
-    DWORD startTime;           /* Quit before RDR times us out */
-    int rpcError;                      /* RPC error code */
+    DWORD startTime;           /* GetTickCount() when this struct was initialized */
+    int rpcError;              /* RPC error code */
     int volumeError;           /* volume error code */
     int accessError;           /* access error code */
     struct cm_server * tokenIdleErrorServp;  /* server that reported a token/idle error other than expired */
index 0b70dab0f6e38f18d0ac9a4e1a66d9ca75a821be..cdcfbf2c5c5e55832bb3b0b7e4c1b31aa62bb6a8 100644 (file)
@@ -40,6 +40,7 @@ long cm_daemonTokenCheckInterval = 180;
 long cm_daemonCheckOfflineVolInterval = 600;
 long cm_daemonPerformanceTuningInterval = 0;
 long cm_daemonRankServerInterval = 600;
+long cm_daemonRDRShakeExtentsInterval = 0;
 
 osi_rwlock_t cm_daemonLock;
 
@@ -164,7 +165,8 @@ void cm_BkgDaemon(void * parm)
         case CM_ERROR_ALLDOWN:
         case CM_ERROR_ALLOFFLINE:
         case CM_ERROR_PARTIALWRITE:
-            if (rp->procp == cm_BkgStore) {
+            if (rp->procp == cm_BkgStore ||
+                rp->procp == RDR_BkgFetch) {
                 osi_Log2(afsd_logp,
                          "cm_BkgDaemon re-queueing failed request 0x%p code 0x%x",
                          rp, code);
@@ -349,6 +351,13 @@ cm_DaemonCheckInit(void)
        cm_daemonCheckOfflineVolInterval = dummy;
     afsi_log("daemonCheckOfflineVolInterval is %d", cm_daemonCheckOfflineVolInterval);
 
+    dummyLen = sizeof(DWORD);
+    code = RegQueryValueEx(parmKey, "daemonRDRShakeExtentsInterval", NULL, NULL,
+                           (BYTE *) &dummy, &dummyLen);
+    if (code == ERROR_SUCCESS && dummy)
+       cm_daemonRDRShakeExtentsInterval = dummy;
+    afsi_log("daemonRDRShakeExtentsInterval is %d", cm_daemonRDRShakeExtentsInterval);
+
     dummyLen = sizeof(DWORD);
     code = RegQueryValueEx(parmKey, "daemonPerformanceTuningInterval", NULL, NULL,
                            (BYTE *) &dummy, &dummyLen);
@@ -418,6 +427,7 @@ void cm_Daemon(long parm)
     time_t lastBusyVolCheck;
     time_t lastPerformanceCheck;
     time_t lastServerRankCheck;
+    time_t lastRDRShakeExtents;
     char thostName[200];
     unsigned long code;
     struct hostent *thp;
@@ -472,6 +482,8 @@ void cm_Daemon(long parm)
     if (cm_daemonPerformanceTuningInterval)
         lastPerformanceCheck = now - cm_daemonPerformanceTuningInterval/2 * (rand() % cm_daemonPerformanceTuningInterval);
     lastServerRankCheck = now - cm_daemonRankServerInterval/2 * (rand() % cm_daemonRankServerInterval);
+    if (cm_daemonRDRShakeExtentsInterval)
+        lastRDRShakeExtents = now - cm_daemonRDRShakeExtentsInterval/2 * (rand() % cm_daemonRDRShakeExtentsInterval);
 
     while (daemon_ShutdownFlag == 0) {
         if (powerStateSuspended) {
@@ -624,6 +636,20 @@ void cm_Daemon(long parm)
            now = osi_Time();
         }
 
+        if (cm_daemonRDRShakeExtentsInterval &&
+            now > lastRDRShakeExtents + cm_daemonRDRShakeExtentsInterval &&
+            daemon_ShutdownFlag == 0 &&
+            powerStateSuspended == 0) {
+            cm_req_t req;
+            cm_InitReq(&req);
+            lastRDRShakeExtents = now;
+            if (cm_data.buf_redirCount > cm_data.buf_freeCount)
+                buf_RDRShakeSomeExtentsFree(&req, FALSE, 10 /* seconds */);
+            if (daemon_ShutdownFlag == 1)
+                break;
+           now = osi_Time();
+        }
+
         /* allow an exit to be called prior to stopping the service */
         hHookDll = cm_LoadAfsdHookLib();
         if (hHookDll)
index d14c8f816eaac8f203931c0784facb5596b32f8f..5e65ab14f624a6dc4bc3c66c596aea7b6d36f502 100644 (file)
@@ -22,6 +22,7 @@
 #include <osi.h>
 
 #include "afsd.h"
+#include "smb.h"
 
 #ifdef DEBUG
 extern void afsi_log(char *pattern, ...);
@@ -732,12 +733,12 @@ cm_BkgStore(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_u
     osi_hyper_t toffset;
     long length;
     long code = 0;
+    afs_uint32 req_flags = reqp->flags;
 
     if (scp->flags & CM_SCACHEFLAG_DELETED) {
        osi_Log4(afsd_logp, "Skipping BKG store - Deleted scp 0x%p, offset 0x%x:%08x, length 0x%x", scp, p2, p1, p3);
     } else {
        /* Retries will be performed by the BkgDaemon thread if appropriate */
-        afs_uint32 req_flags = reqp->flags;
        reqp->flags |= CM_REQ_NORETRY;
 
        toffset.LowPart = p1;
@@ -1420,6 +1421,7 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore, long code, int scp_locked)
     osi_queueData_t *qdp;
     osi_queueData_t *nqdp;
     int flags;
+    int reportErrorToRedir = 0;
 
     /* Give back reserved buffers */
     if (biop->reserved)
@@ -1477,6 +1479,7 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore, long code, int scp_locked)
                         bufp->error = code;
                         bufp->dataVersion = CM_BUF_VERSION_BAD;
                         bufp->dirtyCounter++;
+                        reportErrorToRedir = 1;
                         break;
                     case CM_ERROR_TIMEDOUT:
                     case CM_ERROR_ALLDOWN:
@@ -1501,6 +1504,12 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore, long code, int scp_locked)
            buf_Release(bufp);
            bufp = NULL;
        }
+
+        if (RDR_Initialized && reportErrorToRedir) {
+            DWORD status;
+            smb_MapNTError(cm_MapRPCError(code, biop->reqp), &status, TRUE);
+            RDR_SetFileStatus( &scp->fid, status);
+        }
     } else {
        if (!scp_locked)
             lock_ObtainWrite(&scp->rw);
index 171c3897ee3d394dc3b66c7d986735d9dcf53728..438434246d78557e47c612833ec32eacea40e70f 100644 (file)
@@ -397,6 +397,15 @@ int cm_noteLocalMountPointChange(afs_int32 locked) {
         lock_ObtainMutex(&cm_Freelance_Lock);
     cm_data.fakeDirVersion++;
     cm_localMountPointChangeFlag = 1;
+
+    if (RDR_Initialized) {
+        cm_fid_t fid;
+        cm_FakeRootFid(&fid);
+        RDR_InvalidateObject( fid.cell, fid.volume, fid.vnode, fid.unique, fid.hash,
+                              CM_SCACHETYPE_DIRECTORY,
+                              AFS_INVALIDATE_DATA_VERSION);
+    }
+
     if (!locked)
         lock_ReleaseMutex(&cm_Freelance_Lock);
     return 1;
@@ -459,6 +468,11 @@ int cm_reInitLocalMountPoints() {
                 lock_ReleaseWrite(&scp->rw);
                 lock_ReleaseWrite(&cm_scacheLock);
                 cm_CallbackNotifyChange(scp);
+
+                if (RDR_Initialized)
+                    RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                         scp->fid.hash, scp->fileType, AFS_INVALIDATE_CALLBACK);
+
                 lock_ObtainWrite(&cm_scacheLock);
                 cm_ReleaseSCacheNoLock(scp);
                 lock_ObtainMutex(&cm_Freelance_Lock);
index 66a625ce0a66408f5c283e46612751c6d5fadca2..d9bbc60b802b3171fc64ddb1381b2eae8d8aeb98 100644 (file)
@@ -78,7 +78,12 @@ cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 {
     long code;
 
-    code = cm_FSync(scp, userp, reqp, FALSE);
+    if (RDR_Initialized &&
+        RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                             scp->fid.hash, scp->fileType, AFS_INVALIDATE_FLUSHED))
+        code = CM_ERROR_WOULDBLOCK;
+    else
+        code = cm_FSync(scp, userp, reqp, FALSE);
     if (!code) {
         lock_ObtainWrite(&scp->rw);
         cm_DiscardSCache(scp);
@@ -104,7 +109,16 @@ cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     }
 #endif
 
-    code = buf_FlushCleanPages(scp, userp, reqp);
+    /*
+     * The file system will forget all knowledge of the object
+     * when it receives this message.
+     */
+    if (RDR_Initialized &&
+        RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                             scp->fid.hash, scp->fileType, AFS_INVALIDATE_FLUSHED))
+        code = CM_ERROR_WOULDBLOCK;
+    else
+        code = buf_FlushCleanPages(scp, userp, reqp);
 
     if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
         lock_ObtainWrite(&scp->dirlock);
@@ -530,6 +544,10 @@ cm_IoctlSetACL(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp,
         lock_ObtainWrite(&scp->rw);
         cm_DiscardSCache(scp);
         lock_ReleaseWrite(&scp->rw);
+
+        if (RDR_Initialized)
+            RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                 scp->fid.hash, scp->fileType, AFS_INVALIDATE_CREDS);
     }
 
     return code;
@@ -1185,6 +1203,11 @@ cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
     lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
 
+    if (RDR_Initialized &&
+        !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                              scp->fid.hash, scp->fileType, AFS_INVALIDATE_DELETED))
+        buf_ClearRDRFlag(scp, "deleted mp");
+
   done3:
     if (originalName != NULL)
         free(originalName);
@@ -1409,7 +1432,7 @@ cm_IoctlGetCacheParms(struct cm_ioctl *ioctlp, struct cm_user *userp)
     /* and then the actual # of buffers in use (not in the free list, I guess,
      * will be what we do).
      */
-    parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
+    parms.parms[1] = (cm_data.buf_nbuffers - cm_data.buf_freeCount) * (cm_data.buf_blockSize / 1024);
 
     memcpy(ioctlp->outDatap, &parms, sizeof(parms));
     ioctlp->outDatap += sizeof(parms);
@@ -1679,6 +1702,13 @@ cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp)
  * VIOC_AFS_SYSNAME internals.
  *
  * Assumes that pioctl path has been parsed or skipped.
+ *
+ * In order to support both 32-bit and 64-bit sysname lists
+ * we will treat bit-31 of the setSysName value as a flag
+ * indicating which architecture is being indicated.  If unset
+ * the architecture is 32-bit and if set the architecture is
+ * 64-bit.  This change is backward compatible with cache
+ * managers that do not support this extension.
  */
 afs_int32
 cm_IoctlSysName(struct cm_ioctl *ioctlp, struct cm_user *userp)
@@ -1688,10 +1718,14 @@ cm_IoctlSysName(struct cm_ioctl *ioctlp, struct cm_user *userp)
     clientchar_t *inname = NULL;
     int t;
     unsigned int count;
+    int arch64 = 0;
 
     memcpy(&setSysName, ioctlp->inDatap, sizeof(afs_uint32));
     ioctlp->inDatap += sizeof(afs_uint32);
 
+    arch64 = (setSysName & 0x8000000) ? 1 : 0;
+    setSysName &= 0x7FFFFFF;
+
     if (setSysName) {
         /* check my args */
         if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
@@ -1716,46 +1750,57 @@ cm_IoctlSysName(struct cm_ioctl *ioctlp, struct cm_user *userp)
     }
 
     /* Not xlating, so local case */
-    if (!cm_sysName)
-        osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
-
     if (setSysName) {
         /* Local guy; only root can change sysname */
         /* clear @sys entries from the dnlc, once afs_lookup can
          * do lookups of @sys entries and thinks it can trust them */
         /* privs ok, store the entry, ... */
 
-        cm_ClientStrCpy(cm_sysName, lengthof(cm_sysName), inname);
-        cm_ClientStrCpy(cm_sysNameList[0], MAXSYSNAME, inname);
+        cm_ClientStrCpy(arch64 ? cm_sysName64List[0] : cm_sysNameList[0], MAXSYSNAME, inname);
 
         if (setSysName > 1) {       /* ... or list */
             for (count = 1; count < setSysName; ++count) {
                 clientchar_t * newsysname;
 
-                if (!cm_sysNameList[count])
+                if (!(arch64 ? cm_sysName64List[count] : cm_sysNameList[count]))
                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
                               __FILE__, __LINE__);
 
                 newsysname = cm_ParseIoctlStringAlloc(ioctlp, NULL);
-                cm_ClientStrCpy(cm_sysNameList[count], MAXSYSNAME, newsysname);
+                cm_ClientStrCpy(arch64 ? cm_sysName64List[count] : cm_sysNameList[count], MAXSYSNAME, newsysname);
                 free(newsysname);
             }
         }
-        cm_sysNameCount = setSysName;
+        if ( arch64 ) {
+            cm_sysName64Count = setSysName;
+            if (cm_sysName64Count)
+                RDR_SysName( AFS_SYSNAME_ARCH_64BIT, cm_sysName64Count, cm_sysName64List );
+            else if (cm_sysNameCount)
+                RDR_SysName( AFS_SYSNAME_ARCH_64BIT, cm_sysNameCount, cm_sysNameList );
+        } else {
+            cm_sysNameCount = setSysName;
+            RDR_SysName( AFS_SYSNAME_ARCH_32BIT, cm_sysNameCount, cm_sysNameList );
+        }
     } else {
         afs_uint32 i32;
 
-        /* return the sysname to the caller */
-        i32 = cm_sysNameCount;
+        /* return the sysname list to the caller.
+         * if there is no 64-bit list and 64-bit is requested, use the 32-bit list.
+         */
+        if ( arch64 && cm_sysName64Count == 0 )
+            arch64 = 0;
+
+        i32 = arch64 ? cm_sysName64Count : cm_sysNameCount;
         memcpy(ioctlp->outDatap, &i32, sizeof(afs_int32));
         ioctlp->outDatap += sizeof(afs_int32); /* skip found flag */
 
-        if (cm_sysNameCount) {
-            for ( count=0; count < cm_sysNameCount ; ++count) {   /* ... or list */
-                if ( !cm_sysNameList[count] || *cm_sysNameList[count] == _C('\0'))
+        if (i32) {
+            for ( count=0; count < i32 ; ++count) {   /* ... or list */
+                if ( !(arch64 ? cm_sysName64List[count] : cm_sysNameList[count]) ||
+                     *(arch64 ? cm_sysName64List[count] : cm_sysNameList[count]) == _C('\0'))
                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n",
                               __FILE__, __LINE__);
-                cm_UnparseIoctlString(ioctlp, NULL, cm_sysNameList[count], -1);
+                cm_UnparseIoctlString(ioctlp, NULL, arch64 ? cm_sysName64List[count] : cm_sysNameList[count], -1);
             }
         }
     }
@@ -2346,6 +2391,11 @@ cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *
     lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
 
+    if (RDR_Initialized &&
+        !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                              scp->fid.hash, scp->fileType, AFS_INVALIDATE_DELETED))
+        buf_ClearRDRFlag(scp, "deleted link");
+
   done3:
     free(clientp);
 
@@ -2529,8 +2579,14 @@ cm_IoctlSetToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
     }
 
     if (flags & PIOCTL_LOGON) {
-        userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
+        clientchar_t *cname;
+
+        cname = cm_FsStringToClientStringAlloc(smbname, -1, NULL);
+
+        userp = smb_FindCMUserByName(cname, ioctlp->fidp->vcp->rname,
                                     SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+        if (cname)
+            free(cname);
        release_userp = 1;
     }
 
index 048683c0702ec07990d66e65b5f1e74fb5b40f89..605f5e7f57e5a5abebf984b211300c8402db9118 100644 (file)
@@ -118,9 +118,10 @@ typedef struct cm_IoctlQueryOptions {
 
 #define MAXNUMSYSNAMES    16      /* max that current constants allow */
 #define   MAXSYSNAME      128     /* max sysname (i.e. @sys) size */
-extern clientchar_t  *cm_sysName;
 extern unsigned int   cm_sysNameCount;
 extern clientchar_t  *cm_sysNameList[MAXNUMSYSNAMES];
+extern unsigned int   cm_sysName64Count;
+extern clientchar_t  *cm_sysName64List[MAXNUMSYSNAMES];
 
 /* Paths that are passed into pioctl calls can be specified using
    UTF-8.  These strings are prefixed with UTF8_PREFIX defined below.
index b7bc9ca9ce85239dfea8607fff7a9e671167d6d8..d43728052fed53d6693223253bd9ad7fec1e2870 100644 (file)
@@ -266,15 +266,15 @@ cm_ShutdownMappedMemory(void)
         HeapDestroy(hCacheHeap);
         afsi_log("Memory Heap has been destroyed");
     } else {
-    if (cm_ValidateCache == 2)
-        dirty = !cm_IsCacheValid();
+        if (cm_ValidateCache == 2)
+            dirty = !cm_IsCacheValid();
 
-    *config_data_p = cm_data;
-    config_data_p->dirty = dirty;
-    UnmapViewOfFile(config_data_p);
-    CloseHandle(hMemoryMappedFile);
-    hMemoryMappedFile = NULL;
-    afsi_log("Memory Mapped File has been closed");
+        *config_data_p = cm_data;
+        config_data_p->dirty = dirty;
+        UnmapViewOfFile(config_data_p);
+        CloseHandle(hMemoryMappedFile);
+        hMemoryMappedFile = NULL;
+        afsi_log("Memory Mapped File has been closed");
     }
     return 0;
 }
@@ -794,44 +794,44 @@ cm_InitMappedMemory(DWORD virtualCache, char * cachePath, DWORD stats, DWORD max
             CloseHandle(hm);
         }
 
-    hm = CreateFileMapping( hf,
-                            NULL,
-                            PAGE_READWRITE,
-                           (DWORD)(mappingSize >> 32),
-                           (DWORD)(mappingSize & 0xFFFFFFFF),
-                            NULL);
-    if (hm == NULL) {
-        if (GetLastError() == ERROR_DISK_FULL) {
-            afsi_log("Error creating file mapping for \"%s\": disk full [2]",
-                      cachePath);
-            return CM_ERROR_TOOMANYBUFS;
-        }
-        afsi_log("Error creating file mapping for \"%s\": %d",
-                  cachePath, GetLastError());
-        return CM_ERROR_INVAL;
-    }
-    baseAddress = MapViewOfFileEx( hm,
-                                   FILE_MAP_ALL_ACCESS,
-                                   0,
-                                  0,
-                                  (SIZE_T)mappingSize,
-                                   baseAddress );
-    if (baseAddress == NULL) {
-        afsi_log("Error mapping view of file: %d", GetLastError());
-        baseAddress = MapViewOfFile( hm,
-                                     FILE_MAP_ALL_ACCESS,
-                                     0,
-                                    0,
-                                    (SIZE_T)mappingSize);
-        if (baseAddress == NULL) {
-            if (hf != INVALID_HANDLE_VALUE)
-                CloseHandle(hf);
-            CloseHandle(hm);
+        hm = CreateFileMapping( hf,
+                                NULL,
+                                PAGE_READWRITE,
+                                (DWORD)(mappingSize >> 32),
+                                (DWORD)(mappingSize & 0xFFFFFFFF),
+                                NULL);
+        if (hm == NULL) {
+            if (GetLastError() == ERROR_DISK_FULL) {
+                afsi_log("Error creating file mapping for \"%s\": disk full [2]",
+                          cachePath);
+                return CM_ERROR_TOOMANYBUFS;
+            }
+            afsi_log("Error creating file mapping for \"%s\": %d",
+                      cachePath, GetLastError());
             return CM_ERROR_INVAL;
         }
+        baseAddress = MapViewOfFileEx( hm,
+                                       FILE_MAP_ALL_ACCESS,
+                                       0,
+                                       0,
+                                       (SIZE_T)mappingSize,
+                                       baseAddress );
+        if (baseAddress == NULL) {
+            afsi_log("Error mapping view of file: %d", GetLastError());
+            baseAddress = MapViewOfFile( hm,
+                                         FILE_MAP_ALL_ACCESS,
+                                         0,
+                                         0,
+                                         (SIZE_T)mappingSize);
+            if (baseAddress == NULL) {
+                if (hf != INVALID_HANDLE_VALUE)
+                    CloseHandle(hf);
+                CloseHandle(hm);
+                return CM_ERROR_INVAL;
+            }
             newCache = 1;
-    }
-    CloseHandle(hm);
+        }
+        CloseHandle(hm);
         hMemoryMappedFile = hf;
     }
 
@@ -936,10 +936,18 @@ cm_InitMappedMemory(DWORD virtualCache, char * cachePath, DWORD stats, DWORD max
         cm_data.bufEndOfData = (char *) baseAddress;
        cm_data.buf_dirtyListp = NULL;
        cm_data.buf_dirtyListEndp = NULL;
-        cm_data.fakeDirVersion = 0x8;
+        /* Make sure the fakeDirVersion is always increasing */
+        cm_data.fakeDirVersion = time(NULL);
+        cm_data.fakeUnique = 0;
         UuidCreate((UUID *)&cm_data.Uuid);
        cm_data.volSerialNumber = volumeSerialNumber;
        memcpy(cm_data.Sid, machineSid, sizeof(machineSid));
+
+        /*
+         * make sure that the file is fully allocated
+         * by writing a non-zero byte to the end
+         */
+        cm_data.baseAddress[mappingSize-1] = 0xFF;
     } else {
        int gennew = 0;
 
index 62eb2258fe5a1960e654e4bc32f7c8a81a447f85..5f8b4ce9d017ef2c82c3527f4803e10439a455ae 100644 (file)
@@ -83,17 +83,30 @@ typedef struct cm_config_data {
     cm_buf_t    *       buf_freeListEndp;
     cm_buf_t   *       buf_dirtyListp;
     cm_buf_t    *       buf_dirtyListEndp;
+    cm_buf_t    *       buf_redirListp;
+    cm_buf_t    *       buf_redirListEndp;
     cm_buf_t   **      buf_scacheHashTablepp;
     cm_buf_t   **      buf_fileHashTablepp;
     cm_buf_t   *       buf_allp;
-    afs_uint64         buf_nbuffers;
     afs_uint32         buf_blockSize;
     afs_uint32         buf_hashSize;
+#ifdef _M_IX86
+    afs_uint32         buf_nbuffers;
+    afs_uint32         buf_nOrigBuffers;
+    afs_uint32          buf_reservedBufs;
+    afs_uint32          buf_maxReservedBufs;
+    afs_uint32          buf_reserveWaiting;
+    afs_uint32          buf_freeCount;
+    afs_uint32          buf_redirCount;
+#else
+    afs_uint64         buf_nbuffers;
     afs_uint64         buf_nOrigBuffers;
     afs_uint64          buf_reservedBufs;
     afs_uint64          buf_maxReservedBufs;
     afs_uint64          buf_reserveWaiting;
-
+    afs_uint64          buf_freeCount;
+    afs_uint64          buf_redirCount;
+#endif
     time_t              mountRootGen;
     afsUUID             Uuid;
     DWORD              volSerialNumber;
index 6563dab87b1c5c497d2d0a21685dcaef4bf20f38..41343e534edcdd7b89256eec4f2eec95fe6845f5 100644 (file)
@@ -537,7 +537,7 @@ void cm_PerformancePrintReport(void)
                         "SIZEs- 0kb=%u 1kb=%u 4kb=%u 64kb=%u 1mb=%u 20m=%u 100mb=%u 1gb=%u 2gb=%u larger=%u\r\n\r\n",
                          t,
                          cm_data.currentSCaches, cm_data.maxSCaches, cm_data.currentVolumes, cm_data.maxVolumes,
-                         cm_data.buf_nbuffers - buf_CountFreeList(), cm_data.buf_nbuffers,
+                         cm_data.buf_nbuffers - cm_data.buf_freeCount, cm_data.buf_nbuffers,
                          fid_cnt, fid_w_vol, fid_w_scache, fid_w_callbacks, fid_w_buffers,
                          fid_w_scache_no_vol, fid_w_vol_no_scache, fid_w_scache_no_buf, fid_w_buf_no_scache,
                          rw_vols, ro_vols, bk_vols,
diff --git a/src/WINNT/afsd/cm_rdr.h b/src/WINNT/afsd/cm_rdr.h
new file mode 100644 (file)
index 0000000..955ad55
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints Inc.
+ * Copyright (c) 2009-2011 Your File System Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc nor the names of its contributors may be
+ *   used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints Inc and
+ *   Your File System Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef CM_RDR_H
+#define CM_RDR_H
+
+#include <..\afsrdr\common\AFSUserDefines.h>
+#include <..\afsrdr\common\AFSUserStructs.h>
+#include <..\afsrdr\common\AFSUserPrototypes.h>
+
+#endif /* CM_RDR_H */
+
index 687b0cdfe4ddb736c6f3497a0b7091b1c5121f70..e1075714b5816e0e01e586dfe3c2d2c9fe3b3b54 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "afsd.h"
 #include "cm_btree.h"
+#include <afs/unified_afs.h>
 
 /*extern void afsi_log(char *pattern, ...);*/
 
@@ -154,6 +155,11 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
        return -1;
     }
 
+    if (scp->redirBufCount != 0) {
+        return -1;
+    }
+
+    cm_RemoveSCacheFromHashTable(scp);
 
     /* invalidate so next merge works fine;
      * also initialize some flags */
@@ -233,36 +239,64 @@ cm_scache_t *cm_GetNewSCache(void)
        /* There were no deleted scache objects that we could use.  Try to find
         * one that simply hasn't been used in a while.
         */
-        for ( scp = cm_data.scacheLRULastp;
-              scp;
-              scp = (cm_scache_t *) osi_QPrev(&scp->q))
-        {
-            /* It is possible for the refCount to be zero and for there still
-             * to be outstanding dirty buffers.  If there are dirty buffers,
-             * we must not recycle the scp. */
-            if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
-                if (!buf_DirtyBuffersExist(&scp->fid)) {
-                    if (!lock_TryWrite(&scp->rw))
-                        continue;
-
-                    if (!cm_RecycleSCache(scp, 0)) {
-                        /* we found an entry, so return it */
-                        /* now remove from the LRU queue and put it back at the
-                         * head of the LRU queue.
-                         */
-                        cm_AdjustScacheLRU(scp);
-
-                        /* and we're done */
-                        return scp;
+        for (retry = 0 ; retry < 2; retry++) {
+            for ( scp = cm_data.scacheLRULastp;
+                  scp;
+                  scp = (cm_scache_t *) osi_QPrev(&scp->q))
+            {
+                /* It is possible for the refCount to be zero and for there still
+                 * to be outstanding dirty buffers.  If there are dirty buffers,
+                 * we must not recycle the scp.
+                 *
+                 * If the object is in use by the redirector, then avoid recycling
+                 * it unless we have to.
+                 */
+                if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
+                    if (!buf_DirtyBuffersExist(&scp->fid) && !buf_RDRBuffersExist(&scp->fid)) {
+                        cm_fid_t   fid;
+                        afs_uint32 fileType;
+
+                        if (!lock_TryWrite(&scp->rw))
+                            continue;
+
+                        /* Found a likely candidate.  Save type and fid in case we succeed */
+                        fid = scp->fid;
+                        fileType = scp->fileType;
+
+                        if (!cm_RecycleSCache(scp, 0)) {
+                            /* we found an entry, so return it.
+                             * remove from the LRU queue and put it back at the
+                             * head of the LRU queue.
+                             */
+                            cm_AdjustScacheLRU(scp);
+
+                            if (RDR_Initialized) {
+                                /*
+                                 * We drop the cm_scacheLock because it may be required to
+                                 * satisfy an ioctl request from the redirector.  It should
+                                 * be safe to hold the scp->rw lock here because at this
+                                 * point (a) the object has just been recycled so the fid
+                                 * is nul and there are no requests that could possibly
+                                 * be issued by the redirector that would depend upon it.
+                                 */
+                                lock_ReleaseWrite(&cm_scacheLock);
+                                RDR_InvalidateObject( fid.cell, fid.volume, fid.vnode,
+                                                      fid.unique, fid.hash,
+                                                      fileType, AFS_INVALIDATE_EXPIRED);
+                                lock_ObtainWrite(&cm_scacheLock);
+                            }
+
+                            /* and we're done */
+                            return scp;
+                        }
+                        lock_ReleaseWrite(&scp->rw);
+                    } else {
+                        osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%p", scp);
                     }
-                    lock_ReleaseWrite(&scp->rw);
-                } else {
-                    osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%x", scp);
                 }
             }
+            osi_Log1(afsd_logp, "GetNewSCache all scache entries in use (retry = %d)", retry);
         }
-        osi_Log1(afsd_logp, "GetNewSCache all scache entries in use (retry = %d)", retry);
-
         return NULL;
     }
 
@@ -567,7 +601,11 @@ void cm_InitSCache(int newFile, long maxSCaches)
                 scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
 #endif
                 scp->waitQueueT = NULL;
-                _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_WAITING);
+                _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_WAITING | CM_SCACHEFLAG_RDR_IN_USE));
+
+                scp->redirBufCount = 0;
+                scp->redirQueueT = NULL;
+                scp->redirQueueH = NULL;
             }
         }
         cm_allFileLocks = NULL;
@@ -981,6 +1019,9 @@ int cm_SyncOpCheckContinue(cm_scache_t * scp, afs_int32 flags, cm_buf_t * bufp)
  * possibly resulting in a bogus truncation.  The simplest way to avoid this
  * is to serialize all StoreData RPC's.  This is the reason we defined
  * CM_SCACHESYNC_STOREDATA_EXCL and CM_SCACHEFLAG_DATASTORING.
+ *
+ * CM_SCACHESYNC_BULKREAD is used to permit synchronization of multiple bulk
+ * readers which may be requesting overlapping ranges.
  */
 long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *reqp,
                afs_uint32 rights, afs_uint32 flags)
@@ -1208,6 +1249,14 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
             }
         }
 
+        if (flags & CM_SCACHESYNC_BULKREAD) {
+            /* Don't allow concurrent fiddling with lock lists */
+            if (scp->flags & CM_SCACHEFLAG_BULKREADING) {
+                osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is BULKREADING want BULKREAD", scp);
+                goto sleep;
+            }
+        }
+
         /* if we get here, we're happy */
         break;
 
@@ -1276,6 +1325,8 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_ASYNCSTORING);
     if (flags & CM_SCACHESYNC_LOCK)
         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_LOCKING);
+    if (flags & CM_SCACHESYNC_BULKREAD)
+        _InterlockedOr(&scp->flags, CM_SCACHEFLAG_BULKREADING);
 
     /* now update the buffer pointer */
     if (bufp && (flags & CM_SCACHESYNC_FETCHDATA)) {
@@ -1347,6 +1398,8 @@ void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags)
         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_ASYNCSTORING);
     if (flags & CM_SCACHESYNC_LOCK)
         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_LOCKING);
+    if (flags & CM_SCACHESYNC_BULKREAD)
+        _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_BULKREADING);
 
     /* now update the buffer pointer */
     if (bufp && (flags & CM_SCACHESYNC_FETCHDATA)) {
@@ -1468,10 +1521,20 @@ void cm_MergeStatus(cm_scache_t *dscp,
 #endif /* AFS_FREELANCE_CLIENT */
 
     if (statusp->errorCode != 0) {
-        _InterlockedOr(&scp->flags, CM_SCACHEFLAG_EACCESS);
-       osi_Log2(afsd_logp, "Merge, Failure scp 0x%p code 0x%x", scp, statusp->errorCode);
+       _InterlockedOr(&scp->flags, CM_SCACHEFLAG_EACCESS);
+        switch (statusp->errorCode) {
+        case EACCES:
+        case UAEACCES:
+        case EPERM:
+        case UAEPERM:
+            _InterlockedOr(&scp->flags, CM_SCACHEFLAG_EACCESS);
+        }
+        osi_Log2(afsd_logp, "Merge, Failure scp 0x%p code 0x%x", scp, statusp->errorCode);
 
-       scp->fileType = 0;      /* unknown */
+        if (scp->fid.vnode & 0x1)
+            scp->fileType = CM_SCACHETYPE_DIRECTORY;
+        else
+            scp->fileType = 0; /* unknown */
 
        scp->serverModTime = 0;
        scp->clientModTime = 0;
@@ -1634,7 +1697,8 @@ void cm_MergeStatus(cm_scache_t *dscp,
             if (cm_FidCmp(&scp->fid, &bp->fid) == 0 &&
                  lock_TryMutex(&bp->mx)) {
                 if (bp->refCount == 0 &&
-                    !(bp->flags & CM_BUF_READING | CM_BUF_WRITING | CM_BUF_DIRTY)) {
+                    !(bp->flags & (CM_BUF_READING | CM_BUF_WRITING | CM_BUF_DIRTY)) &&
+                    !(bp->qFlags & CM_BUF_QREDIR)) {
                     prevBp = bp->fileHashBackp;
                     bp->fileHashBackp = bp->fileHashp = NULL;
                     if (prevBp)
@@ -1671,9 +1735,19 @@ void cm_MergeStatus(cm_scache_t *dscp,
      * does not update a mountpoint or symlink by altering the contents of
      * the file data; but the Unix CM does.
      */
-    if (scp->dataVersion != dataVersion && !(flags & CM_MERGEFLAG_FETCHDATA))
+    if (scp->dataVersion != dataVersion && !(flags & CM_MERGEFLAG_FETCHDATA)) {
         scp->mountPointStringp[0] = '\0';
 
+        osi_Log5(afsd_logp, "cm_MergeStatus data version change scp 0x%p cell %u vol %u vn %u uniq %u",
+                 scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
+
+        osi_Log4(afsd_logp, ".... oldDV 0x%x:%x -> newDV 0x%x:%x",
+                 (afs_uint32)((scp->dataVersion >> 32) & 0xFFFFFFFF),
+                 (afs_uint32)(scp->dataVersion & 0xFFFFFFFF),
+                 (afs_uint32)((dataVersion >> 32) & 0xFFFFFFFF),
+                 (afs_uint32)(dataVersion & 0xFFFFFFFF));
+    }
+
     /* We maintain a range of buffer dataVersion values which are considered
      * valid.  This avoids the need to update the dataVersion on each buffer
      * object during an uncontested storeData operation.  As a result this
@@ -1685,6 +1759,19 @@ void cm_MergeStatus(cm_scache_t *dscp,
          scp->bufDataVersionLow == 0)
         scp->bufDataVersionLow = dataVersion;
 
+    if (RDR_Initialized && scp->dataVersion != CM_SCACHE_VERSION_BAD) {
+        if ( ( !(reqp->flags & CM_REQ_SOURCE_REDIR) || !(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA))) &&
+             scp->dataVersion != dataVersion ) {
+            RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+                                 scp->fid.unique, scp->fid.hash,
+                                 scp->fileType, AFS_INVALIDATE_DATA_VERSION);
+        } else if ( (reqp->flags & CM_REQ_SOURCE_REDIR) && (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
+                    dataVersion - scp->dataVersion > 1) {
+            RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+                                 scp->fid.unique, scp->fid.hash,
+                                 scp->fileType, AFS_INVALIDATE_DATA_VERSION);
+        }
+    }
     scp->dataVersion = dataVersion;
 
     /*
@@ -1735,7 +1822,7 @@ void cm_DiscardSCache(cm_scache_t *scp)
     }
     scp->cbExpires = 0;
     scp->volumeCreationDate = 0;
-    _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_LOCAL));
+    _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_LOCAL | CM_SCACHEFLAG_RDR_IN_USE));
     cm_dnlcPurgedp(scp);
     cm_dnlcPurgevp(scp);
     cm_FreeAllACLEnts(scp);
@@ -1965,7 +2052,7 @@ int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
             for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
-                cm_file_lock_t * lockp = (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
+                cm_file_lock_t * lockp = fileq_to_cm_file_lock_t(q);
                 sprintf(output, "  %s lockp=0x%p scp=0x%p, cm_userp=0x%p offset=0x%I64x len=0x%08I64x type=0x%x "
                         "key=0x%I64x flags=0x%x update=0x%I64u\r\n",
                         cookie, lockp, lockp->scp, lockp->userp, lockp->range.offset, lockp->range.length,
index d14f398614c861f7656a0663c0d9bdc663f265b9..f0ab19a53422bd3d6de99b8c7c2b94195a6c76da 100644 (file)
@@ -62,6 +62,8 @@ typedef struct cm_file_lock {
                                  * cm_scacheLock] */
 } cm_file_lock_t;
 
+#define fileq_to_cm_file_lock_t(q) ((cm_file_lock_t *)((char *) (q) - offsetof(cm_file_lock_t, fileq)))
+
 #define CM_FILELOCK_FLAG_DELETED         0x01
 #define CM_FILELOCK_FLAG_LOST            0x02
 
@@ -223,8 +225,16 @@ typedef struct cm_scache {
                                        Holds queue of
                                        cm_scache_waiter_t
                                        objects. Protected by
-                                       cm_cacheLock. */
+                                       cm_scacheLock. */
     osi_queue_t * waitQueueT;       /* locked by cm_scacheLock */
+
+    /* redirector state - protected by scp->rw */
+    osi_queue_t * redirQueueH;      /* LRU queue of buffers for this
+                                       file that are assigned to the
+                                       afsredir kernel module. */
+    osi_queue_t * redirQueueT;
+    afs_uint32    redirBufCount;    /* Number of buffers held by the redirector */
+    time_t        redirLastAccess;  /* last time redir accessed the vnode */
 } cm_scache_t;
 
 /* dataVersion */
@@ -277,6 +287,8 @@ typedef struct cm_scache {
 #define CM_SCACHEFLAG_EACCESS           0x200000 /* Bulk Stat returned EACCES */
 #define CM_SCACHEFLAG_SMB_FID          0x400000
 #define CM_SCACHEFLAG_LOCAL             0x800000 /* Locally modified */
+#define CM_SCACHEFLAG_BULKREADING       0x1000000/* Bulk read in progress */
+#define CM_SCACHEFLAG_RDR_IN_USE        0x2000000/* in use by Redirector; advisory */
 
 /* sync flags for calls to the server.  The CM_SCACHEFLAG_FETCHING,
  * CM_SCACHEFLAG_STORING and CM_SCACHEFLAG_SIZESTORING flags correspond to the
@@ -314,6 +326,8 @@ typedef struct cm_scache {
 #define CM_SCACHESYNC_FORCECB          0x200000/* when calling cm_GetCallback()
                                                  * set the force flag */
 
+#define CM_SCACHESYNC_BULKREAD          0x400000/* reading many buffers */
+
 /* flags for cm_RecycleSCache  */
 #define CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS  0x1
 
index 10f022bafe4151fe55af10f727c044d3b5d24888..32eeff8ac96cef04f24a26fda4b33bae6844a4d3 100644 (file)
@@ -172,13 +172,14 @@ cm_PingServer(cm_server_t *tsp)
     }  /* got an unauthenticated connection to this server */
 
     lock_ObtainMutex(&tsp->mx);
-    if (code >= 0 || code == RXGEN_OPCODE) {
+    if (code >= 0 || code == RXGEN_OPCODE || code == CM_RX_RETRY_BUSY_CALL) {
        /* mark server as up */
        _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
         tsp->downTime = 0;
 
        /* we currently handle 32-bits of capabilities */
-       if (code != RXGEN_OPCODE && caps.Capabilities_len > 0) {
+       if (code != RXGEN_OPCODE && code != CM_RX_RETRY_BUSY_CALL &&
+            caps.Capabilities_len > 0) {
            tsp->capabilities = caps.Capabilities_val[0];
            xdr_free((xdrproc_t) xdr_Capabilities, &caps);
            caps.Capabilities_len = 0;
@@ -455,13 +456,15 @@ static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
             lock_ObtainMutex(&tsp->mx);
             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
 
-            if (results[i] >= 0 || results[i] == RXGEN_OPCODE)  {
+            if (results[i] >= 0 || results[i] == RXGEN_OPCODE ||
+                results[i] == CM_RX_RETRY_BUSY_CALL)  {
                 /* mark server as up */
                 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
                 tsp->downTime = 0;
 
                 /* we currently handle 32-bits of capabilities */
-                if (results[i] != RXGEN_OPCODE && caps[i].Capabilities_len > 0) {
+                if (results[i] != RXGEN_OPCODE && results[i] != CM_RX_RETRY_BUSY_CALL &&
+                    caps[i].Capabilities_len > 0) {
                     tsp->capabilities = caps[i].Capabilities_val[0];
                     xdr_free((xdrproc_t) xdr_Capabilities, &caps[i]);
                     caps[i].Capabilities_len = 0;
@@ -620,7 +623,7 @@ static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
             lock_ObtainMutex(&tsp->mx);
             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
 
-            if (results[i] >= 0)  {
+            if (results[i] >= 0 || results[i] == CM_RX_RETRY_BUSY_CALL)  {
                 /* mark server as up */
                 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
                 tsp->downTime = 0;
index d0c04e94c95fcd841b5a167a4a2afc6d08657f34..aff45a81e8bcda827a0aa027175a0964ccb79caa 100644 (file)
@@ -197,6 +197,10 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
     if (desiredAccess == DELETE)
         goto done_2;
 
+    /* Always allow reading attributes (Hidden, System, Readonly, ...) */
+    if (desiredAccess == FILE_READ_ATTRIBUTES)
+        goto done_2;
+
     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
         rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
 
@@ -1327,10 +1331,16 @@ notfound:
     return code;
 }
 
-int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
+int cm_ExpandSysName(cm_req_t * reqp, clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
 {
     clientchar_t *tp;
     int prefixCount;
+#ifdef _WIN64
+    int use_sysname64 = 0;
+
+    if (cm_sysName64Count > 0 && reqp && (reqp->flags & CM_REQ_WOW64) && (reqp->flags & CM_REQ_SOURCE_REDIR))
+        use_sysname64 = 1;
+#endif
 
     tp = cm_ClientStrRChr(inp, '@');
     if (tp == NULL)
@@ -1343,6 +1353,11 @@ int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, uns
     if (outp == NULL)
         return 1;
 
+#ifdef _WIN64
+    if (use_sysname64 && index >= cm_sysName64Count)
+        return -1;
+    else
+#endif
     if (index >= cm_sysNameCount)
         return -1;
 
@@ -1350,8 +1365,14 @@ int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, uns
     prefixCount = (int)(tp - inp);
 
     cm_ClientStrCpyN(outp, outSizeCch, inp, prefixCount);      /* copy out "a." from "a.@sys" */
-    outp[prefixCount] = 0;             /* null terminate the "a." */
-    cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);/* append i386_nt40 */
+    outp[prefixCount] = 0;                                     /* null terminate the "a." */
+#ifdef _WIN64
+    if (use_sysname64)
+        cm_ClientStrCat(outp, outSizeCch, cm_sysName64List[index]);
+    else
+#endif
+        cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);
+
     return 1;
 }
 
@@ -1494,9 +1515,9 @@ long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *us
         return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outScpp);
     }
 
-    if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
+    if (cm_ExpandSysName(reqp, namep, NULL, 0, 0) > 0) {
         for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
-            code = cm_ExpandSysName(namep, tname, lengthof(tname), sysNameIndex);
+            code = cm_ExpandSysName(reqp, namep, tname, lengthof(tname), sysNameIndex);
             if (code > 0) {
                 code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
 #ifdef DEBUG_REFCOUNT
@@ -1654,6 +1675,11 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
     cm_dnlcRemove(dscp, cnamep);
     if (code == 0) {
         cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+        if (RDR_Initialized &&
+            scp->fileType != CM_SCACHETYPE_FILE && scp->fileType != CM_SCACHETYPE_DIRECTORY)
+            RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+                                 dscp->fid.unique, dscp->fid.hash,
+                                 dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
     } else if (code == CM_ERROR_NOSUCHFILE) {
        /* windows would not have allowed the request to delete the file
         * if it did not believe the file existed.  therefore, we must
@@ -1685,6 +1711,11 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
             }
             cm_DiscardSCache(scp);
            lock_ReleaseWrite(&scp->rw);
+            if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR) &&
+                !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+                                      scp->fid.unique, scp->fid.hash,
+                                      scp->fileType, AFS_INVALIDATE_DELETED))
+                buf_ClearRDRFlag(scp, "unlink");
         }
     }
 
@@ -2789,7 +2820,7 @@ long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *a
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
-    if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+    if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
         return CM_ERROR_ATSYS;
     }
 
@@ -2973,7 +3004,7 @@ long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
-    if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+    if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
         return CM_ERROR_ATSYS;
     }
 
@@ -3171,6 +3202,10 @@ long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long fl
     lock_ObtainWrite(&dscp->rw);
     if (code == 0) {
         cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+        if (RDR_Initialized)
+            RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+                                 dscp->fid.unique, dscp->fid.hash,
+                                 dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
     }
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     lock_ReleaseWrite(&dscp->rw);
@@ -3452,6 +3487,11 @@ long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_
             cm_RemoveSCacheFromHashTable(scp);
             lock_ReleaseWrite(&cm_scacheLock);
            lock_ReleaseWrite(&scp->rw);
+            if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR) &&
+                !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+                                      scp->fid.unique, scp->fid.hash,
+                                      scp->fileType, AFS_INVALIDATE_DELETED))
+                buf_ClearRDRFlag(scp, "rmdir");
         }
     }
 
@@ -3830,6 +3870,9 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
     cm_DiscardSCache(oldScp);
     lock_ReleaseWrite(&oldScp->rw);
 
+    if (RDR_Initialized)
+        RDR_InvalidateObject(oldScp->fid.cell, oldScp->fid.volume, oldScp->fid.vnode, oldScp->fid.unique,
+                              oldScp->fid.hash, oldScp->fileType, AFS_INVALIDATE_CALLBACK);
   done:
     if (oldScp)
         cm_ReleaseSCache(oldScp);
@@ -5108,6 +5151,12 @@ long cm_UnlockByKey(cm_scache_t * scp,
 
             fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
 
+            cm_ReleaseUser(fileLock->userp);
+            cm_ReleaseSCacheNoLock(scp);
+
+            fileLock->userp = NULL;
+            fileLock->scp = NULL;
+
             n_unlocks++;
         }
     }
@@ -5122,9 +5171,9 @@ long cm_UnlockByKey(cm_scache_t * scp,
         return 0;
     }
 
-    osi_Log1(afsd_logp, "cm_UnlockByKey done with %d locks", n_unlocks);
-
+    code = cm_IntUnlock(scp, userp, reqp);
     osi_Log1(afsd_logp, "cm_UnlockByKey code 0x%x", code);
+
     osi_Log4(afsd_logp, "   Leaving scp with excl[%d], shared[%d], client[%d], serverLock[%d]",
              scp->exclusiveLocks, scp->sharedLocks, scp->clientLocks,
              (int)(signed char) scp->serverLock);
@@ -5132,6 +5181,7 @@ long cm_UnlockByKey(cm_scache_t * scp,
     return code;
 }
 
+/* Called with scp->rw held */
 long cm_Unlock(cm_scache_t *scp,
                unsigned char sLockType,
                LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
@@ -5234,8 +5284,20 @@ long cm_Unlock(cm_scache_t *scp,
     }
 
     fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
+
+    if (userp != NULL) {
+        cm_ReleaseUser(fileLock->userp);
+    } else {
+        userp = fileLock->userp;
+        release_userp = TRUE;
+    }
+    cm_ReleaseSCacheNoLock(scp);
+    fileLock->userp = NULL;
+    fileLock->scp = NULL;
     lock_ReleaseWrite(&cm_scacheLock);
 
+    code = cm_IntUnlock(scp, userp, reqp);
+
     if (release_userp) {
         cm_ReleaseUser(userp);
         release_userp = FALSE;
@@ -5321,15 +5383,16 @@ void cm_CheckLocks()
             fileLock->userp = NULL;
             fileLock->scp = NULL;
 
-            lock_ReleaseWrite(&cm_scacheLock);
-            lock_ObtainWrite(&scp->rw);
-            code = cm_IntUnlock(scp, userp, &req);
-            lock_ReleaseWrite(&scp->rw);
-
-            cm_ReleaseUser(fileLock->userp);
-            lock_ObtainWrite(&cm_scacheLock);
-            cm_ReleaseSCacheNoLock(scp);
+            if (scp && userp) {
+                lock_ReleaseWrite(&cm_scacheLock);
+                lock_ObtainWrite(&scp->rw);
+                code = cm_IntUnlock(scp, userp, &req);
+                lock_ReleaseWrite(&scp->rw);
 
+                cm_ReleaseUser(userp);
+                lock_ObtainWrite(&cm_scacheLock);
+                cm_ReleaseSCacheNoLock(scp);
+            }
             osi_QRemove(&cm_allFileLocks, q);
             cm_PutFileLock(fileLock);
 
@@ -5830,7 +5893,7 @@ cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16
 int cm_KeyEquals(cm_key_t *k1, cm_key_t *k2, int flags)
 {
     return (k1->session_id == k2->session_id) && (k1->file_id == k2->file_id) &&
-        ((flags & CM_UNLOCK_BY_FID) || (k1->process_id == k2->process_id));
+        ((flags & CM_UNLOCK_FLAG_BY_FID) || (k1->process_id == k2->process_id));
 }
 
 void cm_ReleaseAllLocks(void)
index fcabb743848cb0eb8ad949f17ae88b4a6313c933..b251f4a7b24cdfe2ebcefce48565d39f3238ece4 100644 (file)
@@ -149,7 +149,7 @@ extern long cm_AssembleLink(cm_scache_t *linkScp, fschar_t *pathSuffixp,
                             cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
                             cm_user_t *userp, cm_req_t *reqp);
 
-extern int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch,
+extern int cm_ExpandSysName(cm_req_t *reqp, clientchar_t *inp, clientchar_t *outp, long outSizeCch,
                             unsigned int sysNameIndex);
 
 extern long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp);
@@ -197,15 +197,14 @@ extern long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
                     int allowWait, cm_user_t *userp, cm_req_t *reqp,
                     cm_file_lock_t **lockpp);
 
-#define CM_UNLOCK_BY_FID       0x0001
-
 extern long cm_UnlockByKey(cm_scache_t * scp,
                            cm_key_t key,
                            afs_uint32 flags,
                            cm_user_t * userp,
                            cm_req_t * reqp);
 
-#define CM_UNLOCK_FLAG_MATCH_RANGE      0x01
+#define CM_UNLOCK_FLAG_BY_FID          0x0001
+#define CM_UNLOCK_FLAG_MATCH_RANGE      0x0002
 
 extern long cm_Unlock(cm_scache_t *scp, unsigned char sLockType,
                       LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
index bb15846c33510aac34fea706ebaa0345c3c95790..2097ab3102cfdf94f88245752122a8e06f8e63e7 100644 (file)
 #include "smb.h"
 #include <WINNT/afsreg.h>
 
+extern DWORD RDR_NetworkAddrChange(void);
+extern DWORD RDR_VolumeStatus(ULONG cellID, ULONG volID, BOOLEAN online);
+extern DWORD RDR_NetworkStatus(BOOLEAN status);
+
 HMODULE hVolStatus = NULL;
 dll_VolStatus_Funcs_t dll_funcs;
 cm_VolStatus_Funcs_t cm_funcs;
 
 static char volstat_NetbiosName[64] = "";
 
+static DWORD RDR_Notifications = 0;
+
+rdr_volstat_evt_t *rdr_evtH = NULL;
+rdr_volstat_evt_t *rdr_evtT = NULL;
+
+static EVENT_HANDLE rdr_q_event = NULL;
+
+static osi_mutex_t rdr_evt_lock;
+
+void
+cm_VolStatus_SetRDRNotifications(DWORD onoff)
+{
+    RDR_Notifications = onoff;
+}
+
 afs_uint32
 cm_VolStatus_Active(void)
 {
@@ -77,16 +96,21 @@ cm_VolStatus_Initialization(void)
         code = RegQueryValueEx(parmKey, "VolStatusHandler", NULL, NULL,
                                 (BYTE *) &wd, &dummyLen);
 
-        if (code == 0) {
+        if (code == ERROR_SUCCESS) {
             dummyLen = sizeof(volstat_NetbiosName);
             code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
                                    (BYTE *)volstat_NetbiosName, &dummyLen);
         }
+        if (code == ERROR_SUCCESS && wd[0])
+            hVolStatus = LoadLibrary(wd);
+
+        dummyLen = sizeof(wd);
+        code = RegQueryValueEx(parmKey, "RDRVolStatNotify", NULL, NULL,
+                                (BYTE *) &RDR_Notifications, &dummyLen);
+
         RegCloseKey (parmKey);
     }
 
-    if (code == ERROR_SUCCESS && wd[0])
-        hVolStatus = LoadLibrary(wd);
     if (hVolStatus) {
         (FARPROC) dll_VolStatus_Initialization = GetProcAddress(hVolStatus, "@VolStatus_Initialization@8");
         if (dll_VolStatus_Initialization) {
@@ -106,6 +130,23 @@ cm_VolStatus_Initialization(void)
         }
     }
 
+    if (RDR_Initialized && RDR_Notifications) {
+        long pid;
+        thread_t phandle;
+
+        lock_InitializeMutex(&rdr_evt_lock, "rdr_evt_lock", LOCK_HIERARCHY_IGNORE);
+
+        phandle = thrd_Create((SecurityAttrib) NULL, 0,
+                                       (ThreadFunc) cm_VolStatus_DeliverNotifications,
+                                       0, 0, &pid, "cm_VolStatus_DeliverNotifications");
+        osi_assertx(phandle != NULL, "cm_VolStatus_DeliverNotifications thread creation failure");
+        thrd_CloseHandle(phandle);
+
+        rdr_q_event = thrd_CreateEvent(NULL, TRUE, TRUE, "rdr_q_event");
+        if ( GetLastError() == ERROR_ALREADY_EXISTS )
+            afsi_log("Event Object Already Exists: rdr_q_event");
+    }
+
     osi_Log1(afsd_logp,"cm_VolStatus_Initialization 0x%x", code);
 
     return code;
@@ -119,6 +160,10 @@ cm_VolStatus_Finalize(void)
 {
     osi_Log1(afsd_logp,"cm_VolStatus_Finalize handle 0x%x", hVolStatus);
 
+    if ( RDR_Initialized && RDR_Notifications ) {
+        CloseHandle(rdr_q_event);
+    }
+
     if (hVolStatus == NULL)
         return 0;
 
@@ -180,6 +225,18 @@ cm_VolStatus_Network_Started(const char * netbios32)
 {
     long code = 0;
 
+    if (RDR_Initialized && RDR_Notifications) {
+        rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
+        evp->type = netstatus;
+        evp->netstatus_data.status = TRUE;
+
+        lock_ObtainMutex(&rdr_evt_lock);
+        osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
+        lock_ReleaseMutex(&rdr_evt_lock);
+
+        thrd_SetEvent(rdr_q_event);
+    }
+
     if (hVolStatus == NULL)
         return 0;
 
@@ -205,6 +262,18 @@ cm_VolStatus_Network_Stopped(const char * netbios32)
 {
     long code = 0;
 
+    if (RDR_Initialized && RDR_Notifications) {
+        rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
+        evp->type = netstatus;
+        evp->netstatus_data.status = FALSE;
+
+        lock_ObtainMutex(&rdr_evt_lock);
+        osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
+        lock_ReleaseMutex(&rdr_evt_lock);
+
+        thrd_SetEvent(rdr_q_event);
+    }
+
     if (hVolStatus == NULL)
         return 0;
 
@@ -227,6 +296,17 @@ cm_VolStatus_Network_Addr_Change(void)
 {
     long code = 0;
 
+    if (RDR_Initialized && RDR_Notifications) {
+        rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
+        evp->type = addrchg;
+
+        lock_ObtainMutex(&rdr_evt_lock);
+        osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
+        lock_ReleaseMutex(&rdr_evt_lock);
+
+        thrd_SetEvent(rdr_q_event);
+    }
+
     if (hVolStatus == NULL)
         return 0;
 
@@ -243,6 +323,34 @@ cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volst
 {
     long code = 0;
 
+    if (RDR_Initialized && RDR_Notifications) {
+        rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
+        switch (status) {
+        case vl_alldown:
+        case vl_offline:
+            evp->type = volstatus;
+            evp->volstatus_data.cellID = cellID;
+            evp->volstatus_data.volID = volID;
+            evp->volstatus_data.online = FALSE;
+
+            lock_ObtainMutex(&rdr_evt_lock);
+            osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
+            lock_ReleaseMutex(&rdr_evt_lock);
+            break;
+        default:
+            evp->type = volstatus;
+            evp->volstatus_data.cellID = cellID;
+            evp->volstatus_data.volID = volID;
+            evp->volstatus_data.online = TRUE;
+
+            lock_ObtainMutex(&rdr_evt_lock);
+            osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
+            lock_ReleaseMutex(&rdr_evt_lock);
+        }
+
+        thrd_SetEvent(rdr_q_event);
+    }
+
     if (hVolStatus == NULL)
         return 0;
 
@@ -446,3 +554,38 @@ cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *
     osi_Log1(afsd_logp,"cm_VolStatus_Path_To_DFSlink code 0x%x",code);
     return code;
 }
+
+void
+cm_VolStatus_DeliverNotifications(void * dummy)
+{
+    rdr_volstat_evt_t *evp, *evprev;
+    afs_uint32 code;
+
+    while ( TRUE ) {
+        code = thrd_WaitForSingleObject_Event( rdr_q_event, INFINITE );
+
+        lock_ObtainMutex(&rdr_evt_lock);
+        for (evp = rdr_evtT; evp; evp = evprev)
+        {
+            evprev = (rdr_volstat_evt_t *) osi_QPrev(&evp->q);
+            osi_QRemoveHT((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
+            lock_ReleaseMutex(&rdr_evt_lock);
+
+            switch ( evp->type ) {
+            case addrchg:
+                RDR_NetworkAddrChange();
+                break;
+            case volstatus:
+                RDR_VolumeStatus(evp->volstatus_data.cellID, evp->volstatus_data.volID, evp->volstatus_data.online);
+                break;
+            case netstatus:
+                RDR_NetworkStatus(evp->netstatus_data.status);
+                break;
+            }
+
+            free(evp);
+            lock_ObtainMutex(&rdr_evt_lock);
+        }
+        lock_ReleaseMutex(&rdr_evt_lock);
+    }
+}
index 245fcfcf22299c8a1ee661dab7e7a6db60ff5157..533e59631e297792fd1d1c96477ca68e9916e82b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Secure Endpoints Inc.
+ * Copyright (c) 2007-2011 Secure Endpoints Inc.
  *
  * All rights reserved.
  *
@@ -73,6 +73,11 @@ extern long cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp,
 
 extern long cm_VolStatus_Invalidate_DFS_Mapping(cm_scache_t *scp);
 
+extern void cm_VolStatus_DeliverNotifications(void * dummy);
+
+extern void cm_VolStatus_SetRDRNotifications(DWORD onoff);
+
+
 #define DLL_VOLSTATUS_FUNCS_VERSION 2
 typedef struct dll_VolStatus_Funcs {
     afs_uint32          version;
@@ -112,3 +117,22 @@ struct VolStatTest {
 #define VOLSTAT_TEST_NETWORK_UP      4
 #define VOLSTAT_TEST_NETWORK_DOWN    8
 
+/* redirector - native file system */
+
+enum rdr_event_type { addrchg, volstatus, netstatus };
+
+typedef struct rdr_volstat_evt {
+    osi_queue_t q;
+    enum rdr_event_type type;
+    union {
+        struct {
+            ULONG cellID;
+            ULONG volID;
+            BOOLEAN online;
+        } volstatus_data;
+        struct {
+            BOOLEAN status;
+        } netstatus_data;
+    };
+} rdr_volstat_evt_t;
+
index d0cfdc3703b5c98b8c88dd6ff9104b52532caa29..5efb9f33e88c7cb851c6508132a8816143acc943 100644 (file)
@@ -312,7 +312,7 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         lock_ReleaseWrite(&volp->rw);
 
         if (cellp->flags & CM_CELLFLAG_VLSERVER_INVALID)
-            cm_UpdateCell(cellp, 0);
+             cm_UpdateCell(cellp, 0);
 
         /* now we have volume structure locked and held; make RPC to fill it */
         code = cm_GetEntryByName(cellp, volp->namep, &vldbEntry, &nvldbEntry,
index 8423fb98ddc6975ac7e5f969e0db6077afd50a59..3a993435d6e357935565cbb518821175d9fc632f 100644 (file)
@@ -4839,7 +4839,7 @@ ChGrpCmd(struct cmd_syndesc *as, void *arock)
     for(ti=as->parms[1].items; ti; ti=ti->next) {
         cm_fid_t fid;
         afs_uint32 filetype;
-       char cell[CELL_MAXNAMELEN];
+        char cell[CELL_MAXNAMELEN];
 
         /* once per file */
         memset(&fid, 0, sizeof(fid));
index f69c003061a4b389c6dba3b0f5d5c4e3fd1fb1e3..88638b63810d861fbccd4c9b2bd2a06cef742283 100644 (file)
@@ -24,17 +24,21 @@ SOFTWARE.
 */
 
 
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <roken.h>
+
+
 //#pragma keyword("interface",on)
 //#define interface struct
 #define SECURITY_WIN32
-#include "afslogon.h"
-
 #if (_WIN32_WINNT < 0x0500)
 #error _WIN32_WINNT < 0x0500
 #endif
 
 /**/
 #include <security.h>
+#include <winioctl.h>
 #include <sddl.h>
 #include <unknwn.h>
 #include <oaidl.h>
@@ -42,171 +46,177 @@ SOFTWARE.
 #include <adshlp.h>
 /**/
 
+#include "afslogon.h"
+
+#include "..\afsrdr\common\AFSUserDefines.h"
+#include "..\afsrdr\common\AFSUserIoctl.h"
+#include "..\afsrdr\common\AFSUserStructs.h"
+#include "..\afsrdr\common\AFSProvider.h"
+
 #define SEC_ERR_VALUE(v) if (status==v) return #v
 
 char * _get_sec_err_text(SECURITY_STATUS status) {
-       SEC_ERR_VALUE(SEC_E_OK);
-       SEC_ERR_VALUE(SEC_I_CONTINUE_NEEDED);
-       SEC_ERR_VALUE(SEC_I_COMPLETE_NEEDED);
-       SEC_ERR_VALUE(SEC_I_COMPLETE_AND_CONTINUE);
-       SEC_ERR_VALUE(SEC_E_INCOMPLETE_MESSAGE);
-       SEC_ERR_VALUE(SEC_I_INCOMPLETE_CREDENTIALS);
-       SEC_ERR_VALUE(SEC_E_INVALID_HANDLE);
-       SEC_ERR_VALUE(SEC_E_TARGET_UNKNOWN);
-       SEC_ERR_VALUE(SEC_E_LOGON_DENIED);
-       SEC_ERR_VALUE(SEC_E_INTERNAL_ERROR);
-       SEC_ERR_VALUE(SEC_E_NO_CREDENTIALS);
-       SEC_ERR_VALUE(SEC_E_NO_AUTHENTICATING_AUTHORITY);
-       SEC_ERR_VALUE(SEC_E_INSUFFICIENT_MEMORY);
-       SEC_ERR_VALUE(SEC_E_INVALID_TOKEN);
-       SEC_ERR_VALUE(SEC_E_UNSUPPORTED_FUNCTION);
-       SEC_ERR_VALUE(SEC_E_WRONG_PRINCIPAL);
-       return "Unknown";
+    SEC_ERR_VALUE(SEC_E_OK);
+    SEC_ERR_VALUE(SEC_I_CONTINUE_NEEDED);
+    SEC_ERR_VALUE(SEC_I_COMPLETE_NEEDED);
+    SEC_ERR_VALUE(SEC_I_COMPLETE_AND_CONTINUE);
+    SEC_ERR_VALUE(SEC_E_INCOMPLETE_MESSAGE);
+    SEC_ERR_VALUE(SEC_I_INCOMPLETE_CREDENTIALS);
+    SEC_ERR_VALUE(SEC_E_INVALID_HANDLE);
+    SEC_ERR_VALUE(SEC_E_TARGET_UNKNOWN);
+    SEC_ERR_VALUE(SEC_E_LOGON_DENIED);
+    SEC_ERR_VALUE(SEC_E_INTERNAL_ERROR);
+    SEC_ERR_VALUE(SEC_E_NO_CREDENTIALS);
+    SEC_ERR_VALUE(SEC_E_NO_AUTHENTICATING_AUTHORITY);
+    SEC_ERR_VALUE(SEC_E_INSUFFICIENT_MEMORY);
+    SEC_ERR_VALUE(SEC_E_INVALID_TOKEN);
+    SEC_ERR_VALUE(SEC_E_UNSUPPORTED_FUNCTION);
+    SEC_ERR_VALUE(SEC_E_WRONG_PRINCIPAL);
+    return "Unknown";
 }
 
 #undef SEC_ERR_VALUE
 
-DWORD LogonSSP(PLUID lpLogonId, PCtxtHandle outCtx) {
-       DWORD code = 1;
+DWORD
+LogonSSP(PLUID lpLogonId, PCtxtHandle outCtx) {
+    DWORD code = 1;
     SECURITY_STATUS status;
-       CredHandle creds;
-       CtxtHandle ctxclient,ctxserver;
-       TimeStamp expiry;
-       BOOL cont = TRUE;
-       BOOL first = TRUE;
-       SecBufferDesc sdescc,sdescs;
-       SecBuffer stokc,stoks;
-       ULONG cattrs,sattrs;
-       int iters = 10;
-
-       outCtx->dwLower = 0;
-       outCtx->dwUpper = 0;
-
-       cattrs = 0;
-       sattrs = 0;
-
-       status = AcquireCredentialsHandle(
-               NULL,
-               "Negotiate",
-               SECPKG_CRED_BOTH,
-               lpLogonId,
-               NULL,
-               NULL,
-               NULL,
-               &creds,
-               &expiry);
-
-       if (status != SEC_E_OK) {
-               DebugEvent("AcquireCredentialsHandle failed: %lX", status);
-               goto ghp_0;
-       }
-
-       sdescc.cBuffers = 1;
-       sdescc.pBuffers = &stokc;
-       sdescc.ulVersion = SECBUFFER_VERSION;
-
-       stokc.BufferType = SECBUFFER_TOKEN;
-       stokc.cbBuffer = 0;
-       stokc.pvBuffer = NULL;
-
-       sdescs.cBuffers = 1;
-       sdescs.pBuffers = &stoks;
-       sdescs.ulVersion = SECBUFFER_VERSION;
-
-       stoks.BufferType = SECBUFFER_TOKEN;
-       stoks.cbBuffer = 0;
-       stoks.pvBuffer = NULL;
-
-       do {
-               status = InitializeSecurityContext(
-                       &creds,
-                       ((first)? NULL:&ctxclient),
-            NULL,
-                       ISC_REQ_DELEGATE | ISC_REQ_ALLOCATE_MEMORY,
-                       0,
-                       SECURITY_NATIVE_DREP,
-                       ((first)?NULL:&sdescs),
-                       0,
-                       &ctxclient,
-                       &sdescc,
-                       &cattrs,
-                       &expiry
-                       );
-
-               DebugEvent("InitializeSecurityContext returns status[%lX](%s)",status,_get_sec_err_text(status));
-
-               if (!first) FreeContextBuffer(stoks.pvBuffer);
-
-               if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
-                       CompleteAuthToken(&ctxclient, &sdescc);
-               }
-
-               if (status != SEC_I_CONTINUE_NEEDED && status != SEC_I_COMPLETE_AND_CONTINUE) {
-                       cont = FALSE;
-               }
-
-               if (!stokc.cbBuffer && !cont) {
-                       DebugEvent("Breaking out after InitializeSecurityContext");
-                       break;
-               }
-
-               status = AcceptSecurityContext(
-                       &creds,
-                       ((first)?NULL:&ctxserver),
-                       &sdescc,
-                       ASC_REQ_DELEGATE | ASC_REQ_ALLOCATE_MEMORY,
-                       SECURITY_NATIVE_DREP,
-                       &ctxserver,
-                       &sdescs,
-                       &sattrs,
-                       &expiry);
-
-               DebugEvent("AcceptSecurityContext returns status[%lX](%s)", status, _get_sec_err_text(status));
-
-               FreeContextBuffer(stokc.pvBuffer);
-
-               if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
-                       CompleteAuthToken(&ctxserver,&sdescs);
-               }
-
-               if (status == SEC_I_CONTINUE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
-                       cont = TRUE;
-               }
-
-               if (!cont)
-                       FreeContextBuffer(stoks.pvBuffer);
-
-               first = FALSE;
-               iters--; /* just in case, hard limit on loop */
-       } while (cont && iters);
-
-       if (sattrs & ASC_RET_DELEGATE) {
-               DebugEvent("Received delegate context");
-               *outCtx = ctxserver;
-               code = 0;
-       } else {
-               DebugEvent("Didn't receive delegate context");
-               outCtx->dwLower = 0;
-               outCtx->dwUpper = 0;
-               DeleteSecurityContext(&ctxserver);
-       }
-
-       DeleteSecurityContext(&ctxclient);
+    CredHandle creds;
+    CtxtHandle ctxclient,ctxserver;
+    TimeStamp expiry;
+    BOOL cont = TRUE;
+    BOOL first = TRUE;
+    SecBufferDesc sdescc,sdescs;
+    SecBuffer stokc,stoks;
+    ULONG cattrs,sattrs;
+    int iters = 10;
+
+    outCtx->dwLower = 0;
+    outCtx->dwUpper = 0;
+
+    cattrs = 0;
+    sattrs = 0;
+
+    status = AcquireCredentialsHandle( NULL,
+                                       "Negotiate",
+                                       SECPKG_CRED_BOTH,
+                                       lpLogonId,
+                                       NULL,
+                                       NULL,
+                                       NULL,
+                                       &creds,
+                                       &expiry);
+
+    if (status != SEC_E_OK) {
+        DebugEvent("AcquireCredentialsHandle failed: %lX", status);
+        goto ghp_0;
+    }
+
+    sdescc.cBuffers = 1;
+    sdescc.pBuffers = &stokc;
+    sdescc.ulVersion = SECBUFFER_VERSION;
+
+    stokc.BufferType = SECBUFFER_TOKEN;
+    stokc.cbBuffer = 0;
+    stokc.pvBuffer = NULL;
+
+    sdescs.cBuffers = 1;
+    sdescs.pBuffers = &stoks;
+    sdescs.ulVersion = SECBUFFER_VERSION;
+
+    stoks.BufferType = SECBUFFER_TOKEN;
+    stoks.cbBuffer = 0;
+    stoks.pvBuffer = NULL;
+
+    do {
+        status = InitializeSecurityContext( &creds,
+                                            ((first)? NULL:&ctxclient),
+                                            NULL,
+                                            ISC_REQ_DELEGATE | ISC_REQ_ALLOCATE_MEMORY,
+                                            0,
+                                            SECURITY_NATIVE_DREP,
+                                            ((first)?NULL:&sdescs),
+                                            0,
+                                            &ctxclient,
+                                            &sdescc,
+                                            &cattrs,
+                                            &expiry
+                                            );
+
+        DebugEvent("InitializeSecurityContext returns status[%lX](%s)",status,_get_sec_err_text(status));
+
+        if (!first) FreeContextBuffer(stoks.pvBuffer);
+
+        if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
+            CompleteAuthToken(&ctxclient, &sdescc);
+        }
+
+        if (status != SEC_I_CONTINUE_NEEDED && status != SEC_I_COMPLETE_AND_CONTINUE) {
+            cont = FALSE;
+        }
+
+        if (!stokc.cbBuffer && !cont) {
+            DebugEvent("Breaking out after InitializeSecurityContext");
+            break;
+        }
+
+        status = AcceptSecurityContext( &creds,
+                                        ((first)?NULL:&ctxserver),
+                                        &sdescc,
+                                        ASC_REQ_DELEGATE | ASC_REQ_ALLOCATE_MEMORY,
+                                        SECURITY_NATIVE_DREP,
+                                        &ctxserver,
+                                        &sdescs,
+                                        &sattrs,
+                                        &expiry);
+
+        DebugEvent("AcceptSecurityContext returns status[%lX](%s)", status, _get_sec_err_text(status));
+
+        FreeContextBuffer(stokc.pvBuffer);
+
+        if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
+            CompleteAuthToken(&ctxserver,&sdescs);
+        }
+
+        if (status == SEC_I_CONTINUE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
+            cont = TRUE;
+        }
+
+        if (!cont)
+            FreeContextBuffer(stoks.pvBuffer);
+
+        first = FALSE;
+        iters--; /* just in case, hard limit on loop */
+    } while (cont && iters);
+
+    if (sattrs & ASC_RET_DELEGATE) {
+        DebugEvent("Received delegate context");
+        *outCtx = ctxserver;
+        code = 0;
+    } else {
+        DebugEvent("Didn't receive delegate context");
+        outCtx->dwLower = 0;
+        outCtx->dwUpper = 0;
+        DeleteSecurityContext(&ctxserver);
+    }
+
+    DeleteSecurityContext(&ctxclient);
     FreeCredentialsHandle(&creds);
-ghp_0:
-       return code;
+  ghp_0:
+    return code;
 }
 
-DWORD QueryAdHomePathFromSid(char * homePath, size_t homePathLen, PSID psid, PWSTR domain) {
-       DWORD code = 1; /* default is failure */
-       NTSTATUS rv = 0;
-       HRESULT hr = S_OK;
-       LPWSTR p = NULL;
-       WCHAR adsPath[MAX_PATH] = L"";
-       BOOL coInitialized = FALSE;
+DWORD
+QueryAdHomePathFromSid(char * homePath, size_t homePathLen, PSID psid, PWSTR domain) {
+    DWORD code = 1; /* default is failure */
+    NTSTATUS rv = 0;
+    HRESULT hr = S_OK;
+    LPWSTR p = NULL;
+    WCHAR adsPath[MAX_PATH] = L"";
+    BOOL coInitialized = FALSE;
     CHAR ansidomain[256], *a;
 
-       homePath[0] = '\0';
+    homePath[0] = '\0';
 
     /* I trust this is an ASCII domain name */
     for ( p=domain, a=ansidomain; *a = (CHAR)*p; p++, a++);
@@ -227,7 +237,9 @@ DWORD QueryAdHomePathFromSid(char * homePath, size_t homePathLen, PSID psid, PWS
                                IID_IADsNameTranslate,
                                (void**)&pNto);
 
-        if (FAILED(hr)) { DebugEvent("Can't create nametranslate object"); }
+        if (FAILED(hr)) {
+            DebugEvent("Can't create nametranslate object");
+        }
         else {
             hr = pNto->Init(ADS_NAME_INITTYPE_GC,L"");
             if (FAILED(hr)) {
@@ -242,7 +254,9 @@ DWORD QueryAdHomePathFromSid(char * homePath, size_t homePathLen, PSID psid, PWS
 
             if (!FAILED(hr)) {
                 hr = pNto->Set(ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME, p);
-                if (FAILED(hr)) { DebugEvent("Can't set sid string"); }
+                if (FAILED(hr)) {
+                    DebugEvent("Can't set sid string");
+                }
                 else {
                     BSTR bstr;
 
@@ -262,103 +276,104 @@ DWORD QueryAdHomePathFromSid(char * homePath, size_t homePathLen, PSID psid, PWS
         }
 
         LocalFree(p);
-
     } else {
         DebugEvent("Can't convert sid to string");
     }
 
-       if (adsPath[0]) {
-               WCHAR fAdsPath[MAX_PATH];
-               IADsUser *pAdsUser;
-               BSTR bstHomeDir = NULL;
+    if (adsPath[0]) {
+        WCHAR fAdsPath[MAX_PATH];
+        IADsUser *pAdsUser;
+        BSTR bstHomeDir = NULL;
 
-               hr = StringCchPrintfW(fAdsPath, MAX_PATH, L"LDAP://%s", adsPath);
-               if (hr != S_OK) {
-                       DebugEvent("Can't format full adspath");
-                       goto cleanup;
-               }
+        hr = StringCchPrintfW(fAdsPath, MAX_PATH, L"LDAP://%s", adsPath);
+        if (hr != S_OK) {
+            DebugEvent("Can't format full adspath");
+            goto cleanup;
+        }
 
-               DebugEvent("Trying adsPath=[%S]", fAdsPath);
+        DebugEvent("Trying adsPath=[%S]", fAdsPath);
 
-               hr = ADsGetObject( fAdsPath, IID_IADsUser, (LPVOID *) &pAdsUser);
-               if (hr != S_OK) {
-                       DebugEvent("Can't open IADs object");
-                       goto cleanup;
-               }
+        hr = ADsGetObject( fAdsPath, IID_IADsUser, (LPVOID *) &pAdsUser);
+        if (hr != S_OK) {
+            DebugEvent("Can't open IADs object");
+            goto cleanup;
+        }
 
         hr = pAdsUser->get_Profile(&bstHomeDir);
-               if (hr != S_OK) {
-                       DebugEvent("Can't get profile directory");
-                       goto cleanup_homedir_section;
-               }
+        if (hr != S_OK) {
+            DebugEvent("Can't get profile directory");
+            goto cleanup_homedir_section;
+        }
 
-               wcstombs(homePath, bstHomeDir, homePathLen);
+        wcstombs(homePath, bstHomeDir, homePathLen);
 
-               DebugEvent("Got homepath [%s]", homePath);
+        DebugEvent("Got homepath [%s]", homePath);
 
-               SysFreeString(bstHomeDir);
+        SysFreeString(bstHomeDir);
 
-               code = 0;
+        code = 0;
 
-cleanup_homedir_section:
-               pAdsUser->Release();
-       }
+      cleanup_homedir_section:
+        pAdsUser->Release();
+    }
 
-cleanup:
-       if (coInitialized)
-               CoUninitialize();
+  cleanup:
+    if (coInitialized)
+        CoUninitialize();
 
-       return code;
+    return code;
 }
 
 /* Try to determine the user's AD home path.  *homePath is assumed to be at least MAXPATH bytes.
    If successful, opt.flags is updated with LOGON_FLAG_AD_REALM to indicate that we are dealing with
    an AD realm. */
-DWORD GetAdHomePath(char * homePath, size_t homePathLen, PLUID lpLogonId, LogonOptions_t * opt) {
-       CtxtHandle ctx;
-       DWORD code = 0;
-       SECURITY_STATUS status;
+DWORD
+GetAdHomePath(char * homePath, size_t homePathLen, PLUID lpLogonId, LogonOptions_t * opt) {
+    CtxtHandle ctx;
+    DWORD code = 0;
+    SECURITY_STATUS status;
 
-       homePath[0] = '\0';
+    homePath[0] = '\0';
 
-       if (LogonSSP(lpLogonId,&ctx)) {
+    if (LogonSSP(lpLogonId,&ctx)) {
         DebugEvent("Failed LogonSSP");
-               return 1;
-    } else {
-               status = ImpersonateSecurityContext(&ctx);
-               if (status == SEC_E_OK) {
-                   PSECURITY_LOGON_SESSION_DATA plsd;
-            NTSTATUS rv;
-
-            rv = LsaGetLogonSessionData(lpLogonId, &plsd);
-            if (rv == 0) {
-                PWSTR domain;
-
-                domain = (PWSTR)malloc(sizeof(WCHAR) * (plsd->LogonDomain.Length+1));
-                memcpy(domain, plsd->LogonDomain.Buffer, sizeof(WCHAR) * (plsd->LogonDomain.Length));
-                domain[plsd->LogonDomain.Length] = 0;
-
-                if (!QueryAdHomePathFromSid(homePath,homePathLen,plsd->Sid,domain)) {
-                    DebugEvent("Returned home path [%s]",homePath);
-                    opt->flags |= LOGON_FLAG_AD_REALM;
-                }
-                free(domain);
-                LsaFreeReturnBuffer(plsd);
-            } else {
-                DebugEvent("LsaGetLogonSessionData failed [%lX]", rv);
+        return 1;
+    }
+
+    status = ImpersonateSecurityContext(&ctx);
+    if (status == SEC_E_OK) {
+        PSECURITY_LOGON_SESSION_DATA plsd;
+        NTSTATUS rv;
+
+        rv = LsaGetLogonSessionData(lpLogonId, &plsd);
+        if (rv == 0) {
+            PWSTR domain;
+
+            domain = (PWSTR)malloc(sizeof(WCHAR) * (plsd->LogonDomain.Length+1));
+            memcpy(domain, plsd->LogonDomain.Buffer, sizeof(WCHAR) * (plsd->LogonDomain.Length));
+            domain[plsd->LogonDomain.Length] = 0;
+
+            if (!QueryAdHomePathFromSid(homePath,homePathLen,plsd->Sid,domain)) {
+                DebugEvent("Returned home path [%s]",homePath);
+                opt->flags |= LOGON_FLAG_AD_REALM;
             }
-            RevertSecurityContext(&ctx);
-               } else {
-                       DebugEvent("Can't impersonate context [%lX]",status);
-                       code = 1;
-               }
-
-        DeleteSecurityContext(&ctx);
-               return code;
-       }
+            free(domain);
+            LsaFreeReturnBuffer(plsd);
+        } else {
+            DebugEvent("LsaGetLogonSessionData failed [%lX]", rv);
+        }
+        RevertSecurityContext(&ctx);
+    } else {
+        DebugEvent("Can't impersonate context [%lX]",status);
+        code = 1;
+    }
+
+    DeleteSecurityContext(&ctx);
+    return code;
 }
 
-BOOL GetLocalShortDomain(PWSTR Domain, DWORD cbDomain)
+BOOL
+GetLocalShortDomain(PWSTR Domain, DWORD cbDomain)
 {
     HRESULT hr;
     IADsADSystemInfo *pADsys;
@@ -369,7 +384,7 @@ BOOL GetLocalShortDomain(PWSTR Domain, DWORD cbDomain)
     if (SUCCEEDED(hr))
         coInitialized = TRUE;
 
-    hr = CoCreateInstance(CLSID_ADSystemInfo,
+    hr = CoCreateInstance( CLSID_ADSystemInfo,
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            IID_IADsADSystemInfo,
@@ -388,8 +403,260 @@ BOOL GetLocalShortDomain(PWSTR Domain, DWORD cbDomain)
         pADsys->Release();
     }
 
-       if (coInitialized)
-               CoUninitialize();
+    if (coInitialized)
+        CoUninitialize();
 
     return retval;
 }
+
+static HANDLE
+OpenRedirector(void)
+{
+    HANDLE hControlDevice = NULL;
+
+    hControlDevice = CreateFileW( AFS_SYMLINK_W,
+                                 GENERIC_READ | GENERIC_WRITE,
+                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 0,
+                                 NULL );
+
+    if( hControlDevice == INVALID_HANDLE_VALUE)
+    {
+        hControlDevice = NULL;
+        DebugEvent("OpenRedirector Failed to open control device error: %d",
+                    GetLastError());
+    }
+
+    return hControlDevice;
+}
+
+void
+AFSCreatePAG(PLUID lpLogonId)
+{
+    BOOLEAN             bRet = FALSE;
+    HANDLE              hControlDevice = NULL;
+    DWORD               dwCopyBytes = 0;
+    AFSAuthGroupRequestCB *pAuthGroup = NULL;
+    WCHAR *             pwchSIDString = NULL;
+    CtxtHandle          ctx;
+    SECURITY_STATUS     status;
+    PSECURITY_LOGON_SESSION_DATA plsd = NULL;
+    NTSTATUS            rv;
+    BOOLEAN             bImpersonated = FALSE;
+
+    GUID stAuthGroup;
+    unsigned char *pchGUID = NULL;
+    DWORD bytesReturned;
+
+    if (LogonSSP(lpLogonId, &ctx)) {
+        DebugEvent("AFSCreatePAG unable to obtain LogonSSP context");
+        return;
+    }
+
+    status = ImpersonateSecurityContext(&ctx);
+    if (status == SEC_E_OK)
+    {
+        bImpersonated = TRUE;
+
+        rv = LsaGetLogonSessionData(lpLogonId, &plsd);
+        if (rv == 0)
+        {
+            if( !ConvertSidToStringSidW( plsd->Sid,
+                                         &pwchSIDString))
+            {
+                DebugEvent("AFSCreatePAG Failed to convert sid to string Error %08X", GetLastError());
+                goto cleanup;
+            }
+
+            pAuthGroup = (AFSAuthGroupRequestCB *)LocalAlloc( LPTR, 0x1000);
+
+            if( pAuthGroup == NULL)
+            {
+                DebugEvent0("AFSCreatePAG Failed auth group allocation");
+                goto cleanup;
+            }
+
+            memset( pAuthGroup, 0, 0x1000);
+
+            pAuthGroup->SIDLength = (USHORT) (wcslen( pwchSIDString) * sizeof( WCHAR));
+            pAuthGroup->SessionId = plsd->Session;
+
+            memcpy( pAuthGroup->SIDString,
+                    pwchSIDString,
+                    pAuthGroup->SIDLength);
+
+            RevertSecurityContext(&ctx);
+
+            bImpersonated = FALSE;
+
+            hControlDevice = OpenRedirector();
+
+            if( hControlDevice == NULL)
+            {
+                DebugEvent0("AFSCreatePAG Failed to open redirector");
+                goto cleanup;
+            }
+
+            bRet = DeviceIoControl( hControlDevice,
+                                   IOCTL_AFS_AUTHGROUP_SID_QUERY,
+                                   NULL,
+                                   0,
+                                   &stAuthGroup,
+                                   sizeof( GUID),
+                                   &bytesReturned,
+                                   NULL);
+
+            if( bRet == FALSE)
+            {
+                DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Error 0x%08X", GetLastError());
+            }
+            else
+            {
+                if( UuidToString( (UUID *)&stAuthGroup,
+                                  &pchGUID) == RPC_S_OK)
+                {
+                    DebugEvent("AFSCreatePAG Initial AuthGroup %s\n", pchGUID);
+                    RpcStringFree( &pchGUID);
+                }
+                else
+                {
+                    DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
+                }
+            }
+
+            ImpersonateSecurityContext(&ctx); bImpersonated = TRUE;
+
+            bRet = DeviceIoControl( hControlDevice,
+                                    IOCTL_AFS_AUTHGROUP_SID_QUERY,
+                                    NULL,
+                                    0,
+                                    &stAuthGroup,
+                                    sizeof( GUID),
+                                    &bytesReturned,
+                                    NULL);
+
+            if( bRet == FALSE)
+            {
+                DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Impersonation Error 0x%08X", GetLastError());
+            }
+            else
+            {
+                if( UuidToString( (UUID *)&stAuthGroup,
+                                  &pchGUID) == RPC_S_OK)
+                {
+                    DebugEvent("AFSCreatePAG Initial Impersonation AuthGroup %s\n", pchGUID);
+                    RpcStringFree( &pchGUID);
+                }
+                else
+                {
+                    DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
+                }
+            }
+
+            RevertSecurityContext(&ctx); bImpersonated = FALSE;
+
+
+            bRet = DeviceIoControl( hControlDevice,
+                                    IOCTL_AFS_AUTHGROUP_LOGON_CREATE,
+                                    pAuthGroup,
+                                    sizeof( AFSAuthGroupRequestCB) + pAuthGroup->SIDLength - 1,
+                                    NULL,
+                                    0,
+                                    &dwCopyBytes,
+                                    NULL);
+
+            if( bRet == FALSE)
+            {
+                DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_CREATE Error 0x%08X", GetLastError());
+            }
+            else
+            {
+                bRet = DeviceIoControl( hControlDevice,
+                                        IOCTL_AFS_AUTHGROUP_SID_QUERY,
+                                        NULL,
+                                        0,
+                                        &stAuthGroup,
+                                        sizeof( GUID),
+                                        &bytesReturned,
+                                        NULL);
+
+                if( bRet == FALSE)
+                {
+                    DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Error 0x%08X", GetLastError());
+                }
+                else
+                {
+                    if( UuidToString( (UUID *)&stAuthGroup,
+                                      &pchGUID) == RPC_S_OK)
+                    {
+                        DebugEvent("AFSCreatePAG New AuthGroup %s\n", pchGUID);
+                        RpcStringFree( &pchGUID);
+                    }
+                    else
+                    {
+                        DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
+                    }
+                }
+            }
+
+            ImpersonateSecurityContext(&ctx);
+
+            bRet = DeviceIoControl( hControlDevice,
+                                    IOCTL_AFS_AUTHGROUP_SID_QUERY,
+                                    NULL,
+                                    0,
+                                    &stAuthGroup,
+                                    sizeof( GUID),
+                                    &bytesReturned,
+                                    NULL);
+
+            if( bRet == FALSE)
+            {
+                DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Impersonation Error 0x%08X", GetLastError());
+            }
+            else
+            {
+                if( UuidToString( (UUID *)&stAuthGroup,
+                                  &pchGUID) == RPC_S_OK)
+                {
+                    DebugEvent("AFSCreatePAG New Impersonation AuthGroup %s\n", pchGUID);
+                    RpcStringFree( &pchGUID);
+                }
+                else
+                {
+                    DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
+                }
+            }
+
+            RevertSecurityContext(&ctx);
+        }
+        else
+        {
+            DebugEvent("AFSCreatePAG LsaGetLogonSessionData failed [%lX]", rv);
+        }
+
+    }
+    else
+    {
+        DebugEvent("AFSCreatePAG cannot impersonate context [%lX]", status);
+    }
+
+
+  cleanup:
+
+    if (bImpersonated)
+        RevertSecurityContext(&ctx);
+
+    DeleteSecurityContext(&ctx);
+
+    if (plsd != NULL)
+        LsaFreeReturnBuffer(plsd);
+
+    if ( hControlDevice != NULL)
+        CloseHandle( hControlDevice);
+
+    if( pwchSIDString != NULL)
+        LocalFree( pwchSIDString);
+}
index 24cd62a040c8e37704ecbd445b1a0ba06b0d9f0d..2b7df2206f130c00469076ff48385bbee93b573c 100644 (file)
@@ -3117,11 +3117,11 @@ void smb_MapNTError(long code, unsigned long *NTStatusp, afs_uint32 redir)
             NTStatus = 0xC000022DL;    /* Retry */
         else {
 #ifdef COMMENT
-        NTStatus = 0xC000022DL;        /* Retry */
+            NTStatus = 0xC000022DL;    /* Retry */
 #else
-        NTStatus = 0xC00000B5L; /* I/O Timeout */
+            NTStatus = 0xC00000B5L; /* I/O Timeout */
 #endif
-    }
+        }
     }
     else if (code == CM_ERROR_NOACCESS) {
         NTStatus = 0xC0000022L;        /* Access denied */
@@ -3281,7 +3281,10 @@ void smb_MapNTError(long code, unsigned long *NTStatusp, afs_uint32 redir)
     else if (code == CM_ERROR_RPC_MOREDATA) {
        NTStatus = 0x80000005L; /* Buffer overflow */
     }
-    else  {
+    else {
+        char foo[256];
+        sprintf(foo, "No mapping for 0x%X using 0xC0982001\r\n", code);
+        OutputDebugString(foo);
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
 
@@ -6932,8 +6935,10 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
         lock_ReleaseMutex(&fidp->mx);
 
-        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
-              * in zero. */
+        /*
+         * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
+         * We pass in zero.
+         */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
         lock_ObtainWrite(&scp->rw);
 
@@ -6948,7 +6953,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             goto post_syncopdone;
         }
 
-        cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
+        cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
 
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
 
index af59a3852547deab36f0a1168e400494ffb69188..7c453f3e1f5cec6dd71e143d4ad696fb1958d0d5 100644 (file)
@@ -1087,6 +1087,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             * be freed when the refCount returns to zero.
             */
            unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
+            if (usernIsSID)
+                unp->flags |= SMB_USERNAMEFLAG_SID;
        }
     if (usernIsSID)
         unp->flags |= SMB_USERNAMEFLAG_SID;
diff --git a/src/WINNT/afsrdr/user/RDRFunction.c b/src/WINNT/afsrdr/user/RDRFunction.c
new file mode 100644 (file)
index 0000000..eb71773
--- /dev/null
@@ -0,0 +1,5334 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints, Inc.
+ * Copyright (c) 2009-2011 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#define _CRT_SECURE_NO_DEPRECATE
+#define _CRT_NON_CONFORMING_SWPRINTFS
+#define INITGUID        /* define AFS_AUTH_GUID_NO_PAG */
+
+#include <ntstatus.h>
+#define WIN32_NO_STATUS
+#include <windows.h>
+
+#include <roken.h>
+
+#include <afs/stds.h>
+
+#include <ntsecapi.h>
+#include <sddl.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
+
+#include <devioctl.h>
+
+#include "..\\Common\\AFSUserDefines.h"
+#include "..\\Common\\AFSUserStructs.h"
+
+#pragma warning(pop)
+
+#include <tchar.h>
+#include <wchar.h>
+#include <winbase.h>
+#include <winreg.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <strsafe.h>
+
+#include "afsd.h"
+#include "smb.h"
+#include "cm_btree.h"
+#include "msrpc.h"
+#include <RDRPrototypes.h>
+#include <RDRIoctl.h>
+#include <RDRPipe.h>
+
+static CHAR * RDR_extentBaseAddress = NULL;
+
+void
+RDR_InitReq(cm_req_t *reqp)
+{
+    cm_InitReq(reqp);
+    reqp->flags |= CM_REQ_SOURCE_REDIR;
+}
+
+void
+RDR_fid2FID( cm_fid_t *fid, AFSFileID *FileId)
+{
+    FileId->Cell = fid->cell;
+    FileId->Volume = fid->volume;
+    FileId->Vnode = fid->vnode;
+    FileId->Unique = fid->unique;
+    FileId->Hash = fid->hash;
+}
+
+void
+RDR_FID2fid( AFSFileID *FileId, cm_fid_t *fid)
+{
+    fid->cell = FileId->Cell;
+    fid->volume = FileId->Volume;
+    fid->vnode = FileId->Vnode;
+    fid->unique = FileId->Unique;
+    fid->hash = FileId->Hash;
+}
+
+DWORD
+RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRedirInitInfoLen )
+{
+    extern char cm_CachePath[];
+    extern cm_config_data_t cm_data;
+    extern int smb_hideDotFiles;
+    size_t cm_CachePathLen = strlen(cm_CachePath);
+    size_t err;
+    DWORD TempPathLen = ExpandEnvironmentStringsW(L"%TEMP%", NULL, 0);
+    MEMORYSTATUSEX memStatus;
+    DWORD maxMemoryCacheSize;
+
+    memStatus.dwLength = sizeof(memStatus);
+    if (GlobalMemoryStatusEx(&memStatus)) {
+        /*
+         * Use the memory extent interface in the afs redirector
+         * whenever the cache size is less than equal to 10% of
+         * physical memory.  Do not use too much because this memory
+         * will be locked by the redirector so it can't be swapped
+         * out.
+         */
+        maxMemoryCacheSize = (DWORD)(memStatus.ullTotalPhys / 1024 / 10);
+    } else {
+        /*
+         * If we can't determine the amount of physical memory
+         * in the system, be conservative and limit the use of
+         * memory extent interface to 64MB data caches.
+         */
+        maxMemoryCacheSize = 65536;
+    }
+
+    *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (cm_CachePathLen + TempPathLen) * sizeof(WCHAR));
+    *ppRedirInitInfo = (AFSRedirectorInitInfo *)malloc(*pRedirInitInfoLen);
+    (*ppRedirInitInfo)->Flags = smb_hideDotFiles ? AFS_REDIR_INIT_FLAG_HIDE_DOT_FILES : 0;
+    (*ppRedirInitInfo)->MaximumChunkLength = cm_data.chunkSize;
+    (*ppRedirInitInfo)->GlobalFileId.Cell   = cm_data.rootFid.cell;
+    (*ppRedirInitInfo)->GlobalFileId.Volume = cm_data.rootFid.volume;
+    (*ppRedirInitInfo)->GlobalFileId.Vnode  = cm_data.rootFid.vnode;
+    (*ppRedirInitInfo)->GlobalFileId.Unique = cm_data.rootFid.unique;
+    (*ppRedirInitInfo)->GlobalFileId.Hash   = cm_data.rootFid.hash;
+    (*ppRedirInitInfo)->ExtentCount.QuadPart = cm_data.buf_nbuffers;
+    (*ppRedirInitInfo)->CacheBlockSize = cm_data.blockSize;
+    (*ppRedirInitInfo)->MaxPathLinkCount = 512; /* this needs to become a registry value */
+    (*ppRedirInitInfo)->NameArrayLength = 32;   /* this needs to become a registry value */
+    if (cm_virtualCache || cm_data.bufferSize <= maxMemoryCacheSize) {
+        osi_Log0(afsd_logp, "RDR_SetInitParams Initializing Memory Extent Interface");
+        (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = (LONGLONG)cm_data.bufDataBaseAddress;
+        (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = cm_data.bufEndOfData - cm_data.bufDataBaseAddress;
+        (*ppRedirInitInfo)->CacheFileNameLength = 0;
+        RDR_extentBaseAddress = cm_data.bufDataBaseAddress;
+    } else {
+        (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = 0;
+        (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = 0;
+        (*ppRedirInitInfo)->CacheFileNameLength = (ULONG) (cm_CachePathLen * sizeof(WCHAR));
+        err = mbstowcs((*ppRedirInitInfo)->CacheFileName, cm_CachePath, (cm_CachePathLen + 1) *sizeof(WCHAR));
+        if (err == -1) {
+            free(*ppRedirInitInfo);
+            osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
+            return STATUS_OBJECT_NAME_INVALID;
+        }
+        RDR_extentBaseAddress = cm_data.baseAddress;
+    }
+    (*ppRedirInitInfo)->DumpFileLocationOffset = FIELD_OFFSET(AFSRedirectorInitInfo, CacheFileName) + (*ppRedirInitInfo)->CacheFileNameLength;
+    (*ppRedirInitInfo)->DumpFileLocationLength = (TempPathLen - 1) * sizeof(WCHAR);
+    ExpandEnvironmentStringsW(L"%TEMP%",
+                              (LPWSTR)(((PBYTE)(*ppRedirInitInfo)) + (*ppRedirInitInfo)->DumpFileLocationOffset),
+                              TempPathLen);
+
+    osi_Log0(afsd_logp,"RDR_SetInitParams Success");
+    return 0;
+}
+
+cm_user_t *
+RDR_GetLocalSystemUser( void)
+{
+    smb_username_t *unp;
+    cm_user_t *userp = NULL;
+    wchar_t cname[MAX_COMPUTERNAME_LENGTH+1];
+    int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
+
+    GetComputerNameW(cname, &cnamelen);
+    _wcsupr(cname);
+
+    unp = smb_FindUserByName(NTSID_LOCAL_SYSTEM, cname, SMB_FLAG_CREATE);
+    lock_ObtainMutex(&unp->mx);
+    if (!unp->userp)
+        unp->userp = cm_NewUser();
+    unp->flags |= SMB_USERNAMEFLAG_SID;
+    lock_ReleaseMutex(&unp->mx);
+    userp = unp->userp;
+    cm_HoldUser(userp);
+    smb_ReleaseUsername(unp);
+
+    if (!userp) {
+        userp = cm_rootUserp;
+        cm_HoldUser(userp);
+    }
+
+    return userp;
+}
+
+cm_user_t *
+RDR_UserFromCommRequest( IN AFSCommRequest *RequestBuffer)
+{
+
+    return RDR_UserFromAuthGroup( &RequestBuffer->AuthGroup);
+}
+
+cm_user_t *
+RDR_UserFromAuthGroup( IN GUID *pGuid)
+{
+    smb_username_t *unp;
+    cm_user_t * userp = NULL;
+    RPC_WSTR UuidString = NULL;
+    wchar_t cname[MAX_COMPUTERNAME_LENGTH+1];
+    int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
+
+    if (UuidToStringW((UUID *)pGuid, &UuidString) != RPC_S_OK)
+        goto done;
+
+    GetComputerNameW(cname, &cnamelen);
+    _wcsupr(cname);
+
+    unp = smb_FindUserByName(UuidString, cname, SMB_FLAG_CREATE);
+    lock_ObtainMutex(&unp->mx);
+    if (!unp->userp)
+        unp->userp = cm_NewUser();
+    unp->flags |= SMB_USERNAMEFLAG_SID;
+    lock_ReleaseMutex(&unp->mx);
+    userp = unp->userp;
+    cm_HoldUser(userp);
+    smb_ReleaseUsername(unp);
+
+  done:
+    if (!userp) {
+        userp = cm_rootUserp;
+        cm_HoldUser(userp);
+    }
+
+    osi_Log2(afsd_logp, "RDR_UserFromCommRequest Guid %S userp = 0x%p",
+             osi_LogSaveStringW(afsd_logp, UuidString),
+             userp);
+
+    if (UuidString)
+        RpcStringFreeW(&UuidString);
+
+    return userp;
+}
+
+void
+RDR_ReleaseUser( IN cm_user_t *userp )
+{
+    osi_Log1(afsd_logp, "RDR_ReleaseUser userp = 0x%p", userp);
+    cm_ReleaseUser(userp);
+}
+
+
+/*
+ * RDR_FlagScpInUse flags the scp with CM_SCACHEFLAG_RDR_IN_USE
+ */
+static void
+RDR_FlagScpInUse( IN cm_scache_t *scp, IN BOOL bLocked )
+{
+    if (!bLocked)
+        lock_ObtainWrite(&scp->rw);
+
+    lock_AssertWrite(&scp->rw);
+    scp->flags |= CM_SCACHEFLAG_RDR_IN_USE;
+
+    if (!bLocked)
+        lock_ReleaseWrite(&scp->rw);
+}
+
+/*
+ * Obtain the status information for the specified object and
+ *
+ */
+static afs_uint32
+RDR_BulkStatLookup( cm_scache_t *dscp,
+                    cm_scache_t *scp,
+                    cm_user_t   *userp,
+                    cm_req_t    *reqp)
+{
+    cm_direnum_t *      enump = NULL;
+    afs_uint32  code = 0;
+    cm_dirOp_t    dirop;
+
+    code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
+    if (code == 0) {
+        code = cm_BPlusDirEnumerate(dscp, userp, reqp, TRUE, NULL, TRUE, &enump);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumerate failure code=0x%x",
+                      code);
+        }
+        cm_EndDirOp(&dirop);
+    } else {
+        osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BeginDirOp failure code=0x%x",
+                  code);
+    }
+
+
+    if (enump)
+    {
+        code = cm_BPlusDirEnumBulkStatOne(enump, scp);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumBulkStatOne failure code=0x%x",
+                      code);
+        }
+        cm_BPlusDirFreeEnumeration(enump);
+    }
+
+    return code;
+}
+
+
+#define RDR_POP_FOLLOW_MOUNTPOINTS 0x01
+#define RDR_POP_EVALUATE_SYMLINKS  0x02
+#define RDR_POP_WOW64              0x04
+#define RDR_POP_NO_GETSTATUS       0x08
+
+afs_uint32
+RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
+                          IN  DWORD             dwMaxEntryLength,
+                          IN  cm_scache_t     * dscp,
+                          IN  cm_scache_t     * scp,
+                          IN  cm_user_t       * userp,
+                          IN  cm_req_t        * reqp,
+                          IN  wchar_t         * name,
+                          IN  wchar_t         * shortName,
+                          IN  DWORD             dwFlags,
+                          OUT AFSDirEnumEntry **ppNextEntry,
+                          OUT DWORD           * pdwRemainingLength)
+{
+    FILETIME ft;
+    WCHAR *  wname, *wtarget;
+    size_t   len;
+    DWORD      dwEntryLength;
+    afs_uint32 code = 0, code2 = 0;
+    BOOL          bMustFake = FALSE;
+
+    osi_Log5(afsd_logp, "RDR_PopulateCurrentEntry dscp=0x%p scp=0x%p name=%S short=%S flags=0x%x",
+             dscp, scp, osi_LogSaveStringW(afsd_logp, name),
+             osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
+    osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
+
+    if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
+        if (ppNextEntry)
+            *ppNextEntry = pCurrentEntry;
+        if (pdwRemainingLength)
+            *pdwRemainingLength = dwMaxEntryLength;
+        osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry Not Enough Room for Entry %d < %d",
+                 dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
+        return CM_ERROR_TOOBIG;
+    }
+
+    if (!name)
+        name = L"";
+    if (!shortName)
+        shortName = L"";
+
+    dwEntryLength = sizeof(AFSDirEnumEntry);
+
+    lock_ObtainWrite(&scp->rw);
+    if (dwFlags & RDR_POP_NO_GETSTATUS) {
+        if (!cm_HaveCallback(scp))
+            bMustFake = TRUE;
+    } else {
+#ifdef AFS_FREELANCE_CLIENT
+        if (scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
+            /*
+             * If the FID is from the Freelance Local Root always perform
+             * a single item status check.
+             */
+            code = cm_SyncOp( scp, NULL, userp, reqp, 0,
+                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+            if (code) {
+                lock_ReleaseWrite(&scp->rw);
+                osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_SyncOp failed for scp=0x%p code=0x%x",
+                         scp, code);
+                return code;
+            }
+        } else
+#endif
+        {
+            /*
+             * For non-Freelance objects, check to see if we have current
+             * status information.  If not, perform a bulk status lookup of multiple
+             * entries in order to reduce the number of RPCs issued to the file server.
+             */
+            if ((scp->flags & CM_SCACHEFLAG_EACCESS))
+                bMustFake = TRUE;
+            else if (!cm_HaveCallback(scp)) {
+                lock_ReleaseWrite(&scp->rw);
+                code = RDR_BulkStatLookup(dscp, scp, userp, reqp);
+                if (code) {
+                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RXR_BulkStatLookup failed for scp=0x%p code=0x%x",
+                             scp, code);
+                    return code;
+                }
+                lock_ObtainWrite(&scp->rw);
+                /*
+                 * RDR_BulkStatLookup can succeed but it may be the case that there
+                 * still is not valid status info.  If we get this far, generate fake
+                 * status info.
+                 */
+                if (!cm_HaveCallback(scp))
+                    bMustFake = TRUE;
+            }
+        }
+
+    }
+
+    /* Populate the real or fake data */
+    pCurrentEntry->FileId.Cell = scp->fid.cell;
+    pCurrentEntry->FileId.Volume = scp->fid.volume;
+    pCurrentEntry->FileId.Vnode = scp->fid.vnode;
+    pCurrentEntry->FileId.Unique = scp->fid.unique;
+    pCurrentEntry->FileId.Hash = scp->fid.hash;
+
+    pCurrentEntry->FileType = scp->fileType;
+
+    pCurrentEntry->DataVersion.QuadPart = scp->dataVersion;
+
+    if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+        scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {
+        cm_LargeSearchTimeFromUnixTime(&ft, MAX_AFS_UINT32);
+    } else {
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->cbExpires);
+    }
+    pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
+    pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
+
+    if (bMustFake) {
+        /* 1969-12-31 23:59:59 +00 */
+        ft.dwHighDateTime = 0x19DB200;
+        ft.dwLowDateTime = 0x5BB78980;
+    } else
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+    pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
+    pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
+    pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
+    pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
+    pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
+
+    pCurrentEntry->EndOfFile = scp->length;
+    pCurrentEntry->AllocationSize = scp->length;
+
+    if (bMustFake) {
+        switch (scp->fileType) {
+        case CM_SCACHETYPE_DIRECTORY:
+        case CM_SCACHETYPE_MOUNTPOINT:
+        case CM_SCACHETYPE_INVALID:
+            pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
+            break;
+        case CM_SCACHETYPE_SYMLINK:
+            if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
+            else
+                pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
+            break;
+        default:
+            /* if we get here we either have a normal file
+            * or we have a file for which we have never
+            * received status info.  In this case, we can
+            * check the even/odd value of the entry's vnode.
+            * odd means it is to be treated as a directory
+            * and even means it is to be treated as a file.
+            */
+            if (scp->fid.vnode & 0x1)
+                pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
+            else
+                pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
+        }
+    } else
+        pCurrentEntry->FileAttributes = smb_ExtAttributes(scp);
+    pCurrentEntry->EaSize = 0;
+    pCurrentEntry->Links = scp->linkCount;
+
+    len = wcslen(shortName);
+    wcsncpy(pCurrentEntry->ShortName, shortName, len);
+    pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
+
+    pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
+    len = wcslen(name);
+    wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
+    wcsncpy(wname, name, len);
+    pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
+
+    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d",
+              scp, scp->fileType);
+
+    if (!(dwFlags & RDR_POP_NO_GETSTATUS))
+        cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+    if ((dwFlags & RDR_POP_NO_GETSTATUS) || !cm_HaveCallback(scp)) {
+        pCurrentEntry->TargetNameOffset = 0;
+        pCurrentEntry->TargetNameLength = 0;
+    }
+    else
+    switch (scp->fileType) {
+    case CM_SCACHETYPE_MOUNTPOINT:
+        if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
+            if ((code2 = cm_ReadMountPoint(scp, userp, reqp)) == 0) {
+                cm_scache_t *targetScp = NULL;
+
+                pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
+                len = strlen(scp->mountPointStringp);
+                wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
+
+#ifdef UNICODE
+                cch = MultiByteToWideChar( CP_UTF8, 0, scp->mountPointStringp,
+                                           len * sizeof(char),
+                                           wtarget,
+                                           len * sizeof(WCHAR));
+#else
+                mbstowcs(wtarget, scp->mountPointStringp, len);
+#endif
+                pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
+
+                code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
+
+                if (code2 == 0) {
+                    pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
+                    pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
+                    pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
+                    pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
+                    pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
+
+                    osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+                              pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
+                              pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
+
+                    cm_ReleaseSCache(targetScp);
+                } else {
+                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
+                              scp, code2);
+                }
+            } else {
+                osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_ReadMountPoint failed scp=0x%p code=0x%x",
+                          scp, code2);
+            }
+        }
+        break;
+    case CM_SCACHETYPE_SYMLINK:
+    case CM_SCACHETYPE_DFSLINK:
+        {
+            pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
+            wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
+
+            if (dwFlags & RDR_POP_EVALUATE_SYMLINKS) {
+                char * mp;
+
+                code2 = cm_HandleLink(scp, userp, reqp);
+                if (code2 == 0) {
+                    mp = scp->mountPointStringp;
+                    len = strlen(mp);
+                    if ( len != 0 ) {
+                        /* Strip off the msdfs: prefix from the target name for the file system */
+                        if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+                            osi_Log0(afsd_logp, "RDR_PopulateCurrentEntry DFSLink Detected");
+                            pCurrentEntry->FileType = scp->fileType;
+
+                            if (!strncmp("msdfs:", mp, 6)) {
+                                mp += 6;
+                                len -= 6;
+                            }
+                        }
+                        /* only send one slash to the redirector */
+                        if (mp[0] == '\\' && mp[1] == '\\') {
+                            mp++;
+                            len--;
+                        }
+#ifdef UNICODE
+                        cch = MultiByteToWideChar( CP_UTF8, 0, mp,
+                                                   len * sizeof(char),
+                                                   wtarget,
+                                                   len * sizeof(WCHAR));
+#else
+                        mbstowcs(wtarget, mp, len);
+#endif
+                    }
+                    pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
+                } else {
+                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_HandleLink failed scp=0x%p code=0x%x",
+                             scp, code2);
+                }
+            }
+
+        }
+        break;
+
+    default:
+        pCurrentEntry->TargetNameOffset = 0;
+        pCurrentEntry->TargetNameLength = 0;
+    }
+    lock_ReleaseWrite(&scp->rw);
+
+    dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
+    dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
+    if (ppNextEntry)
+        *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
+    if (pdwRemainingLength)
+        *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
+
+    osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
+              pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
+
+    return code;
+}
+
+afs_uint32
+RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
+                               IN  DWORD             dwMaxEntryLength,
+                               IN  cm_scache_t     * dscp,
+                               IN  cm_fid_t        * fidp,
+                               IN  cm_user_t       * userp,
+                               IN  cm_req_t        * reqp,
+                               IN  wchar_t         * name,
+                               IN  wchar_t         * shortName,
+                               IN  DWORD             dwFlags,
+                               OUT AFSDirEnumEntry **ppNextEntry,
+                               OUT DWORD           * pdwRemainingLength)
+{
+    FILETIME ft;
+    WCHAR *  wname;
+    size_t   len;
+    DWORD      dwEntryLength;
+    afs_uint32 code = 0, code2 = 0;
+
+    osi_Log4(afsd_logp, "RDR_PopulateCurrentEntryNoEntry dscp=0x%p name=%S short=%S flags=0x%x",
+             dscp, osi_LogSaveStringW(afsd_logp, name),
+             osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
+    osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
+
+    if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
+        if (ppNextEntry)
+            *ppNextEntry = pCurrentEntry;
+        if (pdwRemainingLength)
+            *pdwRemainingLength = dwMaxEntryLength;
+        osi_Log2(afsd_logp, "RDR_PopulateCurrentEntryNoEntry Not Enough Room for Entry %d < %d",
+                 dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
+        return CM_ERROR_TOOBIG;
+    }
+
+    if (!name)
+        name = L"";
+    if (!shortName)
+        shortName = L"";
+
+    dwEntryLength = sizeof(AFSDirEnumEntry);
+
+    pCurrentEntry->FileId.Cell = fidp->cell;
+    pCurrentEntry->FileId.Volume = fidp->volume;
+    pCurrentEntry->FileId.Vnode = fidp->vnode;
+    pCurrentEntry->FileId.Unique = fidp->unique;
+    pCurrentEntry->FileId.Hash = fidp->hash;
+
+    pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
+
+    pCurrentEntry->DataVersion.QuadPart = CM_SCACHE_VERSION_BAD;
+
+    cm_LargeSearchTimeFromUnixTime(&ft, 0);
+    pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
+    pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
+
+    cm_LargeSearchTimeFromUnixTime(&ft, 0);
+    pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
+    pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
+    pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
+    pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
+    pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
+
+    pCurrentEntry->EndOfFile.QuadPart = 0;
+    pCurrentEntry->AllocationSize.QuadPart = 0;
+    pCurrentEntry->FileAttributes = 0;
+    pCurrentEntry->EaSize = 0;
+    pCurrentEntry->Links = 0;
+
+    len = wcslen(shortName);
+    wcsncpy(pCurrentEntry->ShortName, shortName, len);
+    pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
+
+    pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
+    len = wcslen(name);
+    wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
+    wcsncpy(wname, name, len);
+    pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
+
+    pCurrentEntry->TargetNameOffset = 0;
+    pCurrentEntry->TargetNameLength = 0;
+
+    dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
+    dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
+    if (ppNextEntry)
+        *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
+    if (pdwRemainingLength)
+        *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
+
+    osi_Log3(afsd_logp, "RDR_PopulateCurrentEntryNoScp Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
+              pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
+
+    return code;
+}
+
+void
+RDR_EnumerateDirectory( IN cm_user_t *userp,
+                        IN AFSFileID DirID,
+                        IN AFSDirQueryCB *QueryCB,
+                        IN BOOL bWow64,
+                        IN BOOL bSkipStatus,
+                        IN DWORD ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB)
+{
+    DWORD status;
+    cm_direnum_t *      enump = NULL;
+    AFSDirEnumResp  * pDirEnumResp;
+    AFSDirEnumEntry * pCurrentEntry;
+    size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
+    DWORD             dwMaxEntryLength;
+    afs_uint32  code = 0;
+    cm_fid_t      fid;
+    cm_scache_t * dscp = NULL;
+    cm_req_t      req;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_EnumerateDirectory FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+             DirID.Cell, DirID.Volume, DirID.Vnode, DirID.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc(size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_EnumerateDirectory Out of Memory");
+       return;
+    }
+
+    memset(*ResultCB, 0, size);
+
+    if (QueryCB->EnumHandle == (ULONG_PTR)-1) {
+        osi_Log0(afsd_logp, "RDR_EnumerateDirectory No More Entries");
+        (*ResultCB)->ResultStatus = STATUS_NO_MORE_ENTRIES;
+        (*ResultCB)->ResultBufferLength = 0;
+        return;
+    }
+
+    (*ResultCB)->ResultBufferLength = dwMaxEntryLength = ResultBufferLength;
+    if (ResultBufferLength) {
+        pDirEnumResp = (AFSDirEnumResp *)&(*ResultCB)->ResultData;
+        pCurrentEntry = (AFSDirEnumEntry *)&pDirEnumResp->Entry;
+        dwMaxEntryLength -= FIELD_OFFSET( AFSDirEnumResp, Entry);      /* AFSDirEnumResp */
+    }
+
+    if (DirID.Cell != 0) {
+        fid.cell   = DirID.Cell;
+        fid.volume = DirID.Volume;
+        fid.vnode  = DirID.Vnode;
+        fid.unique = DirID.Unique;
+        fid.hash   = DirID.Hash;
+
+        code = cm_GetSCache(&fid, &dscp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+        osi_Log0(afsd_logp, "RDR_EnumerateDirectory Object Name Invalid - Cell = 0");
+        return;
+    }
+
+    /* get the directory size */
+    lock_ObtainWrite(&dscp->rw);
+    code = cm_SyncOp(dscp, NULL, userp, &req, PRSFS_LOOKUP,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&dscp->rw);
+        cm_ReleaseSCache(dscp);
+        osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_SyncOp failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&dscp->rw);
+
+    if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(dscp);
+        osi_Log1(afsd_logp, "RDR_EnumerateDirectory Not a Directory dscp=0x%p",
+                 dscp);
+        return;
+    }
+
+    /*
+     * If there is no enumeration handle, then this is a new query
+     * and we must perform an enumeration for the specified object
+     */
+    if (QueryCB->EnumHandle == (ULONG_PTR)NULL) {
+        cm_dirOp_t    dirop;
+
+        code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
+        if (code == 0) {
+            code = cm_BPlusDirEnumerate(dscp, userp, &req, TRUE, NULL, !bSkipStatus, &enump);
+            if (code) {
+                osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumerate failure code=0x%x",
+                          code);
+            }
+            cm_EndDirOp(&dirop);
+        } else {
+            osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BeginDirOp failure code=0x%x",
+                      code);
+        }
+    } else {
+        enump = (cm_direnum_t *)QueryCB->EnumHandle;
+    }
+
+    if (enump && ResultBufferLength) {
+        cm_direnum_entry_t * entryp = NULL;
+
+      getnextentry:
+        if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
+            osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
+            goto outofspace;
+        }
+
+        code = cm_BPlusDirNextEnumEntry(enump, &entryp);
+
+        if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
+            cm_scache_t *scp;
+            int stopnow = (code == CM_ERROR_STOPNOW);
+
+            if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
+                osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
+                if (stopnow)
+                    goto outofspace;
+                goto getnextentry;
+            }
+
+            if ( FALSE /* bSkipStatus */) {
+                scp = cm_FindSCache(&entryp->fid);
+                code = 0;
+            } else {
+                code = cm_GetSCache(&entryp->fid, &scp, userp, &req);
+            }
+
+            if (!code) {
+                if (scp) {
+                    code = RDR_PopulateCurrentEntry(pCurrentEntry, dwMaxEntryLength,
+                                                     dscp, scp, userp, &req,
+                                                     entryp->name, entryp->shortName,
+                                                     (bWow64 ? RDR_POP_WOW64 : 0) |
+                                                     (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
+                                                     &pCurrentEntry, &dwMaxEntryLength);
+                    cm_ReleaseSCache(scp);
+                } else {
+                    code = RDR_PopulateCurrentEntryNoScp( pCurrentEntry, dwMaxEntryLength,
+                                                          dscp, &entryp->fid, userp, &req,
+                                                          entryp->name, entryp->shortName,
+                                                          (bWow64 ? RDR_POP_WOW64 : 0),
+                                                          &pCurrentEntry, &dwMaxEntryLength);
+                }
+                if (stopnow)
+                    goto outofspace;
+                goto getnextentry;
+            } else {
+                osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure scp=0x%p code=0x%x",
+                          scp, code);
+                if (stopnow)
+                    goto outofspace;
+                goto getnextentry;
+            }
+        }
+    }
+
+    if (enump && ResultBufferLength == 0) {
+        code = cm_BPlusDirEnumBulkStat(enump);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
+                      code);
+        }
+    }
+  outofspace:
+
+    if (code || enump->next == enump->count || ResultBufferLength == 0) {
+        cm_BPlusDirFreeEnumeration(enump);
+        enump = (cm_direnum_t *)(ULONG_PTR)-1;
+    }
+
+    if (code == 0 || code == CM_ERROR_STOPNOW) {
+        (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+        osi_Log0(afsd_logp, "RDR_EnumerateDirectory SUCCESS");
+    } else {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_EnumerateDirectory Failure code=0x%x status=0x%x",
+                  code, status);
+    }
+
+    if (ResultBufferLength) {
+        (*ResultCB)->ResultBufferLength = ResultBufferLength - dwMaxEntryLength;
+
+        pDirEnumResp->EnumHandle = (ULONG_PTR) enump;
+    }
+
+    if (dscp)
+        cm_ReleaseSCache(dscp);
+
+    return;
+}
+
+void
+RDR_EvaluateNodeByName( IN cm_user_t *userp,
+                        IN AFSFileID ParentID,
+                        IN WCHAR   *FileNameCounted,
+                        IN DWORD    FileNameLength,
+                        IN BOOL     CaseSensitive,
+                        IN BOOL     bWow64,
+                        IN BOOL     bHoldFid,
+                        IN BOOL     bNoFollow,
+                        IN DWORD    ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB)
+{
+    AFSDirEnumEntry * pCurrentEntry;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    afs_uint32  code = 0;
+    cm_scache_t * scp = NULL;
+    cm_scache_t * dscp = NULL;
+    cm_req_t      req;
+    cm_fid_t      parentFid;
+    DWORD         status;
+    DWORD         dwRemaining;
+    WCHAR       * wszName = NULL;
+    size_t        cbName;
+    BOOL          bVol = FALSE;
+    wchar_t       FileName[260];
+
+    StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_EvaluateNodeByName parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+             ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
+
+    /* Allocate enough room to add a volume prefix if necessary */
+    cbName = FileNameLength + (CM_PREFIX_VOL_CCH + 1) * sizeof(WCHAR);
+    wszName = malloc(cbName);
+    if (!wszName) {
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
+       return;
+    }
+    StringCbCopyNW(wszName, cbName, FileName, FileNameLength);
+    osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, wszName));
+
+    *ResultCB = (AFSCommResult *)malloc(size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
+        free(wszName);
+        return;
+    }
+
+    memset(*ResultCB, 0, size);
+    (*ResultCB)->ResultBufferLength = ResultBufferLength;
+    if (ResultBufferLength)
+        pCurrentEntry = (AFSDirEnumEntry *)&(*ResultCB)->ResultData;
+
+    if (ParentID.Cell != 0) {
+        parentFid.cell   = ParentID.Cell;
+        parentFid.volume = ParentID.Volume;
+        parentFid.vnode  = ParentID.Vnode;
+        parentFid.unique = ParentID.Unique;
+        parentFid.hash   = ParentID.Hash;
+
+        code = cm_GetSCache(&parentFid, &dscp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_EvaluateNodeByName cm_GetSCache parentFID failure code=0x%x status=0x%x",
+                      code, status);
+            free(wszName);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Object Name Invalid - Cell = 0");
+        return;
+    }
+
+    /* get the directory size */
+    lock_ObtainWrite(&dscp->rw);
+    code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                     CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&dscp->rw);
+        cm_ReleaseSCache(dscp);
+        osi_Log3(afsd_logp, "RDR_EvaluateNodeByName cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
+                 dscp, code, status);
+        free(wszName);
+        return;
+    }
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&dscp->rw);
+
+    if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(dscp);
+        osi_Log1(afsd_logp, "RDR_EvaluateNodeByName Not a Directory dscp=0x%p",
+                 dscp);
+        free(wszName);
+        return;
+    }
+
+    code = cm_Lookup(dscp, wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
+
+    if ((code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
+         (wcschr(wszName, '%') != NULL || wcschr(wszName, '#') != NULL)) {
+        /*
+         * A volume reference:  <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
+         */
+        StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
+        StringCbCatNW(wszName, cbName, FileName, FileNameLength);
+        cm_strlwr_utf16(wszName);
+        bVol = TRUE;
+
+        code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
+    }
+
+    if (code == 0 && scp) {
+        wchar_t shortName[13]=L"";
+
+        if (bVol) {
+            cm_Gen8Dot3VolNameW(scp->fid.cell, scp->fid.volume, shortName, NULL);
+        } else if (!cm_Is8Dot3(wszName)) {
+            cm_dirFid_t dfid;
+
+            dfid.vnode = htonl(scp->fid.vnode);
+            dfid.unique = htonl(scp->fid.unique);
+
+            cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
+        } else {
+            shortName[0] = '\0';
+        }
+
+        code = RDR_PopulateCurrentEntry(pCurrentEntry, ResultBufferLength,
+                                        dscp, scp, userp, &req,
+                                        FileName, shortName,
+                                        (bWow64 ? RDR_POP_WOW64 : 0) |
+                                        (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
+                                        NULL, &dwRemaining);
+        if (bHoldFid)
+            RDR_FlagScpInUse( scp, FALSE );
+        cm_ReleaseSCache(scp);
+
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
+                      code, status);
+        } else {
+            (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+            (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+            osi_Log0(afsd_logp, "RDR_EvaluateNodeByName SUCCESS");
+        }
+    } else if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
+                 code, status);
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_NO_SUCH_FILE;
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByName No Such File");
+    }
+    cm_ReleaseSCache(dscp);
+    free(wszName);
+
+    return;
+}
+
+void
+RDR_EvaluateNodeByID( IN cm_user_t *userp,
+                      IN AFSFileID ParentID,            /* not used */
+                      IN AFSFileID SourceID,
+                      IN BOOL      bWow64,
+                      IN BOOL      bNoFollow,
+                      IN BOOL      bHoldFid,
+                      IN DWORD     ResultBufferLength,
+                      IN OUT AFSCommResult **ResultCB)
+{
+    AFSDirEnumEntry * pCurrentEntry;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    afs_uint32  code = 0;
+    cm_scache_t * scp = NULL;
+    cm_scache_t * dscp = NULL;
+    cm_req_t      req;
+    cm_fid_t      Fid;
+    cm_fid_t      parentFid;
+    DWORD         status;
+    DWORD         dwRemaining;
+
+    osi_Log4(afsd_logp, "RDR_EvaluateNodeByID source FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              SourceID.Cell, SourceID.Volume, SourceID.Vnode, SourceID.Unique);
+    osi_Log4(afsd_logp, "... parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc(size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Out of Memory");
+       return;
+    }
+
+    memset(*ResultCB, 0, size);
+    (*ResultCB)->ResultBufferLength = ResultBufferLength;
+    dwRemaining = ResultBufferLength;
+    if (ResultBufferLength)
+        pCurrentEntry = (AFSDirEnumEntry *)&(*ResultCB)->ResultData;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    if (SourceID.Cell != 0) {
+        Fid.cell   = SourceID.Cell;
+        Fid.volume = SourceID.Volume;
+        Fid.vnode  = SourceID.Vnode;
+        Fid.unique = SourceID.Unique;
+        Fid.hash   = SourceID.Hash;
+
+        code = cm_GetSCache(&Fid, &scp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache SourceFID failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Name Invalid - Cell = 0");
+        return;
+    }
+
+    if (ParentID.Cell != 0) {
+        cm_SetFid(&parentFid, ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
+        code = cm_GetSCache(&parentFid, &dscp, userp, &req);
+        if (code) {
+            cm_ReleaseSCache(scp);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else if (SourceID.Vnode == 1) {
+        dscp = scp;
+        cm_HoldSCache(dscp);
+    } else if (scp->parentVnode) {
+        cm_SetFid(&parentFid, SourceID.Cell, SourceID.Volume, scp->parentVnode, scp->parentUnique);
+        code = cm_GetSCache(&parentFid, &dscp, userp, &req);
+        if (code) {
+            cm_ReleaseSCache(scp);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Path Invalid - Unknown Parent");
+        return;
+    }
+
+    /* Make sure the directory is current */
+    lock_ObtainWrite(&dscp->rw);
+    code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&dscp->rw);
+        cm_ReleaseSCache(dscp);
+        cm_ReleaseSCache(scp);
+        osi_Log3(afsd_logp, "RDR_EvaluateNodeByID cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
+                 dscp, code, status);
+        return;
+    }
+
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&dscp->rw);
+
+    if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(dscp);
+        cm_ReleaseSCache(scp);
+        osi_Log1(afsd_logp, "RDR_EvaluateNodeByID Not a Directory dscp=0x%p", dscp);
+        return;
+    }
+
+    code = RDR_PopulateCurrentEntry(pCurrentEntry, ResultBufferLength,
+                                    dscp, scp, userp, &req, NULL, NULL,
+                                    (bWow64 ? RDR_POP_WOW64 : 0) |
+                                    (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
+                                    NULL, &dwRemaining);
+
+    if (bHoldFid)
+        RDR_FlagScpInUse( scp, FALSE );
+    cm_ReleaseSCache(scp);
+    cm_ReleaseSCache(dscp);
+
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_EvaluateNodeByID FAILURE code=0x%x status=0x%x",
+                 code, status);
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+        (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+        osi_Log0(afsd_logp, "RDR_EvaluateNodeByID SUCCESS");
+    }
+    return;
+}
+
+void
+RDR_CreateFileEntry( IN cm_user_t *userp,
+                     IN WCHAR *FileNameCounted,
+                     IN DWORD FileNameLength,
+                     IN AFSFileCreateCB *CreateCB,
+                     IN BOOL bWow64,
+                     IN BOOL bHoldFid,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB)
+{
+    AFSFileCreateResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    cm_fid_t            parentFid;
+    afs_uint32          code;
+    cm_scache_t *       dscp = NULL;
+    afs_uint32          flags = 0;
+    cm_attr_t           setAttr;
+    cm_scache_t *       scp = NULL;
+    cm_req_t            req;
+    DWORD               status;
+    wchar_t             FileName[260];
+
+    StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
+
+    osi_Log4(afsd_logp, "RDR_CreateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              CreateCB->ParentId.Cell, CreateCB->ParentId.Volume,
+              CreateCB->ParentId.Vnode, CreateCB->ParentId.Unique);
+    osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+    memset(&setAttr, 0, sizeof(cm_attr_t));
+
+    *ResultCB = (AFSCommResult *)malloc(size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_CreateFileEntry out of memory");
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            size);
+
+    parentFid.cell   = CreateCB->ParentId.Cell;
+    parentFid.volume = CreateCB->ParentId.Volume;
+    parentFid.vnode  = CreateCB->ParentId.Vnode;
+    parentFid.unique = CreateCB->ParentId.Unique;
+    parentFid.hash   = CreateCB->ParentId.Hash;
+
+    code = cm_GetSCache(&parentFid, &dscp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_CreateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&dscp->rw);
+    code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&dscp->rw);
+        cm_ReleaseSCache(dscp);
+        osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
+                 dscp, code, status);
+        return;
+    }
+
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&dscp->rw);
+
+    if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(dscp);
+        osi_Log1(afsd_logp, "RDR_CreateFileEntry Not a Directory dscp=0x%p",
+                 dscp);
+        return;
+    }
+
+    /* Use current time */
+    setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+    setAttr.clientModTime = time(NULL);
+
+    if (CreateCB->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+        if (smb_unixModeDefaultDir) {
+            setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+            setAttr.unixModeBits = smb_unixModeDefaultDir;
+            if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
+                setAttr.unixModeBits &= ~0222;          /* disable the write bits */
+        }
+
+        code = cm_MakeDir(dscp, FileName, flags, &setAttr, userp, &req, &scp);
+    } else {
+        if (smb_unixModeDefaultFile) {
+            setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+            setAttr.unixModeBits = smb_unixModeDefaultFile;
+            if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
+                setAttr.unixModeBits &= ~0222;          /* disable the write bits */
+        }
+
+        setAttr.mask |= CM_ATTRMASK_LENGTH;
+        setAttr.length.LowPart = CreateCB->AllocationSize.LowPart;
+        setAttr.length.HighPart = CreateCB->AllocationSize.HighPart;
+        code = cm_Create(dscp, FileName, flags, &setAttr, &scp, userp, &req);
+    }
+    if (code == 0) {
+        wchar_t shortName[13]=L"";
+        cm_dirFid_t dfid;
+        DWORD dwRemaining;
+
+        (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
+
+        (*ResultCB)->ResultBufferLength = sizeof( AFSFileCreateResultCB);
+
+        pResultCB = (AFSFileCreateResultCB *)(*ResultCB)->ResultData;
+
+        dwRemaining = ResultBufferLength - sizeof( AFSFileCreateResultCB) + sizeof( AFSDirEnumEntry);
+
+        lock_ObtainWrite(&dscp->rw);
+        code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            lock_ReleaseWrite(&dscp->rw);
+            cm_ReleaseSCache(dscp);
+            cm_ReleaseSCache(scp);
+            osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
+                      dscp, code, status);
+            return;
+        }
+
+        pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+
+        cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&dscp->rw);
+
+        dfid.vnode = htonl(scp->fid.vnode);
+        dfid.unique = htonl(scp->fid.unique);
+
+        if (!cm_Is8Dot3(FileName))
+            cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
+        else
+            shortName[0] = '\0';
+        code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
+                                        dscp, scp, userp, &req, FileName, shortName,
+                                        RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
+                                        NULL, &dwRemaining);
+
+        if (bHoldFid)
+            RDR_FlagScpInUse( scp, FALSE );
+        cm_ReleaseSCache(scp);
+        (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+        osi_Log0(afsd_logp, "RDR_CreateFileEntry SUCCESS");
+    } else {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_CreateFileEntry FAILURE code=0x%x status=0x%x",
+                  code, status);
+    }
+
+    cm_ReleaseSCache(dscp);
+
+    return;
+}
+
+void
+RDR_UpdateFileEntry( IN cm_user_t *userp,
+                     IN AFSFileID FileId,
+                     IN AFSFileUpdateCB *UpdateCB,
+                     IN BOOL bWow64,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB)
+{
+    AFSFileUpdateResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    cm_fid_t            Fid;
+    cm_fid_t            parentFid;
+    afs_uint32          code;
+    afs_uint32          flags = 0;
+    cm_attr_t           setAttr;
+    cm_scache_t *       scp = NULL;
+    cm_scache_t *       dscp = NULL;
+    cm_req_t            req;
+    time_t              clientModTime;
+    FILETIME            ft;
+    DWORD               status;
+    BOOL                bScpLocked = FALSE;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+    memset(&setAttr, 0, sizeof(cm_attr_t));
+
+    osi_Log4(afsd_logp, "RDR_UpdateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              UpdateCB->ParentId.Cell, UpdateCB->ParentId.Volume,
+              UpdateCB->ParentId.Vnode, UpdateCB->ParentId.Unique);
+    osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc( size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_UpdateFileEntry Out of Memory");
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            size);
+
+    parentFid.cell   = UpdateCB->ParentId.Cell;
+    parentFid.volume = UpdateCB->ParentId.Volume;
+    parentFid.vnode  = UpdateCB->ParentId.Vnode;
+    parentFid.unique = UpdateCB->ParentId.Unique;
+    parentFid.hash   = UpdateCB->ParentId.Hash;
+
+    code = cm_GetSCache(&parentFid, &dscp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&dscp->rw);
+    bScpLocked = TRUE;
+    code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&dscp->rw);
+        cm_ReleaseSCache(dscp);
+        osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
+                 dscp, code, status);
+        return;
+    }
+
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&dscp->rw);
+    bScpLocked = FALSE;
+
+    if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(dscp);
+        osi_Log1(afsd_logp, "RDR_UpdateFileEntry Not a Directory dscp=0x%p",
+                 dscp);
+        return;
+    }
+
+    Fid.cell   = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode  = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash   = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        cm_ReleaseSCache(dscp);
+        osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache object FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+    bScpLocked = TRUE;
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+    if (code) {
+        lock_ReleaseWrite(&scp->rw);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        cm_ReleaseSCache(dscp);
+        cm_ReleaseSCache(scp);
+        osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+    if (UpdateCB->ChangeTime.QuadPart) {
+
+        if (scp->fileType == CM_SCACHETYPE_FILE) {
+            /* Do not set length and other attributes at the same time */
+            if (scp->length.QuadPart != UpdateCB->AllocationSize.QuadPart) {
+                osi_Log2(afsd_logp, "RDR_UpdateFileEntry Length Change 0x%x -> 0x%x",
+                          (afs_uint32)scp->length.QuadPart, (afs_uint32)UpdateCB->AllocationSize.QuadPart);
+                setAttr.mask |= CM_ATTRMASK_LENGTH;
+                setAttr.length.LowPart = UpdateCB->AllocationSize.LowPart;
+                setAttr.length.HighPart = UpdateCB->AllocationSize.HighPart;
+                lock_ReleaseWrite(&scp->rw);
+                bScpLocked = FALSE;
+                code = cm_SetAttr(scp, &setAttr, userp, &req);
+                if (code)
+                    goto on_error;
+                setAttr.mask = 0;
+            }
+        }
+
+        if (!bScpLocked) {
+            lock_ObtainWrite(&scp->rw);
+            bScpLocked = TRUE;
+        }
+        if ((scp->unixModeBits & 0200) && (UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
+            setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+            setAttr.unixModeBits = scp->unixModeBits & ~0222;
+        } else if (!(scp->unixModeBits & 0200) && !(UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
+            setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+            setAttr.unixModeBits = scp->unixModeBits | 0222;
+        }
+    }
+
+    if (UpdateCB->LastWriteTime.QuadPart) {
+        ft.dwLowDateTime = UpdateCB->LastWriteTime.LowPart;
+        ft.dwHighDateTime = UpdateCB->LastWriteTime.HighPart;
+
+        cm_UnixTimeFromLargeSearchTime(& clientModTime, &ft);
+
+        if (!bScpLocked) {
+            lock_ObtainWrite(&scp->rw);
+            bScpLocked = TRUE;
+        }
+        if (scp->clientModTime != clientModTime) {
+            setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
+            setAttr.clientModTime = clientModTime;
+        }
+
+        /* call setattr */
+        if (setAttr.mask) {
+            lock_ReleaseWrite(&scp->rw);
+            bScpLocked = FALSE;
+            code = cm_SetAttr(scp, &setAttr, userp, &req);
+        } else
+            code = 0;
+    }
+
+  on_error:
+    if (bScpLocked) {
+        lock_ReleaseWrite(&scp->rw);
+    }
+
+    if (code == 0) {
+        DWORD dwRemaining = ResultBufferLength - sizeof( AFSFileUpdateResultCB) + sizeof( AFSDirEnumEntry);
+
+        pResultCB = (AFSFileUpdateResultCB *)(*ResultCB)->ResultData;
+
+        code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
+                                        dscp, scp, userp, &req, NULL, NULL,
+                                        RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
+                                        NULL, &dwRemaining);
+        (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+        osi_Log0(afsd_logp, "RDR_UpdateFileEntry SUCCESS");
+    } else {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_UpdateFileEntry FAILURE code=0x%x status=0x%x",
+                  code, status);
+    }
+    cm_ReleaseSCache(scp);
+    cm_ReleaseSCache(dscp);
+
+    return;
+}
+
+void
+RDR_CleanupFileEntry( IN cm_user_t *userp,
+                      IN AFSFileID FileId,
+                      IN WCHAR *FileNameCounted,
+                      IN DWORD FileNameLength,
+                      IN AFSFileCleanupCB *CleanupCB,
+                      IN BOOL bWow64,
+                      IN BOOL bLastHandle,
+                      IN BOOL bDeleteFile,
+                      IN BOOL bUnlockFile,
+                      IN DWORD ResultBufferLength,
+                      IN OUT AFSCommResult **ResultCB)
+{
+    size_t size = sizeof(AFSCommResult);
+    cm_fid_t            Fid;
+    cm_fid_t            parentFid;
+    afs_uint32          code = 0;
+    afs_uint32          flags = 0;
+    cm_attr_t           setAttr;
+    cm_scache_t *       scp = NULL;
+    cm_scache_t *       dscp = NULL;
+    cm_req_t            req;
+    time_t              clientModTime;
+    FILETIME            ft;
+    DWORD               status;
+    BOOL                bScpLocked = FALSE;
+    BOOL                bDscpLocked = FALSE;
+    BOOL                bFlushFile = FALSE;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+    memset(&setAttr, 0, sizeof(cm_attr_t));
+
+    osi_Log4(afsd_logp, "RDR_CleanupFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              CleanupCB->ParentId.Cell, CleanupCB->ParentId.Volume,
+              CleanupCB->ParentId.Vnode, CleanupCB->ParentId.Unique);
+    osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc( size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_CleanupFileEntry Out of Memory");
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            size);
+
+    parentFid.cell   = CleanupCB->ParentId.Cell;
+    parentFid.volume = CleanupCB->ParentId.Volume;
+    parentFid.vnode  = CleanupCB->ParentId.Vnode;
+    parentFid.unique = CleanupCB->ParentId.Unique;
+    parentFid.hash   = CleanupCB->ParentId.Hash;
+
+    if (parentFid.cell) {
+        code = cm_GetSCache(&parentFid, &dscp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
+                     code, status);
+            return;
+        }
+
+        lock_ObtainWrite(&dscp->rw);
+        bDscpLocked = TRUE;
+        code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code) {
+            osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure dscp=0x%p code=0x%x",
+                    dscp, code);
+            if (code)
+                goto on_error;
+        }
+
+        cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&dscp->rw);
+        bDscpLocked = FALSE;
+
+        if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+            (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+            cm_ReleaseSCache(dscp);
+            osi_Log1(afsd_logp, "RDR_CleanupFileEntry Not a Directory dscp=0x%p",
+                     dscp);
+            if (code)
+                goto on_error;
+        }
+    }
+
+    Fid.cell   = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode  = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash   = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        osi_Log1(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache object FID failure code=0x%x",
+                 code);
+        goto on_error;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+    bScpLocked = TRUE;
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+    if (code) {
+        osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure scp=0x%p code=0x%x",
+                 scp, code);
+        goto on_error;
+    }
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+    if (scp->redirBufCount > 0) {
+        LARGE_INTEGER heldExtents;
+        AFSFileExtentCB extentList[1024];
+        DWORD extentCount = 0;
+        cm_buf_t *srbp;
+        time_t now;
+
+        time(&now);
+        heldExtents.QuadPart = 0;
+
+        for ( srbp = redirq_to_cm_buf_t(scp->redirQueueT);
+              srbp;
+              srbp = redirq_to_cm_buf_t(osi_QPrev(&srbp->redirq)))
+        {
+            extentList[extentCount].Flags = 0;
+            extentList[extentCount].Length = cm_data.blockSize;
+            extentList[extentCount].FileOffset.QuadPart = srbp->offset.QuadPart;
+            extentList[extentCount].CacheOffset.QuadPart = srbp->datap - RDR_extentBaseAddress;
+            lock_ObtainWrite(&buf_globalLock);
+            srbp->redirReleaseRequested = now;
+            lock_ReleaseWrite(&buf_globalLock);
+            extentCount++;
+
+            if (extentCount == 1024) {
+                lock_ReleaseWrite(&scp->rw);
+                code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
+                if (code) {
+                    if (code == CM_ERROR_RETRY) {
+                        /*
+                         * The redirector either is not holding the extents or cannot let them
+                         * go because they are otherwise in use.  At the moment, do nothing.
+                         */
+                    } else
+                        break;
+                }
+                extentCount = 0;
+                bFlushFile = TRUE;
+                lock_ObtainWrite(&scp->rw);
+            }
+        }
+
+        if (code == 0 && extentCount > 0) {
+            if (bScpLocked) {
+                lock_ReleaseWrite(&scp->rw);
+                bScpLocked = FALSE;
+            }
+            code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
+            bFlushFile = TRUE;
+        }
+    }
+
+    /* No longer in use by redirector */
+    if (!bScpLocked) {
+        lock_ObtainWrite(&scp->rw);
+        bScpLocked = TRUE;
+    }
+
+    if (bLastHandle) {
+        lock_AssertWrite(&scp->rw);
+        scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
+    }
+
+    if (bLastHandle || bFlushFile) {
+        if (bScpLocked) {
+            lock_ReleaseWrite(&scp->rw);
+            bScpLocked = FALSE;
+        }
+        code = buf_CleanVnode(scp, userp, &req);
+        if (bLastHandle && code)
+            goto on_error;
+    }
+
+    if (bUnlockFile || bDeleteFile) {
+        cm_key_t    key;
+
+        if (!bScpLocked) {
+            lock_ObtainWrite(&scp->rw);
+            bScpLocked = TRUE;
+        }
+        code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+        if (code) {
+            osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp (2) failure scp=0x%p code=0x%x",
+                     scp, code);
+            goto on_error;
+        }
+
+        /* the scp is now locked and current */
+        key = cm_GenerateKey(CM_SESSION_IFS, CleanupCB->ProcessId, 0);
+
+        code = cm_UnlockByKey(scp, key,
+                              bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
+                              userp, &req);
+
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+
+        if (code)
+            goto on_error;
+    }
+
+    if (CleanupCB->ChangeTime.QuadPart) {
+
+        if (scp->fileType == CM_SCACHETYPE_FILE) {
+            /* Do not set length and other attributes at the same time */
+            if (scp->length.QuadPart != CleanupCB->AllocationSize.QuadPart) {
+                osi_Log2(afsd_logp, "RDR_CleanupFileEntry Length Change 0x%x -> 0x%x",
+                          (afs_uint32)scp->length.QuadPart, (afs_uint32)CleanupCB->AllocationSize.QuadPart);
+                setAttr.mask |= CM_ATTRMASK_LENGTH;
+                setAttr.length.LowPart = CleanupCB->AllocationSize.LowPart;
+                setAttr.length.HighPart = CleanupCB->AllocationSize.HighPart;
+
+                if (bScpLocked) {
+                    lock_ReleaseWrite(&scp->rw);
+                    bScpLocked = FALSE;
+                }
+                code = cm_SetAttr(scp, &setAttr, userp, &req);
+                if (code)
+                    goto on_error;
+                setAttr.mask = 0;
+            }
+        }
+
+        if (!bScpLocked) {
+            lock_ObtainWrite(&scp->rw);
+            bScpLocked = TRUE;
+        }
+
+        if ((scp->unixModeBits & 0200) && (CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
+            setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+            setAttr.unixModeBits = scp->unixModeBits & ~0222;
+        } else if (!(scp->unixModeBits & 0200) && !(CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
+            setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+            setAttr.unixModeBits = scp->unixModeBits | 0222;
+        }
+    }
+
+    if (CleanupCB->LastWriteTime.QuadPart) {
+        ft.dwLowDateTime = CleanupCB->LastWriteTime.LowPart;
+        ft.dwHighDateTime = CleanupCB->LastWriteTime.HighPart;
+
+        cm_UnixTimeFromLargeSearchTime(&clientModTime, &ft);
+        if (scp->clientModTime != clientModTime) {
+            setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
+            setAttr.clientModTime = clientModTime;
+        }
+    }
+
+    /* call setattr */
+    if (setAttr.mask) {
+        lock_ReleaseWrite(&scp->rw);
+        bScpLocked = FALSE;
+        code = cm_SetAttr(scp, &setAttr, userp, &req);
+    } else
+        code = 0;
+
+  on_error:
+    if (bDscpLocked)
+        lock_ReleaseWrite(&dscp->rw);
+    if (bScpLocked)
+        lock_ReleaseWrite(&scp->rw);
+
+    if (dscp && bDeleteFile) {
+        WCHAR FileName[260];
+
+        StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
+
+        if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
+            code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
+        else
+            code = cm_Unlink(dscp, NULL, FileName, userp, &req);
+    }
+
+    if (code == 0) {
+        (*ResultCB)->ResultStatus = 0;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log0(afsd_logp, "RDR_CleanupFileEntry SUCCESS");
+    } else {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_CleanupFileEntry FAILURE code=0x%x status=0x%x",
+                  code, status);
+    }
+    if (scp)
+        cm_ReleaseSCache(scp);
+    if (dscp)
+        cm_ReleaseSCache(dscp);
+
+    return;
+}
+
+void
+RDR_DeleteFileEntry( IN cm_user_t *userp,
+                     IN AFSFileID ParentId,
+                     IN ULONGLONG ProcessId,
+                     IN WCHAR *FileNameCounted,
+                     IN DWORD FileNameLength,
+                     IN BOOL bWow64,
+                     IN BOOL bCheckOnly,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB)
+{
+
+    AFSFileDeleteResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    cm_fid_t            parentFid;
+    afs_uint32          code;
+    cm_scache_t *       dscp = NULL;
+    cm_scache_t *       scp = NULL;
+    afs_uint32          flags = 0;
+    cm_attr_t           setAttr;
+    cm_req_t            req;
+    DWORD               status;
+    wchar_t             FileName[260];
+    cm_key_t            key;
+
+    StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
+
+    osi_Log4(afsd_logp, "RDR_DeleteFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              ParentId.Cell,  ParentId.Volume,
+              ParentId.Vnode, ParentId.Unique);
+    osi_Log2(afsd_logp, "... name=%S checkOnly=%x",
+             osi_LogSaveStringW(afsd_logp, FileName),
+             bCheckOnly);
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+    memset(&setAttr, 0, sizeof(cm_attr_t));
+
+    *ResultCB = (AFSCommResult *)malloc( size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_DeleteFileEntry out of memory");
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            size);
+
+    parentFid.cell   = ParentId.Cell;
+    parentFid.volume = ParentId.Volume;
+    parentFid.vnode  = ParentId.Vnode;
+    parentFid.unique = ParentId.Unique;
+    parentFid.hash   = ParentId.Hash;
+
+    code = cm_GetSCache(&parentFid, &dscp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&dscp->rw);
+
+    code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        lock_ReleaseWrite(&dscp->rw);
+        cm_ReleaseSCache(dscp);
+        osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
+                 dscp, code, status);
+        return;
+    }
+
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&dscp->rw);
+
+    if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(dscp);
+        osi_Log1(afsd_logp, "RDR_DeleteFileEntry Not a Directory dscp=0x%p",
+                 dscp);
+        return;
+    }
+
+    code = cm_Lookup(dscp, FileName, 0, userp, &req, &scp);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        cm_ReleaseSCache(dscp);
+        osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_Lookup failure code=0x%x status=0x%x",
+                 code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_DELETE,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        cm_ReleaseSCache(dscp);
+        osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    if (!bCheckOnly) {
+        /* Drop all locks since the file is being deleted */
+        code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            (*ResultCB)->ResultBufferLength = 0;
+            lock_ReleaseWrite(&scp->rw);
+            cm_ReleaseSCache(scp);
+            cm_ReleaseSCache(dscp);
+            osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp Lock failure scp=0x%p code=0x%x status=0x%x",
+                     scp, code, status);
+        }
+
+        /* the scp is now locked and current */
+        key = cm_GenerateKey(CM_SESSION_IFS, ProcessId, 0);
+
+        code = cm_UnlockByKey(scp, key,
+                              CM_UNLOCK_FLAG_BY_FID,
+                              userp, &req);
+
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+        lock_ReleaseWrite(&scp->rw);
+
+        if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
+            code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
+        else
+            code = cm_Unlink(dscp, NULL, FileName, userp, &req);
+    } else {
+        lock_ReleaseWrite(&scp->rw);
+    }
+
+    if (code == 0) {
+        (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
+
+        (*ResultCB)->ResultBufferLength = sizeof( AFSFileDeleteResultCB);
+
+        pResultCB = (AFSFileDeleteResultCB *)(*ResultCB)->ResultData;
+
+        pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+        osi_Log0(afsd_logp, "RDR_DeleteFileEntry SUCCESS");
+    } else {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_DeleteFileEntry FAILURE code=0x%x status=0x%x",
+                  code, status);
+    }
+
+    cm_ReleaseSCache(dscp);
+    cm_ReleaseSCache(scp);
+
+    return;
+}
+
+void
+RDR_RenameFileEntry( IN cm_user_t *userp,
+                     IN WCHAR    *SourceFileNameCounted,
+                     IN DWORD     SourceFileNameLength,
+                     IN AFSFileID SourceFileId,
+                     IN AFSFileRenameCB *pRenameCB,
+                     IN BOOL bWow64,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB)
+{
+
+    AFSFileRenameResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    AFSFileID              SourceParentId   = pRenameCB->SourceParentId;
+    AFSFileID              TargetParentId   = pRenameCB->TargetParentId;
+    WCHAR *                TargetFileNameCounted = pRenameCB->TargetName;
+    DWORD                  TargetFileNameLength = pRenameCB->TargetNameLength;
+    cm_fid_t               SourceParentFid;
+    cm_fid_t               TargetParentFid;
+    cm_scache_t *          oldDscp;
+    cm_scache_t *          newDscp;
+    wchar_t                shortName[13];
+    wchar_t                SourceFileName[260];
+    wchar_t                TargetFileName[260];
+    cm_dirFid_t            dfid;
+    cm_req_t               req;
+    afs_uint32             code;
+    DWORD                  status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
+    StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
+
+    osi_Log4(afsd_logp, "RDR_RenameFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              SourceParentId.Cell,  SourceParentId.Volume,
+              SourceParentId.Vnode, SourceParentId.Unique);
+    osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
+    osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              TargetParentId.Cell,  TargetParentId.Volume,
+              TargetParentId.Vnode, TargetParentId.Unique);
+    osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
+
+    *ResultCB = (AFSCommResult *)malloc( size);
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            size);
+
+    pResultCB = (AFSFileRenameResultCB *)(*ResultCB)->ResultData;
+
+    if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
+    {
+        osi_Log2(afsd_logp, "RDR_RenameFileEntry Invalid Name Length: src %u target %u",
+                 SourceFileNameLength, TargetFileNameLength);
+        (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
+        return;
+    }
+
+    SourceParentFid.cell   = SourceParentId.Cell;
+    SourceParentFid.volume = SourceParentId.Volume;
+    SourceParentFid.vnode  = SourceParentId.Vnode;
+    SourceParentFid.unique = SourceParentId.Unique;
+    SourceParentFid.hash   = SourceParentId.Hash;
+
+    TargetParentFid.cell   = TargetParentId.Cell;
+    TargetParentFid.volume = TargetParentId.Volume;
+    TargetParentFid.vnode  = TargetParentId.Vnode;
+    TargetParentFid.unique = TargetParentId.Unique;
+    TargetParentFid.hash   = TargetParentId.Hash;
+
+    code = cm_GetSCache(&SourceParentFid, &oldDscp, userp, &req);
+    if (code) {
+        osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache source parent failed code 0x%x", code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+
+    lock_ObtainWrite(&oldDscp->rw);
+    code = cm_SyncOp(oldDscp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp oldDscp 0x%p failed code 0x%x", oldDscp, code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&oldDscp->rw);
+        cm_ReleaseSCache(oldDscp);
+        return;
+    }
+
+    cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&oldDscp->rw);
+
+
+    if (oldDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        osi_Log1(afsd_logp, "RDR_RenameFileEntry oldDscp 0x%p not a directory", oldDscp);
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(oldDscp);
+        return;
+    }
+
+    code = cm_GetSCache(&TargetParentFid, &newDscp, userp, &req);
+    if (code) {
+        osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target parent failed code 0x%x", code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        cm_ReleaseSCache(oldDscp);
+        return;
+    }
+
+    lock_ObtainWrite(&newDscp->rw);
+    code = cm_SyncOp(newDscp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp newDscp 0x%p failed code 0x%x", newDscp, code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&newDscp->rw);
+        cm_ReleaseSCache(oldDscp);
+        cm_ReleaseSCache(newDscp);
+        return;
+    }
+
+    cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&newDscp->rw);
+
+
+    if (newDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        osi_Log1(afsd_logp, "RDR_RenameFileEntry newDscp 0x%p not a directory", newDscp);
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(oldDscp);
+        cm_ReleaseSCache(newDscp);
+        return;
+    }
+
+    code = cm_Rename( oldDscp, NULL, SourceFileName,
+                      newDscp, TargetFileName, userp, &req);
+    if (code == 0) {
+        cm_dirOp_t dirop;
+        cm_fid_t   targetFid;
+        cm_scache_t *scp = 0;
+        DWORD dwRemaining;
+
+        (*ResultCB)->ResultBufferLength = ResultBufferLength;
+        dwRemaining = ResultBufferLength - sizeof( AFSFileRenameResultCB) + sizeof( AFSDirEnumEntry);
+        (*ResultCB)->ResultStatus = 0;
+
+        pResultCB->SourceParentDataVersion.QuadPart = oldDscp->dataVersion;
+        pResultCB->TargetParentDataVersion.QuadPart = newDscp->dataVersion;
+
+        osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p SUCCESS",
+                 oldDscp, newDscp);
+
+        code = cm_BeginDirOp( newDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
+        if (code == 0) {
+            code = cm_BPlusDirLookup(&dirop, TargetFileName, &targetFid);
+            cm_EndDirOp(&dirop);
+        }
+
+        if (code != 0) {
+            osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_BPlusDirLookup failed code 0x%x",
+                     code);
+            (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
+            cm_ReleaseSCache(oldDscp);
+            cm_ReleaseSCache(newDscp);
+            return;
+        }
+
+        osi_Log4(afsd_logp, "RDR_RenameFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+                  targetFid.cell,  targetFid.volume,
+                  targetFid.vnode, targetFid.unique);
+
+        code = cm_GetSCache(&targetFid, &scp, userp, &req);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target failed code 0x%x", code);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            cm_ReleaseSCache(oldDscp);
+            cm_ReleaseSCache(newDscp);
+            return;
+        }
+
+        /* Make sure the source vnode is current */
+        lock_ObtainWrite(&scp->rw);
+        code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code) {
+            osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp scp 0x%p failed code 0x%x", scp, code);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            lock_ReleaseWrite(&scp->rw);
+            cm_ReleaseSCache(oldDscp);
+            cm_ReleaseSCache(newDscp);
+            cm_ReleaseSCache(scp);
+            return;
+        }
+
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&scp->rw);
+
+        dfid.vnode = htonl(scp->fid.vnode);
+        dfid.unique = htonl(scp->fid.unique);
+
+        if (!cm_Is8Dot3(TargetFileName))
+            cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
+        else
+            shortName[0] = '\0';
+        RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
+                                 newDscp, scp, userp, &req, TargetFileName, shortName,
+                                 RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
+                                 NULL, &dwRemaining);
+        (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+        cm_ReleaseSCache(scp);
+
+        osi_Log0(afsd_logp, "RDR_RenameFileEntry SUCCESS");
+    } else {
+        osi_Log3(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p failed code 0x%x",
+                 oldDscp, newDscp, code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+    }
+
+    cm_ReleaseSCache(oldDscp);
+    cm_ReleaseSCache(newDscp);
+    return;
+}
+
+void
+RDR_FlushFileEntry( IN cm_user_t *userp,
+                    IN AFSFileID FileId,
+                    IN BOOL bWow64,
+                    IN DWORD ResultBufferLength,
+                    IN OUT AFSCommResult **ResultCB)
+{
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+#ifdef ODS_DEBUG
+    char        dbgstr[1024];
+#endif
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+#ifdef ODS_DEBUG
+    snprintf( dbgstr, 1024,
+              "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x\n",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+    OutputDebugStringA( dbgstr);
+#endif
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_FlushFileEntry out of memory");
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    /* Process the release */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_FlushFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+    if (scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseWrite(&scp->rw);
+        (*ResultCB)->ResultStatus = STATUS_INVALID_HANDLE;
+        return;
+    }
+
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log3(afsd_logp, "RDR_FlushFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&scp->rw);
+
+    code = cm_FSync(scp, userp, &req, FALSE);
+    cm_ReleaseSCache(scp);
+
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_FlushFileEntry FAILURE code=0x%x status=0x%x",
+                  code, status);
+    } else {
+        (*ResultCB)->ResultStatus = 0;
+        osi_Log0(afsd_logp, "RDR_FlushFileEntry SUCCESS");
+    }
+    (*ResultCB)->ResultBufferLength = 0;
+
+    return;
+}
+
+afs_uint32
+RDR_CheckAccess( IN cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
+                 ULONG access,
+                 ULONG *granted)
+{
+    ULONG afs_acc, afs_gr;
+    BOOLEAN file, dir;
+    afs_uint32 code = 0;
+
+    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 (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
+       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 (file && (access & FILE_EXECUTE))
+       afs_acc |= PRSFS_WRITE;
+    if (dir && (access & FILE_TRAVERSE))
+       afs_acc |= PRSFS_READ;
+    if (dir && (access & FILE_DELETE_CHILD))
+       afs_acc |= PRSFS_DELETE;
+    if ((access & DELETE))
+       afs_acc |= PRSFS_DELETE;
+
+    /* check ACL with server */
+    lock_ObtainWrite(&scp->rw);
+    while (1)
+    {
+       if (cm_HaveAccessRights(scp, userp, reqp, afs_acc, &afs_gr))
+        {
+            break;
+        }
+       else
+        {
+            /* we don't know the required access rights */
+            code = cm_GetAccessRights(scp, userp, reqp);
+            if (code)
+                break;
+            continue;
+        }
+    }
+    lock_ReleaseWrite(&(scp->rw));
+
+    if (code == 0) {
+        *granted = 0;
+        if (afs_gr & PRSFS_READ)
+            *granted |= FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE;
+        if (afs_gr & PRSFS_WRITE)
+            *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE;
+        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);
+        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;
+
+        /* don't give more access than what was requested */
+        *granted &= access;
+        osi_Log3(afsd_logp, "RDR_CheckAccess SUCCESS scp=0x%p requested=0x%x granted=0x%x", scp, access, *granted);
+    } else
+        osi_Log2(afsd_logp, "RDR_CheckAccess FAILURE scp=0x%p code=0x%x",
+                 scp, code);
+
+    return code;
+}
+
+void
+RDR_OpenFileEntry( IN cm_user_t *userp,
+                   IN AFSFileID FileId,
+                   IN AFSFileOpenCB *OpenCB,
+                   IN BOOL bWow64,
+                   IN BOOL bHoldFid,
+                   IN DWORD ResultBufferLength,
+                   IN OUT AFSCommResult **ResultCB)
+{
+    AFSFileOpenResultCB *pResultCB = NULL;
+    cm_scache_t *scp = NULL;
+    cm_user_t   *sysUserp = NULL;
+    cm_fid_t    Fid;
+    cm_lock_data_t      *ldp = NULL;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_OpenFileEntry File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_OpenFileEntry out of memory");
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
+
+    pResultCB = (AFSFileOpenResultCB *)(*ResultCB)->ResultData;
+
+    /* Process the release */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_OpenFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log3(afsd_logp, "RDR_OpenFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&scp->rw);
+
+    sysUserp = RDR_GetLocalSystemUser();
+
+    /*
+     * Skip the open check if the request is coming from the local system account.
+     * The local system has no tokens and therefore any requests sent to a file
+     * server will fail.  Unfortunately, there are special system processes that
+     * perform actions on files and directories in preparation for memory mapping
+     * executables.  If the open check fails, the real request from the user process
+     * will never be issued.
+     *
+     * Permitting the file system to allow subsequent operations to proceed does
+     * not compromise security.  All requests to obtain file data or directory
+     * enumerations will subsequently fail if they are not submitted under the
+     * context of a process for that have access to the necessary credentials.
+     */
+
+    if ( userp == sysUserp)
+    {
+        osi_Log1(afsd_logp, "RDR_OpenFileEntry LOCAL_SYSTEM access check skipped scp=0x%p",
+                 scp);
+        pResultCB->GrantedAccess = OpenCB->DesiredAccess;
+        code = 0;
+    } else {
+        int count = 0;
+        do {
+            if (count++ > 0) {
+                Sleep(350);
+                osi_Log3(afsd_logp,
+                         "RDR_OpenFileEntry repeating open check scp=0x%p userp=0x%p code=0x%x",
+                         scp, userp, code);
+            }
+            code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OPEN_ALWAYS, userp, &req, &ldp);
+            if (code == 0)
+                code = RDR_CheckAccess(scp, userp, &req, OpenCB->DesiredAccess, &pResultCB->GrantedAccess);
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+        } while (count < 100 && (code == CM_ERROR_RETRY || code == CM_ERROR_WOULDBLOCK));
+    }
+
+    cm_ReleaseUser(sysUserp);
+    if (bHoldFid)
+        RDR_FlagScpInUse( scp, FALSE );
+    cm_ReleaseSCache(scp);
+
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_OpenFileEntry FAILURE code=0x%x status=0x%x",
+                  code, status);
+    } else {
+        (*ResultCB)->ResultStatus = 0;
+        (*ResultCB)->ResultBufferLength = sizeof( AFSFileOpenResultCB);
+        osi_Log0(afsd_logp, "RDR_OpenFileEntry SUCCESS");
+    }
+    return;
+}
+
+static const char *
+HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
+{
+    int i, k;
+    static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+    if (buflen < 33)
+        return "buffer length too small to HexCheckSum";
+
+    for (i=0;i<16;i++) {
+        k = md5cksum[i];
+
+        buf[i*2] = tr[k / 16];
+        buf[i*2+1] = tr[k % 16];
+    }
+    buf[32] = '\0';
+
+    return buf;
+}
+
+/*
+ * Extent requests from the file system are triggered when a file
+ * page is not resident in the Windows cache.  The file system is
+ * responsible for loading the page but cannot block the request
+ * while doing so.  The AFS Redirector forwards the requests to
+ * the AFS cache manager while indicating to Windows that the page
+ * is not yet available.  A polling operation will then ensue with
+ * the AFS Redirector issuing a RDR_RequestFileExtentsXXX call for
+ * each poll attempt.  As each request is received and processed
+ * by a separate worker thread in the service, this can lead to
+ * contention by multiple threads attempting to claim the same
+ * cm_buf_t objects.  Therefore, it is important that
+ *
+ *  (a) the service avoid processing more than one overlapping
+ *      extent request at a time
+ *  (b) background daemon processing be used to avoid blocking
+ *      of ioctl threads
+ *
+ * Beginning with the 20091122 build of the redirector, the redirector
+ * will not issue an additional RDR_RequestFileExtentsXXX call for
+ * each poll request.  Instead, afsd_service is required to track
+ * the requests and return them to the redirector or fail the
+ * portions of the request that cannot be satisfied.
+ *
+ * The request processing returns any extents that can be returned
+ * immediately to the redirector.  The rest of the requested range(s)
+ * are queued as background operations using RDR_BkgFetch().
+ */
+
+/* do the background fetch. */
+afs_int32
+RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
+             cm_user_t *userp, cm_req_t *reqp)
+{
+    osi_hyper_t length;
+    osi_hyper_t base;
+    osi_hyper_t offset;
+    osi_hyper_t end;
+    osi_hyper_t fetched;
+    osi_hyper_t tblocksize;
+    afs_int32 code;
+    int rwheld = 0;
+    cm_buf_t *bufp = NULL;
+    DWORD dwResultBufferLength;
+    AFSSetFileExtentsCB *pResultCB;
+    DWORD status;
+    afs_uint32 count=0;
+    AFSFileID FileId;
+    int reportErrorToRedir = 0;
+    int force_retry = 0;
+
+    FileId.Cell = scp->fid.cell;
+    FileId.Volume = scp->fid.volume;
+    FileId.Vnode = scp->fid.vnode;
+    FileId.Unique = scp->fid.unique;
+    FileId.Hash = scp->fid.hash;
+
+    if ((GetTickCount() - reqp->startTime) / 1000 > HardDeadtimeout * 5) {
+        RDR_SetFileStatus( &scp->fid, STATUS_IO_TIMEOUT);
+        return 0;
+    }
+
+    fetched.LowPart = 0;
+    fetched.HighPart = 0;
+    tblocksize = ConvertLongToLargeInteger(cm_data.buf_blockSize);
+    base.LowPart = p1;
+    base.HighPart = p2;
+    length.LowPart = p3;
+    length.HighPart = p4;
+
+    end = LargeIntegerAdd(base, length);
+
+    osi_Log5(afsd_logp, "Starting BKG Fetch scp 0x%p offset 0x%x:%x length 0x%x:%x",
+             scp, p2, p1, p4, p3);
+
+    /*
+     * Make sure we have a callback.
+     * This is necessary so that we can return access denied
+     * if a callback cannot be granted.
+     */
+    lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_READ,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        lock_ReleaseWrite(&scp->rw);
+        osi_Log2(afsd_logp, "RDR_BkgFetch cm_SyncOp failure scp=0x%p code=0x%x",
+                 scp, code);
+        smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
+        RDR_SetFileStatus( &scp->fid, status);
+        return code;
+    }
+    lock_ReleaseWrite(&scp->rw);
+
+    dwResultBufferLength = (DWORD)(sizeof( AFSSetFileExtentsCB) + sizeof( AFSSetFileExtentsCB) * (length.QuadPart / cm_data.blockSize + 1));
+    pResultCB = (AFSSetFileExtentsCB *)malloc( dwResultBufferLength );
+    if (!pResultCB)
+        return CM_ERROR_RETRY;
+
+    memset( pResultCB, '\0', dwResultBufferLength );
+    pResultCB->FileId = FileId;
+
+    for ( code = 0, offset = base;
+          code == 0 && LargeIntegerLessThan(offset, end);
+          offset = LargeIntegerAdd(offset, tblocksize) )
+    {
+        int bBufRelease = TRUE;
+
+        if (rwheld) {
+            lock_ReleaseWrite(&scp->rw);
+            rwheld = 0;
+        }
+
+        code = buf_Get(scp, &offset, reqp, &bufp);
+        if (code) {
+            /*
+             * any error from buf_Get() is non-fatal.
+             * we need to re-queue this extent fetch.
+             */
+            force_retry = 1;
+            continue;
+        }
+
+        if (!rwheld) {
+            lock_ObtainWrite(&scp->rw);
+            rwheld = 1;
+        }
+
+        code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
+        if (code == 0) {
+            if (bufp->flags & CM_BUF_DIRTY) {
+                if (rwheld) {
+                    lock_ReleaseWrite(&scp->rw);
+                    rwheld = 0;
+                }
+                cm_BufWrite(scp, &bufp->offset, cm_chunkSize, 0, userp, reqp);
+            }
+
+            if (!(bufp->qFlags & CM_BUF_QREDIR)) {
+#ifdef VALIDATE_CHECK_SUM
+#ifdef ODS_DEBUG
+                char md5dbg[33];
+                char dbgstr[1024];
+#endif
+#endif
+                if (!rwheld) {
+                    lock_ObtainWrite(&scp->rw);
+                    rwheld = 1;
+                }
+                lock_ObtainWrite(&buf_globalLock);
+                if (!(bufp->flags & CM_BUF_DIRTY) &&
+                    bufp->cmFlags == 0 &&
+                    !(bufp->qFlags & CM_BUF_QREDIR)) {
+                    buf_InsertToRedirQueue(scp, bufp);
+                    lock_ReleaseWrite(&buf_globalLock);
+                    lock_ReleaseWrite(&scp->rw);
+                    rwheld = 0;
+
+#ifdef VALIDATE_CHECK_SUM
+                    buf_ComputeCheckSum(bufp);
+#endif
+                    pResultCB->FileExtents[count].Flags = 0;
+                    pResultCB->FileExtents[count].FileOffset.QuadPart = bufp->offset.QuadPart;
+                    pResultCB->FileExtents[count].CacheOffset.QuadPart = bufp->datap - RDR_extentBaseAddress;
+                    pResultCB->FileExtents[count].Length = cm_data.blockSize;
+                    count++;
+                    fetched = LargeIntegerAdd(fetched, tblocksize);
+                    bBufRelease = FALSE;
+
+#ifdef VALIDATE_CHECK_SUM
+#ifdef ODS_DEBUG
+                    HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
+                    snprintf( dbgstr, 1024,
+                              "RDR_BkgFetch md5 %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                              md5dbg,
+                              scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                              pResultCB->FileExtents[count].FileOffset.HighPart,
+                              pResultCB->FileExtents[count].FileOffset.LowPart,
+                              pResultCB->FileExtents[count].CacheOffset.HighPart,
+                              pResultCB->FileExtents[count].CacheOffset.LowPart);
+                    OutputDebugStringA( dbgstr);
+#endif
+#endif
+                    osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
+                              bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
+                } else {
+                    lock_ReleaseWrite(&buf_globalLock);
+                    if ((bufp->cmFlags != 0) || (bufp->flags & CM_BUF_DIRTY)) {
+                        /* An I/O operation is already in progress */
+                        force_retry = 1;
+                        osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Not delivering to Redirector Dirty or Busy bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
+                                  bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
+                    } else {
+                        osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
+                                  bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
+                    }
+                }
+            } else {
+                osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
+                          bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
+            }
+
+            if (rwheld) {
+                lock_ReleaseWrite(&scp->rw);
+                rwheld = 0;
+            }
+
+        } else {
+            /*
+             * depending on what the error from cm_GetBuffer is
+             * it may or may not be fatal.  Only return fatal errors.
+             * Re-queue a request for others.
+             */
+            osi_Log5(afsd_logp, "RDR_BkgFetch Extent2FS FAILURE bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x code 0x%x",
+                      bufp, offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize, code);
+            switch (code) {
+            case CM_ERROR_NOACCESS:
+            case CM_ERROR_NOSUCHFILE:
+            case CM_ERROR_NOSUCHPATH:
+            case CM_ERROR_NOSUCHVOLUME:
+            case CM_ERROR_NOSUCHCELL:
+            case CM_ERROR_INVAL:
+            case CM_ERROR_BADFD:
+            case CM_ERROR_CLOCKSKEW:
+            case RXKADNOAUTH:
+            case CM_ERROR_QUOTA:
+            case CM_ERROR_LOCK_CONFLICT:
+                /*
+                 * these are fatal errors.  deliver what we can
+                 * and halt.
+                 */
+                reportErrorToRedir = 1;
+                break;
+            default:
+                /*
+                 * non-fatal errors.  re-queue the exent
+                 */
+                code = CM_ERROR_RETRY;
+            }
+        }
+
+        if (bBufRelease)
+            buf_Release(bufp);
+    }
+
+    if (!rwheld) {
+        lock_ObtainWrite(&scp->rw);
+        rwheld = 1;
+    }
+
+    /* wakeup anyone who is waiting */
+    if (scp->flags & CM_SCACHEFLAG_WAITING) {
+        osi_Log1(afsd_logp, "RDR Bkg Fetch Waking scp 0x%p", scp);
+        osi_Wakeup((LONG_PTR) &scp->flags);
+    }
+    lock_ReleaseWrite(&scp->rw);
+
+    if (count > 0) {
+        pResultCB->ExtentCount = count;
+        RDR_SetFileExtents( pResultCB, dwResultBufferLength);
+    }
+    free(pResultCB);
+
+    if (reportErrorToRedir) {
+        smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
+        RDR_SetFileStatus( &scp->fid, status);
+    }
+
+    osi_Log4(afsd_logp, "Ending BKG Fetch scp 0x%p code 0x%x fetched 0x%x:%x",
+             scp, code, fetched.HighPart, fetched.LowPart);
+
+    return force_retry ? CM_ERROR_RETRY : code;
+}
+
+
+BOOL
+RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
+                             IN AFSFileID FileId,
+                             IN AFSRequestExtentsCB *RequestExtentsCB,
+                             IN BOOL bWow64,
+                             IN OUT DWORD * ResultBufferLength,
+                             IN OUT AFSSetFileExtentsCB **ResultCB)
+{
+    AFSSetFileExtentsCB *pResultCB = NULL;
+    DWORD Length;
+    DWORD count;
+    DWORD status;
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    cm_buf_t    *bufp;
+    afs_uint32  code = 0;
+    osi_hyper_t thyper;
+    LARGE_INTEGER ByteOffset, BeginOffset, EndOffset, QueueOffset;
+    afs_uint32  QueueLength;
+    cm_req_t    req;
+    BOOLEAN     bBufRelease = TRUE;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+    req.flags |= CM_REQ_NORETRY;
+
+    osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+    osi_Log4(afsd_logp, "... Flags 0x%x ByteOffset 0x%x:%x Length 0x%x",
+             RequestExtentsCB->Flags,
+             RequestExtentsCB->ByteOffset.HighPart, RequestExtentsCB->ByteOffset.LowPart,
+             RequestExtentsCB->Length);
+    Length = sizeof( AFSSetFileExtentsCB) + sizeof( AFSFileExtentCB) * (RequestExtentsCB->Length / cm_data.blockSize + 1);
+
+    pResultCB = *ResultCB = (AFSSetFileExtentsCB *)malloc( Length );
+    if (*ResultCB == NULL) {
+        *ResultBufferLength = 0;
+        return FALSE;
+    }
+    *ResultBufferLength = Length;
+
+    memset( pResultCB, '\0', Length );
+    pResultCB->FileId = FileId;
+
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        osi_Log1(afsd_logp, "RDR_RequestFileExtentsAsync cm_GetSCache FID failure code=0x%x",
+                  code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        RDR_SetFileStatus( &scp->fid, status);
+        return FALSE;
+    }
+
+    /*
+     * Make sure we have a callback.
+     * This is necessary so that we can return access denied
+     * if a callback cannot be granted.
+     */
+    lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&scp->rw);
+    if (code) {
+        cm_ReleaseSCache(scp);
+        osi_Log2(afsd_logp, "RDR_RequestFileExtentsAsync cm_SyncOp failure scp=0x%p code=0x%x",
+                 scp, code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        RDR_SetFileStatus( &scp->fid, status);
+        return FALSE;
+    }
+
+    /* Allocate the extents from the buffer package */
+    for ( count = 0,
+          ByteOffset = BeginOffset = RequestExtentsCB->ByteOffset,
+          EndOffset.QuadPart = ByteOffset.QuadPart + RequestExtentsCB->Length;
+          code == 0 && ByteOffset.QuadPart < EndOffset.QuadPart;
+          ByteOffset.QuadPart += cm_data.blockSize)
+    {
+        BOOL bHaveBuffer = FALSE;
+
+        QueueLength = 0;
+        thyper.QuadPart = ByteOffset.QuadPart;
+
+        code = buf_Get(scp, &thyper, &req, &bufp);
+        if (code == 0) {
+            lock_ObtainMutex(&bufp->mx);
+            bBufRelease = TRUE;
+
+            if (bufp->qFlags & CM_BUF_QREDIR) {
+                bHaveBuffer = TRUE;
+            } else if (bufp->flags & CM_BUF_DIRTY) {
+                bHaveBuffer = FALSE;
+#if 0
+                code = buf_CleanAsyncLocked(scp, bufp, &req, 0, NULL);
+                switch (code) {
+                case 0:
+                    bHaveBuffer = TRUE;
+                    break;
+                case CM_ERROR_RETRY:
+                    /* Couldn't flush it, obtain it asynchronously so we don't block the thread. */
+                    bHaveBuffer = FALSE;
+                    code = 0;
+                    break;
+                default:
+                    smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+                    RDR_SetFileStatus(&FileId, status);
+                    bHaveBuffer = FALSE;
+                    code = 0;
+                }
+#endif
+            } else {
+                osi_hyper_t minLength;  /* effective end of file */
+
+                lock_ObtainRead(&scp->rw);
+                bHaveBuffer = cm_HaveBuffer(scp, bufp, TRUE);
+
+                if (LargeIntegerGreaterThan(scp->length, scp->serverLength))
+                    minLength = scp->serverLength;
+                else
+                    minLength = scp->length;
+
+                if (LargeIntegerGreaterThanOrEqualTo(bufp->offset, minLength)) {
+                    memset(bufp->datap, 0, cm_data.buf_blockSize);
+                    bufp->dataVersion = scp->dataVersion;
+                    bHaveBuffer = TRUE;
+                }
+                lock_ReleaseRead(&scp->rw);
+
+                if ((RequestExtentsCB->Flags & AFS_EXTENT_FLAG_CLEAN) &&
+                     ByteOffset.QuadPart <= bufp->offset.QuadPart &&
+                     EndOffset.QuadPart >= bufp->offset.QuadPart + cm_data.blockSize) {
+                    memset(bufp->datap, 0, cm_data.blockSize);
+                    bufp->dataVersion = scp->dataVersion;
+                    buf_SetDirty(bufp, &req, 0, cm_data.blockSize, userp);
+                    bHaveBuffer = TRUE;
+                }
+            }
+
+            /*
+             * if this buffer is already up to date, skip it.
+             */
+            if (bHaveBuffer) {
+                if (ByteOffset.QuadPart == BeginOffset.QuadPart) {
+                    BeginOffset.QuadPart += cm_data.blockSize;
+                } else {
+                    QueueLength = (afs_uint32)(ByteOffset.QuadPart - BeginOffset.QuadPart);
+                    QueueOffset = BeginOffset;
+                    BeginOffset = ByteOffset;
+                }
+
+                if (!(bufp->qFlags & CM_BUF_QREDIR)) {
+#ifdef VALIDATE_CHECK_SUM
+#ifdef ODS_DEBUG
+                    char md5dbg[33];
+                    char dbgstr[1024];
+#endif
+#endif
+                    lock_ObtainWrite(&scp->rw);
+                    lock_ObtainWrite(&buf_globalLock);
+                    if (!(bufp->qFlags & CM_BUF_QREDIR)) {
+                        buf_InsertToRedirQueue(scp, bufp);
+                        lock_ReleaseWrite(&buf_globalLock);
+                        lock_ReleaseWrite(&scp->rw);
+
+#ifdef VALIDATE_CHECK_SUM
+                        buf_ComputeCheckSum(bufp);
+#endif
+                        /* we already have the buffer, return it now */
+                        pResultCB->FileExtents[count].Flags = 0;
+                        pResultCB->FileExtents[count].FileOffset = ByteOffset;
+                        pResultCB->FileExtents[count].CacheOffset.QuadPart = bufp->datap - RDR_extentBaseAddress;
+                        pResultCB->FileExtents[count].Length = cm_data.blockSize;
+                        count++;
+
+                        bBufRelease = FALSE;
+
+#ifdef VALIDATE_CHECK_SUM
+#ifdef ODS_DEBUG
+                        HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
+                        snprintf( dbgstr, 1024,
+                                  "RDR_RequestFileExtentsAsync md5 %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                  md5dbg,
+                                  scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                                  pResultCB->FileExtents[count].FileOffset.HighPart,
+                                  pResultCB->FileExtents[count].FileOffset.LowPart,
+                                  pResultCB->FileExtents[count].CacheOffset.HighPart,
+                                  pResultCB->FileExtents[count].CacheOffset.LowPart);
+                        OutputDebugStringA( dbgstr);
+#endif
+#endif
+                        osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync Extent2FS bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
+                                 bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
+                    } else {
+                        lock_ReleaseWrite(&buf_globalLock);
+                        lock_ReleaseWrite(&scp->rw);
+                    }
+                } else {
+                    if (bBufRelease) {
+                        /*
+                         * The service is not handing off the extent to the redirector in this pass.
+                         * However, we know the buffer is in recent use so move the buffer to the
+                         * front of the queue
+                         */
+                        lock_ObtainWrite(&scp->rw);
+                        lock_ObtainWrite(&buf_globalLock);
+                        buf_MoveToHeadOfRedirQueue(scp, bufp);
+                        lock_ReleaseWrite(&buf_globalLock);
+                        lock_ReleaseWrite(&scp->rw);
+
+                        osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
+                                 bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
+                    }
+                }
+            }
+            lock_ReleaseMutex(&bufp->mx);
+            if (bBufRelease)
+                buf_Release(bufp);
+
+            if (QueueLength) {
+                cm_QueueBKGRequest(scp, RDR_BkgFetch, QueueOffset.LowPart, QueueOffset.HighPart,
+                                   QueueLength, 0, userp, &req);
+                osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
+                         QueueOffset.HighPart, QueueOffset.LowPart, QueueLength);
+            }
+        } else {
+            /* No error from buf_Get() can be fatal */
+            osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync buf_Get FAILURE offset 0x%x:%x code 0x%x",
+                     BeginOffset.HighPart, BeginOffset.LowPart, code);
+        }
+    }
+
+    if (BeginOffset.QuadPart != EndOffset.QuadPart) {
+        afs_uint32 length = (afs_uint32)(EndOffset.QuadPart - BeginOffset.QuadPart);
+
+        cm_QueueBKGRequest(scp, RDR_BkgFetch, BeginOffset.LowPart, BeginOffset.HighPart,
+                           length, 0, userp, &req);
+        osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
+                  BeginOffset.HighPart, BeginOffset.LowPart, length);
+    }
+    cm_ReleaseSCache(scp);
+
+    (*ResultCB)->ExtentCount = count;
+    osi_Log1(afsd_logp, "RDR_RequestFileExtentsAsync replying with 0x%x extent records", count);
+    return FALSE;
+}
+
+/*
+ * When processing an extent release the extents must be accepted back by
+ * the service even if there is an error condition returned to the redirector.
+ * For example, there may no longer be a callback present or the file may
+ * have been deleted on the file server.  Regardless, the extents must be
+ * put back into the pool.
+ */
+void
+RDR_ReleaseFileExtents( IN cm_user_t *userp,
+                        IN AFSFileID FileId,
+                        IN AFSReleaseExtentsCB *ReleaseExtentsCB,
+                        IN BOOL bWow64,
+                        IN DWORD ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB)
+{
+    DWORD count;
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    cm_buf_t    *bufp;
+    afs_uint32  code;
+    osi_hyper_t thyper;
+    cm_req_t    req;
+    int         dirty = 0;
+    int         released = 0;
+    DWORD       status;
+#ifdef ODS_DEBUG
+#ifdef VALIDATE_CHECK_SUM
+    char md5dbg[33], md5dbg2[33], md5dbg3[33];
+#endif
+    char dbgstr[1024];
+#endif
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_ReleaseFileExtents File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    /* Process the release */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_ReleaseFileExtents cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+    }
+
+    /*
+     * We do not stop processing as a result of being unable to find the cm_scache object.
+     * If this occurs something really bad has happened since the cm_scache object must have
+     * been recycled while extents were held by the redirector.  However, we will be resilient
+     * and carry on without it.
+     */
+    if (scp && ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart) {
+        cm_attr_t setAttr;
+
+        memset(&setAttr, 0, sizeof(cm_attr_t));
+        lock_ObtainWrite(&scp->rw);
+        if (ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart) {
+
+            osi_Log4(afsd_logp, "RDR_ReleaseFileExtents new length fid vol 0x%x vno 0x%x length 0x%x:%x",
+                      scp->fid.volume, scp->fid.vnode,
+                      ReleaseExtentsCB->AllocationSize.HighPart,
+                      ReleaseExtentsCB->AllocationSize.LowPart);
+
+            setAttr.mask |= CM_ATTRMASK_LENGTH;
+            setAttr.length.LowPart = ReleaseExtentsCB->AllocationSize.LowPart;
+            setAttr.length.HighPart = ReleaseExtentsCB->AllocationSize.HighPart;
+        }
+        lock_ReleaseWrite(&scp->rw);
+        if (setAttr.mask)
+            code = cm_SetAttr(scp, &setAttr, userp, &req);
+    }
+
+    for ( count = 0; count < ReleaseExtentsCB->ExtentCount; count++) {
+        AFSFileExtentCB * pExtent = &ReleaseExtentsCB->FileExtents[count];
+
+        thyper.QuadPart = pExtent->FileOffset.QuadPart;
+
+        bufp = buf_Find(&Fid, &thyper);
+        if (bufp) {
+            if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
+                if (!(bufp->qFlags & CM_BUF_QREDIR)) {
+                    osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                              Fid.volume, Fid.vnode,
+                              pExtent->FileOffset.HighPart,
+                              pExtent->FileOffset.LowPart);
+                    osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; previously released",
+                              pExtent->CacheOffset.HighPart,
+                              pExtent->CacheOffset.LowPart);
+                } else {
+                    osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                              Fid.volume, Fid.vnode,
+                              pExtent->FileOffset.HighPart,
+                              pExtent->FileOffset.LowPart);
+                    osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; owned by redirector",
+                              pExtent->CacheOffset.HighPart,
+                              pExtent->CacheOffset.LowPart);
+                }
+                buf_Release(bufp);
+                continue;
+            }
+
+            if (pExtent->Flags & AFS_EXTENT_FLAG_IN_USE) {
+                osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                          Fid.volume, Fid.vnode,
+                          pExtent->FileOffset.HighPart,
+                          pExtent->FileOffset.LowPart);
+                osi_Log2(afsd_logp, "... coffset 0x%x:%x IN_USE by file system",
+                          pExtent->CacheOffset.HighPart,
+                          pExtent->CacheOffset.LowPart);
+
+                /* Move the buffer to the front of the queue */
+                if (scp)
+                    lock_ObtainWrite(&scp->rw);
+                lock_ObtainWrite(&buf_globalLock);
+                buf_MoveToHeadOfRedirQueue(scp, bufp);
+                lock_ReleaseWrite(&buf_globalLock);
+                if (scp)
+                    lock_ReleaseWrite(&scp->rw);
+                buf_Release(bufp);
+                continue;
+            }
+
+            if (bufp->datap - RDR_extentBaseAddress == pExtent->CacheOffset.QuadPart) {
+                if (!(bufp->qFlags & CM_BUF_QREDIR)) {
+                    osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x not held by file system",
+                             Fid.volume, Fid.vnode, pExtent->FileOffset.HighPart,
+                             pExtent->FileOffset.LowPart);
+                    osi_Log2(afsd_logp, "... coffset 0x%x:%x",
+                             pExtent->CacheOffset.HighPart,
+                             pExtent->CacheOffset.LowPart);
+                } else {
+                    osi_Log4(afsd_logp, "RDR_ReleaseFileExtents bufp 0x%p vno 0x%x foffset 0x%x:%x",
+                              bufp, bufp->fid.vnode, pExtent->FileOffset.HighPart,
+                              pExtent->FileOffset.LowPart);
+                    osi_Log2(afsd_logp, "... coffset 0x%x:%x",
+                             pExtent->CacheOffset.HighPart,
+                             pExtent->CacheOffset.LowPart);
+
+                    if (pExtent->Flags || ReleaseExtentsCB->Flags) {
+                        lock_ObtainMutex(&bufp->mx);
+                        if ( (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_RELEASE) ||
+                             (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
+                        {
+                            if (bufp->qFlags & CM_BUF_QREDIR) {
+                                if (scp)
+                                    lock_ObtainWrite(&scp->rw);
+                                lock_ObtainWrite(&buf_globalLock);
+                                if (bufp->qFlags & CM_BUF_QREDIR) {
+                                    buf_RemoveFromRedirQueue(scp, bufp);
+                                    lock_ReleaseWrite(&scp->rw);
+                                    buf_ReleaseLocked(bufp, TRUE);
+                                } else {
+                                    if (scp)
+                                        lock_ReleaseWrite(&scp->rw);
+                                }
+                                if (scp)
+                                    lock_ReleaseWrite(&buf_globalLock);
+                            }
+#ifdef ODS_DEBUG
+                            snprintf( dbgstr, 1024,
+                                      "RDR_ReleaseFileExtents releasing: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                      Fid.volume, Fid.vnode, Fid.unique,
+                                      pExtent->FileOffset.HighPart,
+                                      pExtent->FileOffset.LowPart,
+                                      pExtent->CacheOffset.HighPart,
+                                      pExtent->CacheOffset.LowPart);
+                            OutputDebugStringA( dbgstr);
+#endif
+                            released++;
+                        } else {
+#ifdef ODS_DEBUG
+                            snprintf( dbgstr, 1024,
+                                      "RDR_ReleaseFileExtents not releasing: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                      Fid.volume, Fid.vnode, Fid.unique,
+                                      pExtent->FileOffset.HighPart,
+                                      pExtent->FileOffset.LowPart,
+                                      pExtent->CacheOffset.HighPart,
+                                      pExtent->CacheOffset.LowPart);
+                            OutputDebugStringA( dbgstr);
+#endif
+                            osi_Log4( afsd_logp, "RDR_ReleaseFileExtents not releasing vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                      Fid.volume, Fid.vnode,
+                                      pExtent->FileOffset.HighPart,
+                                      pExtent->FileOffset.LowPart);
+                            osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                                      pExtent->CacheOffset.HighPart,
+                                      pExtent->CacheOffset.LowPart);
+                        }
+
+                        if ( (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
+                             (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY) )
+                        {
+#ifdef VALIDATE_CHECK_SUM
+#ifdef ODS_DEBUG
+                            HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
+#endif
+
+                            /*
+                             * if the saved checksum matches the checksum of the current state of the buffer
+                             * then the buffer is the same as what was given to the kernel.
+                             */
+                            if ( buf_ValidateCheckSum(bufp) ) {
+                                buf_ComputeCheckSum(bufp);
+
+                                if (pExtent->Flags & AFS_EXTENT_FLAG_MD5_SET)
+                                {
+#ifdef ODS_DEBUG
+                                    HexCheckSum(md5dbg2, sizeof(md5dbg2), pExtent->MD5);
+                                    HexCheckSum(md5dbg3, sizeof(md5dbg3), bufp->md5cksum);
+#endif
+                                    if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
+                                    {
+#ifdef ODS_DEBUG
+                                        snprintf( dbgstr, 1024,
+                                                  "RDR_ReleaseFileExtents dirty flag set but not dirty and user != kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                                  md5dbg, md5dbg2,md5dbg3,
+                                                  Fid.volume, Fid.vnode, Fid.unique,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart,
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                        OutputDebugStringA( dbgstr);
+#endif
+                                        osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set and checksums do not match! vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                                  Fid.volume, Fid.vnode,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart);
+                                        osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                        buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                        dirty++;
+                                    } else {
+#ifdef ODS_DEBUG
+                                        snprintf( dbgstr, 1024,
+                                                  "RDR_ReleaseFileExtents dirty flag set but not dirty and user == kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                                  md5dbg, md5dbg2, md5dbg3,
+                                                  Fid.volume, Fid.vnode, Fid.unique,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart,
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                        OutputDebugStringA( dbgstr);
+#endif
+                                        osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                                  Fid.volume, Fid.vnode,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart);
+                                        osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                    }
+                                } else {
+#ifdef ODS_DEBUG
+                                        snprintf( dbgstr, 1024,
+                                                  "RDR_ReleaseFileExtents dirty flag set but not dirty: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                                  Fid.volume, Fid.vnode, Fid.unique,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart,
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                        OutputDebugStringA( dbgstr);
+#endif
+                                        osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                                  Fid.volume, Fid.vnode,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart);
+                                        osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                }
+                            } else {
+                                buf_ComputeCheckSum(bufp);
+#ifdef ODS_DEBUG
+                                if (pExtent->Flags & AFS_EXTENT_FLAG_MD5_SET)
+                                {
+                                    HexCheckSum(md5dbg3, sizeof(md5dbg3), bufp->md5cksum);
+                                    if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
+                                    {
+                                        snprintf( dbgstr, 1024,
+                                                  "RDR_ReleaseFileExtents dirty flag set and dirty and user != kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                                  md5dbg, md5dbg2,md5dbg3,
+                                                  Fid.volume, Fid.vnode, Fid.unique,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart,
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                        OutputDebugStringA( dbgstr);
+                                    } else {
+                                        snprintf( dbgstr, 1024,
+                                                  "RDR_ReleaseFileExtents dirty flag set and dirty and user == kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                                  md5dbg, md5dbg2,md5dbg3,
+                                                  Fid.volume, Fid.vnode, Fid.unique,
+                                                  pExtent->FileOffset.HighPart,
+                                                  pExtent->FileOffset.LowPart,
+                                                  pExtent->CacheOffset.HighPart,
+                                                  pExtent->CacheOffset.LowPart);
+                                        OutputDebugStringA( dbgstr);
+                                    }
+                                } else {
+                                    snprintf( dbgstr, 1024,
+                                              "RDR_ReleaseFileExtents dirty flag set: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                              Fid.volume, Fid.vnode, Fid.unique,
+                                              pExtent->FileOffset.HighPart,
+                                              pExtent->FileOffset.LowPart,
+                                              pExtent->CacheOffset.HighPart,
+                                              pExtent->CacheOffset.LowPart);
+                                    OutputDebugStringA( dbgstr);
+                                }
+#endif
+                                buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                dirty++;
+                            }
+#else /* !VALIDATE_CHECK_SUM */
+                            buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                            dirty++;
+#endif /* VALIDATE_CHECK_SUM */
+                        }
+#ifdef VALIDATE_CHECK_SUM
+                        else {
+#ifdef ODS_DEBUG
+                            HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
+#endif
+                            if ( !buf_ValidateCheckSum(bufp) ) {
+                                buf_ComputeCheckSum(bufp);
+#ifdef ODS_DEBUG
+                                HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
+                                snprintf( dbgstr, 1024,
+                                          "RDR_ReleaseFileExtents dirty flag not set but dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                          md5dbg, md5dbg3,
+                                          Fid.volume, Fid.vnode, Fid.unique,
+                                          pExtent->FileOffset.HighPart,
+                                          pExtent->FileOffset.LowPart,
+                                          pExtent->CacheOffset.HighPart,
+                                          pExtent->CacheOffset.LowPart);
+                                OutputDebugStringA( dbgstr);
+#endif
+                                osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag not set but extent has changed vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                          Fid.volume, Fid.vnode,
+                                          pExtent->FileOffset.HighPart,
+                                          pExtent->FileOffset.LowPart);
+                                osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                                          pExtent->CacheOffset.HighPart,
+                                          pExtent->CacheOffset.LowPart);
+                                buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                dirty++;
+                            } else {
+                                buf_ComputeCheckSum(bufp);
+#ifdef ODS_DEBUG
+                                HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
+                                snprintf( dbgstr, 1024,
+                                          "RDR_ReleaseFileExtents dirty flag not set: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                          Fid.volume, Fid.vnode, Fid.unique,
+                                          pExtent->FileOffset.HighPart,
+                                          pExtent->FileOffset.LowPart,
+                                          pExtent->CacheOffset.HighPart,
+                                          pExtent->CacheOffset.LowPart);
+                                OutputDebugStringA( dbgstr);
+#endif
+                                osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag not set: vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                          Fid.volume, Fid.vnode,
+                                          pExtent->FileOffset.HighPart,
+                                          pExtent->FileOffset.LowPart);
+                                osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                                          pExtent->CacheOffset.HighPart,
+                                          pExtent->CacheOffset.LowPart);
+                            }
+                        }
+#endif /* VALIDATE_CHECK_SUM */
+                        lock_ReleaseMutex(&bufp->mx);
+                    }
+                }
+            }
+            else {
+                char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
+                cm_buf_t *wbp;
+
+                for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
+                    if (wbp->datap == datap)
+                        break;
+                }
+
+#ifdef ODS_DEBUG
+                snprintf( dbgstr, 1024,
+                          "RDR_ReleaseFileExtents non-matching extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                          Fid.volume, Fid.vnode, Fid.unique,
+                          pExtent->FileOffset.HighPart,
+                          pExtent->FileOffset.LowPart,
+                          pExtent->CacheOffset.HighPart,
+                          pExtent->CacheOffset.LowPart);
+                OutputDebugStringA( dbgstr);
+#endif
+                osi_Log4( afsd_logp, "RDR_ReleaseFileExtents non-matching extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                          Fid.volume, Fid.vnode,
+                          pExtent->FileOffset.HighPart,
+                          pExtent->FileOffset.LowPart);
+                osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                          pExtent->CacheOffset.HighPart,
+                          pExtent->CacheOffset.LowPart);
+                osi_Log5( afsd_logp, "... belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
+                          wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
+#ifdef DEBUG
+                DebugBreak();
+#endif
+            }
+            buf_Release(bufp);
+        }
+        else {
+            char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
+            cm_buf_t *wbp;
+
+            for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
+                if (wbp->datap == datap)
+                    break;
+            }
+
+#ifdef ODS_DEBUG
+            snprintf( dbgstr, 1024,
+                      "RDR_ReleaseFileExtents unknown extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                      Fid.volume, Fid.vnode, Fid.unique,
+                      pExtent->FileOffset.HighPart,
+                      pExtent->FileOffset.LowPart,
+                      pExtent->CacheOffset.HighPart,
+                      pExtent->CacheOffset.LowPart);
+            OutputDebugStringA( dbgstr);
+#endif
+            osi_Log4( afsd_logp, "RDR_ReleaseFileExtents unknown extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                      Fid.volume, Fid.vnode,
+                      pExtent->FileOffset.HighPart,
+                      pExtent->FileOffset.LowPart);
+            osi_Log2( afsd_logp, "... coffset 0x%x:%x",
+                      pExtent->CacheOffset.HighPart,
+                      pExtent->CacheOffset.LowPart);
+            osi_Log5( afsd_logp, "... belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
+                      wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
+        }
+    }
+
+    if (scp) {
+        if (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_FLUSH) {
+            code = buf_CleanVnode(scp, userp, &req);
+        }
+        else if (dirty) {
+            osi_hyper_t offset = {0,0};
+            afs_uint32  length = 0;
+            afs_uint32  rights = 0;
+
+            lock_ObtainWrite(&scp->rw);
+            code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
+                             CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+            lock_ReleaseWrite(&scp->rw);
+            if (code == 0) {
+                /*
+                 * there is at least one dirty extent on this file.  queue up background store
+                 * requests for contiguous blocks
+                 */
+                for ( count = 0; count < ReleaseExtentsCB->ExtentCount; count++) {
+                    if (ReleaseExtentsCB->FileExtents[count].FileOffset.QuadPart == offset.QuadPart + length &&
+                         length + cm_data.buf_blockSize <= cm_chunkSize)
+                    {
+                        length += cm_data.buf_blockSize;
+                    } else {
+                        if (!(offset.QuadPart == 0 && length == 0))
+                            cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
+                                                length, 0, userp, &req);
+                        offset.QuadPart = ReleaseExtentsCB->FileExtents[count].FileOffset.QuadPart;
+                        length = cm_data.buf_blockSize;
+                    }
+                }
+                cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
+                                   length, 0, userp, &req);
+            }
+        }
+        cm_ReleaseSCache(scp);
+    }
+
+    osi_Log5(afsd_logp, "RDR_ReleaseFileExtents File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x Released %d",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique, released);
+    if (code && code != CM_ERROR_WOULDBLOCK) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_ReleaseFileExtents FAILURE code=0x%x status=0x%x",
+                  code, status);
+    } else {
+        (*ResultCB)->ResultStatus = 0;
+        osi_Log0(afsd_logp, "RDR_ReleaseFileExtents SUCCESS");
+    }
+    (*ResultCB)->ResultBufferLength = 0;
+
+    return;
+}
+
+DWORD
+RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFileExtentsResultCB,
+                                     IN DWORD ResultBufferLength)
+{
+    afs_uint32  code = 0;
+    cm_req_t    req;
+    osi_hyper_t thyper;
+    cm_buf_t    *bufp;
+    unsigned int fileno, extentno, total_extents = 0;
+    AFSReleaseFileExtentsResultFileCB *pNextFileCB;
+#ifdef ODS_DEBUG
+#ifdef VALIDATE_CHECK_SUM
+    char md5dbg[33], md5dbg2[33], md5dbg3[33];
+#endif
+    char dbgstr[1024];
+#endif
+    RDR_InitReq(&req);
+
+    for ( fileno = 0, pNextFileCB = &ReleaseFileExtentsResultCB->Files[0];
+          fileno < ReleaseFileExtentsResultCB->FileCount;
+          fileno++ ) {
+        AFSReleaseFileExtentsResultFileCB *pFileCB = pNextFileCB;
+        cm_user_t       *userp = NULL;
+        cm_fid_t         Fid;
+        cm_scache_t *    scp = NULL;
+        int              dirty = 0;
+        int              released = 0;
+        char * p;
+
+        userp = RDR_UserFromAuthGroup( &pFileCB->AuthGroup);
+
+        osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult %d.%d.%d.%d",
+                  pFileCB->FileId.Cell, pFileCB->FileId.Volume,
+                  pFileCB->FileId.Vnode, pFileCB->FileId.Unique);
+
+        /* Process the release */
+        Fid.cell = pFileCB->FileId.Cell;
+        Fid.volume = pFileCB->FileId.Volume;
+        Fid.vnode = pFileCB->FileId.Vnode;
+        Fid.unique = pFileCB->FileId.Unique;
+        Fid.hash = pFileCB->FileId.Hash;
+
+        if (Fid.cell == 0) {
+            osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult Invalid FID %d.%d.%d.%d",
+                     Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
+            code = CM_ERROR_INVAL;
+            goto cleanup_file;
+        }
+
+        code = cm_GetSCache(&Fid, &scp, userp, &req);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult cm_GetSCache FID failure code=0x%x",
+                     code);
+            /*
+             * A failure to find the cm_scache object cannot prevent the service
+             * from accepting the extents back from the redirector.
+             */
+        }
+
+        /* if the scp was not found, do not perform the length check */
+        if (scp && (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart)) {
+            cm_attr_t setAttr;
+
+            memset(&setAttr, 0, sizeof(cm_attr_t));
+            lock_ObtainWrite(&scp->rw);
+            if (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart) {
+                osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult length change vol 0x%x vno 0x%x length 0x%x:%x",
+                          scp->fid.volume, scp->fid.vnode,
+                          pFileCB->AllocationSize.HighPart,
+                          pFileCB->AllocationSize.LowPart);
+                setAttr.mask |= CM_ATTRMASK_LENGTH;
+                setAttr.length.LowPart = pFileCB->AllocationSize.LowPart;
+                setAttr.length.HighPart = pFileCB->AllocationSize.HighPart;
+            }
+            lock_ReleaseWrite(&scp->rw);
+            if (setAttr.mask)
+                code = cm_SetAttr(scp, &setAttr, userp, &req);
+        }
+
+        for ( extentno = 0; extentno < pFileCB->ExtentCount; total_extents++, extentno++ ) {
+            AFSFileExtentCB *pExtent = &pFileCB->FileExtents[extentno];
+
+            thyper.QuadPart = pExtent->FileOffset.QuadPart;
+
+            bufp = buf_Find(&Fid, &thyper);
+            if (bufp) {
+                if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
+                    if (!(bufp->qFlags & CM_BUF_QREDIR)) {
+                        osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                 Fid.volume, Fid.vnode,
+                                 pExtent->FileOffset.HighPart,
+                                 pExtent->FileOffset.LowPart);
+                        osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; previously released",
+                                 pExtent->CacheOffset.HighPart,
+                                 pExtent->CacheOffset.LowPart);
+                    } else {
+                        osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                 Fid.volume, Fid.vnode,
+                                 pExtent->FileOffset.HighPart,
+                                 pExtent->FileOffset.LowPart);
+                        osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; owned by redirector",
+                                 pExtent->CacheOffset.HighPart,
+                                 pExtent->CacheOffset.LowPart);
+                    }
+                    buf_Release(bufp);
+                    continue;
+                }
+
+                if (pExtent->Flags & AFS_EXTENT_FLAG_IN_USE) {
+                    osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                              Fid.volume, Fid.vnode,
+                              pExtent->FileOffset.HighPart,
+                              pExtent->FileOffset.LowPart);
+                    osi_Log2(afsd_logp, "... coffset 0x%x:%x IN_USE by file system",
+                              pExtent->CacheOffset.HighPart,
+                              pExtent->CacheOffset.LowPart);
+
+                    /* Move the buffer to the front of the queue */
+                    if (scp)
+                        lock_ObtainWrite(&scp->rw);
+                    lock_ObtainWrite(&buf_globalLock);
+                    buf_MoveToHeadOfRedirQueue(scp, bufp);
+                    lock_ReleaseWrite(&buf_globalLock);
+                    if (scp)
+                        lock_ReleaseWrite(&scp->rw);
+                    buf_Release(bufp);
+                    continue;
+                }
+
+                if (bufp->datap - RDR_extentBaseAddress == pExtent->CacheOffset.QuadPart) {
+                    if (!(bufp->qFlags & CM_BUF_QREDIR)) {
+                        osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                 Fid.volume, Fid.vnode,
+                                 pExtent->FileOffset.HighPart,
+                                 pExtent->FileOffset.LowPart);
+                        osi_Log2(afsd_logp, "... coffset 0x%x:%x not held by file system",
+                                 pExtent->CacheOffset.HighPart,
+                                 pExtent->CacheOffset.LowPart);
+#ifdef ODS_DEBUG
+                        snprintf(dbgstr, 1024,
+                                  "RDR_ProcessReleaseFileExtentsResult not held by redirector! flags 0x%x:%x vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                  ReleaseFileExtentsResultCB->Flags, pExtent->Flags,
+                                  Fid.volume, Fid.vnode, Fid.unique,
+                                  pExtent->FileOffset.HighPart,
+                                  pExtent->FileOffset.LowPart,
+                                  pExtent->CacheOffset.HighPart,
+                                  pExtent->CacheOffset.LowPart);
+                        OutputDebugStringA( dbgstr);
+#endif
+                    } else {
+                        osi_Log5(afsd_logp, "RDR_ProcessReleaseFileExtentsResult bufp 0x%p foffset 0x%x:%x coffset 0x%x:%x",
+                                 bufp, pExtent->FileOffset.HighPart, pExtent->FileOffset.LowPart,
+                                 pExtent->CacheOffset.HighPart, pExtent->CacheOffset.LowPart);
+
+                        if (pExtent->Flags || ReleaseFileExtentsResultCB->Flags) {
+                            lock_ObtainMutex(&bufp->mx);
+                            if ( (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_RELEASE) ||
+                                 (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
+                            {
+                                if (bufp->qFlags & CM_BUF_QREDIR) {
+                                    if (scp)
+                                        lock_ObtainWrite(&scp->rw);
+                                    lock_ObtainWrite(&buf_globalLock);
+                                    if (bufp->qFlags & CM_BUF_QREDIR) {
+                                        buf_RemoveFromRedirQueue(scp, bufp);
+                                        if (scp)
+                                            lock_ReleaseWrite(&scp->rw);
+                                        buf_ReleaseLocked(bufp, TRUE);
+                                    } else {
+                                        if (scp)
+                                            lock_ReleaseWrite(&scp->rw);
+                                    }
+                                    lock_ReleaseWrite(&buf_globalLock);
+                                }
+
+#ifdef ODS_DEBUG
+                                snprintf(dbgstr, 1024,
+                                          "RDR_ProcessReleaseFileExtentsResult extent released: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                          Fid.volume, Fid.vnode, Fid.unique,
+                                          pExtent->FileOffset.HighPart,
+                                          pExtent->FileOffset.LowPart,
+                                          pExtent->CacheOffset.HighPart,
+                                          pExtent->CacheOffset.LowPart);
+                                OutputDebugStringA( dbgstr);
+#endif
+
+                                released++;
+                            } else {
+                                osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult not releasing vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                         Fid.volume, Fid.vnode,
+                                         pExtent->FileOffset.HighPart,
+                                         pExtent->FileOffset.LowPart);
+                                osi_Log2(afsd_logp, "... coffset 0x%x:%x",
+                                         pExtent->CacheOffset.HighPart,
+                                         pExtent->CacheOffset.LowPart);
+#ifdef ODS_DEBUG
+                                snprintf(dbgstr, 1024,
+                                          "RDR_ProcessReleaseFileExtentsResult not released! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                          Fid.volume, Fid.vnode, Fid.unique,
+                                          pExtent->FileOffset.HighPart,
+                                          pExtent->FileOffset.LowPart,
+                                          pExtent->CacheOffset.HighPart,
+                                          pExtent->CacheOffset.LowPart);
+                                OutputDebugStringA( dbgstr);
+#endif
+                            }
+
+                            if ( (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
+                                 (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY) )
+                            {
+#ifdef VALIDATE_CHECK_SUM
+                                if ( buf_ValidateCheckSum(bufp) ) {
+#ifdef ODS_DEBUG
+                                    HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
+                                    if (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_MD5_SET)
+                                        HexCheckSum(md5dbg2, sizeof(md5dbg2), pExtent->MD5);
+#endif
+                                    buf_ComputeCheckSum(bufp);
+#ifdef ODS_DEBUG
+                                    HexCheckSum(md5dbg3, sizeof(md5dbg), bufp->md5cksum);
+#endif
+                                    if (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_MD5_SET)
+                                    {
+                                        if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
+                                        {
+#ifdef ODS_DEBUG
+                                            snprintf(dbgstr, 1024,
+                                                      "RDR_ProcessReleaseFileExtentsResult dirty flag set and checksums do not match! user %s kernel %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                                      md5dbg3, md5dbg2,
+                                                      Fid.volume, Fid.vnode, Fid.unique,
+                                                      pExtent->FileOffset.HighPart,
+                                                      pExtent->FileOffset.LowPart,
+                                                      pExtent->CacheOffset.HighPart,
+                                                      pExtent->CacheOffset.LowPart);
+                                            OutputDebugStringA( dbgstr);
+#endif
+                                            osi_Log4(afsd_logp,
+                                                      "RDR_ProcessReleaseFileExtentsResult dirty flag set and checksums do not match! vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                                      Fid.volume, Fid.vnode,
+                                                      pExtent->FileOffset.HighPart,
+                                                      pExtent->FileOffset.LowPart);
+                                            osi_Log2(afsd_logp,
+                                                      "... coffset 0x%x:%x",
+                                                      pExtent->CacheOffset.HighPart,
+                                                      pExtent->CacheOffset.LowPart);
+
+                                            buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                            dirty++;
+                                        } else {
+#ifdef ODS_DEBUG
+                                            snprintf(dbgstr, 1024,
+                                                      "RDR_ProcessReleaseFileExtentsResult dirty flag set but extent has not changed! old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                                      md5dbg, md5dbg2, md5dbg3,
+                                                      Fid.volume, Fid.vnode, Fid.unique,
+                                                      pExtent->FileOffset.HighPart,
+                                                      pExtent->FileOffset.LowPart,
+                                                      pExtent->CacheOffset.HighPart,
+                                                      pExtent->CacheOffset.LowPart);
+                                            OutputDebugStringA( dbgstr);
+#endif
+                                            osi_Log4(afsd_logp,
+                                                      "RDR_ProcessReleaseFileExtentsResult dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                                      Fid.volume, Fid.vnode,
+                                                      pExtent->FileOffset.HighPart,
+                                                      pExtent->FileOffset.LowPart);
+                                            osi_Log2(afsd_logp,
+                                                      "... coffset 0x%x:%x",
+                                                      pExtent->CacheOffset.HighPart,
+                                                      pExtent->CacheOffset.LowPart);
+                                        }
+                                    }
+                                }
+#else /* !VALIDATE_CHECK_SUM */
+                                buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                dirty++;
+#ifdef ODS_DEBUG
+                                snprintf(dbgstr, 1024,
+                                          "RDR_ProcessReleaseFileExtentsResult dirty! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                          Fid.volume, Fid.vnode, Fid.unique,
+                                          pExtent->FileOffset.HighPart,
+                                          pExtent->FileOffset.LowPart,
+                                          pExtent->CacheOffset.HighPart,
+                                          pExtent->CacheOffset.LowPart);
+                                OutputDebugStringA( dbgstr);
+#endif
+#endif /* VALIDATE_CHECK_SUM */
+                            }
+#ifdef VALIDATE_CHECK_SUM
+                            else {
+#ifdef ODS_DEBUG
+                                HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
+#endif
+                                if ( !buf_ValidateCheckSum(bufp) ) {
+                                    buf_ComputeCheckSum(bufp);
+#ifdef ODS_DEBUG
+                                    HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
+                                    snprintf(dbgstr, 1024,
+                                             "RDR_ProcessReleaseFileExtentsResult dirty flag not set but dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                             md5dbg, md5dbg3,
+                                             Fid.volume, Fid.vnode, Fid.unique,
+                                             pExtent->FileOffset.HighPart,
+                                             pExtent->FileOffset.LowPart,
+                                             pExtent->CacheOffset.HighPart,
+                                             pExtent->CacheOffset.LowPart);
+                                    OutputDebugStringA( dbgstr);
+#endif
+                                    osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult dirty flag NOT set but extent has changed! vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                             Fid.volume, Fid.vnode,
+                                             pExtent->FileOffset.HighPart,
+                                             pExtent->FileOffset.LowPart);
+                                    osi_Log2(afsd_logp, "... coffset 0x%x:%x",
+                                             pExtent->CacheOffset.HighPart,
+                                             pExtent->CacheOffset.LowPart);
+#ifdef DEBUG
+                                    DebugBreak();
+#endif
+                                    buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                    dirty++;
+                                } else {
+                                    buf_ComputeCheckSum(bufp);
+#ifdef ODS_DEBUG
+                                    HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
+                                    snprintf(dbgstr, 1024,
+                                             "RDR_ProcessReleaseFileExtentsResult dirty flag not set and not dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                                             md5dbg, md5dbg3,
+                                             Fid.volume, Fid.vnode, Fid.unique,
+                                             pExtent->FileOffset.HighPart,
+                                             pExtent->FileOffset.LowPart,
+                                             pExtent->CacheOffset.HighPart,
+                                             pExtent->CacheOffset.LowPart);
+                                    OutputDebugStringA( dbgstr);
+#endif
+                                }
+                            }
+#endif /* VALIDATE_CHECK_SUM */
+                            lock_ReleaseMutex(&bufp->mx);
+                        }
+                    }
+                } else {
+                    /* CacheOffset doesn't match bufp->datap */
+                    char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
+                    cm_buf_t *wbp;
+
+                    for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
+                        if (wbp->datap == datap)
+                            break;
+                    }
+
+#ifdef ODS_DEBUG
+                    snprintf(dbgstr, 1024,
+                             "RDR_ProcessReleaseFileExtentsResult non-matching extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x flags 0x%x\n",
+                             Fid.volume, Fid.vnode, Fid.unique,
+                             pExtent->FileOffset.HighPart,
+                             pExtent->FileOffset.LowPart,
+                             pExtent->CacheOffset.HighPart,
+                             pExtent->CacheOffset.LowPart,
+                             pExtent->Flags);
+                    OutputDebugStringA( dbgstr);
+#endif
+                    osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult non-matching extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                             Fid.volume, Fid.vnode,
+                             pExtent->FileOffset.HighPart,
+                             pExtent->FileOffset.LowPart);
+                    osi_Log3(afsd_logp, "... coffset 0x%x:%x flags 0x%x",
+                             pExtent->CacheOffset.HighPart,
+                             pExtent->CacheOffset.LowPart,
+                             pExtent->Flags);
+                    if (wbp)
+                        osi_Log5(afsd_logp, "... coffset belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
+                                 wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
+                    else
+                        osi_Log0(afsd_logp, "... coffset cannot be found");
+#ifdef DEBUG
+                    DebugBreak();
+#endif
+                }
+                buf_Release(bufp);
+            } else {
+                if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
+                    osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
+                             Fid.volume, Fid.vnode, pExtent->FileOffset.HighPart,
+                             pExtent->FileOffset.LowPart);
+                    osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; cm_buf not found -- recycled?",
+                             pExtent->CacheOffset.HighPart,
+                             pExtent->CacheOffset.LowPart);
+
+                    continue;
+                }
+
+#ifdef ODS_DEBUG
+                snprintf(dbgstr, 1024,
+                         "RDR_ProcessReleaseFileExtentsResult buf not found vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
+                         Fid.volume, Fid.vnode, Fid.unique,
+                         pExtent->FileOffset.HighPart,
+                         pExtent->FileOffset.LowPart,
+                         pExtent->CacheOffset.HighPart,
+                         pExtent->CacheOffset.LowPart);
+                OutputDebugStringA( dbgstr);
+#endif
+                osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult buf not found vol 0x%x vno 0x%x foffset 0x%x:%x",
+                         Fid.volume, Fid.vnode,
+                         pExtent->FileOffset.HighPart,
+                         pExtent->FileOffset.LowPart);
+                osi_Log2(afsd_logp, "... coffset 0x%x:%x",
+                         pExtent->CacheOffset.HighPart,
+                         pExtent->CacheOffset.LowPart);
+            }
+        }
+
+        if (scp && dirty) {
+            osi_hyper_t offset = {0,0};
+            afs_uint32  length = 0;
+
+            /*
+             * there is at least one dirty extent on this file.  queue up background store
+             * requests for contiguous blocks
+             */
+            for ( extentno = 0; extentno < pFileCB->ExtentCount; extentno++ ) {
+                AFSFileExtentCB *pExtent = &pFileCB->FileExtents[extentno];
+                if (pExtent->FileOffset.QuadPart == offset.QuadPart + length &&
+                     length < cm_chunkSize) {
+                    length += cm_data.buf_blockSize;
+                } else {
+                    if (!(offset.QuadPart == 0 && length == 0))
+                        cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
+                                            length, 0, userp, &req);
+                    offset.QuadPart = pExtent->FileOffset.QuadPart;
+                    length = cm_data.buf_blockSize;
+                }
+            }
+            cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
+                                length, 0, userp, &req);
+        }
+
+        osi_Log5(afsd_logp, "RDR_ProcessReleaseFileExtentsResult File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x Released %d",
+                  Fid.cell, Fid.volume, Fid.vnode, Fid.unique, released);
+
+      cleanup_file:
+        if (userp)
+            cm_ReleaseUser(userp);
+        if (scp)
+            cm_ReleaseSCache(scp);
+
+        p = (char *)pFileCB;
+        p += sizeof(AFSReleaseFileExtentsResultFileCB);
+        p += sizeof(AFSFileExtentCB) * (pFileCB->ExtentCount - 1);
+        pNextFileCB = (AFSReleaseFileExtentsResultFileCB *)p;
+    }
+
+    if (total_extents == 0) {
+        osi_Log0(afsd_logp, "RDR_ProcessReleaseFileExtentsResult is empty");
+        code = CM_ERROR_RETRY;
+    }
+
+    if (code)
+        osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult FAILURE code=0x%x", code);
+    else
+        osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult DONE code=0x%x", code);
+
+    return code;
+}
+
+DWORD
+RDR_ReleaseFailedSetFileExtents( IN cm_user_t *userp,
+                                 IN AFSSetFileExtentsCB *SetFileExtentsResultCB,
+                                 IN DWORD ResultBufferLength)
+{
+    afs_uint32  code = 0;
+    cm_req_t    req;
+    unsigned int extentno;
+    cm_fid_t         Fid;
+    cm_scache_t *    scp = NULL;
+    int              dirty = 0;
+
+    RDR_InitReq(&req);
+
+    osi_Log4(afsd_logp, "RDR_ReleaseFailedSetFileExtents %d.%d.%d.%d",
+              SetFileExtentsResultCB->FileId.Cell, SetFileExtentsResultCB->FileId.Volume,
+              SetFileExtentsResultCB->FileId.Vnode, SetFileExtentsResultCB->FileId.Unique);
+
+    /* Process the release */
+    Fid.cell = SetFileExtentsResultCB->FileId.Cell;
+    Fid.volume = SetFileExtentsResultCB->FileId.Volume;
+    Fid.vnode = SetFileExtentsResultCB->FileId.Vnode;
+    Fid.unique = SetFileExtentsResultCB->FileId.Unique;
+    Fid.hash = SetFileExtentsResultCB->FileId.Hash;
+
+    if (Fid.cell == 0) {
+        osi_Log4(afsd_logp, "RDR_ReleaseFailedSetFile Invalid FID %d.%d.%d.%d",
+                  Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
+        code = CM_ERROR_INVAL;
+        goto cleanup_file;
+    }
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        osi_Log1(afsd_logp, "RDR_ReleaseFailedSetFileExtents cm_GetSCache FID failure code=0x%x",
+                  code);
+        /* Failure to find the cm_scache object cannot block return of the extents */
+    }
+
+    for ( extentno = 0; extentno < SetFileExtentsResultCB->ExtentCount; extentno++ ) {
+        osi_hyper_t thyper;
+        cm_buf_t    *bufp;
+        AFSFileExtentCB *pExtent = &SetFileExtentsResultCB->FileExtents[extentno];
+
+        thyper.QuadPart = pExtent->FileOffset.QuadPart;
+
+        bufp = buf_Find(&Fid, &thyper);
+        if (bufp) {
+            osi_Log5(afsd_logp, "RDR_ReleaseFailedSetFileExtents bufp 0x%p foffset 0x%x:%x coffset 0x%x:%x",
+                      bufp, pExtent->FileOffset.HighPart, pExtent->FileOffset.LowPart,
+                      pExtent->CacheOffset.HighPart, pExtent->CacheOffset.LowPart);
+
+            lock_ObtainMutex(&bufp->mx);
+            if (bufp->qFlags & CM_BUF_QREDIR) {
+                if (scp)
+                    lock_ObtainWrite(&scp->rw);
+                lock_ObtainWrite(&buf_globalLock);
+                if (bufp->qFlags & CM_BUF_QREDIR) {
+                    buf_RemoveFromRedirQueue(scp, bufp);
+                    if (scp)
+                        lock_ReleaseWrite(&scp->rw);
+                    buf_ReleaseLocked(bufp, TRUE);
+                } else {
+                    if (scp)
+                        lock_ReleaseWrite(&scp->rw);
+                }
+                lock_ReleaseWrite(&buf_globalLock);
+            }
+            lock_ReleaseMutex(&bufp->mx);
+            buf_Release(bufp);
+        }
+    }
+
+  cleanup_file:
+    if (userp)
+        cm_ReleaseUser(userp);
+    if (scp)
+        cm_ReleaseSCache(scp);
+
+    osi_Log1(afsd_logp, "RDR_ReleaseFailedSetFileExtents DONE code=0x%x", code);
+    return code;
+}
+
+void
+RDR_PioctlOpen( IN cm_user_t *userp,
+                IN AFSFileID  ParentId,
+                IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
+                IN BOOL bWow64,
+                IN DWORD ResultBufferLength,
+                IN OUT AFSCommResult **ResultCB)
+{
+    cm_fid_t    ParentFid;
+    cm_fid_t    RootFid;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    /* Get the active directory */
+    ParentFid.cell = ParentId.Cell;
+    ParentFid.volume = ParentId.Volume;
+    ParentFid.vnode = ParentId.Vnode;
+    ParentFid.unique = ParentId.Unique;
+    ParentFid.hash = ParentId.Hash;
+
+    /* Get the root directory */
+    RootFid.cell = pPioctlCB->RootId.Cell;
+    RootFid.volume = pPioctlCB->RootId.Volume;
+    RootFid.vnode = pPioctlCB->RootId.Vnode;
+    RootFid.unique = pPioctlCB->RootId.Unique;
+    RootFid.hash = pPioctlCB->RootId.Hash;
+
+    /* Create the pioctl index */
+    RDR_SetupIoctl(pPioctlCB->RequestId, &ParentFid, &RootFid, userp);
+
+    return;
+}
+
+
+void
+RDR_PioctlClose( IN cm_user_t *userp,
+                 IN AFSFileID  ParentId,
+                 IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
+                 IN BOOL bWow64,
+                 IN DWORD ResultBufferLength,
+                 IN OUT AFSCommResult **ResultCB)
+{
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    /* Cleanup the pioctl index */
+    RDR_CleanupIoctl(pPioctlCB->RequestId);
+
+    return;
+}
+
+
+void
+RDR_PioctlWrite( IN cm_user_t *userp,
+                 IN AFSFileID  ParentId,
+                 IN AFSPIOCtlIORequestCB *pPioctlCB,
+                 IN BOOL bWow64,
+                 IN DWORD ResultBufferLength,
+                 IN OUT AFSCommResult **ResultCB)
+{
+    AFSPIOCtlIOResultCB *pResultCB;
+    cm_scache_t *dscp = NULL;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
+
+    pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
+
+    code = RDR_IoctlWrite(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+
+    pResultCB->BytesProcessed = pPioctlCB->BufferLength;
+    (*ResultCB)->ResultBufferLength = sizeof( AFSPIOCtlIOResultCB);
+}
+
+void
+RDR_PioctlRead( IN cm_user_t *userp,
+                IN AFSFileID  ParentId,
+                IN AFSPIOCtlIORequestCB *pPioctlCB,
+                IN BOOL bWow64,
+                IN BOOL bIsLocalSystem,
+                IN DWORD ResultBufferLength,
+                IN OUT AFSCommResult **ResultCB)
+{
+    AFSPIOCtlIOResultCB *pResultCB;
+    cm_scache_t *dscp = NULL;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+    afs_uint32  pflags = (bIsLocalSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
+
+    pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
+
+    code = RDR_IoctlRead(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer,
+                         &pResultCB->BytesProcessed, &req, pflags);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+
+    (*ResultCB)->ResultBufferLength = sizeof( AFSPIOCtlIOResultCB);
+}
+
+void
+RDR_ByteRangeLockSync( IN cm_user_t     *userp,
+                       IN AFSFileID     FileId,
+                       IN AFSByteRangeLockRequestCB *pBRLRequestCB,
+                       IN BOOL bWow64,
+                       IN DWORD ResultBufferLength,
+                       IN OUT AFSCommResult **ResultCB)
+{
+    AFSByteRangeLockResultCB *pResultCB = NULL;
+    LARGE_INTEGER ProcessId;
+    DWORD       Length;
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    cm_key_t    key;
+    DWORD       i;
+    DWORD       status;
+
+    ProcessId.QuadPart = pBRLRequestCB->ProcessId;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_ByteRangeLockSync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+    osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
+             ProcessId.HighPart, ProcessId.LowPart);
+
+    Length = sizeof( AFSByteRangeLockResultCB) + ((pBRLRequestCB->Count - 1) * sizeof(AFSByteRangeLockResult));
+    if (Length > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult));
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+
+    *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length + sizeof( AFSCommResult) );
+    (*ResultCB)->ResultBufferLength = Length;
+
+    pResultCB = (AFSByteRangeLockResultCB *)(*ResultCB)->ResultData;
+    pResultCB->FileId = FileId;
+    pResultCB->Count = pBRLRequestCB->Count;
+
+    /* Allocate the extents from the buffer package */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_ByteRangeLockSync cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+
+    /* start by looking up the file's end */
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    if (code) {
+        lock_ReleaseWrite(&scp->rw);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log3(afsd_logp, "RDR_ByteRangeLockSync cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    /* the scp is now locked and current */
+    key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
+
+    for ( i=0; i<pBRLRequestCB->Count; i++ ) {
+        pResultCB->Result[i].LockType = pBRLRequestCB->Request[i].LockType;
+        pResultCB->Result[i].Offset = pBRLRequestCB->Request[i].Offset;
+        pResultCB->Result[i].Length = pBRLRequestCB->Request[i].Length;
+
+        code = cm_Lock(scp,
+                       pBRLRequestCB->Request[i].LockType == AFS_BYTE_RANGE_LOCK_TYPE_SHARED,
+                       pBRLRequestCB->Request[i].Offset,
+                       pBRLRequestCB->Request[i].Length,
+                       key, 0, userp, &req, NULL);
+
+        if (code) {
+            osi_Log4(afsd_logp, "RDR_ByteRangeLockSync FAILURE code 0x%x type 0x%u offset 0x%x:%x",
+                     code,
+                     pBRLRequestCB->Request[i].LockType,
+                     pBRLRequestCB->Request[i].Offset.HighPart,
+                     pBRLRequestCB->Request[i].Offset.LowPart);
+            osi_Log2(afsd_logp, "... length 0x%x:%x",
+                     pBRLRequestCB->Request[i].Length.HighPart,
+                     pBRLRequestCB->Request[i].Length.LowPart);
+        }
+
+        switch (code) {
+        case 0:
+            pResultCB->Result[i].Status = 0;
+            break;
+        case CM_ERROR_WOULDBLOCK:
+            pResultCB->Result[i].Status = STATUS_FILE_LOCK_CONFLICT;
+            break;
+        default:
+            pResultCB->Result[i].Status = STATUS_LOCK_NOT_GRANTED;
+        }
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
+
+    (*ResultCB)->ResultStatus = 0;
+    osi_Log0(afsd_logp, "RDR_ByteRangeLockSync SUCCESS");
+    return;
+}
+
+void
+RDR_ByteRangeUnlock( IN cm_user_t     *userp,
+                     IN AFSFileID     FileId,
+                     IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
+                     IN BOOL bWow64,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB)
+{
+    AFSByteRangeUnlockResultCB *pResultCB = NULL;
+    LARGE_INTEGER ProcessId;
+    DWORD       Length;
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    cm_key_t    key;
+    DWORD       i;
+    DWORD       status;
+
+    ProcessId.QuadPart = pBRURequestCB->ProcessId;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_ByteRangeUnlock File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+    osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
+             ProcessId.HighPart, ProcessId.LowPart);
+
+    Length = sizeof( AFSByteRangeUnlockResultCB) + ((pBRURequestCB->Count - 1) * sizeof(AFSByteRangeLockResult));
+    if (Length > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult));
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+
+    *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length + sizeof( AFSCommResult) );
+    (*ResultCB)->ResultBufferLength = Length;
+
+    pResultCB = (AFSByteRangeUnlockResultCB *)(*ResultCB)->ResultData;
+    pResultCB->Count = pBRURequestCB->Count;
+
+    /* Allocate the extents from the buffer package */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_ByteRangeUnlock cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+
+    /* start by looking up the file's end */
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    if (code) {
+        lock_ReleaseWrite(&scp->rw);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log3(afsd_logp, "RDR_ByteRangeUnlock cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    /* the scp is now locked and current */
+    key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
+
+    for ( i=0; i<pBRURequestCB->Count; i++ ) {
+        pResultCB->Result[i].LockType = pBRURequestCB->Request[i].LockType;
+        pResultCB->Result[i].Offset = pBRURequestCB->Request[i].Offset;
+        pResultCB->Result[i].Length = pBRURequestCB->Request[i].Length;
+
+        code = cm_Unlock(scp,
+                         pBRURequestCB->Request[i].LockType == AFS_BYTE_RANGE_LOCK_TYPE_SHARED,
+                         pBRURequestCB->Request[i].Offset,
+                         pBRURequestCB->Request[i].Length,
+                         key, CM_UNLOCK_FLAG_MATCH_RANGE, userp, &req);
+
+        if (code) {
+            osi_Log4(afsd_logp, "RDR_ByteRangeUnlock FAILURE code 0x%x type 0x%u offset 0x%x:%x",
+                     code, pBRURequestCB->Request[i].LockType,
+                     pBRURequestCB->Request[i].Offset.HighPart,
+                     pBRURequestCB->Request[i].Offset.LowPart);
+            osi_Log2(afsd_logp, "... length 0x%x:%x",
+                     pBRURequestCB->Request[i].Length.HighPart,
+                     pBRURequestCB->Request[i].Length.LowPart);
+        }
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        pResultCB->Result[i].Status = status;
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
+
+    (*ResultCB)->ResultStatus = 0;
+    osi_Log0(afsd_logp, "RDR_ByteRangeUnlock SUCCESS");
+    return;
+}
+
+void
+RDR_ByteRangeUnlockAll( IN cm_user_t     *userp,
+                        IN AFSFileID     FileId,
+                        IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
+                        IN BOOL bWow64,
+                        IN DWORD ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB)
+{
+    AFSByteRangeUnlockResultCB *pResultCB = NULL;
+    LARGE_INTEGER ProcessId;
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    cm_key_t    key;
+    DWORD       status;
+
+    ProcessId.QuadPart = pBRURequestCB->ProcessId;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_ByteRangeUnlockAll File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+    osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
+             ProcessId.HighPart, ProcessId.LowPart);
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', sizeof( AFSCommResult));
+    (*ResultCB)->ResultBufferLength = 0;
+
+    /* Allocate the extents from the buffer package */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_ByteRangeUnlockAll cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+
+    /* start by looking up the file's end */
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    if (code) {
+        lock_ReleaseWrite(&scp->rw);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log3(afsd_logp, "RDR_ByteRangeUnlockAll cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    /* the scp is now locked and current */
+    key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
+
+    code = cm_UnlockByKey(scp, key, 0, userp, &req);
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
+
+    smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+    (*ResultCB)->ResultStatus = status;
+
+    if (code)
+        osi_Log1(afsd_logp, "RDR_ByteRangeUnlockAll FAILURE code 0x%x", code);
+    else
+        osi_Log0(afsd_logp, "RDR_ByteRangeUnlockAll SUCCESS");
+    return;
+
+}
+
+void
+RDR_GetVolumeInfo( IN cm_user_t     *userp,
+                   IN AFSFileID     FileId,
+                   IN BOOL bWow64,
+                   IN DWORD ResultBufferLength,
+                   IN OUT AFSCommResult **ResultCB)
+{
+    AFSVolumeInfoCB *pResultCB = NULL;
+    DWORD       Length;
+    cm_scache_t *scp = NULL;
+    cm_volume_t *volp = NULL;
+    cm_vol_state_t *volstatep = NULL;
+    afs_uint32   volType;
+    cm_cell_t   *cellp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+    FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
+
+    char volName[32]="(unknown)";
+    char offLineMsg[256]="server temporarily inaccessible";
+    char motd[256]="server temporarily inaccessible";
+    cm_conn_t *connp;
+    AFSFetchVolumeStatus volStat;
+    char *Name;
+    char *OfflineMsg;
+    char *MOTD;
+    struct rx_connection * rxconnp;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_GetVolumeInfo File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+             FileId.Cell, FileId.Volume,
+             FileId.Vnode, FileId.Unique);
+
+    Length = sizeof( AFSCommResult) + sizeof(AFSVolumeInfoCB);
+    if (sizeof(AFSVolumeInfoCB) > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+
+    *ResultCB = (AFSCommResult *)malloc( Length );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length );
+    (*ResultCB)->ResultBufferLength = sizeof(AFSVolumeInfoCB);
+    pResultCB = (AFSVolumeInfoCB *)(*ResultCB)->ResultData;
+
+    /* Allocate the extents from the buffer package */
+    if (FileId.Cell != 0) {
+        Fid.cell = FileId.Cell;
+        Fid.volume = FileId.Volume;
+        Fid.vnode = FileId.Vnode;
+        Fid.unique = FileId.Unique;
+        Fid.hash = FileId.Hash;
+
+        code = cm_GetSCache(&Fid, &scp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            (*ResultCB)->ResultBufferLength = 0;
+            osi_Log2(afsd_logp, "RDR_GetVolumeInfo cm_GetSCache FID failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+        osi_Log0(afsd_logp, "RDR_GetVolumeInfo Object Name Invalid - Cell = 0");
+        return;
+    }
+    lock_ObtainWrite(&scp->rw);
+
+    /* start by looking up the file's end */
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        lock_ReleaseWrite(&scp->rw);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log3(afsd_logp, "RDR_GetVolumeInfo cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    /* Fake for now */
+    pResultCB->SectorsPerAllocationUnit = 1;
+    pResultCB->BytesPerSector = 1024;
+
+    pResultCB->CellID = scp->fid.cell;
+    pResultCB->VolumeID = scp->fid.volume;
+    pResultCB->Characteristics = FILE_REMOTE_DEVICE;
+    pResultCB->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK |
+        FILE_SUPPORTS_REPARSE_POINTS;
+
+    if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
+    {
+        pResultCB->TotalAllocationUnits.QuadPart = 100;
+        memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
+
+        pResultCB->AvailableAllocationUnits.QuadPart = 0;
+        pResultCB->Characteristics |= FILE_READ_ONLY_DEVICE;
+
+        pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( "Freelance.Local.Root", -1, pResultCB->VolumeLabel,
+                                                       (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
+        if ( pResultCB->VolumeLabelLength )
+            pResultCB->VolumeLabelLength--;
+    } else {
+        memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
+
+        volp = cm_GetVolumeByFID(&scp->fid);
+        if (!volp) {
+            code = CM_ERROR_NOSUCHVOLUME;
+            goto _done;
+        }
+        volstatep = cm_VolumeStateByID(volp, scp->fid.volume);
+        volType = cm_VolumeType(volp, scp->fid.volume);
+
+        pResultCB->Characteristics |= ((volType == ROVOL || volType == BACKVOL) ? FILE_READ_ONLY_DEVICE : 0);
+
+        Name = volName;
+       OfflineMsg = offLineMsg;
+       MOTD = motd;
+       lock_ReleaseWrite(&scp->rw);
+       do {
+           code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
+           if (code) continue;
+
+           rxconnp = cm_GetRxConn(connp);
+           code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
+                                        &volStat, &Name, &OfflineMsg, &MOTD);
+           rx_PutConnection(rxconnp);
+
+       } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
+       code = cm_MapRPCError(code, &req);
+        if (code == 0) {
+            pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
+            pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
+
+            pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( Name, -1, pResultCB->VolumeLabel,
+                                                           (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
+        } else {
+            pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
+            pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
+
+            pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( volp->namep, -1, pResultCB->VolumeLabel,
+                                                           (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
+            code = 0;
+        }
+        if ( pResultCB->VolumeLabelLength )
+            pResultCB->VolumeLabelLength--;
+
+        lock_ObtainWrite(&scp->rw);
+    }
+    pResultCB->VolumeLabelLength *= sizeof(WCHAR);  /* convert to bytes from chars */
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+  _done:
+    lock_ReleaseWrite(&scp->rw);
+    if (volp)
+       cm_PutVolume(volp);
+    cm_ReleaseSCache(scp);
+
+    smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+    (*ResultCB)->ResultStatus = status;
+    osi_Log0(afsd_logp, "RDR_GetVolumeInfo SUCCESS");
+    return;
+}
+
+void
+RDR_HoldFid( IN cm_user_t     *userp,
+             IN AFSHoldFidRequestCB * pHoldFidCB,
+             IN BOOL bFast,
+             IN DWORD ResultBufferLength,
+             IN OUT AFSCommResult **ResultCB)
+{
+    AFSHoldFidResultCB *pResultCB = NULL;
+    DWORD       index;
+    DWORD       Length;
+    cm_req_t    req;
+
+    RDR_InitReq(&req);
+
+    osi_Log1(afsd_logp, "RDR_HoldFid Count=%u", pHoldFidCB->Count);
+
+    Length = sizeof(AFSHoldFidResultCB) + (pHoldFidCB->Count-1) * sizeof(AFSFidResult);
+    if (Length > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+    *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length );
+    (*ResultCB)->ResultBufferLength = Length;
+    pResultCB = (AFSHoldFidResultCB *)(*ResultCB)->ResultData;
+
+    for ( index = 0; index < pHoldFidCB->Count; index++ )
+    {
+        cm_scache_t *scp = NULL;
+        cm_fid_t    Fid;
+
+        Fid.cell   = pResultCB->Result[index].FileID.Cell   = pHoldFidCB->FileID[index].Cell;
+        Fid.volume = pResultCB->Result[index].FileID.Volume = pHoldFidCB->FileID[index].Volume;
+        Fid.vnode  = pResultCB->Result[index].FileID.Vnode  = pHoldFidCB->FileID[index].Vnode;
+        Fid.unique = pResultCB->Result[index].FileID.Unique = pHoldFidCB->FileID[index].Unique;
+        Fid.hash   = pResultCB->Result[index].FileID.Hash   = pHoldFidCB->FileID[index].Hash;
+
+        osi_Log4( afsd_logp,
+                  "RDR_HoldFid File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+                  Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
+
+        scp = cm_FindSCache(&Fid);
+        if (scp) {
+            RDR_FlagScpInUse( scp, FALSE );
+            cm_ReleaseSCache(scp);
+        }
+        pResultCB->Result[index].Status = 0;
+    }
+
+    (*ResultCB)->ResultStatus = 0;
+    osi_Log0(afsd_logp, "RDR_HoldFid SUCCESS");
+    return;
+}
+
+void
+RDR_ReleaseFid( IN cm_user_t     *userp,
+                IN AFSReleaseFidRequestCB * pReleaseFidCB,
+                IN BOOL bFast,
+                IN DWORD ResultBufferLength,
+                IN OUT AFSCommResult **ResultCB)
+{
+    AFSReleaseFidResultCB *pResultCB = NULL;
+    DWORD       index;
+    DWORD       Length;
+    cm_req_t    req;
+
+    RDR_InitReq(&req);
+
+    osi_Log1(afsd_logp, "RDR_ReleaseFid Count=%u", pReleaseFidCB->Count);
+
+    Length = sizeof(AFSReleaseFidResultCB) + (pReleaseFidCB->Count ? pReleaseFidCB->Count-1 : 0) * sizeof(AFSFidResult);
+    if (Length > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+    *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length );
+    (*ResultCB)->ResultBufferLength = Length;
+    pResultCB = (AFSReleaseFidResultCB *)(*ResultCB)->ResultData;
+
+    for ( index = 0; index < pReleaseFidCB->Count; index++ )
+    {
+        cm_scache_t *scp = NULL;
+        cm_fid_t    Fid;
+
+        Fid.cell   = pResultCB->Result[index].FileID.Cell   = pReleaseFidCB->FileID[index].Cell;
+        Fid.volume = pResultCB->Result[index].FileID.Volume = pReleaseFidCB->FileID[index].Volume;
+        Fid.vnode  = pResultCB->Result[index].FileID.Vnode  = pReleaseFidCB->FileID[index].Vnode;
+        Fid.unique = pResultCB->Result[index].FileID.Unique = pReleaseFidCB->FileID[index].Unique;
+        Fid.hash   = pResultCB->Result[index].FileID.Hash   = pReleaseFidCB->FileID[index].Hash;
+
+        osi_Log4( afsd_logp,
+                  "RDR_ReleaseFid File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+                  Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
+
+        scp = cm_FindSCache(&Fid);
+        if (scp) {
+            lock_ObtainWrite(&scp->rw);
+            scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
+            lock_ReleaseWrite(&scp->rw);
+
+            cm_ReleaseSCache(scp);
+        }
+        pResultCB->Result[index].Status = 0;
+    }
+    pResultCB->Count = pReleaseFidCB->Count;
+
+    (*ResultCB)->ResultStatus = 0;
+    osi_Log0(afsd_logp, "RDR_ReleaseFid SUCCESS");
+    return;
+}
+
+/*
+ * The redirector makes several assumptions regarding the
+ * SRVSVC and WKSSVC pipes transactions.  First, the interface
+ * versions are those indicated below.  Secondly, the encoding
+ * will be performed using NDR version 2.  These assumptions
+ * may not hold in the future and end-to-end MSRPC Bind
+ * negotiations may need to be supported.  Of course, these
+ * are the only interface versions that are supported by the
+ * service.
+ */
+#define MSRPC_PIPE_PREFIX L".\\"
+
+static const UUID MSRPC_SRVSVC_UUID = {0x4B324FC8, 0x1670, 0x01D3,
+                                       {0x12, 0x78, 0x5A, 0x47, 0xBF, 0x6E, 0xE1, 0x88}};
+#define MSRPC_SRVSVC_NAME L"PIPE\\SRVSVC"
+#define MSRPC_SRVSVC_VERS 3
+
+static const UUID MSRPC_WKSSVC_UUID = {0x6BFFD098, 0xA112, 0x3610,
+                                       {0x98, 0x33, 0x46, 0xC3, 0xF8, 0x7E, 0x34, 0x5A}};
+#define MSRPC_WKSSVC_NAME L"PIPE\\WKSSVC"
+#define MSRPC_WKSSVC_VERS 1
+
+static const UUID MSRPC_NDR_UUID = {0x8A885D04, 0x1CEB, 0x11C9,
+                                    {0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60}};
+#define MSRPC_NDR_NAME    L"NDR"
+#define MSRPC_NDR_VERS    2
+
+extern RPC_IF_HANDLE srvsvc_v3_0_s_ifspec;
+extern RPC_IF_HANDLE wkssvc_v1_0_s_ifspec;
+
+void
+RDR_PipeOpen( IN cm_user_t *userp,
+              IN AFSFileID  ParentId,
+              IN WCHAR     *Name,
+              IN DWORD      NameLength,
+              IN AFSPipeOpenCloseRequestCB *pPipe_CB,
+              IN BOOL bWow64,
+              IN DWORD ResultBufferLength,
+              IN OUT AFSCommResult **ResultCB)
+{
+    cm_fid_t    ParentFid;
+    cm_fid_t    RootFid;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    /* Get the active directory */
+    ParentFid.cell = ParentId.Cell;
+    ParentFid.volume = ParentId.Volume;
+    ParentFid.vnode = ParentId.Vnode;
+    ParentFid.unique = ParentId.Unique;
+    ParentFid.hash = ParentId.Hash;
+
+    /* Get the root directory */
+    RootFid.cell = pPipe_CB->RootId.Cell;
+    RootFid.volume = pPipe_CB->RootId.Volume;
+    RootFid.vnode = pPipe_CB->RootId.Vnode;
+    RootFid.unique = pPipe_CB->RootId.Unique;
+    RootFid.hash = pPipe_CB->RootId.Hash;
+
+    /* Create the pipe index */
+    (*ResultCB)->ResultStatus =
+      RDR_SetupPipe( pPipe_CB->RequestId, &ParentFid, &RootFid,
+                     Name, NameLength, userp);
+    return;
+}
+
+
+void
+RDR_PipeClose( IN cm_user_t *userp,
+               IN AFSFileID  ParentId,
+               IN AFSPipeOpenCloseRequestCB *pPipe_CB,
+               IN BOOL bWow64,
+               IN DWORD ResultBufferLength,
+               IN OUT AFSCommResult **ResultCB)
+{
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    /* Cleanup the pipe index */
+    RDR_CleanupPipe(pPipe_CB->RequestId);
+
+    return;
+}
+
+
+void
+RDR_PipeWrite( IN cm_user_t *userp,
+               IN AFSFileID  ParentId,
+               IN AFSPipeIORequestCB *pPipe_CB,
+               IN BYTE *pPipe_Data,
+               IN BOOL bWow64,
+               IN DWORD ResultBufferLength,
+               IN OUT AFSCommResult **ResultCB)
+{
+    AFSPipeIOResultCB *pResultCB;
+    cm_scache_t *dscp = NULL;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
+
+    pResultCB = (AFSPipeIOResultCB *)(*ResultCB)->ResultData;
+
+    code = RDR_Pipe_Write( pPipe_CB->RequestId, pPipe_CB->BufferLength, pPipe_Data, &req, userp);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+
+    pResultCB->BytesProcessed = pPipe_CB->BufferLength;
+    (*ResultCB)->ResultBufferLength = sizeof( AFSPipeIOResultCB);
+}
+
+
+void
+RDR_PipeRead( IN cm_user_t *userp,
+              IN AFSFileID  ParentId,
+              IN AFSPipeIORequestCB *pPipe_CB,
+              IN BOOL bWow64,
+              IN DWORD ResultBufferLength,
+              IN OUT AFSCommResult **ResultCB)
+{
+    BYTE *pPipe_Data;
+    cm_scache_t *dscp = NULL;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    pPipe_Data = (BYTE *)(*ResultCB)->ResultData;
+
+    code = RDR_Pipe_Read( pPipe_CB->RequestId, ResultBufferLength, pPipe_Data,
+                          &(*ResultCB)->ResultBufferLength, &req, userp);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+}
+
+
+void
+RDR_PipeSetInfo( IN cm_user_t *userp,
+                 IN AFSFileID  ParentId,
+                 IN AFSPipeInfoRequestCB *pPipeInfo_CB,
+                 IN BYTE *pPipe_Data,
+                 IN BOOL bWow64,
+                 IN DWORD ResultBufferLength,
+                 IN OUT AFSCommResult **ResultCB)
+{
+    cm_scache_t *dscp = NULL;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    status = RDR_Pipe_SetInfo( pPipeInfo_CB->RequestId, pPipeInfo_CB->InformationClass,
+                               pPipeInfo_CB->BufferLength, pPipe_Data, &req, userp);
+
+    (*ResultCB)->ResultStatus = status;
+}
+
+
+void
+RDR_PipeQueryInfo( IN cm_user_t *userp,
+                   IN AFSFileID  ParentId,
+                   IN AFSPipeInfoRequestCB *pPipeInfo_CB,
+                   IN BOOL bWow64,
+                   IN DWORD ResultBufferLength,
+                   IN OUT AFSCommResult **ResultCB)
+{
+    BYTE *pPipe_Data;
+    cm_scache_t *dscp = NULL;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
+
+    pPipe_Data = (BYTE *)(*ResultCB)->ResultData;
+
+    status = RDR_Pipe_QueryInfo( pPipeInfo_CB->RequestId, pPipeInfo_CB->InformationClass,
+                                 ResultBufferLength, pPipe_Data,
+                                 &(*ResultCB)->ResultBufferLength, &req, userp);
+
+    (*ResultCB)->ResultStatus = status;
+}
+
+void
+RDR_PipeTransceive( IN cm_user_t     *userp,
+                    IN AFSFileID  ParentId,
+                    IN AFSPipeIORequestCB *pPipe_CB,
+                    IN BYTE *pPipe_InData,
+                    IN BOOL bWow64,
+                    IN DWORD ResultBufferLength,
+                    IN OUT AFSCommResult **ResultCB)
+{
+    /*
+     * This function processes a Pipe Service request
+     * that would normally be sent to a LAN Manager server
+     * across an authenticated SMB-PIPE/MSRPC/SVC request
+     * stack.  The request is being sent here because the
+     * application (e.g., Explorer Shell or Common Control File
+     * dialog) believes that because the UNC path it is
+     * processing has specified a server name that is not
+     * "." and that the Server is remote and that the Share
+     * list cannot be obtained using the Network Provider
+     * interface.
+     *
+     * The file system driver is faking the Bind-Ack response
+     * to the MSRPC Bind request but cannot decode the NDR
+     * encoded Pipe Service requests.  For that we will use
+     * the service's MSRPC module.  However, unlike the SMB
+     * server usage we must fake the MSRPC Bind exchange and
+     * map the PipeName to an interface instead of using the
+     * GUID specified in the MSRPC Bind request.
+     *
+     * None of the requests that are being processed by the
+     * service require authentication.  As a result the userp
+     * parameter will be ignored.
+     *
+     * Although there are dozens of Pipe Services, the only
+     * ones that we are implementing are WKSSVC and SRVSVC.
+     * These support NetShareEnum, NetShareGetInfo,
+     * NetServerGetInfo, and NetWorkstaGetInfo which are
+     * commonly queried by NET VIEW, the Explorer Shell,
+     * and the Common Control File dialog.
+     */
+    BYTE *pPipe_OutData;
+    cm_scache_t *dscp = NULL;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+    DWORD Length = ResultBufferLength + sizeof( AFSCommResult);
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    *ResultCB = (AFSCommResult *)malloc( Length);
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length );
+
+    code = RDR_Pipe_Write( pPipe_CB->RequestId, pPipe_CB->BufferLength, pPipe_InData, &req, userp);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        osi_Log2( afsd_logp, "RDR_Pipe_Transceive Write FAILURE code=0x%x status=0x%x",
+                  code, status);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+
+    pPipe_OutData = (BYTE *)(*ResultCB)->ResultData;
+    code = RDR_Pipe_Read( pPipe_CB->RequestId, ResultBufferLength, pPipe_OutData,
+                          &(*ResultCB)->ResultBufferLength, &req, userp);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        osi_Log2( afsd_logp, "RDR_Pipe_Transceive Read FAILURE code=0x%x status=0x%x",
+                  code, status);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+
+    (*ResultCB)->ResultStatus = 0;
+    osi_Log0(afsd_logp, "RDR_Pipe_Transceive SUCCESS");
+}
diff --git a/src/WINNT/afsrdr/user/RDRInit.cpp b/src/WINNT/afsrdr/user/RDRInit.cpp
new file mode 100644 (file)
index 0000000..7d123e2
--- /dev/null
@@ -0,0 +1,2033 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints, Inc.
+ * Copyright (c) 2009-2011 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#define _CRT_SECURE_NO_DEPRECATE
+#define _CRT_NON_CONFORMING_SWPRINTFS
+#define UNICODE 1
+#define STRSAFE_NO_DEPRECATE
+
+#include <ntstatus.h>
+#define WIN32_NO_STATUS
+#include <windows.h>
+typedef LONG NTSTATUS, *PNTSTATUS;      // not declared in ntstatus.h
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <devioctl.h>
+
+#include <tchar.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <strsafe.h>
+
+#include "..\\Common\\AFSUserDefines.h"
+#include "..\\Common\\AFSUserIoctl.h"
+#include "..\\Common\\AFSUserStructs.h"
+
+extern "C" {
+#include <osilog.h>
+extern osi_log_t *afsd_logp;
+
+#include <WINNT/afsreg.h>
+#include <afs/cm_config.h>
+#include <afs/cm_error.h>
+}
+#include <RDRPrototypes.h>
+
+#ifndef FlagOn
+#define FlagOn(_F,_SF)        ((_F) & (_SF))
+#endif
+
+#ifndef BooleanFlagOn
+#define BooleanFlagOn(F,SF)   ((BOOLEAN)(((F) & (SF)) != 0))
+#endif
+
+#ifndef SetFlag
+#define SetFlag(_F,_SF)       ((_F) |= (_SF))
+#endif
+
+#ifndef ClearFlag
+#define ClearFlag(_F,_SF)     ((_F) &= ~(_SF))
+#endif
+
+#define QuadAlign(Ptr) (                \
+    ((((ULONG)(Ptr)) + 7) & 0xfffffff8) \
+    )
+
+#define MIN_WORKER_THREADS 5
+#define MAX_WORKER_THREADS 512
+
+typedef struct _worker_thread_info {
+
+    HANDLE hThread;
+
+    ULONG  Flags;
+
+    HANDLE hEvent;
+
+} WorkerThreadInfo;
+
+WorkerThreadInfo glWorkerThreadInfo[ MAX_WORKER_THREADS];
+
+UINT   glThreadHandleIndex = 0;
+
+HANDLE glDevHandle = INVALID_HANDLE_VALUE;
+
+static DWORD Exit = false;
+
+static DWORD ExitPending = false;
+
+DWORD  dwOvEvIdx = 0;
+
+extern "C" wchar_t RDR_UNCName[64]=L"AFS";
+
+/* returns 0 on success */
+extern "C" DWORD
+RDR_Initialize(void)
+{
+
+    DWORD dwRet = 0;
+    HKEY parmKey;
+    DWORD dummyLen;
+    DWORD numSvThreads = CM_CONFIGDEFAULT_SVTHREADS;
+
+    dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+                         0, KEY_QUERY_VALUE, &parmKey);
+    if (dwRet == ERROR_SUCCESS) {
+        dummyLen = sizeof(numSvThreads);
+        dwRet = RegQueryValueEx(parmKey, TEXT("ServerThreads"), NULL, NULL,
+                                (BYTE *) &numSvThreads, &dummyLen);
+
+        dummyLen = sizeof(RDR_UNCName);
+        dwRet = RegQueryValueExW(parmKey, L"NetbiosName", NULL, NULL,
+                                 (BYTE *) RDR_UNCName, &dummyLen);
+
+        RegCloseKey (parmKey);
+    }
+
+    // Initialize the Thread local storage index for the overlapped i/o
+    // Event Handle
+    dwOvEvIdx = TlsAlloc();
+
+    Exit = false;
+
+    //
+    // Launch our workers down to the
+    // filters control device for processing requests
+    //
+
+    dwRet = RDR_ProcessWorkerThreads(numSvThreads);
+
+    if (dwRet == ERROR_SUCCESS) {
+
+        RDR_InitIoctl();
+    }
+
+    return dwRet;
+}
+
+BOOL RDR_DeviceIoControl( HANDLE hDevice,
+                          DWORD dwIoControlCode,
+                          LPVOID lpInBuffer,
+                          DWORD nInBufferSize,
+                          LPVOID lpOutBuffer,
+                          DWORD nOutBufferSize,
+                          LPDWORD lpBytesReturned )
+{
+    OVERLAPPED ov;
+    HANDLE hEvent;
+    BOOL rc = FALSE;
+    DWORD gle;
+
+    ZeroMemory(&ov, sizeof(OVERLAPPED));
+
+    hEvent = (HANDLE)TlsGetValue(dwOvEvIdx);
+    if (hEvent == NULL) {
+        hEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
+        if (hEvent == INVALID_HANDLE_VALUE || hEvent == NULL)
+            return FALSE;
+        TlsSetValue( dwOvEvIdx, (LPVOID) hEvent );
+    }
+
+    ResetEvent( hEvent);
+    ov.hEvent = hEvent;
+    *lpBytesReturned = 0;
+
+    rc = DeviceIoControl( hDevice,
+                          dwIoControlCode,
+                          lpInBuffer,
+                          nInBufferSize,
+                          lpOutBuffer,
+                          nOutBufferSize,
+                          lpBytesReturned,
+                          &ov );
+    if ( !rc ) {
+        gle = GetLastError();
+
+        if ( gle == ERROR_IO_PENDING )
+            rc = GetOverlappedResult( hDevice, &ov, lpBytesReturned, TRUE );
+    }
+
+    return rc;
+}
+
+extern "C" DWORD
+RDR_ShutdownFinal(void)
+{
+
+    DWORD dwIndex = 0;
+
+    Exit = true;
+
+    //
+    // Close all the worker thread handles
+    //
+
+    while( dwIndex < glThreadHandleIndex)
+    {
+
+        CloseHandle( glWorkerThreadInfo[ dwIndex].hThread);
+
+        dwIndex++;
+    }
+
+    if( glDevHandle != INVALID_HANDLE_VALUE)
+    {
+
+        CloseHandle( glDevHandle);
+    }
+
+    return 0;
+}
+
+extern "C" DWORD
+RDR_ShutdownNotify(void)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+
+    //
+    // First, notify the file system driver that
+    // we are shutting down.
+    //
+
+    ExitPending = true;
+
+    if( !RDR_DeviceIoControl( hDevHandle,
+                              IOCTL_AFS_SHUTDOWN,
+                              NULL,
+                              0,
+                              NULL,
+                              0,
+                              &bytesReturned ))
+    {
+        // log the error, nothing to do
+    }
+
+    return 0;
+}
+
+//
+// Here we launch the worker threads for the given volume
+//
+
+DWORD
+RDR_ProcessWorkerThreads(DWORD numThreads)
+{
+    DWORD WorkerID;
+    HANDLE hEvent;
+    DWORD index = 0;
+    DWORD bytesReturned = 0;
+    DWORD dwRedirInitInfo;
+    AFSRedirectorInitInfo * redirInitInfo = NULL;
+    DWORD dwErr;
+
+    if (dwErr = RDR_SetInitParams(&redirInitInfo, &dwRedirInitInfo))
+        return dwErr;
+
+    glDevHandle = CreateFile( AFS_SYMLINK_W,
+                             GENERIC_READ | GENERIC_WRITE,
+                             FILE_SHARE_READ | FILE_SHARE_WRITE,
+                             NULL,
+                             OPEN_EXISTING,
+                             FILE_FLAG_OVERLAPPED,
+                             NULL);
+
+    if( glDevHandle == INVALID_HANDLE_VALUE)
+    {
+        free(redirInitInfo);
+        return GetLastError();
+    }
+
+    //
+    // Now call down to initialize the pool.
+    //
+
+    if( !RDR_DeviceIoControl( glDevHandle,
+                              IOCTL_AFS_INITIALIZE_CONTROL_DEVICE,
+                              NULL,
+                              0,
+                              NULL,
+                              0,
+                              &bytesReturned ))
+    {
+
+        CloseHandle( glDevHandle);
+
+        glDevHandle = NULL;
+
+        free(redirInitInfo);
+
+        return GetLastError();
+    }
+
+    //
+    // OK, now launch the workers
+    //
+
+    hEvent = CreateEvent( NULL,
+                         TRUE,
+                         FALSE,
+                         NULL);
+
+    //
+    // Here we create a pool of worker threads but you can create the pool with as many requests
+    // as you want
+    //
+
+    if (numThreads < MIN_WORKER_THREADS)
+        numThreads = MIN_WORKER_THREADS;
+    else if (numThreads > MAX_WORKER_THREADS)
+        numThreads = MAX_WORKER_THREADS;
+
+    for (index = 0; index < numThreads; index++)
+    {
+        //
+        // 20% of worker threads should be reserved for release extent
+        // event processing
+        //
+        glWorkerThreadInfo[ glThreadHandleIndex].Flags =
+            (glThreadHandleIndex % 5) ? 0 : AFS_REQUEST_RELEASE_THREAD;
+        glWorkerThreadInfo[ glThreadHandleIndex].hEvent = hEvent;
+        glWorkerThreadInfo[ glThreadHandleIndex].hThread =
+            CreateThread( NULL,
+                          0,
+                          RDR_RequestWorkerThread,
+                          (void *)&glWorkerThreadInfo[ glThreadHandleIndex],
+                          0,
+                          &WorkerID);
+
+        if( glWorkerThreadInfo[ glThreadHandleIndex].hThread != NULL)
+        {
+
+            //
+            // Wait for the thread to signal it is ready for processing
+            //
+
+            WaitForSingleObject( hEvent,
+                                INFINITE);
+
+            glThreadHandleIndex++;
+
+            ResetEvent( hEvent);
+        }
+        else
+        {
+
+            //
+            // Perform cleanup specific to your application
+            //
+
+        }
+    }
+
+    if( !RDR_DeviceIoControl( glDevHandle,
+                              IOCTL_AFS_INITIALIZE_REDIRECTOR_DEVICE,
+                              redirInitInfo,
+                              dwRedirInitInfo,
+                              NULL,
+                              0,
+                              &bytesReturned ))
+    {
+
+        CloseHandle( glDevHandle);
+
+        glDevHandle = NULL;
+
+        free(redirInitInfo);
+
+        return GetLastError();
+    }
+
+    free(redirInitInfo);
+
+    return 0;
+}
+
+//
+// Entry point for the worker thread
+//
+
+DWORD
+WINAPI
+RDR_RequestWorkerThread( LPVOID lpParameter)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+    AFSCommRequest *requestBuffer;
+    bool bError = false;
+    WorkerThreadInfo * pInfo = (WorkerThreadInfo *)lpParameter;
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+    //
+    // Allocate a request buffer.
+    //
+
+    requestBuffer = (AFSCommRequest *)malloc( sizeof( AFSCommRequest) + AFS_PAYLOAD_BUFFER_SIZE);
+
+    if( requestBuffer)
+    {
+
+        //
+        // Here we simply signal back to the main thread that we ahve started
+        //
+
+        SetEvent( pInfo->hEvent);
+
+        //
+        // Process requests until we are told to stop
+        //
+
+        while( !Exit)
+       {
+
+            memset( requestBuffer, '\0', sizeof( AFSCommRequest) + AFS_PAYLOAD_BUFFER_SIZE);
+
+            requestBuffer->RequestFlags = pInfo->Flags;
+
+            if( !RDR_DeviceIoControl( hDevHandle,
+                                      IOCTL_AFS_PROCESS_IRP_REQUEST,
+                                      (void *)requestBuffer,
+                                      sizeof( AFSCommRequest),
+                                      (void *)requestBuffer,
+                                      sizeof( AFSCommRequest) + AFS_PAYLOAD_BUFFER_SIZE,
+                                      &bytesReturned ))
+            {
+
+                //
+                // Error condition back from driver
+                //
+
+                break;
+            }
+
+            //
+            // Go process the request
+            //
+
+            if (!Exit)
+                RDR_ProcessRequest( requestBuffer);
+        }
+
+       free( requestBuffer);
+    }
+
+    ExitThread( 0);
+
+    return 0;
+}
+
+//
+// This is the entry point for the worker threads to process the request from the TC Filter driver
+//
+
+void
+RDR_ProcessRequest( AFSCommRequest *RequestBuffer)
+{
+
+    DWORD              bytesReturned;
+    DWORD              result = 0;
+    ULONG              ulIndex = 0;
+    ULONG              ulCreateFlags = 0;
+    AFSCommResult *     pResultCB = NULL;
+    AFSCommResult      stResultCB;
+    DWORD              dwResultBufferLength = 0;
+    AFSSetFileExtentsCB * SetFileExtentsResultCB = NULL;
+    AFSSetByteRangeLockResultCB *SetByteRangeLockResultCB = NULL;
+    WCHAR              wchBuffer[1024];
+    char *pBuffer = (char *)wchBuffer;
+    DWORD gle;
+    cm_user_t *         userp = NULL;
+    BOOL                bWow64 = (RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_WOW64) ? TRUE : FALSE;
+    BOOL                bFast  = (RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_FAST_REQUEST) ? TRUE : FALSE;
+    BOOL                bHoldFid = (RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_HOLD_FID) ? TRUE : FALSE;
+    BOOL                bFlushFile = (RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_FLUSH_FILE) ? TRUE : FALSE;
+    BOOL                bDeleteFile = (RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_FILE_DELETED) ? TRUE : FALSE;
+    BOOL                bUnlockFile = (RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL) ? TRUE : FALSE;
+    BOOL                bCheckOnly = (RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_CHECK_ONLY) ? TRUE : FALSE;
+    BOOL                bRetry = FALSE;
+    BOOL                bUnsupported = FALSE;
+    BOOL                bIsLocalSystem = (RequestBuffer->RequestFlags & AFS_REQUEST_LOCAL_SYSTEM_PAG) ? TRUE : FALSE;
+
+    userp = RDR_UserFromCommRequest(RequestBuffer);
+
+  retry:
+    //
+    // Build up the string to display based on the request type.
+    //
+
+    switch( RequestBuffer->RequestType)
+    {
+
+        case AFS_REQUEST_TYPE_DIR_ENUM:
+        {
+
+            AFSDirQueryCB *pQueryCB = (AFSDirQueryCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer,
+                          L"ProcessRequest Processing AFS_REQUEST_TYPE_DIR_ENUM Index %08lX",
+                          RequestBuffer->RequestIndex);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            //
+            // Here is where the content of the specific directory is enumerated.
+            //
+
+            RDR_EnumerateDirectory( userp, RequestBuffer->FileId,
+                                   pQueryCB, bWow64, bFast,
+                                   RequestBuffer->ResultBufferLength,
+                                   &pResultCB);
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_EVAL_TARGET_BY_ID:
+        {
+            AFSEvalTargetCB *pEvalTargetCB = (AFSEvalTargetCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer,
+                          L"ProcessRequest Processing AFS_REQUEST_TYPE_EVAL_TARGET_BY_ID Index %08lX",
+                          RequestBuffer->RequestIndex);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+            //
+            // Here is where the specified node is evaluated.
+            //
+
+            RDR_EvaluateNodeByID( userp, pEvalTargetCB->ParentId,
+                                  RequestBuffer->FileId,
+                                  bWow64, bFast, bHoldFid,
+                                  RequestBuffer->ResultBufferLength,
+                                  &pResultCB);
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_EVAL_TARGET_BY_NAME:
+        {
+            AFSEvalTargetCB *pEvalTargetCB = (AFSEvalTargetCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer,
+                          L"ProcessRequest Processing AFS_REQUEST_TYPE_EVAL_TARGET_BY_NAME Index %08lX",
+                          RequestBuffer->RequestIndex);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+            //
+            // Here is where the specified node is evaluated.
+            //
+
+            RDR_EvaluateNodeByName( userp, pEvalTargetCB->ParentId,
+                                    RequestBuffer->Name,
+                                    RequestBuffer->NameLength,
+                                    RequestBuffer->RequestFlags & AFS_REQUEST_FLAG_CASE_SENSITIVE ? TRUE : FALSE,
+                                    bWow64, bFast, bHoldFid,
+                                    RequestBuffer->ResultBufferLength,
+                                    &pResultCB);
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_CREATE_FILE:
+        {
+
+            AFSFileCreateCB *pCreateCB = (AFSFileCreateCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            WCHAR wchFileName[ 256];
+
+            if (afsd_logp->enabled) {
+                memset( wchFileName, '\0', 256 * sizeof( WCHAR));
+
+                memcpy( wchFileName,
+                        RequestBuffer->Name,
+                        RequestBuffer->NameLength);
+
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_CREATE_FILE Index %08lX File %S",
+                          RequestBuffer->RequestIndex, wchFileName);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_CreateFileEntry( userp,
+                                 RequestBuffer->Name,
+                                RequestBuffer->NameLength,
+                                pCreateCB,
+                                 bWow64,
+                                 bHoldFid,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_UPDATE_FILE:
+        {
+
+            AFSFileUpdateCB *pUpdateCB = (AFSFileUpdateCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_UPDATE_FILE Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_UpdateFileEntry( userp, RequestBuffer->FileId,
+                                pUpdateCB,
+                                 bWow64,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_DELETE_FILE:
+        {
+
+            AFSFileDeleteCB *pDeleteCB = (AFSFileDeleteCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_DELETE_FILE Index %08lX %08lX.%08lX.%08lX.%08lX CheckOnly %X",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique,
+                          bCheckOnly);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_DeleteFileEntry( userp,
+                                 pDeleteCB->ParentId,
+                                 pDeleteCB->ProcessId,
+                                 RequestBuffer->Name,
+                                RequestBuffer->NameLength,
+                                 bWow64,
+                                 bCheckOnly,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_RENAME_FILE:
+        {
+
+            AFSFileRenameCB *pFileRenameCB = (AFSFileRenameCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_RENAME_FILE Index %08lX File %08lX.%08lX.%08lX.%08lX NameLength %08lX Name %*S",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique,
+                          RequestBuffer->NameLength, (int)RequestBuffer->NameLength, RequestBuffer->Name);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_RenameFileEntry( userp,
+                                 RequestBuffer->Name,
+                                RequestBuffer->NameLength,
+                                 RequestBuffer->FileId,
+                                pFileRenameCB,
+                                 bWow64,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS:
+        {
+
+            AFSRequestExtentsCB *pFileRequestExtentsCB = (AFSRequestExtentsCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS Index %08lX File %08lX.%08lX.%08lX.%08lX %S",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique,
+                          BooleanFlagOn( RequestBuffer->RequestFlags, AFS_REQUEST_FLAG_SYNCHRONOUS) ? L"Sync" : L"Async");
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            if (BooleanFlagOn( RequestBuffer->RequestFlags, AFS_REQUEST_FLAG_SYNCHRONOUS))
+                osi_panic("SYNCHRONOUS AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS not supported",
+                          __FILE__, __LINE__);
+            else
+                bRetry = RDR_RequestFileExtentsAsync( userp, RequestBuffer->FileId,
+                                                      pFileRequestExtentsCB,
+                                                      bWow64,
+                                                      &dwResultBufferLength,
+                                                      &SetFileExtentsResultCB );
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS:
+        {
+
+            AFSReleaseExtentsCB *pFileReleaseExtentsCB = (AFSReleaseExtentsCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_ReleaseFileExtents( userp, RequestBuffer->FileId,
+                                   pFileReleaseExtentsCB,
+                                    bWow64,
+                                   RequestBuffer->ResultBufferLength,
+                                   &pResultCB);
+
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_FLUSH_FILE:
+        {
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_FLUSH_FILE Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_FlushFileEntry( userp, RequestBuffer->FileId,
+                                bWow64,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_OPEN_FILE:
+        {
+            AFSFileOpenCB *pFileOpenCB = (AFSFileOpenCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_OPEN_FILE Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_OpenFileEntry( userp, RequestBuffer->FileId,
+                               pFileOpenCB,
+                               bWow64,
+                               bHoldFid,
+                               RequestBuffer->ResultBufferLength,
+                               &pResultCB);
+
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_PIOCTL_OPEN:
+        {
+            AFSPIOCtlOpenCloseRequestCB *pPioctlCB = (AFSPIOCtlOpenCloseRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIOCTL_OPEN Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_PioctlOpen( userp,
+                            RequestBuffer->FileId,
+                            pPioctlCB,
+                            bWow64,
+                            RequestBuffer->ResultBufferLength,
+                            &pResultCB);
+            break;
+        }
+
+        case AFS_REQUEST_TYPE_PIOCTL_WRITE:
+        {
+            AFSPIOCtlIORequestCB *pPioctlCB = (AFSPIOCtlIORequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIOCTL_WRITE Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_PioctlWrite( userp,
+                             RequestBuffer->FileId,
+                             pPioctlCB,
+                             bWow64,
+                             RequestBuffer->ResultBufferLength,
+                             &pResultCB);
+            break;
+        }
+
+    case AFS_REQUEST_TYPE_PIOCTL_READ:
+            {
+                AFSPIOCtlIORequestCB *pPioctlCB = (AFSPIOCtlIORequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIOCTL_READ Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PioctlRead( userp,
+                                RequestBuffer->FileId,
+                                pPioctlCB,
+                                bWow64,
+                                bIsLocalSystem,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_PIOCTL_CLOSE:
+            {
+                AFSPIOCtlOpenCloseRequestCB *pPioctlCB = (AFSPIOCtlOpenCloseRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIOCTL_CLOSE Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PioctlClose( userp,
+                                RequestBuffer->FileId,
+                                pPioctlCB,
+                                bWow64,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+                break;
+            }
+
+
+    case AFS_REQUEST_TYPE_BYTE_RANGE_LOCK:
+            {
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_BYTE_RANGE_LOCK Index %08lX File %08lX.%08lX.%08lX.%08lX %S",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique,
+                              BooleanFlagOn( RequestBuffer->RequestFlags, AFS_REQUEST_FLAG_SYNCHRONOUS) ? L"Sync" : L"Async");
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                AFSByteRangeLockRequestCB *pBRLRequestCB = (AFSByteRangeLockRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                RDR_ByteRangeLockSync( userp,
+                                       RequestBuffer->FileId,
+                                       pBRLRequestCB,
+                                       bWow64,
+                                       RequestBuffer->ResultBufferLength,
+                                       &pResultCB);
+
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_BYTE_RANGE_UNLOCK:
+            {
+                AFSByteRangeUnlockRequestCB *pBRURequestCB = (AFSByteRangeUnlockRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_BYTE_RANGE_UNLOCK Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_ByteRangeUnlock( userp,
+                                     RequestBuffer->FileId,
+                                     pBRURequestCB,
+                                     bWow64,
+                                     RequestBuffer->ResultBufferLength,
+                                     &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_BYTE_RANGE_UNLOCK_ALL:
+            {
+                AFSByteRangeUnlockRequestCB *pBRURequestCB = (AFSByteRangeUnlockRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_BYTE_RANGE_UNLOCK_ALL Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_ByteRangeUnlockAll( userp,
+                                        RequestBuffer->FileId,
+                                        pBRURequestCB,
+                                        bWow64,
+                                        RequestBuffer->ResultBufferLength,
+                                        &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_GET_VOLUME_INFO:
+            {
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_GET_VOLUME_INFO Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_GetVolumeInfo( userp,
+                                   RequestBuffer->FileId,
+                                   bWow64,
+                                   RequestBuffer->ResultBufferLength,
+                                   &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_HOLD_FID:
+            {
+
+                AFSHoldFidRequestCB *pHoldFidCB = (AFSHoldFidRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_HOLD_FID Index %08lX",
+                              RequestBuffer->RequestIndex);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_HoldFid( userp,
+                             pHoldFidCB,
+                             bFast,
+                             RequestBuffer->ResultBufferLength,
+                             &pResultCB);
+
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_RELEASE_FID:
+            {
+
+                AFSReleaseFidRequestCB *pReleaseFidCB = (AFSReleaseFidRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_RELEASE_FID Index %08lX",
+                              RequestBuffer->RequestIndex);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_ReleaseFid( userp,
+                                pReleaseFidCB,
+                                bFast,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_CLEANUP_PROCESSING:
+            {
+
+                AFSFileCleanupCB *pCleanupCB = (AFSFileCleanupCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_CLEANUP_FILE Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_CleanupFileEntry( userp,
+                                      RequestBuffer->FileId,
+                                      RequestBuffer->Name,
+                                      RequestBuffer->NameLength,
+                                      pCleanupCB,
+                                      bWow64,
+                                      bFlushFile,
+                                      bDeleteFile,
+                                      bUnlockFile,
+                                      RequestBuffer->ResultBufferLength,
+                                      &pResultCB);
+
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_PIPE_OPEN:
+            {
+                AFSPipeOpenCloseRequestCB *pPipeCB = (AFSPipeOpenCloseRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIPE_OPEN Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PipeOpen( userp,
+                              RequestBuffer->FileId,
+                              RequestBuffer->Name,
+                              RequestBuffer->NameLength,
+                              pPipeCB,
+                              bWow64,
+                              RequestBuffer->ResultBufferLength,
+                              &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_PIPE_WRITE:
+            {
+                AFSPipeIORequestCB *pPipeCB = (AFSPipeIORequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+                BYTE *pPipeData = ((BYTE *)RequestBuffer->Name + RequestBuffer->DataOffset + sizeof(AFSPipeIORequestCB));
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIPE_WRITE Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PipeWrite( userp,
+                               RequestBuffer->FileId,
+                               pPipeCB,
+                               pPipeData,
+                               bWow64,
+                               RequestBuffer->ResultBufferLength,
+                               &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_PIPE_READ:
+            {
+                AFSPipeIORequestCB *pPipeCB = (AFSPipeIORequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIPE_READ Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PipeRead( userp,
+                              RequestBuffer->FileId,
+                              pPipeCB,
+                              bWow64,
+                              RequestBuffer->ResultBufferLength,
+                              &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_PIPE_CLOSE:
+            {
+                AFSPipeOpenCloseRequestCB *pPipeCB = (AFSPipeOpenCloseRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIPE_CLOSE Index %08lX Parent %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PipeClose( userp,
+                                RequestBuffer->FileId,
+                                pPipeCB,
+                                bWow64,
+                                RequestBuffer->ResultBufferLength,
+                                &pResultCB);
+                break;
+            }
+
+
+    case AFS_REQUEST_TYPE_PIPE_TRANSCEIVE:
+            {
+                AFSPipeIORequestCB *pPipeCB = (AFSPipeIORequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+                BYTE *pPipeData = ((BYTE *)RequestBuffer->Name + RequestBuffer->DataOffset + sizeof(AFSPipeIORequestCB));
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIPE_TRANSCEIVE Index %08lX",
+                              RequestBuffer->RequestIndex);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PipeTransceive( userp,
+                                    RequestBuffer->FileId,
+                                    pPipeCB,
+                                    pPipeData,
+                                    bWow64,
+                                    RequestBuffer->ResultBufferLength,
+                                    &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_PIPE_QUERY_INFO:
+            {
+                AFSPipeInfoRequestCB *pPipeInfoCB = (AFSPipeInfoRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIPE_QUERY_INFO Index %08lX",
+                              RequestBuffer->RequestIndex);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PipeQueryInfo( userp,
+                                   RequestBuffer->FileId,
+                                   pPipeInfoCB,
+                                   bWow64,
+                                   RequestBuffer->ResultBufferLength,
+                                   &pResultCB);
+                break;
+            }
+
+    case AFS_REQUEST_TYPE_PIPE_SET_INFO:
+            {
+                AFSPipeInfoRequestCB *pPipeInfoCB = (AFSPipeInfoRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+                BYTE *pPipeData = ((BYTE *)RequestBuffer->Name + RequestBuffer->DataOffset + sizeof(AFSPipeInfoRequestCB));
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_PIPE_SET_INFO Index %08lX",
+                              RequestBuffer->RequestIndex);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_PipeSetInfo( userp,
+                                 RequestBuffer->FileId,
+                                 pPipeInfoCB,
+                                 pPipeData,
+                                 bWow64,
+                                 RequestBuffer->ResultBufferLength,
+                                 &pResultCB);
+
+                break;
+            }
+
+    default:
+            bUnsupported = TRUE;
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Received unknown request type %08lX Index %08lX",
+                          RequestBuffer->RequestType,
+                          RequestBuffer->RequestIndex);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            break;
+    }
+
+    if( BooleanFlagOn( RequestBuffer->RequestFlags, AFS_REQUEST_FLAG_SYNCHRONOUS))
+    {
+       if (pResultCB == NULL) {
+           // We failed probably due to a memory allocation error
+            // unless the unsupported flag was set.
+           pResultCB = &stResultCB;
+            memset(&stResultCB, 0, sizeof(stResultCB));
+            if ( bUnsupported )
+                pResultCB->ResultStatus = STATUS_NOT_IMPLEMENTED;
+            else
+                pResultCB->ResultStatus = STATUS_NO_MEMORY;
+       }
+
+        //
+        // This is how the filter associates the response information passed in the IOCtl below to the
+        // original call. This request index is setup by the filter and should not be modified, otherwise the
+        // filter will not be able to locate the request in its internal queue and the blocking thread will
+        // not be awakened
+        //
+
+        pResultCB->RequestIndex = RequestBuffer->RequestIndex;
+
+        if (afsd_logp->enabled) {
+            swprintf( wchBuffer,
+                      L"ProcessRequest Responding to Index %08lX Length %08lX",
+                      pResultCB->RequestIndex,
+                      pResultCB->ResultBufferLength);
+
+            osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+        }
+
+        //
+        // Now post the result back to the driver.
+        //
+
+        if( !RDR_DeviceIoControl( glDevHandle,
+                                  IOCTL_AFS_PROCESS_IRP_RESULT,
+                                  (void *)pResultCB,
+                                  sizeof( AFSCommResult) + pResultCB->ResultBufferLength,
+                                  (void *)NULL,
+                                  0,
+                                  &bytesReturned ))
+        {
+            char *pBuffer = (char *)wchBuffer;
+            gle = GetLastError();
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer,
+                          L"Failed to post IOCTL_AFS_PROCESS_IRP_RESULT gle %X", gle);
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            sprintf( pBuffer,
+                     "Failed to post IOCTL_AFS_PROCESS_IRP_RESULT gle %X",
+                     GetLastError());
+            osi_panic(pBuffer, __FILE__, __LINE__);
+        }
+
+    }
+    else if (RequestBuffer->RequestType == AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS) {
+
+        if (SetFileExtentsResultCB) {
+
+            if (1 || afsd_logp->enabled) {
+                if (SetFileExtentsResultCB->ResultStatus != 0)
+                    swprintf( wchBuffer,
+                          L"ProcessRequest Responding Asynchronously with FAILURE to REQUEST_FILE_EXTENTS Index %08lX Count %08lX Status %08lX",
+                          RequestBuffer->RequestIndex, SetFileExtentsResultCB->ExtentCount, SetFileExtentsResultCB->ResultStatus);
+                else
+                    swprintf( wchBuffer,
+                          L"ProcessRequest Responding Asynchronously with SUCCESS to REQUEST_FILE_EXTENTS Index %08lX Count %08lX",
+                          RequestBuffer->RequestIndex, SetFileExtentsResultCB->ExtentCount);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            if( (SetFileExtentsResultCB->ExtentCount != 0 ||
+                 SetFileExtentsResultCB->ResultStatus != 0) &&
+                !RDR_DeviceIoControl( glDevHandle,
+                                       IOCTL_AFS_SET_FILE_EXTENTS,
+                                      (void *)SetFileExtentsResultCB,
+                                      dwResultBufferLength,
+                                      (void *)NULL,
+                                      0,
+                                      &bytesReturned ))
+            {
+                gle = GetLastError();
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer,
+                              L"Failed to post IOCTL_AFS_SET_FILE_EXTENTS gle %X",
+                              gle);
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                // The file system returns an error when it can't find the FID
+                // This is a bug in the file system but we should try to avoid
+                // the crash and clean up our own memory space.
+                //
+                // Since we couldn't deliver the extents to the file system
+                // we should release them.
+                if ( SetFileExtentsResultCB->ExtentCount != 0)
+                {
+                    RDR_ReleaseFailedSetFileExtents( userp,
+                                                 SetFileExtentsResultCB,
+                                                 dwResultBufferLength);
+                }
+
+                if (gle != ERROR_GEN_FAILURE) {
+                    sprintf( pBuffer,
+                             "Failed to post IOCTL_AFS_SET_FILE_EXTENTS gle %X",
+                             gle);
+                    osi_panic(pBuffer, __FILE__, __LINE__);
+                }
+            }
+
+            free(SetFileExtentsResultCB);
+
+      } else {
+          /* Must be out of memory */
+          if (afsd_logp->enabled) {
+              swprintf( wchBuffer,
+                        L"ProcessRequest Responding Asynchronously STATUS_NO_MEMORY to REQUEST_FILE_EXTENTS Index %08lX",
+                        RequestBuffer->RequestIndex);
+
+              osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+          }
+
+          RDR_SetFileStatus( (cm_fid_t *)&RequestBuffer->FileId, STATUS_NO_MEMORY);
+       }
+    }
+    else if (RequestBuffer->RequestType == AFS_REQUEST_TYPE_BYTE_RANGE_LOCK) {
+
+        if (afsd_logp->enabled) {
+            swprintf( wchBuffer,
+                      L"ProcessRequest Responding Asynchronously to REQUEST_TYPE_BYTE_RANGELOCK Index %08lX",
+                      RequestBuffer->RequestIndex);
+
+            osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+        }
+
+
+        if (SetByteRangeLockResultCB) {
+
+            if( !RDR_DeviceIoControl( glDevHandle,
+                                  IOCTL_AFS_SET_BYTE_RANGE_LOCKS,
+                                  (void *)SetByteRangeLockResultCB,
+                                  dwResultBufferLength,
+                                  (void *)NULL,
+                                  0,
+                                  &bytesReturned ))
+            {
+                gle = GetLastError();
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer,
+                              L"Failed to post IOCTL_AFS_SET_BYTE_RANGE_LOCKS gle 0x%x", gle);
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+
+                // TODO - instead of a panic we should release the locks
+                sprintf( pBuffer,
+                         "Failed to post IOCTL_AFS_SET_BYTE_RANGE_LOCKS gle %X", gle);
+                osi_panic(pBuffer, __FILE__, __LINE__);
+            }
+
+            free(SetByteRangeLockResultCB);
+        } else {
+            /* Must be out of memory */
+            AFSSetByteRangeLockResultCB SetByteRangeLockResultCB;
+
+            dwResultBufferLength = sizeof(AFSSetByteRangeLockResultCB);
+            memset( &SetByteRangeLockResultCB, '\0', dwResultBufferLength );
+            SetByteRangeLockResultCB.FileId = RequestBuffer->FileId;
+            SetByteRangeLockResultCB.Result[0].Status = STATUS_NO_MEMORY;
+
+            if( !RDR_DeviceIoControl( glDevHandle,
+                                      IOCTL_AFS_SET_BYTE_RANGE_LOCKS,
+                                      (void *)&SetByteRangeLockResultCB,
+                                      dwResultBufferLength,
+                                      (void *)NULL,
+                                      0,
+                                      &bytesReturned ))
+            {
+                gle = GetLastError();
+
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer,
+                              L"Failed to post IOCTL_AFS_SET_BYTE_RANGE_LOCKS gle 0x%x", gle);
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                /* We were out of memory - nothing to do */
+            }
+        }
+    }
+    else {
+
+        if (afsd_logp->enabled) {
+            swprintf( wchBuffer,
+                      L"ProcessRequest Not responding to async Index %08lX",
+                      RequestBuffer->RequestIndex);
+
+            osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+        }
+    }
+
+    if (bRetry)
+        goto retry;
+
+    if (userp)
+        RDR_ReleaseUser(userp);
+
+
+    if( pResultCB && pResultCB != &stResultCB)
+    {
+
+       free( pResultCB);
+    }
+    return;
+}
+
+
+extern "C" DWORD
+RDR_SetFileExtents( AFSSetFileExtentsCB *pSetFileExtentsResultCB,
+                    DWORD dwResultBufferLength)
+{
+    WCHAR wchBuffer[1024];
+    DWORD bytesReturned;
+    DWORD gle;
+
+    if (1 || afsd_logp->enabled) {
+        if (pSetFileExtentsResultCB->ResultStatus != 0)
+            swprintf( wchBuffer,
+               L"RDR_SetFileExtents IOCTL_AFS_SET_FILE_EXTENTS FAILURE Count %08lX Status %08lX",
+               pSetFileExtentsResultCB->ExtentCount, pSetFileExtentsResultCB->ResultStatus);
+        else
+            swprintf( wchBuffer,
+               L"RDR_SetFileExtents IOCTL_AFS_SET_FILE_EXTENTS SUCCESS Count %08lX",
+               pSetFileExtentsResultCB->ExtentCount);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    if( !RDR_DeviceIoControl( glDevHandle,
+                              IOCTL_AFS_SET_FILE_EXTENTS,
+                              (void *)pSetFileExtentsResultCB,
+                              dwResultBufferLength,
+                              (void *)NULL,
+                              0,
+                              &bytesReturned ))
+    {
+        gle = GetLastError();
+        return gle;
+    }
+
+    return 0;
+}
+
+
+extern "C" DWORD
+RDR_SetFileStatus( cm_fid_t *fidp,
+                   DWORD dwStatus)
+{
+    WCHAR               wchBuffer[1024];
+    AFSExtentFailureCB  SetFileStatusCB;
+    DWORD               bytesReturned;
+    DWORD               gle;
+    AFSFileID          *pFileId = (AFSFileID *)fidp;
+
+    SetFileStatusCB.FileId = *pFileId;
+    SetFileStatusCB.FailureStatus = dwStatus;
+
+    if (afsd_logp->enabled) {
+        swprintf( wchBuffer, L"RDR_SetFileStatus IOCTL_AFS_EXTENT_FAILURE_CB Fid %08lX.%08lX.%08lX.%08lX Status 0x%lX",
+                  pFileId->Cell, pFileId->Volume,
+                  pFileId->Vnode, pFileId->Unique,
+                  dwStatus);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    if( !RDR_DeviceIoControl( glDevHandle,
+                              IOCTL_AFS_SET_FILE_EXTENT_FAILURE,
+                              (void *)&SetFileStatusCB,
+                              sizeof(AFSExtentFailureCB),
+                              (void *)NULL,
+                              0,
+                              &bytesReturned ))
+    {
+        gle = GetLastError();
+        return gle;
+    }
+
+    return 0;
+}
+
+
+extern "C" DWORD
+RDR_RequestExtentRelease(cm_fid_t *fidp, LARGE_INTEGER numOfHeldExtents, DWORD numOfExtents, AFSFileExtentCB *extentList)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+    AFSReleaseFileExtentsCB *requestBuffer = NULL;
+    AFSReleaseFileExtentsResultCB *responseBuffer = NULL;
+    DWORD requestBufferLen, responseBufferLen;
+    bool bError = false;
+    DWORD rc = 0;
+    WCHAR wchBuffer[256];
+    DWORD gle;
+
+    if (ExitPending) {
+        if (afsd_logp->enabled) {
+            swprintf( wchBuffer,
+                      L"IOCTL_AFS_RELEASE_FILE_EXTENTS request ignored due to shutdown pending");
+
+            osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+        }
+
+        OutputDebugString(L"RDR_RequestExtentRequest ignored - shutdown pending\n");
+        return CM_ERROR_WOULDBLOCK;
+    }
+
+    if (afsd_logp->enabled) {
+        swprintf( wchBuffer,
+                  L"IOCTL_AFS_RELEASE_FILE_EXTENTS request - number %08lX",
+                  numOfExtents);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+    //
+    // Allocate a request buffer.
+    //
+
+    requestBufferLen = sizeof( AFSReleaseFileExtentsCB) + sizeof(AFSFileExtentCB) * numOfExtents;
+    requestBuffer = (AFSReleaseFileExtentsCB *)malloc( requestBufferLen);
+    responseBufferLen = (sizeof( AFSReleaseFileExtentsResultCB) + sizeof( AFSReleaseFileExtentsResultFileCB)) * numOfExtents;
+    responseBuffer = (AFSReleaseFileExtentsResultCB *)malloc( responseBufferLen);
+
+
+    if( requestBuffer && responseBuffer)
+    {
+
+       memset( requestBuffer, '\0', sizeof( AFSReleaseFileExtentsCB));
+       memset( responseBuffer, '\0', responseBufferLen);
+
+        // If there is a FID provided, use it
+        if (fidp && extentList)
+        {
+            RDR_fid2FID( fidp, &requestBuffer->FileId);
+
+            memcpy(&requestBuffer->FileExtents, extentList, numOfExtents * sizeof(AFSFileExtentCB));
+
+            requestBuffer->Flags = 0;
+        } else {
+
+            requestBuffer->Flags = AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL;
+        }
+
+        // Set the number of extents to be freed
+        // Leave the rest of the structure as zeros to indicate free anything
+        requestBuffer->ExtentCount = numOfExtents;
+
+        requestBuffer->HeldExtentCount = numOfHeldExtents;
+
+        if( !RDR_DeviceIoControl( hDevHandle,
+                                  IOCTL_AFS_RELEASE_FILE_EXTENTS,
+                                  (void *)requestBuffer,
+                                  requestBufferLen,
+                                  (void *)responseBuffer,
+                                  responseBufferLen,
+                                  &bytesReturned ))
+        {
+            //
+            // Error condition back from driver
+            //
+            if (afsd_logp->enabled) {
+                gle = GetLastError();
+                swprintf( wchBuffer,
+                          L"Failed to post IOCTL_AFS_RELEASE_FILE_EXTENTS - gle 0x%x", gle);
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+            rc = -1;
+            goto cleanup;
+        }
+
+        //
+        // Go process the request
+        //
+
+        if (afsd_logp->enabled) {
+            swprintf( wchBuffer,
+                      L"IOCTL_AFS_RELEASE_FILE_EXTENTS returns - serial number %08lX flags %lX FileCount %lX",
+                      responseBuffer->SerialNumber, responseBuffer->Flags, responseBuffer->FileCount);
+            osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+        }
+
+        rc = RDR_ProcessReleaseFileExtentsResult( responseBuffer, bytesReturned);
+    } else {
+
+        rc = ENOMEM;
+    }
+
+  cleanup:
+    if (requestBuffer)
+        free( requestBuffer);
+    if (responseBuffer)
+        free( responseBuffer);
+
+    return rc;
+}
+
+
+extern "C" DWORD
+RDR_NetworkStatus(BOOLEAN status)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+    AFSNetworkStatusCB *requestBuffer = NULL;
+    DWORD rc = 0;
+    WCHAR wchBuffer[256];
+    DWORD gle;
+
+    if (afsd_logp->enabled) {
+        swprintf( wchBuffer,
+                  L"IOCTL_AFS_NETWORK_STATUS request - status %d",
+                  status);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+    //
+    // Allocate a request buffer.
+    //
+
+    requestBuffer = (AFSNetworkStatusCB *)malloc( sizeof( AFSNetworkStatusCB));
+
+
+    if( requestBuffer)
+    {
+
+       memset( requestBuffer, '\0', sizeof( AFSNetworkStatusCB));
+
+        // Set the number of extents to be freed
+        // Leave the rest of the structure as zeros to indicate free anything
+        requestBuffer->Online = status;
+
+        if( !RDR_DeviceIoControl( hDevHandle,
+                                  IOCTL_AFS_NETWORK_STATUS,
+                                  (void *)requestBuffer,
+                                  sizeof( AFSNetworkStatusCB),
+                                  NULL,
+                                  0,
+                                  &bytesReturned ))
+        {
+            //
+            // Error condition back from driver
+            //
+            if (afsd_logp->enabled) {
+                gle = GetLastError();
+                swprintf( wchBuffer,
+                          L"Failed to post IOCTL_AFS_NETWORK_STATUS gle 0x%x",
+                          gle);
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            rc = -1;
+            goto cleanup;
+        }
+    } else
+        rc = ENOMEM;
+
+  cleanup:
+    if (requestBuffer)
+        free( requestBuffer);
+
+    return rc;
+}
+
+
+
+extern "C" DWORD
+RDR_VolumeStatus(ULONG cellID, ULONG volID, BOOLEAN online)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+    AFSVolumeStatusCB *requestBuffer = NULL;
+    DWORD rc = 0;
+    WCHAR wchBuffer[256];
+    DWORD gle;
+
+    if (afsd_logp->enabled) {
+        swprintf( wchBuffer,
+                  L"IOCTL_AFS_VOLUME_STATUS request - cell 0x%x vol 0x%x online %d",
+                  cellID, volID, online);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+    //
+    // Allocate a request buffer.
+    //
+
+    requestBuffer = (AFSVolumeStatusCB *)malloc( sizeof( AFSVolumeStatusCB));
+
+
+    if( requestBuffer)
+    {
+
+       memset( requestBuffer, '\0', sizeof( AFSVolumeStatusCB));
+
+        requestBuffer->FileID.Cell = cellID;
+        requestBuffer->FileID.Volume = volID;
+        requestBuffer->Online = online;
+
+        if( !RDR_DeviceIoControl( hDevHandle,
+                                  IOCTL_AFS_VOLUME_STATUS,
+                                  (void *)requestBuffer,
+                                  sizeof( AFSVolumeStatusCB),
+                                  NULL,
+                                  0,
+                                  &bytesReturned ))
+        {
+            //
+            // Error condition back from driver
+            //
+
+            if (afsd_logp->enabled) {
+                gle = GetLastError();
+                swprintf( wchBuffer,
+                          L"Failed to post IOCTL_AFS_VOLUME_STATUS gle 0x%x", gle);
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            rc = -1;
+            goto cleanup;
+        }
+    } else
+        rc = ENOMEM;
+
+  cleanup:
+    if (requestBuffer)
+        free( requestBuffer);
+
+    return rc;
+}
+
+extern "C" DWORD
+RDR_NetworkAddrChange(void)
+{
+    return 0;
+}
+
+
+extern "C" DWORD
+RDR_InvalidateVolume(ULONG cellID, ULONG volID, ULONG reason)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+    AFSInvalidateCacheCB *requestBuffer = NULL;
+    DWORD rc = 0;
+    WCHAR wchBuffer[256];
+    DWORD gle;
+
+    if (afsd_logp->enabled) {
+        swprintf( wchBuffer,
+                  L"IOCTL_AFS_INVALIDATE_CACHE (vol) request - cell 0x%x vol 0x%x reason %d",
+                  cellID, volID, reason);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+    //
+    // Allocate a request buffer.
+    //
+
+    requestBuffer = (AFSInvalidateCacheCB *)malloc( sizeof( AFSInvalidateCacheCB));
+
+
+    if( requestBuffer)
+    {
+
+       memset( requestBuffer, '\0', sizeof( AFSInvalidateCacheCB));
+
+        requestBuffer->FileID.Cell = cellID;
+        requestBuffer->FileID.Volume = volID;
+        requestBuffer->WholeVolume = TRUE;
+        requestBuffer->Reason = reason;
+
+        if( !RDR_DeviceIoControl( hDevHandle,
+                                  IOCTL_AFS_INVALIDATE_CACHE,
+                                  (void *)requestBuffer,
+                                  sizeof( AFSInvalidateCacheCB),
+                                  NULL,
+                                  0,
+                                  &bytesReturned ))
+        {
+            //
+            // Error condition back from driver
+            //
+
+            if (afsd_logp->enabled) {
+                gle = GetLastError();
+                swprintf( wchBuffer,
+                          L"Failed to post IOCTL_AFS_INVALIDATE_VOLUME gle 0x%x", gle);
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            rc = -1;
+            goto cleanup;
+        }
+    } else
+        rc = ENOMEM;
+
+  cleanup:
+    if (requestBuffer)
+        free( requestBuffer);
+
+    return rc;
+}
+
+
+extern "C" DWORD
+RDR_InvalidateObject(ULONG cellID, ULONG volID, ULONG vnode, ULONG uniq, ULONG hash, ULONG fileType, ULONG reason)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+    AFSInvalidateCacheCB *requestBuffer = NULL;
+    DWORD rc = 0;
+    WCHAR wchBuffer[256];
+    DWORD gle;
+
+    if (afsd_logp->enabled) {
+        swprintf( wchBuffer,
+                  L"IOCTL_AFS_INVALIDATE_CACHE (obj) request - cell 0x%x vol 0x%x vn 0x%x uniq 0x%x hash 0x%x type 0x%x reason %d",
+                  cellID, volID, vnode, uniq, hash, fileType, reason);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+    //
+    // Allocate a request buffer.
+    //
+
+    requestBuffer = (AFSInvalidateCacheCB *)malloc( sizeof( AFSInvalidateCacheCB));
+
+
+    if( requestBuffer)
+    {
+
+       memset( requestBuffer, '\0', sizeof( AFSInvalidateCacheCB));
+
+        requestBuffer->FileID.Cell = cellID;
+        requestBuffer->FileID.Volume = volID;
+        requestBuffer->FileID.Vnode = vnode;
+        requestBuffer->FileID.Unique = uniq;
+        requestBuffer->FileID.Hash = hash;
+        requestBuffer->FileType = fileType;
+        requestBuffer->WholeVolume = FALSE;
+        requestBuffer->Reason = reason;
+
+        if( !RDR_DeviceIoControl( hDevHandle,
+                                  IOCTL_AFS_INVALIDATE_CACHE,
+                                  (void *)requestBuffer,
+                                  sizeof( AFSInvalidateCacheCB),
+                                  NULL,
+                                  0,
+                                  &bytesReturned ))
+        {
+            //
+            // Error condition back from driver
+            //
+            if (afsd_logp->enabled) {
+                gle = GetLastError();
+                swprintf( wchBuffer,
+                          L"Failed to post IOCTL_AFS_INVALIDATE_CACHE gle 0x%x", gle);
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            rc = -1;
+            goto cleanup;
+        }
+    } else
+        rc = ENOMEM;
+
+  cleanup:
+    if (requestBuffer)
+        free( requestBuffer);
+
+    return rc;
+}
+
+
+
+extern "C" DWORD
+RDR_SysName(ULONG Architecture, ULONG Count, WCHAR **NameList)
+{
+
+    HANDLE hDevHandle = NULL;
+    DWORD bytesReturned;
+    AFSSysNameNotificationCB *requestBuffer = NULL;
+    DWORD rc = 0;
+    WCHAR wchBuffer[256];
+    DWORD Length;
+    DWORD gle;
+
+    if (afsd_logp->enabled) {
+        swprintf( wchBuffer,
+                  L"IOCTL_AFS_SYSNAME_NOTIFICATION request - Arch %d Count %d",
+                  Architecture, Count);
+
+        osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+    }
+
+    if (Count <= 0 || NameList == NULL)
+        return -1;
+
+    //
+    // We use the global handle to the control device instance
+    //
+
+    hDevHandle = glDevHandle;
+
+    //
+    // Allocate a request buffer.
+    //
+
+    Length = sizeof (AFSSysNameNotificationCB) + (Count - 1) * sizeof (AFSSysName);
+    requestBuffer = (AFSSysNameNotificationCB *)malloc( Length );
+
+
+    if( requestBuffer)
+    {
+        unsigned int i;
+
+       memset( requestBuffer, '\0', Length);
+
+        requestBuffer->Architecture = Architecture;
+        requestBuffer->NumberOfNames = Count;
+        for ( i=0 ; i<Count; i++) {
+            size_t len = wcslen(NameList[i]);
+            requestBuffer->SysNames[i].Length = (ULONG) (len * sizeof(WCHAR));
+            StringCchCopyNW(requestBuffer->SysNames[i].String, AFS_MAX_SYSNAME_LENGTH,
+                            NameList[i], len);
+        }
+
+        if( !RDR_DeviceIoControl( hDevHandle,
+                                  IOCTL_AFS_SYSNAME_NOTIFICATION,
+                                  (void *)requestBuffer,
+                                  Length,
+                                  NULL,
+                                  0,
+                                  &bytesReturned ))
+        {
+            //
+            // Error condition back from driver
+            //
+            if (afsd_logp->enabled) {
+                gle = GetLastError();
+                swprintf( wchBuffer,
+                          L"Failed to post IOCTL_AFS_SYSNAME_NOTIFICATION gle 0x%x", gle);
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            rc = -1;
+            goto cleanup;
+        }
+    } else
+        rc = ENOMEM;
+
+  cleanup:
+    if (requestBuffer)
+        free( requestBuffer);
+
+    return rc;
+}
diff --git a/src/WINNT/afsrdr/user/RDRIoctl.c b/src/WINNT/afsrdr/user/RDRIoctl.c
new file mode 100644 (file)
index 0000000..09c895b
--- /dev/null
@@ -0,0 +1,1971 @@
+/*
+ * 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
+ */
+
+/*
+ * Copyright (c) 2008 Secure Endpoints, Inc.
+ * Copyright (c) 2009-2011 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <roken.h>
+
+#include <afs/stds.h>
+
+#include <windows.h>
+#include <sddl.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <strsafe.h>
+
+#include <osi.h>
+
+#include "afsd.h"
+
+#include "cm_rpc.h"
+#include "afs/afsrpc.h"
+#include "afs/auth.h"
+
+#include "smb_iocons.h"
+#define RDR_IOCTL_PRIVATE 1
+#include "RDRIoctl.h"
+#include "smb.h"
+#include "cm_nls.h"
+
+static RDR_ioctlProc_t *RDR_ioctlProcsp[CM_IOCTL_MAXPROCS];
+
+static RDR_ioctl_t * RDR_allIoctls = NULL, *RDR_allIoctlsLast = NULL;
+static osi_rwlock_t  RDR_globalIoctlLock;
+
+extern wchar_t       RDR_UNCName[];
+
+void
+RDR_InitIoctl(void)
+{
+    int i;
+
+    lock_InitializeRWLock(&RDR_globalIoctlLock, "RDR global ioctl lock", LOCK_HIERARCHY_RDR_GLOBAL);
+
+    for (i=0; i<CM_IOCTL_MAXPROCS; i++)
+        RDR_ioctlProcsp[i] = NULL;
+
+    RDR_ioctlProcsp[VIOCGETAL] = RDR_IoctlGetACL;
+    RDR_ioctlProcsp[VIOC_FILE_CELL_NAME] = RDR_IoctlGetFileCellName;
+    RDR_ioctlProcsp[VIOCSETAL] = RDR_IoctlSetACL;
+    RDR_ioctlProcsp[VIOC_FLUSHVOLUME] = RDR_IoctlFlushVolume;
+    RDR_ioctlProcsp[VIOCFLUSH] = RDR_IoctlFlushFile;
+    RDR_ioctlProcsp[VIOCSETVOLSTAT] = RDR_IoctlSetVolumeStatus;
+    RDR_ioctlProcsp[VIOCGETVOLSTAT] = RDR_IoctlGetVolumeStatus;
+    RDR_ioctlProcsp[VIOCWHEREIS] = RDR_IoctlWhereIs;
+    RDR_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = RDR_IoctlStatMountPoint;
+    RDR_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = RDR_IoctlDeleteMountPoint;
+    RDR_ioctlProcsp[VIOCCKSERV] = RDR_IoctlCheckServers;
+    RDR_ioctlProcsp[VIOC_GAG] = RDR_IoctlGag;
+    RDR_ioctlProcsp[VIOCCKBACK] = RDR_IoctlCheckVolumes;
+    RDR_ioctlProcsp[VIOCSETCACHESIZE] = RDR_IoctlSetCacheSize;
+    RDR_ioctlProcsp[VIOCGETCACHEPARMS] = RDR_IoctlGetCacheParms;
+    RDR_ioctlProcsp[VIOCGETCELL] = RDR_IoctlGetCell;
+    RDR_ioctlProcsp[VIOCNEWCELL] = RDR_IoctlNewCell;
+    RDR_ioctlProcsp[VIOC_GET_WS_CELL] = RDR_IoctlGetWsCell;
+    RDR_ioctlProcsp[VIOC_AFS_SYSNAME] = RDR_IoctlSysName;
+    RDR_ioctlProcsp[VIOC_GETCELLSTATUS] = RDR_IoctlGetCellStatus;
+    RDR_ioctlProcsp[VIOC_SETCELLSTATUS] = RDR_IoctlSetCellStatus;
+    RDR_ioctlProcsp[VIOC_SETSPREFS] = RDR_IoctlSetSPrefs;
+    RDR_ioctlProcsp[VIOC_GETSPREFS] = RDR_IoctlGetSPrefs;
+    RDR_ioctlProcsp[VIOC_STOREBEHIND] = RDR_IoctlStoreBehind;
+    RDR_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = RDR_IoctlCreateMountPoint;
+    RDR_ioctlProcsp[VIOC_TRACECTL] = RDR_IoctlTraceControl;
+    RDR_ioctlProcsp[VIOCSETTOK] = RDR_IoctlSetToken;
+    RDR_ioctlProcsp[VIOCGETTOK] = RDR_IoctlGetTokenIter;
+    RDR_ioctlProcsp[VIOCNEWGETTOK] = RDR_IoctlGetToken;
+    RDR_ioctlProcsp[VIOCDELTOK] = RDR_IoctlDelToken;
+    RDR_ioctlProcsp[VIOCDELALLTOK] = RDR_IoctlDelAllToken;
+    RDR_ioctlProcsp[VIOC_SYMLINK] = RDR_IoctlSymlink;
+    RDR_ioctlProcsp[VIOC_LISTSYMLINK] = RDR_IoctlListlink;
+    RDR_ioctlProcsp[VIOC_DELSYMLINK] = RDR_IoctlDeletelink;
+    RDR_ioctlProcsp[VIOC_MAKESUBMOUNT] = RDR_IoctlMakeSubmount;
+    RDR_ioctlProcsp[VIOC_GETRXKCRYPT] = RDR_IoctlGetRxkcrypt;
+    RDR_ioctlProcsp[VIOC_SETRXKCRYPT] = RDR_IoctlSetRxkcrypt;
+    RDR_ioctlProcsp[VIOC_ISSYMLINK] = RDR_IoctlIslink;
+    RDR_ioctlProcsp[VIOC_TRACEMEMDUMP] = RDR_IoctlMemoryDump;
+    RDR_ioctlProcsp[VIOC_ISSYMLINK] = RDR_IoctlIslink;
+    RDR_ioctlProcsp[VIOC_FLUSHALL] = RDR_IoctlFlushAllVolumes;
+    RDR_ioctlProcsp[VIOCGETFID] = RDR_IoctlGetFid;
+    RDR_ioctlProcsp[VIOCGETOWNER] = RDR_IoctlGetOwner;
+    RDR_ioctlProcsp[VIOC_RXSTAT_PROC] = RDR_IoctlRxStatProcess;
+    RDR_ioctlProcsp[VIOC_RXSTAT_PEER] = RDR_IoctlRxStatPeer;
+    RDR_ioctlProcsp[VIOC_UUIDCTL] = RDR_IoctlUUIDControl;
+    RDR_ioctlProcsp[VIOC_PATH_AVAILABILITY] = RDR_IoctlPathAvailability;
+    RDR_ioctlProcsp[VIOC_GETFILETYPE] = RDR_IoctlGetFileType;
+    RDR_ioctlProcsp[VIOC_VOLSTAT_TEST] = RDR_IoctlVolStatTest;
+    RDR_ioctlProcsp[VIOC_UNICODECTL] = RDR_IoctlUnicodeControl;
+    RDR_ioctlProcsp[VIOC_SETOWNER] = RDR_IoctlSetOwner;
+    RDR_ioctlProcsp[VIOC_SETGROUP] = RDR_IoctlSetGroup;
+    RDR_ioctlProcsp[VIOCNEWCELL2] = RDR_IoctlNewCell2;
+    RDR_ioctlProcsp[VIOC_GETUNIXMODE] = RDR_IoctlGetUnixMode;
+    RDR_ioctlProcsp[VIOC_SETUNIXMODE] = RDR_IoctlSetUnixMode;
+}
+
+/* called to make a fid structure into an IOCTL fid structure */
+void
+RDR_SetupIoctl(ULONG index, cm_fid_t *parentFid, cm_fid_t *rootFid, cm_user_t *userp)
+{
+    RDR_ioctl_t *iop;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    lock_ObtainWrite(&RDR_globalIoctlLock);
+    for ( iop=RDR_allIoctls; iop; iop=iop->next) {
+        if (iop->index == index)
+            break;
+    }
+
+    if (iop) {
+        /* we are reusing a previous ioctl */
+        if (cm_FidCmp(&iop->parentFid, parentFid)) {
+            iop->parentFid = *parentFid;
+            if (iop->parentScp) {
+                cm_ReleaseSCache(iop->parentScp);
+                iop->parentScp = NULL;
+            }
+            cm_GetSCache(parentFid, &iop->parentScp, userp, &req);
+            iop->rootFid = *rootFid;
+        }
+    } else {
+        /* need to allocate a new one */
+        iop = malloc(sizeof(*iop));
+        memset(iop, 0, sizeof(*iop));
+        if (RDR_allIoctls == NULL)
+            RDR_allIoctls = RDR_allIoctlsLast = iop;
+        else {
+            iop->prev = RDR_allIoctlsLast;
+            RDR_allIoctlsLast->next = iop;
+            RDR_allIoctlsLast = iop;
+        }
+        iop->index = index;
+        if (parentFid->cell == 0) {
+            iop->parentFid = cm_data.rootFid;
+            iop->parentScp = cm_RootSCachep(userp, &req);
+            cm_HoldSCache(iop->parentScp);
+        } else {
+            iop->parentFid = *parentFid;
+            cm_GetSCache(parentFid, &iop->parentScp, userp, &req);
+        }
+        if (rootFid->cell == 0) {
+            iop->rootFid = cm_data.rootFid;
+        } else {
+            iop->rootFid = *rootFid;
+        }
+    }
+    lock_ReleaseWrite(&RDR_globalIoctlLock);
+}
+
+
+void
+RDR_CleanupIoctl(ULONG index)
+{
+    RDR_ioctl_t *iop;
+
+    lock_ObtainWrite(&RDR_globalIoctlLock);
+    for ( iop=RDR_allIoctls; iop; iop=iop->next) {
+        if (iop->index == index)
+            break;
+    }
+
+    if (iop) {
+        if (iop->parentScp)
+            cm_ReleaseSCache(iop->parentScp);
+
+        if (iop->ioctl.inAllocp)
+            free(iop->ioctl.inAllocp);
+        if (iop->ioctl.outAllocp)
+            free(iop->ioctl.outAllocp);
+
+               if (RDR_allIoctls == RDR_allIoctlsLast)
+               RDR_allIoctls = RDR_allIoctlsLast = NULL;
+               else {
+                       if (iop->prev == NULL)
+                               RDR_allIoctls = iop->next;
+                       else
+                               iop->prev->next = iop->next;
+                       if (iop->next == NULL) {
+                               RDR_allIoctlsLast = iop->prev;
+                               iop->prev->next = NULL;
+                       } else
+                               iop->next->prev = iop->prev;
+               }
+               free(iop);
+       }
+    lock_ReleaseWrite(&RDR_globalIoctlLock);
+
+}
+
+/* called when we receive a write call.  If this is the first write call after
+ * a series of reads (or the very first call), then we start a new call.
+ * We also ensure that things are properly initialized for the start of a call.
+ */
+void
+RDR_IoctlPrepareWrite(RDR_ioctl_t *ioctlp)
+{
+    /* make sure the buffer(s) are allocated */
+    if (!ioctlp->ioctl.inAllocp)
+        ioctlp->ioctl.inAllocp = malloc(CM_IOCTL_MAXDATA);
+    if (!ioctlp->ioctl.outAllocp)
+        ioctlp->ioctl.outAllocp = malloc(CM_IOCTL_MAXDATA);
+
+    /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
+    (void) memset(ioctlp->ioctl.inAllocp, 0, CM_IOCTL_MAXDATA);
+    (void) memset(ioctlp->ioctl.outAllocp, 0, CM_IOCTL_MAXDATA);
+
+    /* and make sure that we've reset our state for the new incoming request */
+    if (!(ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN)) {
+        ioctlp->ioctl.inCopied = 0;
+        ioctlp->ioctl.outCopied = 0;
+        ioctlp->ioctl.inDatap = ioctlp->ioctl.inAllocp;
+        ioctlp->ioctl.outDatap = ioctlp->ioctl.outAllocp;
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_DATAIN;
+    }
+}
+
+/* called when we receive a read call, does the send of the received data if
+ * this is the first read call.  This is the function that actually makes the
+ * call to the ioctl code.
+ */
+afs_int32
+RDR_IoctlPrepareRead(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
+{
+    afs_int32 opcode;
+    RDR_ioctlProc_t *procp = NULL;
+    afs_int32 code;
+
+    if (ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN) {
+        ioctlp->ioctl.flags &= ~CM_IOCTLFLAG_DATAIN;
+
+        /* do the call now, or fail if we didn't get an opcode, or
+         * enough of an opcode.
+         */
+        if (ioctlp->ioctl.inCopied < sizeof(afs_int32))
+            return CM_ERROR_INVAL;
+
+        memcpy(&opcode, ioctlp->ioctl.inDatap, sizeof(afs_int32));
+        ioctlp->ioctl.inDatap += sizeof(afs_int32);
+
+        osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
+
+        /* check for opcode out of bounds */
+        if (opcode < 0 || opcode >= CM_IOCTL_MAXPROCS)
+            return CM_ERROR_TOOBIG;
+
+        /* check for no such proc */
+       procp = RDR_ioctlProcsp[opcode];
+        if (procp == NULL)
+            return CM_ERROR_BADOP;
+
+        /* otherwise, make the call */
+        ioctlp->ioctl.outDatap += sizeof(afs_int32); /* reserve room for return code */
+        code = (*procp)(ioctlp, userp, pflags);
+
+        osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
+
+        /* copy in return code */
+        memcpy(ioctlp->ioctl.outAllocp, &code, sizeof(afs_int32));
+    }
+    return 0;
+}
+
+RDR_ioctl_t *
+RDR_FindIoctl(ULONG index)
+{
+    RDR_ioctl_t *iop;
+
+    lock_ObtainRead(&RDR_globalIoctlLock);
+    for ( iop=RDR_allIoctls; iop; iop=iop->next) {
+        if (iop->index == index)
+            break;
+    }
+    lock_ReleaseRead(&RDR_globalIoctlLock);
+    return iop;
+}
+
+/* called from RDR_ReceiveCoreRead when we receive a read on the ioctl fid */
+afs_int32
+RDR_IoctlRead(cm_user_t *userp, ULONG RequestId, ULONG BufferLength, void *MappedBuffer, ULONG *pBytesProcessed, cm_req_t *reqp, afs_uint32 pflags)
+{
+    RDR_ioctl_t *iop;
+    afs_uint32 count;
+    afs_int32 code;
+
+    iop = RDR_FindIoctl(RequestId);
+    if (iop == NULL)
+        return CM_ERROR_BADFD;
+
+    /* turn the connection around, if required */
+    code = RDR_IoctlPrepareRead(iop, userp, pflags);
+    if (code)
+        return code;
+
+    count = (afs_int32)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
+    if (BufferLength < count)
+        count = BufferLength;
+
+    /* now copy the data into the response packet */
+    memcpy((char *)MappedBuffer, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
+
+    /* and adjust the counters */
+    iop->ioctl.outCopied += count;
+
+    *pBytesProcessed = count;
+
+    return 0;
+}
+
+/* called from RDR_PioctWRite when we receive a write call on the IOCTL
+ * file descriptor.
+ */
+afs_int32
+RDR_IoctlWrite(cm_user_t *userp, ULONG RequestId, ULONG BufferLength, void *MappedBuffer, cm_req_t *reqp)
+{
+    RDR_ioctl_t *iop;
+
+    iop = RDR_FindIoctl(RequestId);
+    if (iop == NULL)
+        return CM_ERROR_BADFD;
+
+    RDR_IoctlPrepareWrite(iop);
+
+    if (BufferLength + iop->ioctl.inCopied > CM_IOCTL_MAXDATA)
+        return CM_ERROR_TOOBIG;
+
+    /* copy data */
+    memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, (char *)MappedBuffer, BufferLength);
+
+    /* adjust counts */
+    iop->ioctl.inCopied += BufferLength;
+
+    return 0;
+}
+
+
+/* parse the passed-in file name and do a namei on it.  If we fail,
+ * return an error code, otherwise return the vnode located in *scpp.
+ */
+#define CM_PARSE_FLAG_LITERAL 1
+
+afs_int32
+RDR_ParseIoctlPath(RDR_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                   cm_scache_t **scpp, afs_uint32 flags)
+{
+    afs_int32 code;
+    cm_scache_t *substRootp = NULL;
+    cm_scache_t *iscp = NULL;
+    char     *inPath;
+    wchar_t     *relativePath = NULL;
+    wchar_t     *lastComponent = NULL;
+    afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
+    int free_path = FALSE;
+
+    inPath = ioctlp->ioctl.inDatap;
+    /* setup the next data value for the caller to use */
+    ioctlp->ioctl.inDatap += (long)strlen(ioctlp->ioctl.inDatap) + 1;;
+
+    osi_Log1(afsd_logp, "RDR_ParseIoctlPath inPath %s", osi_LogSaveString(afsd_logp,inPath));
+
+    /* This is usually the file name, but for StatMountPoint it is the path. */
+    /* ioctlp->inDatap can be either of the form:
+     *    \path\.
+     *    \path\file
+     *    \\netbios-name\submount\path\.
+     *    \\netbios-name\submount\path\file
+     */
+
+    /* We do not perform path name translation on the ioctl path data
+     * because these paths were not translated by Windows through the
+     * file system API.  Therefore, they are not OEM characters but
+     * whatever the display character set is.
+     */
+
+    // TranslateExtendedChars(relativePath);
+
+    /* This is usually nothing, but for StatMountPoint it is the file name. */
+    // TranslateExtendedChars(ioctlp->ioctl.inDatap);
+
+    /* If the string starts with our UTF-8 prefix (which is the
+       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+       strings), we assume that the provided path is UTF-8.  Otherwise
+       we have to convert the string to UTF-8, since that is what we
+       want to use everywhere else.*/
+
+    if (memcmp(inPath, utf8_prefix, utf8_prefix_size) == 0) {
+        /* String is UTF-8 */
+        inPath += utf8_prefix_size;
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
+
+        relativePath = cm_Utf8ToClientStringAlloc(inPath, -1, NULL);
+        osi_Log1(afsd_logp, "RDR_ParseIoctlPath UTF8 relativePath %S",
+                 osi_LogSaveStringW(afsd_logp,relativePath));
+    } else {
+        int cch;
+        /* Not a UTF-8 string */
+        /* TODO: If this is an OEM string, we should convert it to UTF-8. */
+        if (smb_StoreAnsiFilenames) {
+            cch = cm_AnsiToClientString(inPath, -1, NULL, 0);
+#ifdef DEBUG
+            osi_assert(cch > 0);
+#endif
+            relativePath = malloc(cch * sizeof(clientchar_t));
+            cm_AnsiToClientString(inPath, -1, relativePath, cch);
+        } else {
+            TranslateExtendedChars(inPath);
+
+            cch = cm_OemToClientString(inPath, -1, NULL, 0);
+#ifdef DEBUG
+            osi_assert(cch > 0);
+#endif
+            relativePath = malloc(cch * sizeof(clientchar_t));
+            cm_OemToClientString(inPath, -1, relativePath, cch);
+        }
+        osi_Log1(afsd_logp, "RDR_ParseIoctlPath ASCII relativePath %S",
+                 osi_LogSaveStringW(afsd_logp,relativePath));
+    }
+
+    if (relativePath[0] == relativePath[1] &&
+         relativePath[1] == '\\' &&
+         !cm_ClientStrCmpNI(RDR_UNCName,relativePath+2,(int)wcslen(RDR_UNCName)))
+    {
+        wchar_t shareName[256];
+        wchar_t *sharePath;
+        int shareFound, i;
+        wchar_t *p;
+
+        /* We may have found a UNC path.
+         * If the first component is the RDR UNC Name,
+         * then throw out the second component (the submount)
+         * since it had better expand into the value of ioctl->tidPathp
+         */
+        p = relativePath + 2 + wcslen(RDR_UNCName) + 1;                        /* buffer overflow vuln.? */
+        if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
+            p += 4;
+
+        for (i = 0; *p && *p != '\\'; i++,p++ ) {
+            shareName[i] = *p;
+        }
+        p++;                    /* skip past trailing slash */
+        shareName[i] = 0;       /* terminate string */
+
+        shareFound = smb_FindShare(NULL, NULL, shareName, &sharePath);
+        if ( shareFound ) {
+            /* we found a sharename, therefore use the resulting path */
+            code = cm_NameI(cm_RootSCachep(userp, reqp), sharePath,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, &substRootp);
+            free(sharePath);
+            if (code) {
+               osi_Log1(afsd_logp,"RDR_ParseIoctlPath [1] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+
+           lastComponent = cm_ClientStrRChr(p, '\\');
+           if (lastComponent && (lastComponent - p) > 1 && wcslen(lastComponent) > 1) {
+               *lastComponent = '\0';
+               lastComponent++;
+
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                userp, NULL, reqp, &iscp);
+               if (code == 0)
+                   code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+                                   userp, NULL, reqp, scpp);
+               if (iscp)
+                   cm_ReleaseSCache(iscp);
+           } else {
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
+                               userp, NULL, reqp, scpp);
+           }
+           cm_ReleaseSCache(substRootp);
+            if (code) {
+               osi_Log1(afsd_logp,"RDR_ParseIoctlPath [2] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+        } else {
+            /* otherwise, treat the name as a cellname mounted off the afs root.
+             * This requires that we reconstruct the shareName string with
+             * leading and trailing slashes.
+             */
+            p = relativePath + 2 + wcslen(RDR_UNCName) + 1;
+            if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
+                p += 4;
+
+            shareName[0] = '/';
+            for (i = 1; *p && *p != '\\'; i++,p++ ) {
+                shareName[i] = *p;
+            }
+            p++;                    /* skip past trailing slash */
+            shareName[i++] = '/';      /* add trailing slash */
+            shareName[i] = 0;       /* terminate string */
+
+
+            code = cm_NameI(cm_RootSCachep(userp, reqp), shareName,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, &substRootp);
+            if (code) {
+               osi_Log1(afsd_logp,"RDR_ParseIoctlPath [3] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+
+           lastComponent = cm_ClientStrRChr(p, '\\');
+           if (lastComponent && (lastComponent - p) > 1 && wcslen(lastComponent) > 1) {
+               *lastComponent = '\0';
+               lastComponent++;
+
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                userp, NULL, reqp, &iscp);
+               if (code == 0)
+                   code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+                                   userp, NULL, reqp, scpp);
+               if (iscp)
+                   cm_ReleaseSCache(iscp);
+           } else {
+               code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
+                               userp, NULL, reqp, scpp);
+           }
+
+           if (code) {
+               cm_ReleaseSCache(substRootp);
+               osi_Log1(afsd_logp,"RDR_ParseIoctlPath code [4] 0x%x", code);
+                if (free_path)
+                    free(relativePath);
+                return code;
+           }
+        }
+    } else {
+        code = cm_GetSCache(&ioctlp->parentFid, &substRootp, userp, reqp);
+        if (code) {
+           osi_Log1(afsd_logp,"RDR_ParseIoctlPath [6] code 0x%x", code);
+            if (free_path)
+                free(relativePath);
+            return code;
+       }
+
+       lastComponent = cm_ClientStrRChr(relativePath, '\\');
+       if (lastComponent && (lastComponent - relativePath) > 1 && wcslen(lastComponent) > 1) {
+           *lastComponent = '\0';
+           lastComponent++;
+
+           code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                            userp, NULL, reqp, &iscp);
+           if (code == 0)
+               code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+                                userp, NULL, reqp, scpp);
+           if (iscp)
+               cm_ReleaseSCache(iscp);
+       } else {
+           code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
+                            userp, NULL, reqp, scpp);
+       }
+        if (code) {
+           cm_ReleaseSCache(substRootp);
+           osi_Log1(afsd_logp,"RDR_ParseIoctlPath [7] code 0x%x", code);
+            if (free_path)
+                free(relativePath);
+            return code;
+       }
+    }
+
+    if (substRootp)
+       cm_ReleaseSCache(substRootp);
+
+    if (free_path)
+        free(relativePath);
+
+    /* Ensure that the status object is up to date */
+    lock_ObtainWrite(&(*scpp)->rw);
+    code = cm_SyncOp( *scpp, NULL, userp, reqp, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code == 0)
+        cm_SyncOpDone( *scpp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&(*scpp)->rw);
+
+    /* and return success */
+    osi_Log1(afsd_logp,"RDR_ParseIoctlPath [8] code 0x%x", code);
+    return 0;
+}
+
+
+
+#define LEAF_SIZE 256
+/* parse the passed-in file name and do a namei on its parent.  If we fail,
+ * return an error code, otherwise return the vnode located in *scpp.
+ */
+afs_int32
+RDR_ParseIoctlParent(RDR_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                     cm_scache_t **scpp, wchar_t *leafp)
+{
+    afs_int32 code;
+    clientchar_t tbuffer[1024];
+    clientchar_t *tp, *jp;
+    cm_scache_t *substRootp = NULL;
+    clientchar_t *inpathp;
+    char *inpathdatap;
+    int free_path = FALSE;
+
+    inpathdatap = ioctlp->ioctl.inDatap;
+
+    /* If the string starts with our UTF-8 prefix (which is the
+       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+       strings), we assume that the provided path is UTF-8.  Otherwise
+       we have to convert the string to UTF-8, since that is what we
+       want to use everywhere else.*/
+
+    if (memcmp(inpathdatap, utf8_prefix, utf8_prefix_size) == 0) {
+        /* String is UTF-8 */
+        inpathdatap += utf8_prefix_size;
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
+
+        inpathp = cm_Utf8ToClientStringAlloc(inpathdatap, -1, NULL);
+        osi_Log1(afsd_logp, "RDR_ParseIoctlParent UTF8 inpathp %S",
+                  osi_LogSaveStringW(afsd_logp, inpathp));
+    } else {
+        int cch;
+
+        /* Not a UTF-8 string */
+        /* TODO: If this is an OEM string, we should convert it to
+           UTF-8. */
+        if (smb_StoreAnsiFilenames) {
+            cch = cm_AnsiToClientString(inpathdatap, -1, NULL, 0);
+#ifdef DEBUG
+            osi_assert(cch > 0);
+#endif
+            inpathp = malloc(cch * sizeof(clientchar_t));
+            cm_AnsiToClientString(inpathdatap, -1, inpathp, cch);
+        } else {
+            TranslateExtendedChars(inpathdatap);
+
+            cch = cm_OemToClientString(inpathdatap, -1, NULL, 0);
+#ifdef DEBUG
+            osi_assert(cch > 0);
+#endif
+            inpathp = malloc(cch * sizeof(clientchar_t));
+            cm_OemToClientString(inpathdatap, -1, inpathp, cch);
+        }
+        osi_Log1(afsd_logp, "RDR_ParseIoctlParent ASCII inpathp %S",
+                 osi_LogSaveStringW(afsd_logp, inpathp));
+    }
+
+    cm_ClientStrCpy(tbuffer, lengthof(tbuffer), inpathp);
+    tp = cm_ClientStrRChr(tbuffer, '\\');
+    jp = cm_ClientStrRChr(tbuffer, '/');
+    if (!tp)
+        tp = jp;
+    else if (jp && (tp - tbuffer) < (jp - tbuffer))
+        tp = jp;
+    if (!tp) {
+        cm_ClientStrCpy(tbuffer, lengthof(tbuffer), _C("\\"));
+        if (leafp)
+            cm_ClientStrCpy(leafp, LEAF_SIZE, inpathp);
+    }
+    else {
+        *tp = 0;
+        if (leafp)
+            cm_ClientStrCpy(leafp, LEAF_SIZE, tp+1);
+    }
+
+    if (free_path)
+        free(inpathp);
+    inpathp = NULL;             /* We don't need this from this point on */
+
+    if (tbuffer[0] == tbuffer[1] &&
+        tbuffer[1] == '\\' &&
+        !cm_ClientStrCmpNI(RDR_UNCName,tbuffer+2, (int)wcslen(RDR_UNCName)))
+    {
+        wchar_t shareName[256];
+        wchar_t *sharePath;
+        int shareFound, i;
+
+        /* We may have found a UNC path.
+         * If the first component is the UNC Name,
+         * then throw out the second component (the submount)
+         * since it had better expand into the value of ioctl->tidPathp
+         */
+        clientchar_t * p;
+        p = tbuffer + 2 + cm_ClientStrLen(RDR_UNCName) + 1;
+        if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
+            p += 4;
+
+        for (i = 0; *p && *p != '\\'; i++,p++ ) {
+            shareName[i] = *p;
+        }
+        p++;                    /* skip past trailing slash */
+        shareName[i] = 0;       /* terminate string */
+
+        shareFound = smb_FindShare(NULL, NULL, shareName, &sharePath);
+        if ( shareFound ) {
+            /* we found a sharename, therefore use the resulting path */
+            code = cm_NameI(cm_RootSCachep(userp, reqp), sharePath,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, &substRootp);
+            free(sharePath);
+            if (code) {
+               osi_Log1(afsd_logp,"RDR_ParseIoctlParent [1] code 0x%x", code);
+                return code;
+            }
+            code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, scpp);
+           cm_ReleaseSCache(substRootp);
+            if (code) {
+               osi_Log1(afsd_logp,"RDR_ParseIoctlParent [2] code 0x%x", code);
+                return code;
+            }
+        } else {
+            /* otherwise, treat the name as a cellname mounted off the afs root.
+             * This requires that we reconstruct the shareName string with
+             * leading and trailing slashes.
+             */
+            p = tbuffer + 2 + wcslen(RDR_UNCName) + 1;
+            if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
+                p += 4;
+
+            shareName[0] = '/';
+            for (i = 1; *p && *p != '\\'; i++,p++ ) {
+                shareName[i] = *p;
+            }
+            p++;                    /* skip past trailing slash */
+            shareName[i++] = '/';      /* add trailing slash */
+            shareName[i] = 0;       /* terminate string */
+
+            code = cm_NameI(cm_RootSCachep(userp, reqp), shareName,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, &substRootp);
+            if (code) {
+               osi_Log1(afsd_logp,"RDR_ParseIoctlParent [3] code 0x%x", code);
+                return code;
+            }
+            code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                            userp, NULL, reqp, scpp);
+           cm_ReleaseSCache(substRootp);
+            if (code) {
+               osi_Log1(afsd_logp,"RDR_ParseIoctlParent [4] code 0x%x", code);
+                return code;
+            }
+        }
+    } else {
+        code = cm_GetSCache(&ioctlp->rootFid, &substRootp, userp, reqp);
+        if (code) {
+            osi_Log1(afsd_logp,"RDR_ParseIoctlParent [5] code 0x%x", code);
+            return code;
+        }
+        code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                        userp, NULL, reqp, scpp);
+       cm_ReleaseSCache(substRootp);
+        if (code) {
+            osi_Log1(afsd_logp,"RDR_ParseIoctlParent [6] code 0x%x", code);
+            return code;
+        }
+    }
+
+    /* # of bytes of path */
+    code = (long)strlen(ioctlp->ioctl.inDatap) + 1;
+    ioctlp->ioctl.inDatap += code;
+
+    /* Ensure that the status object is up to date */
+    lock_ObtainWrite(&(*scpp)->rw);
+    code = cm_SyncOp( *scpp, NULL, userp, reqp, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code == 0)
+        cm_SyncOpDone( *scpp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&(*scpp)->rw);
+
+    /* and return success */
+    osi_Log1(afsd_logp,"RDR_ParseIoctlParent [7] code 0x%x", code);
+    return 0;
+}
+
+afs_int32
+RDR_IoctlSetToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    char *saveDataPtr;
+    char *tp;
+    int ticketLen;
+    char *ticket;
+    int ctSize;
+    struct ClearToken ct;
+    cm_cell_t *cellp;
+    cm_ucell_t *ucellp;
+    afs_uuid_t uuid;
+    int flags;
+    char sessionKey[8];
+    wchar_t *smbname = NULL;
+    wchar_t *uname = NULL;
+    afs_uint32 code = 0;
+    int release_userp = 0;
+
+    saveDataPtr = ioctlp->ioctl.inDatap;
+
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    tp = ioctlp->ioctl.inDatap;
+
+    /* ticket length */
+    memcpy(&ticketLen, tp, sizeof(ticketLen));
+    tp += sizeof(ticketLen);
+    if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN) {
+        code = CM_ERROR_INVAL;
+        goto done;
+    }
+
+    /* remember ticket and skip over it for now */
+    ticket = tp;
+    tp += ticketLen;
+
+    /* clear token size */
+    memcpy(&ctSize, tp, sizeof(ctSize));
+    tp += sizeof(ctSize);
+    if (ctSize != sizeof(struct ClearToken)) {
+        code = CM_ERROR_INVAL;
+        goto done;
+    }
+
+    /* clear token */
+    memcpy(&ct, tp, ctSize);
+    tp += ctSize;
+    if (ct.AuthHandle == -1)
+        ct.AuthHandle = 999;   /* more rxvab compat stuff */
+
+    /* more stuff, if any */
+    if (ioctlp->ioctl.inCopied > tp - saveDataPtr) {
+        /* flags:  logon flag */
+        memcpy(&flags, tp, sizeof(int));
+        tp += sizeof(int);
+
+        /* cell name */
+        cellp = cm_GetCell(tp, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
+        if (!cellp) {
+            code = CM_ERROR_NOSUCHCELL;
+            goto done;
+        }
+        tp += strlen(tp) + 1;
+
+        /* user name */
+        uname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
+        tp += strlen(tp) + 1;
+
+        if (flags & PIOCTL_LOGON) {
+            /* SMB user name with which to associate tokens */
+            smbname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
+            tp += strlen(tp) + 1;
+            osi_Log2(afsd_logp,"RDR_IoctlSetToken for user [%S] smbname [%S]",
+                     osi_LogSaveStringW(afsd_logp,uname),
+                     osi_LogSaveStringW(afsd_logp,smbname));
+        } else {
+            osi_Log1(afsd_logp,"RDR_IoctlSetToken for user [%S]",
+                     osi_LogSaveStringW(afsd_logp, uname));
+        }
+
+        /* uuid */
+        memcpy(&uuid, tp, sizeof(uuid));
+        if (!cm_FindTokenEvent(uuid, sessionKey, NULL)) {
+            code = CM_ERROR_INVAL;
+            goto done;
+        }
+
+#if defined(NO_AUTH_GROUPS)
+        /* after obtaining the session key check whether we can use it */
+        if (!(pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
+            code = CM_ERROR_NOACCESS;
+            goto done;
+        }
+#endif
+    } else {
+        cellp = cm_data.rootCellp;
+        osi_Log0(afsd_logp,"cm_IoctlSetToken - no name specified");
+    }
+
+#if defined(NO_AUTH_GROUPS)
+    if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
+        wchar_t cname[MAX_COMPUTERNAME_LENGTH+1];
+        int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
+        PSID pSid = NULL;
+        DWORD dwSize1, dwSize2;
+        wchar_t *pszRefDomain = NULL;
+        SID_NAME_USE snu = SidTypeGroup;
+        clientchar_t * secSidString = NULL;
+        DWORD gle;
+
+        GetComputerNameW(cname, &cnamelen);
+        wcsupr(cname);
+
+        /*
+         * The input name is probably not a SID for the user which is how
+         * the user is now being identified as a result of the SMB
+         * extended authentication.  See if we can obtain the SID for the
+         * specified name.  If we can, use that instead of the name
+         * provided.
+         */
+
+        dwSize1 = dwSize2 = 0;
+        LookupAccountNameW( NULL /* System Name to begin Search */,
+                            smbname,
+                            NULL, &dwSize1,
+                            NULL, &dwSize2,
+                            &snu);
+        gle = GetLastError();
+        if (gle == ERROR_INSUFFICIENT_BUFFER) {
+            pSid = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwSize1);
+            /*
+             * Although dwSize2 is supposed to include the terminating
+             * NUL character, on Win7 it does not.
+             */
+            pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
+        }
+
+        if ( pSid && pszRefDomain ) {
+            if (LookupAccountNameW( NULL /* System Name to begin Search */,
+                                    smbname,
+                                    pSid, &dwSize1,
+                                    pszRefDomain, &dwSize2,
+                                    &snu))
+                ConvertSidToStringSidW(pSid, &secSidString);
+        }
+
+        if (secSidString) {
+            userp = smb_FindCMUserBySID( secSidString, cname,
+                                         SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+            LocalFree(secSidString);
+        } else {
+            if (pSid) {
+                LocalFree(pSid);
+                pSid = NULL;
+            }
+
+            if (!ConvertStringSidToSidW( smbname, &pSid)) {
+                userp = smb_FindCMUserBySID( smbname, cname,
+                                             SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+            } else {
+                userp = smb_FindCMUserByName( smbname, cname,
+                                              SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+            }
+        }
+
+        if (pSid)
+            LocalFree(pSid);
+        if (pszRefDomain)
+            free(pszRefDomain);
+
+       release_userp = 1;
+    }
+#endif
+
+    /* store the token */
+    lock_ObtainMutex(&userp->mx);
+    ucellp = cm_GetUCell(userp, cellp);
+    osi_Log1(afsd_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
+    ucellp->ticketLen = ticketLen;
+    if (ucellp->ticketp)
+        free(ucellp->ticketp); /* Discard old token if any */
+    ucellp->ticketp = malloc(ticketLen);
+    memcpy(ucellp->ticketp, ticket, ticketLen);
+    /*
+     * Get the session key from the RPC, rather than from the pioctl.
+     */
+    /*
+    memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
+    */
+    memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
+    ucellp->kvno = ct.AuthHandle;
+    ucellp->expirationTime = ct.EndTimestamp;
+    ucellp->gen++;
+#ifdef QUERY_AFSID
+    ucellp->uid = ANONYMOUSID;
+#endif
+    if (uname) {
+        cm_ClientStringToFsString(uname, -1, ucellp->userName, MAXKTCNAMELEN);
+#ifdef QUERY_AFSID
+       cm_UsernameToId(uname, ucellp, &ucellp->uid);
+#endif
+    }
+    ucellp->flags |= CM_UCELLFLAG_RXKAD;
+    lock_ReleaseMutex(&userp->mx);
+
+    if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_LOGON;
+    }
+
+    cm_ResetACLCache(cellp, userp);
+
+  done:
+    SecureZeroMemory(sessionKey, sizeof(sessionKey));
+
+    if (release_userp)
+       cm_ReleaseUser(userp);
+
+    if (uname)
+        free(uname);
+
+    if (smbname)
+        free(smbname);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetACL(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
+{
+    cm_scache_t *scp;
+    afs_int32 code;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetACL(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32
+RDR_IoctlSetACL(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
+{
+    cm_scache_t *scp;
+    afs_int32 code;
+    cm_req_t req;
+
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    if (code)
+        return code;
+
+    code = cm_IoctlSetACL(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetFileCellName(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetFileCellName(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlFlushAllVolumes(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    cm_SkipIoctlPath(&ioctlp->ioctl);  /* we don't care about the path */
+
+    return cm_IoctlFlushAllVolumes(&ioctlp->ioctl, userp, &req);
+}
+
+afs_int32
+RDR_IoctlFlushVolume(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlFlushVolume(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlFlushFile(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+       cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlFlushFile(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32
+RDR_IoctlSetVolumeStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
+    if (code) return code;
+
+    code = cm_IoctlSetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetVolumeStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetFid(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t * optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    if (code)
+        return code;
+
+    code = cm_IoctlGetFid(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetFileType(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t * optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetFileType(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetOwner(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetOwner(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlWhereIs(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlWhereIs(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+
+afs_int32
+RDR_IoctlStatMountPoint(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code)
+        return code;
+
+    code = cm_IoctlStatMountPoint(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlDeleteMountPoint(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code)
+        return code;
+
+    code = cm_IoctlDeleteMountPoint(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlCheckServers(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);  /* we don't care about the path */
+
+    return cm_IoctlCheckServers(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGag(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    /* we don't print anything superfluous, so we don't support the gag call */
+    return CM_ERROR_INVAL;
+}
+
+afs_int32
+RDR_IoctlCheckVolumes(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlCheckVolumes(&ioctlp->ioctl, userp);
+}
+
+afs_int32 RDR_IoctlSetCacheSize(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetCacheSize(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+RDR_IoctlTraceControl(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlTraceControl(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGetCacheParms(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetCacheParms(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGetCell(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetCell(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlNewCell(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlNewCell(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlNewCell2(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlNewCell2(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGetWsCell(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetWsCell(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlSysName(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSysName(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGetCellStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetCellStatus(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlSetCellStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetCellStatus(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlSetSPrefs(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetSPrefs(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGetSPrefs(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetSPrefs(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlStoreBehind(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    /* we ignore default asynchrony since we only have one way
+     * of doing this today.
+     */
+    return 0;
+}
+
+afs_int32
+RDR_IoctlCreateMountPoint(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    wchar_t leaf[LEAF_SIZE];
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
+    if (code)
+        return code;
+
+    code = cm_IoctlCreateMountPoint(&ioctlp->ioctl, userp, dscp, &req, leaf);
+
+    cm_ReleaseSCache(dscp);
+    return code;
+}
+
+afs_int32
+RDR_IoctlSymlink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    wchar_t leaf[LEAF_SIZE];
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
+    if (code) return code;
+
+    code = cm_IoctlSymlink(&ioctlp->ioctl, userp, dscp, &req, leaf);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlListlink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code) return code;
+
+    code = cm_IoctlListlink(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+    return code;
+}
+
+afs_int32
+RDR_IoctlIslink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{/*CHECK FOR VALID SYMLINK*/
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code) return code;
+
+    code = cm_IoctlIslink(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlDeletelink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *dscp;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
+    if (code) return code;
+
+    code = cm_IoctlDeletelink(&ioctlp->ioctl, userp, dscp, &req);
+
+    cm_ReleaseSCache(dscp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetTokenIter(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetTokenIter(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGetToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetToken(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+RDR_IoctlDelToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlDelToken(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+RDR_IoctlDelAllToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlDelAllToken(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+RDR_IoctlMakeSubmount(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlMakeSubmount(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlGetRxkcrypt(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetRxkcrypt(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlSetRxkcrypt(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetRxkcrypt(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlRxStatProcess(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlRxStatProcess(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+RDR_IoctlRxStatPeer(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlRxStatPeer(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlUnicodeControl(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlUnicodeControl(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlUUIDControl(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlUUIDControl(&ioctlp->ioctl, userp);
+}
+
+
+afs_int32
+RDR_IoctlMemoryDump(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlMemoryDump(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+RDR_IoctlPathAvailability(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlPathAvailability(&ioctlp->ioctl, userp, scp, &req);
+    cm_ReleaseSCache(scp);
+    return code;
+}
+
+afs_int32
+RDR_IoctlVolStatTest(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_req_t req;
+
+    cm_InitReq(&req);
+
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlVolStatTest(&ioctlp->ioctl, userp, &req);
+}
+
+/*
+ * VIOC_SETOWNER
+ *
+ * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
+ *
+ */
+afs_int32
+RDR_IoctlSetOwner(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp) {
+        if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+            flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+        if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+            cm_fid_t fid;
+            cm_SkipIoctlPath(&ioctlp->ioctl);
+            cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                       optionsp->fid.vnode, optionsp->fid.unique);
+            code = cm_GetSCache(&fid, &scp, userp, &req);
+        } else {
+            code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+        }
+        if (code)
+            return code;
+
+        cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
+    }
+
+    code = cm_IoctlSetOwner(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+/*
+ * VIOC_SETGROUP
+ *
+ * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
+ *
+ */
+afs_int32
+RDR_IoctlSetGroup(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp) {
+        if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+            flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+        if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+            cm_fid_t fid;
+            cm_SkipIoctlPath(&ioctlp->ioctl);
+            cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                       optionsp->fid.vnode, optionsp->fid.unique);
+            code = cm_GetSCache(&fid, &scp, userp, &req);
+        } else {
+            code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+        }
+        if (code)
+            return code;
+
+        cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
+    }
+
+    code = cm_IoctlSetGroup(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+RDR_IoctlGetUnixMode(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    cm_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, &scp, userp, &req);
+    } else {
+        code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetUnixMode(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+/*
+ * VIOC_SETUNIXMODE
+ *
+ * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
+ *
+ */
+afs_int32
+RDR_IoctlSetUnixMode(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp) {
+        if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+            flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+        if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+            cm_fid_t fid;
+            cm_SkipIoctlPath(&ioctlp->ioctl);
+            cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                       optionsp->fid.vnode, optionsp->fid.unique);
+            code = cm_GetSCache(&fid, &scp, userp, &req);
+        } else {
+            code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+        }
+        if (code)
+            return code;
+
+        cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
+    }
+
+    code = cm_IoctlSetUnixMode(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
diff --git a/src/WINNT/afsrdr/user/RDRIoctl.h b/src/WINNT/afsrdr/user/RDRIoctl.h
new file mode 100644 (file)
index 0000000..9944627
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints, Inc.
+ * Copyright (c) 2009-2011 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+extern void RDR_InitIoctl(void);
+
+extern void RDR_SetupIoctl(ULONG index, cm_fid_t *parentFid, cm_fid_t *rootFid, cm_user_t *userp);
+
+extern void RDR_CleanupIoctl(ULONG index);
+
+extern afs_int32 RDR_IoctlRead(cm_user_t *userp, ULONG RequestId, ULONG BufferLength, void *MappedBuffer,
+                               ULONG *pBytesProcessed, cm_req_t *reqp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlWrite(cm_user_t *userp, ULONG RequestId, ULONG BufferLength, void *MappedBuffer,
+                                cm_req_t *reqp);
+
+#ifdef RDR_IOCTL_PRIVATE
+typedef struct RDR_ioctl {
+    struct RDR_ioctl *next, *prev;
+    ULONG             index;
+    cm_fid_t          parentFid;
+    cm_fid_t          rootFid;
+    cm_scache_t      *parentScp;
+    cm_ioctl_t        ioctl;
+} RDR_ioctl_t;
+
+/* procedure implementing an ioctl */
+typedef long (RDR_ioctlProc_t)(RDR_ioctl_t *, struct cm_user *userp, afs_uint32 pflags);
+
+extern void RDR_IoctlPrepareWrite(RDR_ioctl_t *ioctlp);
+
+extern afs_int32 RDR_IoctlPrepareRead(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern RDR_ioctl_t *RDR_FindIoctl(ULONG index);
+
+extern afs_int32 RDR_ParseIoctlPath(RDR_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                                    cm_scache_t **scpp, afs_uint32 flags);
+
+extern afs_int32 RDR_ParseIoctlParent(RDR_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                                      cm_scache_t **scpp, wchar_t *leafp);
+
+extern afs_int32
+RDR_IoctlSetToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetACL(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetFileCellName(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetACL(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlFlushAllVolumes(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlFlushVolume(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlFlushFile(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetVolumeStatus(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetVolumeStatus(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetFid(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetOwner(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlWhereIs(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlStatMountPoint(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlDeleteMountPoint(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlCheckServers(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGag(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlCheckVolumes(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetCacheSize(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetCacheParms(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetCell(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlNewCell(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlNewCell2(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetWsCell(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSysName(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetCellStatus(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetCellStatus(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetSPrefs(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetSPrefs(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlStoreBehind(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlCreateMountPoint(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+
+extern afs_int32 cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+
+extern afs_int32 cm_FlushVolume(cm_user_t *, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume);
+
+extern afs_int32 cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
+
+extern afs_int32 RDR_IoctlTraceControl(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetToken(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetTokenIter(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetToken(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlDelToken(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlDelAllToken(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSymlink(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlIslink(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlListlink(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlDeletelink(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlMakeSubmount(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetRxkcrypt(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetRxkcrypt(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlShutdown(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlFreemountAddCell(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlFreemountRemoveCell(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlMemoryDump(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlRxStatProcess(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlRxStatPeer(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlUUIDControl(struct RDR_ioctl * ioctlp, struct cm_user *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlPathAvailability(struct RDR_ioctl * ioctlp, struct cm_user *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetFileType(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlVolStatTest(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlUnicodeControl(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetOwner(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetGroup(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlGetUnixMode(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetUnixMode(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+#endif
+
diff --git a/src/WINNT/afsrdr/user/RDRPipe.c b/src/WINNT/afsrdr/user/RDRPipe.c
new file mode 100644 (file)
index 0000000..f0f7685
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints, Inc.
+ * Copyright (c) 2009-2011 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <ntstatus.h>
+#define WIN32_NO_STATUS
+#include <roken.h>
+
+#include <afs/stds.h>
+
+#include <windows.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <strsafe.h>
+
+#include <osi.h>
+
+#include "afsd.h"
+
+#include "cm_rpc.h"
+#include "afs/afsrpc.h"
+#include "afs/auth.h"
+
+#include "msrpc.h"
+#define RDR_PIPE_PRIVATE
+#include "RDRPipe.h"
+#include "smb.h"
+#include "cm_nls.h"
+
+static RDR_pipe_t * RDR_allPipes = NULL, *RDR_allPipesLast = NULL;
+static osi_rwlock_t  RDR_globalPipeLock;
+static wchar_t       RDR_UNCName[64]=L"AFS";
+
+void
+RDR_InitPipe(void)
+{
+    lock_InitializeRWLock(&RDR_globalPipeLock, "RDR global pipe lock", LOCK_HIERARCHY_RDR_GLOBAL);
+}
+
+RDR_pipe_t *
+RDR_FindPipe(ULONG index, int locked)
+{
+    RDR_pipe_t *pipep;
+
+    if ( !locked)
+        lock_ObtainRead(&RDR_globalPipeLock);
+    for ( pipep=RDR_allPipes; pipep; pipep=pipep->next) {
+        if (pipep->index == index)
+            break;
+    }
+    if ( !locked)
+        lock_ReleaseRead(&RDR_globalPipeLock);
+    return pipep;
+}
+
+/* called to make a fid structure into an Pipe fid structure */
+DWORD
+RDR_SetupPipe( ULONG index, cm_fid_t *parentFid, cm_fid_t *rootFid,
+               WCHAR     *Name, DWORD      NameLength,
+               cm_user_t *userp)
+{
+    RDR_pipe_t *pipep;
+    cm_req_t req;
+    DWORD status;
+    char name[MAX_PATH];
+
+    cm_InitReq(&req);
+
+    lock_ObtainWrite(&RDR_globalPipeLock);
+    pipep = RDR_FindPipe(index, TRUE);
+
+    if (pipep) {
+        /* we are reusing a previous pipe */
+        if (cm_FidCmp(&pipep->parentFid, parentFid)) {
+            pipep->parentFid = *parentFid;
+            if (pipep->parentScp) {
+                cm_ReleaseSCache(pipep->parentScp);
+                pipep->parentScp = NULL;
+            }
+            cm_GetSCache(parentFid, &pipep->parentScp, userp, &req);
+            pipep->rootFid = *rootFid;
+        }
+    } else {
+        /* need to allocate a new one */
+        pipep = malloc(sizeof(*pipep));
+        if (pipep == NULL) {
+            status = STATUS_NO_MEMORY;
+            goto done;
+        }
+        memset(pipep, 0, sizeof(*pipep));
+        if (RDR_allPipes == NULL)
+            RDR_allPipes = RDR_allPipesLast = pipep;
+        else {
+            pipep->prev = RDR_allPipesLast;
+            RDR_allPipesLast->next = pipep;
+            RDR_allPipesLast = pipep;
+        }
+        pipep->index = index;
+        if (parentFid->cell == 0) {
+            pipep->parentFid = cm_data.rootFid;
+            pipep->parentScp = cm_RootSCachep(userp, &req);
+            cm_HoldSCache(pipep->parentScp);
+        } else {
+            pipep->parentFid = *parentFid;
+            cm_GetSCache(parentFid, &pipep->parentScp, userp, &req);
+        }
+        if (rootFid->cell == 0) {
+            pipep->rootFid = cm_data.rootFid;
+        } else {
+            pipep->rootFid = *rootFid;
+        }
+    }
+
+    StringCbCopyNW( pipep->name, sizeof(pipep->name), Name, NameLength);
+    cm_Utf16ToUtf8( pipep->name, -1, name, sizeof(name));
+
+    status = MSRPC_InitConn(&pipep->rpc_conn, name);
+    if (status == STATUS_SUCCESS) {
+        pipep->flags |= RDR_PIPEFLAG_MESSAGE_MODE;
+        pipep->devstate = RDR_DEVICESTATE_READMSGFROMPIPE |
+                          RDR_DEVICESTATE_MESSAGEMODEPIPE |
+                          RDR_DEVICESTATE_PIPECLIENTEND;
+    }
+
+  done:
+    lock_ReleaseWrite(&RDR_globalPipeLock);
+
+    return status;
+}
+
+
+void
+RDR_CleanupPipe(ULONG index)
+{
+    RDR_pipe_t *pipep;
+
+    lock_ObtainWrite(&RDR_globalPipeLock);
+    pipep = RDR_FindPipe(index, TRUE);
+
+    if (pipep) {
+        if (pipep->parentScp)
+            cm_ReleaseSCache(pipep->parentScp);
+
+        if (pipep->inAllocp)
+            free(pipep->inAllocp);
+        if (pipep->outAllocp)
+            free(pipep->outAllocp);
+
+        MSRPC_FreeConn(&pipep->rpc_conn);
+
+        if (RDR_allPipes == RDR_allPipesLast)
+            RDR_allPipes = RDR_allPipesLast = NULL;
+        else {
+            if (pipep->prev == NULL)
+                RDR_allPipes = pipep->next;
+            else
+                pipep->prev->next = pipep->next;
+            if (pipep->next == NULL) {
+                RDR_allPipesLast = pipep->prev;
+                pipep->prev->next = NULL;
+            } else
+                pipep->next->prev = pipep->prev;
+        }
+        free(pipep);
+    }
+    lock_ReleaseWrite(&RDR_globalPipeLock);
+
+}
+
+DWORD
+RDR_Pipe_Read(ULONG index, ULONG BufferLength, void *MappedBuffer,
+              ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp)
+{
+    RDR_pipe_t *pipep;
+    DWORD   code = STATUS_INVALID_PIPE_STATE;
+
+    lock_ObtainWrite(&RDR_globalPipeLock);
+    pipep = RDR_FindPipe(index, TRUE);
+
+    if (pipep) {
+        code = MSRPC_PrepareRead(&pipep->rpc_conn);
+        if (code == 0) {
+            *pBytesProcessed = MSRPC_ReadMessageLength(&pipep->rpc_conn, BufferLength);
+            code = MSRPC_ReadMessage(&pipep->rpc_conn, MappedBuffer, *pBytesProcessed);
+        }
+
+    }
+    lock_ReleaseWrite(&RDR_globalPipeLock);
+
+    return code;
+}
+
+DWORD
+RDR_Pipe_Write( ULONG index, ULONG BufferLength, void *MappedBuffer,
+                cm_req_t *reqp, cm_user_t *userp)
+{
+    RDR_pipe_t *pipep;
+    DWORD   code = STATUS_INVALID_PIPE_STATE;
+
+    lock_ObtainWrite(&RDR_globalPipeLock);
+    pipep = RDR_FindPipe(index, TRUE);
+
+    if (pipep) {
+        code = MSRPC_WriteMessage( &pipep->rpc_conn, MappedBuffer,
+                                   BufferLength, userp);
+    }
+    lock_ReleaseWrite(&RDR_globalPipeLock);
+
+    return code;
+}
+
+DWORD
+RDR_Pipe_QueryInfo( ULONG index, ULONG InfoClass,
+                    ULONG BufferLength, void *MappedBuffer,
+                    ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp)
+{
+    RDR_pipe_t *pipep;
+    DWORD   code = STATUS_INVALID_PIPE_STATE;
+    size_t      length;
+
+    lock_ObtainWrite(&RDR_globalPipeLock);
+    pipep = RDR_FindPipe(index, TRUE);
+
+    if (pipep) {
+        switch ( InfoClass ) {
+        case FileBasicInformation: {
+            FILE_BASIC_INFORMATION * fbInfo = (FILE_BASIC_INFORMATION *)MappedBuffer;
+
+            memset(fbInfo, 0, sizeof(FILE_BASIC_INFORMATION));
+            fbInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+            *pBytesProcessed = (DWORD)(sizeof(FILE_BASIC_INFORMATION));
+            code = STATUS_SUCCESS;
+            break;
+        }
+        case FileStandardInformation: {
+            FILE_STANDARD_INFORMATION * fsInfo = (FILE_STANDARD_INFORMATION *)MappedBuffer;
+
+            memset(fsInfo, 0, sizeof(FILE_STANDARD_INFORMATION));
+            *pBytesProcessed = (DWORD)(sizeof(FILE_STANDARD_INFORMATION));
+            code = STATUS_SUCCESS;
+            break;
+        }
+        case FileNameInformation: {
+            FILE_NAME_INFORMATION * fnInfo = (FILE_NAME_INFORMATION *)MappedBuffer;
+
+            StringCbLengthW(pipep->name, sizeof(pipep->name), &length);
+            if (BufferLength < sizeof(FILE_NAME_INFORMATION) + length) {
+                code = STATUS_BUFFER_OVERFLOW;
+                goto done;
+            }
+            fnInfo->FileNameLength = (DWORD)length;
+            memcpy( fnInfo->FileName, pipep->name, length);
+            *pBytesProcessed = (DWORD)(sizeof(DWORD) + length);
+            code = STATUS_SUCCESS;
+            break;
+        }
+        default:
+            code = STATUS_NOT_SUPPORTED;
+        }
+    }
+
+  done:
+    lock_ReleaseWrite(&RDR_globalPipeLock);
+
+    if (code)
+        *pBytesProcessed = 0;
+
+    return code;
+}
+
+DWORD
+RDR_Pipe_SetInfo( ULONG index, ULONG InfoClass,
+                  ULONG BufferLength, void *MappedBuffer,
+                  cm_req_t *reqp, cm_user_t *userp)
+{
+    RDR_pipe_t *pipep;
+    DWORD   code = STATUS_INVALID_PIPE_STATE;
+
+    lock_ObtainWrite(&RDR_globalPipeLock);
+    pipep = RDR_FindPipe(index, TRUE);
+
+    if (pipep) {
+        switch ( InfoClass ) {
+        case FilePipeInformation: {
+            FILE_PIPE_INFORMATION * fpInfo = (FILE_PIPE_INFORMATION *)MappedBuffer;
+
+            if (BufferLength != sizeof(FILE_PIPE_INFORMATION)) {
+                code = STATUS_INFO_LENGTH_MISMATCH;
+                goto done;
+            }
+
+            switch ( fpInfo->ReadMode ) {
+            case FILE_PIPE_BYTE_STREAM_MODE:
+                pipep->flags &= ~RDR_PIPEFLAG_MESSAGE_MODE;
+                break;
+            case FILE_PIPE_MESSAGE_MODE:
+                pipep->flags |= RDR_PIPEFLAG_MESSAGE_MODE;
+                break;
+            }
+            switch ( fpInfo->CompletionMode ) {
+            case FILE_PIPE_QUEUE_OPERATION:
+                pipep->flags |= RDR_PIPEFLAG_BLOCKING;
+                break;
+            case FILE_PIPE_COMPLETE_OPERATION:
+                pipep->flags &= ~RDR_PIPEFLAG_BLOCKING;
+                break;
+            }
+            code = STATUS_SUCCESS;
+            break;
+        }
+        default:
+            code = STATUS_NOT_SUPPORTED;
+        }
+    }
+  done:
+    lock_ReleaseWrite(&RDR_globalPipeLock);
+
+    return code;
+}
diff --git a/src/WINNT/afsrdr/user/RDRPipe.h b/src/WINNT/afsrdr/user/RDRPipe.h
new file mode 100644 (file)
index 0000000..740a2d5
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints, Inc.
+ * Copyright (c) 2009-2011 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+extern void RDR_InitPipe(void);
+
+extern DWORD RDR_SetupPipe( ULONG index, cm_fid_t *parentFid, cm_fid_t *rootFid,
+                            WCHAR *Name, DWORD NameLength,
+                            cm_user_t *userp);
+
+extern void RDR_CleanupPipe(ULONG index);
+
+extern DWORD RDR_Pipe_Read(ULONG index, ULONG BufferLength, void *MappedBuffer,
+                           ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp);
+
+extern DWORD RDR_Pipe_Write(ULONG index, ULONG BufferLength, void *MappedBuffer,
+                            cm_req_t *reqp, cm_user_t *userp);
+
+extern DWORD RDR_Pipe_QueryInfo( ULONG index, ULONG InfoClass,
+                                 ULONG BufferLength, void *MappedBuffer,
+                                 ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp);
+
+extern DWORD RDR_Pipe_SetInfo( ULONG index, ULONG InfoClass,
+                               ULONG BufferLength, void *MappedBuffer,
+                               cm_req_t *reqp, cm_user_t *userp);
+
+#ifdef RDR_PIPE_PRIVATE
+typedef struct RDR_pipe {
+    struct RDR_pipe *next, *prev;
+    ULONG             index;
+    wchar_t           name[MAX_PATH];
+    cm_fid_t          parentFid;
+    cm_fid_t          rootFid;
+    cm_scache_t      *parentScp;
+    afs_uint32        flags;
+    afs_uint32        devstate;
+    msrpc_conn        rpc_conn;
+
+    /* input side */
+    char *inDatap;                      /* current position
+                                         * in input parameter block */
+    char *inAllocp;                     /* allocated input parameter block */
+    afs_uint32 inCopied;                /* # of input bytes copied in so far
+                                         * by write calls */
+    /* output side */
+    char *outDatap;                     /* output results assembled so far */
+    char *outAllocp;                    /* output results assembled so far */
+    afs_uint32 outCopied;               /* # of output bytes copied back so far */
+} RDR_pipe_t;
+
+/* flags for smb_ioctl_t */
+#define RDR_PIPEFLAG_DATAIN     1       /* reading data from client to server */
+#define RDR_PIPEFLAG_LOGON      2       /* got tokens from integrated logon */
+#define RDR_PIPEFLAG_USEUTF8    4       /* this request is using UTF-8 strings */
+#define RDR_PIPEFLAG_DATAOUT    8       /* sending data from server to client */
+
+#define RDR_PIPEFLAG_RPC                0x0010
+#define RDR_PIPEFLAG_MESSAGE_MODE       0x0020
+#define RDR_PIPEFLAG_BLOCKING           0x0040
+#define RDR_PIPEFLAG_INCALL             0x0080
+
+/* Device state constants */
+#define RDR_DEVICESTATE_READASBYTESTREAM    0x0000
+#define RDR_DEVICESTATE_READMSGFROMPIPE     0x0100
+#define RDR_DEVICESTATE_BYTESTREAMPIPE      0x0000
+#define RDR_DEVICESTATE_MESSAGEMODEPIPE     0x0400
+#define RDR_DEVICESTATE_PIPECLIENTEND       0x0000
+#define RDR_DEVICESTATE_PIPESERVEREND       0x4000
+#define RDR_DEVICESTATE_BLOCKING            0x8000
+
+#define RDR_PIPE_MAXDATA        65536
+
+/* procedure implementing an pipe */
+typedef long (RDR_pipeProc_t)(RDR_pipe_t *, struct cm_user *userp);
+
+extern RDR_pipe_t *RDR_FindPipe(ULONG index, int locked);
+
+/*
+ * DDK Data Structures
+ *
+ * This is a userland module and does not include DDK headers.
+ * Replicate the DDK Data Structures required for pipe handling
+ * based on [MS-FSC]: File System Control Codes
+ *   http://msdn.microsoft.com/en-us/library/cc231987%28v=PROT.13%29.aspx
+ */
+typedef enum _FILE_INFORMATION_CLASS {
+    FileDirectoryInformation         = 1,
+    FileFullDirectoryInformation,   // 2
+    FileBothDirectoryInformation,   // 3
+    FileBasicInformation,           // 4
+    FileStandardInformation,        // 5
+    FileInternalInformation,        // 6
+    FileEaInformation,              // 7
+    FileAccessInformation,          // 8
+    FileNameInformation,            // 9
+    FileRenameInformation,          // 10
+    FileLinkInformation,            // 11
+    FileNamesInformation,           // 12
+    FileDispositionInformation,     // 13
+    FilePositionInformation,        // 14
+    FileFullEaInformation,          // 15
+    FileModeInformation,            // 16
+    FileAlignmentInformation,       // 17
+    FileAllInformation,             // 18
+    FileAllocationInformation,      // 19
+    FileEndOfFileInformation,       // 20
+    FileAlternateNameInformation,   // 21
+    FileStreamInformation,          // 22
+    FilePipeInformation,            // 23
+    FilePipeLocalInformation,       // 24
+    FilePipeRemoteInformation,      // 25
+    FileMailslotQueryInformation,   // 26
+    FileMailslotSetInformation,     // 27
+    FileCompressionInformation,     // 28
+    FileObjectIdInformation,        // 29
+    FileCompletionInformation,      // 30
+    FileMoveClusterInformation,     // 31
+    FileQuotaInformation,           // 32
+    FileReparsePointInformation,    // 33
+    FileNetworkOpenInformation,     // 34
+    FileAttributeTagInformation,    // 35
+    FileTrackingInformation,        // 36
+    FileIdBothDirectoryInformation, // 37
+    FileIdFullDirectoryInformation, // 38
+    FileValidDataLengthInformation, // 39
+    FileShortNameInformation,       // 40
+    FileIoCompletionNotificationInformation, // 41
+    FileIoStatusBlockRangeInformation,       // 42
+    FileIoPriorityHintInformation,           // 43
+    FileSfioReserveInformation,              // 44
+    FileSfioVolumeInformation,               // 45
+    FileHardLinkInformation,                 // 46
+    FileProcessIdsUsingFileInformation,      // 47
+    FileNormalizedNameInformation,           // 48
+    FileNetworkPhysicalNameInformation,      // 49
+    FileIdGlobalTxDirectoryInformation,      // 50
+    FileIsRemoteDeviceInformation,           // 51
+    FileAttributeCacheInformation,           // 52
+    FileNumaNodeInformation,                 // 53
+    FileStandardLinkInformation,             // 54
+    FileRemoteProtocolInformation,           // 55
+    FileMaximumInformation
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_BASIC_INFORMATION {
+    LARGE_INTEGER CreationTime;
+    LARGE_INTEGER LastAccessTime;
+    LARGE_INTEGER LastWriteTime;
+    LARGE_INTEGER ChangeTime;
+    ULONG FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef struct _FILE_STANDARD_INFORMATION {
+    LARGE_INTEGER AllocationSize;
+    LARGE_INTEGER EndOfFile;
+    ULONG NumberOfLinks;
+    BOOLEAN DeletePending;
+    BOOLEAN IsDirectory;
+} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
+
+typedef struct _FILE_NAME_INFORMATION {
+    ULONG FileNameLength;
+    WCHAR FileName[1];
+} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
+
+typedef struct _FILE_PIPE_INFORMATION {
+     ULONG ReadMode;
+     ULONG CompletionMode;
+} FILE_PIPE_INFORMATION, *PFILE_PIPE_INFORMATION;
+
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+     ULONG NamedPipeType;
+     ULONG NamedPipeConfiguration;
+     ULONG MaximumInstances;
+     ULONG CurrentInstances;
+     ULONG InboundQuota;
+     ULONG ReadDataAvailable;
+     ULONG OutboundQuota;
+     ULONG WriteQuotaAvailable;
+     ULONG NamedPipeState;
+     ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+typedef struct _FILE_PIPE_REMOTE_INFORMATION {
+     LARGE_INTEGER CollectDataTime;
+     ULONG MaximumCollectionCount;
+} FILE_PIPE_REMOTE_INFORMATION, *PFILE_PIPE_REMOTE_INFORMATION;
+
+#define FILE_PIPE_BYTE_STREAM_TYPE          0x00000000
+#define FILE_PIPE_MESSAGE_TYPE              0x00000001
+
+#define FILE_PIPE_ACCEPT_REMOTE_CLIENTS     0x00000000
+#define FILE_PIPE_REJECT_REMOTE_CLIENTS     0x00000002
+#define FILE_PIPE_TYPE_VALID_MASK           0x00000003
+
+#define FILE_PIPE_QUEUE_OPERATION           0x00000000
+#define FILE_PIPE_COMPLETE_OPERATION        0x00000001
+
+#define FILE_PIPE_BYTE_STREAM_MODE          0x00000000
+#define FILE_PIPE_MESSAGE_MODE              0x00000001
+
+#define FILE_PIPE_INBOUND                   0x00000000
+#define FILE_PIPE_OUTBOUND                  0x00000001
+#define FILE_PIPE_FULL_DUPLEX               0x00000002
+
+#define FILE_PIPE_DISCONNECTED_STATE        0x00000001
+#define FILE_PIPE_LISTENING_STATE           0x00000002
+#define FILE_PIPE_CONNECTED_STATE           0x00000003
+#define FILE_PIPE_CLOSING_STATE             0x00000004
+
+#define FILE_PIPE_CLIENT_END                0x00000000
+#define FILE_PIPE_SERVER_END                0x00000001
+
+#define FILE_PIPE_READ_DATA                 0x00000000
+#define FILE_PIPE_WRITE_SPACE               0x00000001
+#endif
+
diff --git a/src/WINNT/afsrdr/user/RDRPrototypes.h b/src/WINNT/afsrdr/user/RDRPrototypes.h
new file mode 100644 (file)
index 0000000..a323689
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints, Inc.
+ * Copyright (c) 2009-2011 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ntsecapi.h>
+
+// The following are forward declarations of structures
+// which are referenced in the RDR code only by pointer.
+typedef struct cm_user cm_user_t;
+typedef struct cm_req cm_req_t;
+typedef struct cm_fid cm_fid_t;
+typedef struct cm_scache cm_scache_t;
+
+// Function Declarations
+#include <../common/AFSUserPrototypes.h>
+
+void
+RDR_InitReq( IN OUT cm_req_t *reqp );
+
+DWORD
+RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo,
+                   OUT DWORD * pRedirInitInfoLen );
+
+DWORD
+WINAPI
+RDR_RequestWorkerThread( LPVOID lpParameter);
+
+DWORD
+RDR_ProcessWorkerThreads( IN DWORD);
+
+void
+RDR_ProcessRequest( AFSCommRequest *RequestBuffer);
+
+void
+RDR_EnumerateDirectory( IN cm_user_t *userp,
+                        IN AFSFileID ParentID,
+                        IN AFSDirQueryCB *QueryCB,
+                        IN BOOL bWow64,
+                        IN BOOL bQueryStatus,
+                        IN DWORD ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_EvaluateNodeByName( IN cm_user_t *userp,
+                        IN AFSFileID ParentID,
+                        IN WCHAR     *Name,
+                        IN DWORD     NameLength,
+                        IN BOOL      CaseSensitive,
+                        IN BOOL      bWow64,
+                        IN BOOL      bQueryStatus,
+                        IN BOOL      bHoldFid,
+                        IN DWORD     ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_EvaluateNodeByID( IN cm_user_t *userp,
+                      IN AFSFileID ParentID,
+                      IN AFSFileID SourceID,
+                      IN BOOL bWow64,
+                      IN BOOL bQueryStatus,
+                      IN BOOL      bHoldFid,
+                      IN DWORD    ResultBufferLength,
+                      IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_CreateFileEntry( IN cm_user_t *userp,
+                     IN WCHAR *FileName,
+                     IN DWORD FileNameLength,
+                     IN AFSFileCreateCB *CreateCB,
+                     IN BOOL bWow64,
+                     IN BOOL bHoldFid,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_UpdateFileEntry( IN cm_user_t *userp,
+                     IN AFSFileID FileId,
+                     IN AFSFileUpdateCB *UpdateCB,
+                     IN BOOL bWow64,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_DeleteFileEntry( IN cm_user_t *userp,
+                     IN AFSFileID ParentId,
+                     IN ULONGLONG ProcessId,
+                     IN WCHAR *FileName,
+                     IN DWORD FileNameLength,
+                     IN BOOL bWow64,
+                     IN BOOL bCheckOnly,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_RenameFileEntry( IN cm_user_t *userp,
+                     IN WCHAR    *SourceFileName,
+                     IN DWORD     SourceFileNameLength,
+                     IN AFSFileID SourceFileId,
+                     IN AFSFileRenameCB *RenameCB,
+                     IN BOOL bWow64,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_FlushFileEntry( IN cm_user_t *userp,
+                    IN AFSFileID FileId,
+                    IN BOOL bWow64,
+                    IN DWORD ResultBufferLength,
+                    IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_OpenFileEntry( IN cm_user_t *userp,
+                   IN AFSFileID FileId,
+                   IN AFSFileOpenCB *OpenCB,
+                   IN BOOL bWow64,
+                   IN BOOL bHoldFid,
+                   IN DWORD ResultBufferLength,
+                   IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_CleanupFileEntry( IN cm_user_t *userp,
+                      IN AFSFileID FileId,
+                      IN WCHAR *FileName,
+                      IN DWORD FileNameLength,
+                      IN AFSFileCleanupCB *CleanupCB,
+                      IN BOOL bWow64,
+                      IN BOOL bFlushFile,
+                      IN BOOL bDeleteFile,
+                      IN BOOL bUnlockFile,
+                      IN DWORD ResultBufferLength,
+                      IN OUT AFSCommResult **ResultCB);
+
+BOOL
+RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
+                             IN AFSFileID FileId,
+                             IN AFSRequestExtentsCB *RequestExtentsCB,
+                             IN BOOL bWow64,
+                             IN OUT DWORD * ResultBufferLength,
+                             IN OUT AFSSetFileExtentsCB **ResultCB);
+
+void
+RDR_ReleaseFileExtents( IN cm_user_t *userp,
+                        IN AFSFileID FileId,
+                        IN AFSReleaseExtentsCB *ReleaseExtentsCB,
+                        IN BOOL bWow64,
+                        IN DWORD ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB);
+
+DWORD
+RDR_RequestExtentRelease( IN cm_fid_t *fidp,
+                          IN LARGE_INTEGER numOfHeldExtents,
+                          IN DWORD numOfExtents,
+                          IN AFSFileExtentCB *extentList);
+
+DWORD
+RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFileExtentsResultCB,
+                                     IN DWORD ResultBufferLength);
+
+DWORD
+RDR_ReleaseFailedSetFileExtents( IN cm_user_t *userp,
+                                 IN AFSSetFileExtentsCB *SetFileExtentsResultCB,
+                                 IN DWORD ResultBufferLength);
+
+DWORD
+RDR_SetFileExtents( IN AFSSetFileExtentsCB *pSetFileExtentsResultCB,
+                    IN DWORD dwResultBufferLength);
+void
+RDR_PioctlOpen( IN cm_user_t *userp,
+                IN AFSFileID  ParentId,
+                IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
+                IN BOOL bWow64,
+                IN DWORD ResultBufferLength,
+                IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PioctlClose( IN cm_user_t *userp,
+                 IN AFSFileID  ParentId,
+                 IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
+                 IN BOOL bWow64,
+                 IN DWORD ResultBufferLength,
+                 IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PioctlWrite( IN cm_user_t *userp,
+                 IN AFSFileID  ParentId,
+                 IN AFSPIOCtlIORequestCB *pPioctlCB,
+                 IN BOOL bWow64,
+                 IN DWORD ResultBufferLength,
+                 IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PioctlRead( IN cm_user_t *userp,
+                IN AFSFileID  ParentId,
+                IN AFSPIOCtlIORequestCB *pPioctlCB,
+                IN BOOL bWow64,
+                IN BOOL bIsLocalSystem,
+                IN DWORD ResultBufferLength,
+                IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_ByteRangeLockSync( IN cm_user_t     *userp,
+                       IN AFSFileID     FileId,
+                       IN AFSByteRangeLockRequestCB *pBRLRequestCB,
+                       IN BOOL bWow64,
+                       IN DWORD ResultBufferLength,
+                       IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_ByteRangeUnlock( IN cm_user_t     *userp,
+                     IN AFSFileID     FileId,
+                     IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
+                     IN BOOL bWow64,
+                     IN DWORD ResultBufferLength,
+                     IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_ByteRangeUnlockAll( IN cm_user_t     *userp,
+                        IN AFSFileID     FileId,
+                        IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
+                        IN BOOL bWow64,
+                        IN DWORD ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_GetVolumeInfo( IN cm_user_t     *userp,
+                   IN AFSFileID     FileId,
+                   IN BOOL bWow64,
+                   IN DWORD ResultBufferLength,
+                   IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_HoldFid( IN cm_user_t     *userp,
+             IN AFSHoldFidRequestCB * pHoldFidCB,
+             IN BOOL bFast,
+             IN DWORD ResultBufferLength,
+             IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_ReleaseFid( IN cm_user_t     *userp,
+                IN AFSReleaseFidRequestCB * pReleaseFidCB,
+                IN BOOL bFast,
+                IN DWORD ResultBufferLength,
+                IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PipeOpen( IN cm_user_t *userp,
+              IN AFSFileID  ParentId,
+              IN WCHAR     *Name,
+              IN DWORD      NameLength,
+              IN AFSPipeOpenCloseRequestCB *pPipeCB,
+              IN BOOL bWow64,
+              IN DWORD ResultBufferLength,
+              IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PipeClose( IN cm_user_t *userp,
+               IN AFSFileID  ParentId,
+               IN AFSPipeOpenCloseRequestCB *pPipeCB,
+               IN BOOL bWow64,
+               IN DWORD ResultBufferLength,
+               IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PipeWrite( IN cm_user_t *userp,
+               IN AFSFileID  ParentId,
+               IN AFSPipeIORequestCB *pPipeCB,
+               IN BYTE *pPipeData,
+               IN BOOL bWow64,
+               IN DWORD ResultBufferLength,
+               IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PipeRead( IN cm_user_t *userp,
+              IN AFSFileID  ParentId,
+              IN AFSPipeIORequestCB *pPipeCB,
+              IN BOOL bWow64,
+              IN DWORD ResultBufferLength,
+              IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PipeSetInfo( IN cm_user_t *userp,
+                 IN AFSFileID  ParentId,
+                 IN AFSPipeInfoRequestCB *pPipeCB,
+                 IN BYTE *pPipeData,
+                 IN BOOL bWow64,
+                 IN DWORD ResultBufferLength,
+                 IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PipeQueryInfo( IN cm_user_t *userp,
+                   IN AFSFileID  ParentId,
+                   IN AFSPipeInfoRequestCB *pPipeCB,
+                   IN BOOL bWow64,
+                   IN DWORD ResultBufferLength,
+                   IN OUT AFSCommResult **ResultCB);
+
+void
+RDR_PipeTransceive( IN cm_user_t     *userp,
+                    IN AFSFileID  ParentId,
+                    IN AFSPipeIORequestCB *pPipeCB,
+                    IN BYTE *pPipeData,
+                    IN BOOL bWow64,
+                    IN DWORD          ResultBufferLength,
+                    IN OUT AFSCommResult **ResultCB);
+
+cm_user_t *
+RDR_UserFromCommRequest( IN AFSCommRequest * pRequest);
+
+cm_user_t *
+RDR_UserFromAuthGroup( IN GUID *pGuid);
+
+void
+RDR_ReleaseUser( IN cm_user_t *userp);
+
+void
+RDR_fid2FID( IN cm_fid_t *fid,
+             IN AFSFileID *FileId);
+
+void
+RDR_FID2fid( IN AFSFileID *FileId,
+             IN cm_fid_t *fid);
+
+void
+RDR_InitIoctl(void);
+
+#ifdef __cplusplus
+}
+#endif
+