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)
$(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$@ $**
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)
$(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)
#include "cm_memmap.h"
#include "cm_freelance.h"
#include "cm_performance.h"
+#include "cm_rdr.h"
#include "afsd_init.h"
#include "afsd_eventlog.h"
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;
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]) {
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++) {
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,
}
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");
}
/* 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.
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();
afsd_ShutdownCM();
+ RpcShutdown();
+
cm_ShutdownMappedMemory();
+ if (RDR_Initialized) {
+ RDR_ShutdownFinal();
+ afsi_log("RDR shutdown complete");
+ }
+
rx_Finalize();
afsi_log("rx finalization complete");
#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>
return FALSE;
} // UnicodeStringToANSI
-DWORD APIENTRY NPLogonNotify(
+DWORD APIENTRY
+NPLogonNotify(
PLUID lpLogonId,
LPCWSTR lpAuthentInfoType,
LPVOID lpAuthentInfo,
int retryInterval;
int sleepInterval;
+ CtxtHandle LogonContext;
+
/* Are we interactive? */
interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
/* 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");
}
}
- /* loop until AFS is started. */
+ AFSCreatePAG(lpLogonId);
+
if (afsWillAutoStart) {
/*
* If the service is configured for auto start but hasn't started yet,
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);
/* if Integrated Logon */
if (ISLOGONINTEGRATED(opt.LogonOption))
{
+ LogonSSP(lpLogonId, &LogonContext);
+ ImpersonateSecurityContext(&LogonContext);
+
if ( KFW_is_available() ) {
SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
if (opt.realm) {
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);
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
/* We only support VC 1200 and above anyway */
#pragma once
-#include <windows.h>
#include <objbase.h>
#include <npapi.h>
#if (_WIN32_WINNT < 0x0501)
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
#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
#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 */
+
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;
}
}
void
cm_ResetACLCache(cm_cell_t *cellp, cm_user_t *userp)
{
+ cm_volume_t *volp, *nextVolp;
cm_scache_t *scp, *nextScp;
afs_uint32 hash;
}
}
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);
+ }
}
#include <stdio.h>
#include <strsafe.h>
#include <math.h>
+#include <hcrypto\md5.h>
#include "afsd.h"
#include "cm_memmap.h"
/* 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
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)
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);
}
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.
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) {
}
}
+ 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");
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 */
(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 */
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
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.
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
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();
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. */
{
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;
* 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
* 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
/* 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.
(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;
} /* 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 */
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);
(osi_queue_t **) &cm_data.buf_freeListEndp,
&bp->q);
_InterlockedAnd(&bp->qFlags, ~CM_BUF_QINLRU);
+ buf_DecrementFreeCount();
}
lock_ReleaseWrite(&buf_globalLock);
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)
{
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
* 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 */
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);
buf_HoldLocked(bufp);
lock_ReleaseRead(&buf_globalLock);
+
while (bufp) {
lock_ObtainMutex(&bufp->mx);
*/
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 */
/* 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);
}
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);
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)
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;
}
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;
+ }
+}
/* 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 */
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 */
#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 */
extern void buf_Shutdown(void);
-extern long buf_CountFreeList(void);
-
#ifdef DEBUG_REFCOUNT
extern void buf_ReleaseDbg(cm_buf_t *, char *, long);
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 */
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);
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,
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);
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);
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);
}
}
}
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);
break;
}
}
- if (!haveCB &&
+ if (cm_readonlyVolumeVersioning &&
+ !haveCB &&
volp->creationDateRO == scp->volumeCreationDate &&
volp->cbServerpRO != NULL) {
haveCB = 1;
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) {
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:
extern afs_int32 cm_giveUpAllCBs;
extern afs_int32 cm_shutdown;
+
#endif /* OPENAFS_WINNT_AFSD_CM_CALLBACK_H */
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);
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 {
* 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 */
long cm_daemonCheckOfflineVolInterval = 600;
long cm_daemonPerformanceTuningInterval = 0;
long cm_daemonRankServerInterval = 600;
+long cm_daemonRDRShakeExtentsInterval = 0;
osi_rwlock_t cm_daemonLock;
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);
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);
time_t lastBusyVolCheck;
time_t lastPerformanceCheck;
time_t lastServerRankCheck;
+ time_t lastRDRShakeExtents;
char thostName[200];
unsigned long code;
struct hostent *thp;
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) {
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)
#include <osi.h>
#include "afsd.h"
+#include "smb.h"
#ifdef DEBUG
extern void afsi_log(char *pattern, ...);
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;
osi_queueData_t *qdp;
osi_queueData_t *nqdp;
int flags;
+ int reportErrorToRedir = 0;
/* Give back reserved buffers */
if (biop->reserved)
bufp->error = code;
bufp->dataVersion = CM_BUF_VERSION_BAD;
bufp->dirtyCounter++;
+ reportErrorToRedir = 1;
break;
case CM_ERROR_TIMEDOUT:
case CM_ERROR_ALLDOWN:
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);
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;
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);
{
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);
}
#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);
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;
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);
/* 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);
* 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)
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 )
}
/* 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);
}
}
}
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);
}
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;
}
#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.
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;
}
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;
}
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;
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;
"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,
--- /dev/null
+/*
+ * 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 */
+
#include "afsd.h"
#include "cm_btree.h"
+#include <afs/unified_afs.h>
/*extern void afsi_log(char *pattern, ...);*/
return -1;
}
+ if (scp->redirBufCount != 0) {
+ return -1;
+ }
+
+ cm_RemoveSCacheFromHashTable(scp);
/* invalidate so next merge works fine;
* also initialize some flags */
/* 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;
}
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;
* 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)
}
}
+ 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;
_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)) {
_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)) {
#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;
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)
* 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
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;
/*
}
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);
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,
* 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
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 */
#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
#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
} /* 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;
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;
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;
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);
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)
if (outp == NULL)
return 1;
+#ifdef _WIN64
+ if (use_sysname64 && index >= cm_sysName64Count)
+ return -1;
+ else
+#endif
if (index >= cm_sysNameCount)
return -1;
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;
}
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
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
}
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");
}
}
/* 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;
}
/* 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;
}
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);
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");
}
}
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);
fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
+ cm_ReleaseUser(fileLock->userp);
+ cm_ReleaseSCacheNoLock(scp);
+
+ fileLock->userp = NULL;
+ fileLock->scp = NULL;
+
n_unlocks++;
}
}
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);
return code;
}
+/* Called with scp->rw held */
long cm_Unlock(cm_scache_t *scp,
unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
}
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;
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);
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)
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);
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,
#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)
{
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) {
}
}
+ 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;
{
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;
{
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;
{
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;
{
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;
{
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;
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);
+ }
+}
/*
- * Copyright (c) 2007 Secure Endpoints Inc.
+ * Copyright (c) 2007-2011 Secure Endpoints Inc.
*
* All rights reserved.
*
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;
#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;
+
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,
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));
*/
+#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>
#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++);
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)) {
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;
}
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;
if (SUCCEEDED(hr))
coInitialized = TRUE;
- hr = CoCreateInstance(CLSID_ADSystemInfo,
+ hr = CoCreateInstance( CLSID_ADSystemInfo,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsADSystemInfo,
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);
+}
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 */
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 */
}
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);
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);
* 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;
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+