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);
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);
if (code == ERROR_SUCCESS)
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)
+