#include <afs/param.h>
#include <afs/stds.h>
-#ifndef DJGPP
#include <windows.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
#include <ntstatus.h>
#define SECURITY_WIN32
#include <security.h>
#include <lmaccess.h>
-#endif /* !DJGPP */
+#pragma warning(pop)
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <WINNT\afsreg.h>
#include "smb.h"
+#include <strsafe.h>
extern osi_hyper_t hzero;
/* protected by the smb_globalLock */
smb_tran2Packet_t *smb_tran2AssemblyQueuep;
+const clientchar_t **smb_ExecutableExtensions = NULL;
+
/* retrieve a held reference to a user structure corresponding to an incoming
* request */
cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
return up;
}
+/*
+ * Return boolean specifying if the path name is thought to be an
+ * executable file. For now .exe or .dll.
+ */
+afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
+{
+ int i, j, len;
+
+ if ( smb_ExecutableExtensions == NULL || name == NULL)
+ return 0;
+
+ len = (int)cm_ClientStrLen(name);
+
+ for ( i=0; smb_ExecutableExtensions[i]; i++) {
+ j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
+ if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* Return extended attributes.
* Right now, we aren't using any of the "new" bits, so this looks exactly
#endif /* SPECIAL_FOLDERS */
} else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
- } else
+ } else if (scp->fid.vnode & 0x1)
+ attrs = SMB_ATTR_DIRECTORY;
+ else
attrs = 0;
+
/*
* We used to mark a file RO if it was in an RO volume, but that
* turns out to be impolitic in NT. See defect 10007.
return attrs;
}
-int smb_V3IsStarMask(char *maskp)
+int smb_V3IsStarMask(clientchar_t *maskp)
{
- char tc;
+ clientchar_t tc;
while (tc = *maskp++)
if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
return 0;
}
-unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
-{
- if (chainpp) {
- /* skip over null-terminated string */
- *chainpp = inp + strlen(inp) + 1;
- }
- return inp;
-}
-
-void OutputDebugF(char * format, ...) {
+void OutputDebugF(clientchar_t * format, ...) {
va_list args;
- int len;
- char * buffer;
+ clientchar_t vbuffer[1024];
va_start( args, format );
- len = _vscprintf( format, args ) // _vscprintf doesn't count
- + 3; // terminating '\0' + '\n'
- buffer = malloc( len * sizeof(char) );
- vsprintf( buffer, format, args );
- osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
- strcat(buffer, "\n");
- OutputDebugString(buffer);
- free( buffer );
+ cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
+ osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
}
void OutputDebugHexDump(unsigned char * buffer, int len) {
char buf[256];
static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
- OutputDebugF("Hexdump length [%d]",len);
+ OutputDebugF(_C("Hexdump length [%d]"),len);
for (i=0;i<len;i++) {
if(!(i%16)) {
if(i) {
- osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
- strcat(buf,"\n");
- OutputDebugString(buf);
+ osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
}
- sprintf(buf,"%5x",i);
+ StringCchPrintfA(buf, lengthof(buf), "%5x", i);
memset(buf+5,' ',80);
buf[85] = 0;
}
buf[j] = (k>32 && k<127)?k:'.';
}
if(i) {
- osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
- strcat(buf,"\n");
- OutputDebugString(buf);
+ osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
}
}
*secBlob = NULL;
*secBlobLength = 0;
- OutputDebugF("Negotiating Extended Security");
+ OutputDebugF(_C("Negotiating Extended Security"));
status = AcquireCredentialsHandle( NULL,
SMB_EXT_SEC_PACKAGE_NAME,
if (status != SEC_E_OK) {
/* Really bad. We return an empty security blob */
- OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
+ OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
goto nes_0;
}
);
if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
- OutputDebugF("Completing token...");
+ OutputDebugF(_C("Completing token..."));
istatus = CompleteAuthToken(&ctx, &secOut);
if ( istatus != SEC_E_OK )
- OutputDebugF("Token completion failed: %x", istatus);
+ OutputDebugF(_C("Token completion failed: %x"), istatus);
}
if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
}
} else {
if ( status != SEC_E_OK )
- OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
+ OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
}
/* Discard partial security context */
void * partialToken;
};
-long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
+long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
+ char * secBlobIn, int secBlobInLength,
+ char ** secBlobOut, int * secBlobOutLength) {
SECURITY_STATUS status, istatus;
CredHandle creds;
TimeStamp expiry;
int assembledBlobLength = 0;
ULONG flags;
- OutputDebugF("In smb_AuthenticateUserExt");
+ OutputDebugF(_C("In smb_AuthenticateUserExt"));
*secBlobOut = NULL;
*secBlobOutLength = 0;
}
if (secBlobIn) {
- OutputDebugF("Received incoming token:");
+ OutputDebugF(_C("Received incoming token:"));
OutputDebugHexDump(secBlobIn,secBlobInLength);
}
if (secCtx) {
- OutputDebugF("Continuing with existing context.");
+ OutputDebugF(_C("Continuing with existing context."));
creds = secCtx->creds;
ctx = secCtx->ctx;
&expiry);
if (status != SEC_E_OK) {
- OutputDebugF("Can't acquire Credentials handle [%lX]", status);
+ OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
goto aue_0;
}
);
if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
- OutputDebugF("Completing token...");
+ OutputDebugF(_C("Completing token..."));
istatus = CompleteAuthToken(&ctx, &secBufOut);
if ( istatus != SEC_E_OK )
- OutputDebugF("Token completion failed: %lX", istatus);
+ OutputDebugF(_C("Token completion failed: %lX"), istatus);
}
if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
- OutputDebugF("Continue needed");
+ OutputDebugF(_C("Continue needed"));
newSecCtx = malloc(sizeof(*newSecCtx));
if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
secTokOut.pvBuffer) {
- OutputDebugF("Need to send token back to client");
+ OutputDebugF(_C("Need to send token back to client"));
*secBlobOutLength = secTokOut.cbBuffer;
*secBlobOut = malloc(secTokOut.cbBuffer);
memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
- OutputDebugF("Outgoing token:");
+ OutputDebugF(_C("Outgoing token:"));
OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
} else if (status == SEC_E_INCOMPLETE_MESSAGE) {
- OutputDebugF("Incomplete message");
+ OutputDebugF(_C("Incomplete message"));
newSecCtx = malloc(sizeof(*newSecCtx));
if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
/* woo hoo! */
- SecPkgContext_Names names;
+ SecPkgContext_NamesW names;
- OutputDebugF("Authentication completed");
- OutputDebugF("Returned flags : [%lX]", flags);
+ OutputDebugF(_C("Authentication completed"));
+ OutputDebugF(_C("Returned flags : [%lX]"), flags);
- if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
- OutputDebugF("Received name [%s]", names.sUserName);
- strcpy(usern, names.sUserName);
- strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
+ if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
+ OutputDebugF(_C("Received name [%s]"), names.sUserName);
+ cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
+ cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
FreeContextBuffer(names.sUserName);
} else {
/* Force the user to retry if the context is invalid */
- OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
+ OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
code = CM_ERROR_BADPASSWORD;
}
} else if (!code) {
switch ( status ) {
case SEC_E_INVALID_TOKEN:
- OutputDebugF("Returning bad password :: INVALID_TOKEN");
+ OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
break;
case SEC_E_INVALID_HANDLE:
- OutputDebugF("Returning bad password :: INVALID_HANDLE");
+ OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
break;
case SEC_E_LOGON_DENIED:
- OutputDebugF("Returning bad password :: LOGON_DENIED");
+ OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
break;
case SEC_E_UNKNOWN_CREDENTIALS:
- OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
+ OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
break;
case SEC_E_NO_CREDENTIALS:
- OutputDebugF("Returning bad password :: NO_CREDENTIALS");
+ OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
break;
case SEC_E_CONTEXT_EXPIRED:
- OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
+ OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
break;
case SEC_E_INCOMPLETE_CREDENTIALS:
- OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
+ OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
break;
case SEC_E_WRONG_PRINCIPAL:
- OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
+ OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
break;
case SEC_E_TIME_SKEW:
- OutputDebugF("Returning bad password :: TIME_SKEW");
+ OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
break;
default:
- OutputDebugF("Returning bad password :: Status == %lX", status);
+ OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
}
code = CM_ERROR_BADPASSWORD;
}
TOKEN_SOURCE tsource;
};
-long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
+long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
{
NTSTATUS nts, ntsEx;
struct Lm20AuthBlob lmAuth;
LUID lmSession;
HANDLE lmToken;
- OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
- OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
+ OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
+ OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
- OutputDebugF("ciPwdLength or csPwdLength is too long");
+ OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
return CM_ERROR_BADPASSWORD;
}
lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
- mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
+ cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
- mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
+ cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
lmAuth.tgroups.Groups[0].Sid = NULL;
lmAuth.tgroups.Groups[0].Attributes = 0;
+#ifdef _WIN64
lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
+#else
+ lmAuth.tsource.SourceIdentifier.HighPart = 0;
+#endif
lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
- strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
+ StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
+ "OpenAFS"); /* 8 char limit */
nts = LsaLogonUser( smb_lsaHandle,
&smb_lsaLogonOrigin,
osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
nts, ntsEx);
- OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
- OutputDebugF("Extended status is 0x%lX", ntsEx);
+ OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
+ OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
if (nts == ERROR_SUCCESS) {
/* free the token */
}
/* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
-long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
+long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
{
- char * atsign;
- const char * domain;
+ clientchar_t * atsign;
+ const clientchar_t * domain;
/* check if we have sane input */
- if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
+ if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
return 1;
/* we could get : [accountName][domainName]
[user][]/[user][?]
[][]/[][?] */
- atsign = strchr(accountName, '@');
+ atsign = cm_ClientStrChr(accountName, '@');
if (atsign) /* [user@domain][] -> [user@domain][domain] */
domain = atsign + 1;
/* Empty domains and empty usernames are usually sent from tokenless contexts.
This way such logins will get an empty username (easy to check). I don't know
when a non-empty username would be supplied with an anonymous domain, but *shrug* */
- strcpy(usern,accountName);
+ cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
else {
/* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
- strcpy(usern,domain);
- strcat(usern,"\\");
+ cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
+ cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
if (atsign)
- strncat(usern,accountName,atsign - accountName);
+ cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
else
- strcat(usern,accountName);
- }
+ cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
+ }
- strlwr(usern);
+ cm_ClientStrLwr(usern);
return 0;
}
* sending a session setup packet, which means that we can't rely on a
* UID in subsequent packets. Though in practice we get one anyway.
*/
+/* SMB_COM_SESSION_SETUP_ANDX */
long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
char *tp;
unsigned short newUid;
unsigned long caps = 0;
smb_username_t *unp;
- char *s1 = " ";
+ clientchar_t *s1 = _C(" ");
long code = 0;
- char usern[SMB_MAX_USERNAME_LENGTH];
+ clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
char *secBlobOut = NULL;
int secBlobOutLength = 0;
+ int maxBufferSize = 0;
+ int maxMpxCount = 0;
+ int vcNumber = 0;
/* Check for bad conns */
if (vcp->flags & SMB_VCFLAG_REMOTECONN)
return CM_ERROR_REMOTECONN;
+ /* maxBufferSize */
+ maxBufferSize = smb_GetSMBParm(inp, 2);
+ maxMpxCount = smb_GetSMBParm(inp, 3);
+ vcNumber = smb_GetSMBParm(inp, 4);
+
+ osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
+ maxBufferSize, maxMpxCount, vcNumber);
+
+ if (maxMpxCount > smb_maxMpxRequests) {
+ LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
+ osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
+ maxMpxCount, smb_maxMpxRequests);
+ }
+
+ if (maxBufferSize < SMB_PACKETSIZE) {
+ LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
+ osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
+ maxBufferSize, SMB_PACKETSIZE);
+ }
+
+ if (vcNumber == 0) {
+ osi_Log0(smb_logp, "Resetting all VCs");
+ smb_MarkAllVCsDead(vcp);
+ }
+
if (vcp->flags & SMB_VCFLAG_USENT) {
if (smb_authType == SMB_AUTH_EXTENDED) {
/* extended authentication */
char *secBlobIn;
int secBlobInLength;
- OutputDebugF("NT Session Setup: Extended");
+ OutputDebugF(_C("NT Session Setup: Extended"));
if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
if (code == CM_ERROR_GSSCONTINUE) {
+ size_t cb_data = 0;
+
smb_SetSMBParm(outp, 2, 0);
smb_SetSMBParm(outp, 3, secBlobOutLength);
- smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+
tp = smb_GetSMBData(outp, NULL);
if (secBlobOutLength) {
memcpy(tp, secBlobOut, secBlobOutLength);
free(secBlobOut);
tp += secBlobOutLength;
+ cb_data += secBlobOutLength;
}
- memcpy(tp,smb_ServerOS,smb_ServerOSLength);
- tp += smb_ServerOSLength;
- memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
- tp += smb_ServerLanManagerLength;
- memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
- tp += smb_ServerDomainNameLength;
+ tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
+ tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
+ tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
+
+ smb_SetSMBDataLength(outp, cb_data);
}
/* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
} else {
unsigned ciPwdLength, csPwdLength;
char *ciPwd, *csPwd;
- char *accountName;
- char *primaryDomain;
+ clientchar_t *accountName;
+ clientchar_t *primaryDomain;
int datalen;
if (smb_authType == SMB_AUTH_NTLM)
- OutputDebugF("NT Session Setup: NTLM");
+ OutputDebugF(_C("NT Session Setup: NTLM"));
else
- OutputDebugF("NT Session Setup: None");
+ OutputDebugF(_C("NT Session Setup: None"));
/* TODO: parse for extended auth as well */
ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
tp = smb_GetSMBData(inp, &datalen);
- OutputDebugF("Session packet data size [%d]",datalen);
+ OutputDebugF(_C("Session packet data size [%d]"),datalen);
ciPwd = tp;
tp += ciPwdLength;
csPwd = tp;
tp += csPwdLength;
- accountName = smb_ParseString(tp, &tp);
- primaryDomain = smb_ParseString(tp, NULL);
+ accountName = smb_ParseString(inp, tp, &tp, 0);
+ primaryDomain = smb_ParseString(inp, tp, NULL, 0);
- OutputDebugF("Account Name: %s",accountName);
- OutputDebugF("Primary Domain: %s", primaryDomain);
- OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
- OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
+ OutputDebugF(_C("Account Name: %s"),accountName);
+ OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
+ OutputDebugF(_C("Case Sensitive Password: %s"),
+ csPwd && csPwd[0] ? _C("yes") : _C("no"));
+ OutputDebugF(_C("Case Insensitive Password: %s"),
+ ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
/* shouldn't happen */
if (smb_authType == SMB_AUTH_NTLM) {
code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
if ( code )
- OutputDebugF("LM authentication failed [%d]", code);
+ OutputDebugF(_C("LM authentication failed [%d]"), code);
else
- OutputDebugF("LM authentication succeeded");
+ OutputDebugF(_C("LM authentication succeeded"));
}
}
} else { /* V3 */
unsigned ciPwdLength;
char *ciPwd;
- char *accountName;
- char *primaryDomain;
+ clientchar_t *accountName;
+ clientchar_t *primaryDomain;
switch ( smb_authType ) {
case SMB_AUTH_EXTENDED:
- OutputDebugF("V3 Session Setup: Extended");
+ OutputDebugF(_C("V3 Session Setup: Extended"));
break;
case SMB_AUTH_NTLM:
- OutputDebugF("V3 Session Setup: NTLM");
+ OutputDebugF(_C("V3 Session Setup: NTLM"));
break;
default:
- OutputDebugF("V3 Session Setup: None");
+ OutputDebugF(_C("V3 Session Setup: None"));
}
ciPwdLength = smb_GetSMBParm(inp, 7);
tp = smb_GetSMBData(inp, NULL);
ciPwd = tp;
tp += ciPwdLength;
- accountName = smb_ParseString(tp, &tp);
- primaryDomain = smb_ParseString(tp, NULL);
+ accountName = smb_ParseString(inp, tp, &tp, 0);
+ primaryDomain = smb_ParseString(inp, tp, NULL, 0);
- OutputDebugF("Account Name: %s",accountName);
- OutputDebugF("Primary Domain: %s", primaryDomain);
- OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
+ OutputDebugF(_C("Account Name: %s"),accountName);
+ OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
+ OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
/* shouldn't happen */
if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
if ( code )
- OutputDebugF("LM authentication failed [%d]", code);
+ OutputDebugF(_C("LM authentication failed [%d]"), code);
else
- OutputDebugF("LM authentication succeeded");
+ OutputDebugF(_C("LM authentication succeeded"));
}
}
if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
vcp->flags |= SMB_VCFLAG_STATUS32;
}
+
+#ifdef SMB_UNICODE
+ if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
+ vcp->flags |= SMB_VCFLAG_USEUNICODE;
+ }
+#endif
lock_ReleaseMutex(&vcp->mx);
}
return code;
}
- OutputDebugF("Received username=[%s]", usern);
+ OutputDebugF(_C("Received username=[%s]"), usern);
/* On Windows 2000, this function appears to be called more often than
it is expected to be called. This resulted in multiple smb_user_t
lock_ObtainMutex(&vcp->mx);
if (!vcp->uidCounter)
vcp->uidCounter++; /* handle unlikely wraparounds */
- newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
+ newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
lock_ReleaseMutex(&vcp->mx);
/* Create a new smb_user_t structure and connect them up */
lock_ReleaseMutex(&unp->mx);
uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
- lock_ObtainMutex(&uidp->mx);
- uidp->unp = unp;
- osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
- lock_ReleaseMutex(&uidp->mx);
- smb_ReleaseUID(uidp);
+ if (uidp) {
+ lock_ObtainMutex(&uidp->mx);
+ uidp->unp = unp;
+ osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
+ lock_ReleaseMutex(&uidp->mx);
+ smb_ReleaseUID(uidp);
+ }
}
/* Return UID to the client */
/* Also to the next chained message */
((smb_t *)inp)->uid = newUid;
- osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
- osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
+ osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
+ osi_LogSaveClientString(smb_logp, usern), newUid,
+ osi_LogSaveClientString(smb_logp, s1));
smb_SetSMBParm(outp, 2, 0);
if (vcp->flags & SMB_VCFLAG_USENT) {
if (smb_authType == SMB_AUTH_EXTENDED) {
+ size_t cb_data = 0;
+
smb_SetSMBParm(outp, 3, secBlobOutLength);
- smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+
tp = smb_GetSMBData(outp, NULL);
if (secBlobOutLength) {
memcpy(tp, secBlobOut, secBlobOutLength);
free(secBlobOut);
tp += secBlobOutLength;
+ cb_data += secBlobOutLength;
}
- memcpy(tp,smb_ServerOS,smb_ServerOSLength);
- tp += smb_ServerOSLength;
- memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
- tp += smb_ServerLanManagerLength;
- memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
- tp += smb_ServerDomainNameLength;
+
+ tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
+ tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
+ tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
+
+ smb_SetSMBDataLength(outp, cb_data);
} else {
smb_SetSMBDataLength(outp, 0);
}
} else {
if (smb_authType == SMB_AUTH_EXTENDED) {
- smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+ size_t cb_data = 0;
+
tp = smb_GetSMBData(outp, NULL);
- memcpy(tp,smb_ServerOS,smb_ServerOSLength);
- tp += smb_ServerOSLength;
- memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
- tp += smb_ServerLanManagerLength;
- memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
- tp += smb_ServerDomainNameLength;
+
+ tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
+ tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
+ tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
+
+ smb_SetSMBDataLength(outp, cb_data);
} else {
smb_SetSMBDataLength(outp, 0);
}
return 0;
}
+/* SMB_COM_LOGOFF_ANDX */
long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
smb_user_t *uidp;
if (uidp) {
smb_username_t * unp;
- osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
- osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
+ osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
+ osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
lock_ObtainMutex(&uidp->mx);
uidp->flags |= SMB_USERFLAG_DELETE;
#define SMB_SUPPORT_SEARCH_BITS 0x0001
#define SMB_SHARE_IS_IN_DFS 0x0002
+/* SMB_COM_TREE_CONNECT_ANDX */
long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
smb_tid_t *tidp;
- smb_user_t *uidp;
+ smb_user_t *uidp = NULL;
unsigned short newTid;
- char shareName[256];
- char *sharePath;
+ clientchar_t shareName[AFSPATHMAX];
+ clientchar_t *sharePath;
int shareFound;
char *tp;
- char *pathp;
- char *passwordp;
- char *servicep;
- cm_user_t *userp;
+ clientchar_t *slashp;
+ clientchar_t *pathp;
+ clientchar_t *passwordp;
+ clientchar_t *servicep;
+ cm_user_t *userp = NULL;
int ipc = 0;
osi_Log0(smb_logp, "SMB3 receive tree connect");
/* parse input parameters */
tp = smb_GetSMBData(inp, NULL);
- passwordp = smb_ParseString(tp, &tp);
- pathp = smb_ParseString(tp, &tp);
- if (smb_StoreAnsiFilenames)
- OemToChar(pathp,pathp);
- servicep = smb_ParseString(tp, &tp);
-
- tp = strrchr(pathp, '\\');
- if (!tp) {
+ passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
+ pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
+ servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
+
+ slashp = cm_ClientStrRChr(pathp, '\\');
+ if (!slashp) {
return CM_ERROR_BADSMB;
}
- strcpy(shareName, tp+1);
+ cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
- osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
- osi_LogSaveString(smb_logp, pathp),
- osi_LogSaveString(smb_logp, shareName));
+ osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
+ osi_LogSaveClientString(smb_logp, pathp),
+ osi_LogSaveClientString(smb_logp, shareName),
+ osi_LogSaveClientString(smb_logp, servicep));
- if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
+ if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
+ cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
#ifndef NO_IPC
osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
ipc = 1;
}
uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
- userp = smb_GetUserFromUID(uidp);
+ if (uidp)
+ userp = smb_GetUserFromUID(uidp);
lock_ObtainMutex(&vcp->mx);
newTid = vcp->tidCounter++;
tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
if (!ipc) {
+ if (!cm_ClientStrCmp(shareName, _C("*.")))
+ cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
if (!shareFound) {
- smb_ReleaseUID(uidp);
- smb_ReleaseTID(tidp);
+ if (uidp)
+ smb_ReleaseUID(uidp);
+ smb_ReleaseTID(tidp, FALSE);
return CM_ERROR_BADSHARENAME;
}
if (vcp->flags & SMB_VCFLAG_USENT)
{
int policy = smb_FindShareCSCPolicy(shareName);
+ HKEY parmKey;
+ DWORD code;
+ DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
+
+ code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+ 0, KEY_QUERY_VALUE, &parmKey);
+ if (code == ERROR_SUCCESS) {
+ code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
+ (BYTE *)&dwAdvertiseDFS, &dwSize);
+ if (code != ERROR_SUCCESS)
+ dwAdvertiseDFS = 0;
+ RegCloseKey (parmKey);
+ }
smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
-#ifdef DFS_SUPPORT
- SMB_SHARE_IS_IN_DFS |
-#endif
- (policy << 2));
+ (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
+ (policy << 2));
}
} else {
smb_SetSMBParm(outp, 2, 0);
sharePath = NULL;
}
- smb_ReleaseUID(uidp);
+ if (uidp)
+ smb_ReleaseUID(uidp);
lock_ObtainMutex(&tidp->mx);
tidp->userp = userp;
if (ipc)
tidp->flags |= SMB_TIDFLAG_IPC;
lock_ReleaseMutex(&tidp->mx);
- smb_ReleaseTID(tidp);
+ smb_ReleaseTID(tidp, FALSE);
((smb_t *)outp)->tid = newTid;
((smb_t *)inp)->tid = newTid;
tp = smb_GetSMBData(outp, NULL);
if (!ipc) {
- /* XXX - why is this a drive letter? */
- *tp++ = 'A';
- *tp++ = ':';
- *tp++ = 0;
- *tp++ = 'N';
- *tp++ = 'T';
- *tp++ = 'F';
- *tp++ = 'S';
- *tp++ = 0;
- smb_SetSMBDataLength(outp, 8);
+ size_t cb_data = 0;
+
+ tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
+ tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
+ smb_SetSMBDataLength(outp, cb_data);
} else {
- strcpy(tp, "IPC");
- smb_SetSMBDataLength(outp, 4);
+ size_t cb_data = 0;
+
+ tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
+ smb_SetSMBDataLength(outp, cb_data);
}
osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
}
smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
- int totalParms, int totalData)
+ int totalParms, int totalData)
{
smb_tran2Packet_t *tp;
smb_t *smbp;
tp->com = 0x32;
}
tp->flags |= SMB_TRAN2PFLAG_ALLOC;
+#ifdef SMB_UNICODE
+ if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
+ tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
+#endif
return tp;
}
smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
- smb_tran2Packet_t *inp, smb_packet_t *outp,
- int totalParms, int totalData)
+ smb_tran2Packet_t *inp, smb_packet_t *outp,
+ int totalParms, int totalData)
{
smb_tran2Packet_t *tp;
unsigned short parmOffset;
unsigned short dataOffset;
unsigned short dataAlign;
-
+
tp = malloc(sizeof(*tp));
memset(tp, 0, sizeof(*tp));
smb_HoldVC(vcp);
if (t2p->datap)
free(t2p->datap);
}
+ while (t2p->stringsp) {
+ cm_space_t * ns;
+
+ ns = t2p->stringsp;
+ t2p->stringsp = ns->nextp;
+ cm_FreeSpace(ns);
+ }
free(t2p);
}
+clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
+ char ** chainpp, int flags)
+{
+ size_t cb;
+
+#ifdef SMB_UNICODE
+ if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
+ flags |= SMB_STRF_FORCEASCII;
+#endif
+
+ cb = p->totalParms - (inp - (char *)p->parmsp);
+ if (inp < (char *) p->parmsp ||
+ inp >= ((char *) p->parmsp) + p->totalParms) {
+#ifdef DEBUG_UNICODE
+ DebugBreak();
+#endif
+ cb = p->totalParms;
+ }
+
+ return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
+ inp, &cb, chainpp, flags);
+}
+
/* called with a VC, an input packet to respond to, and an error code.
* sends an error response.
*/
void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
- smb_packet_t *tp, long code)
+ smb_packet_t *tp, long code)
{
smb_t *smbp;
unsigned short errCode;
smb_SendPacket(vcp, tp);
}
+
+/* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
smb_tran2Packet_t *asp;
/* We sometimes see 0 word count. What to do? */
if (*inp->wctp == 0) {
osi_Log0(smb_logp, "Transaction2 word count = 0");
-#ifndef DJGPP
LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
-#endif /* !DJGPP */
smb_SetSMBDataLength(outp, 0);
smb_SendPacket(vcp, outp);
return 0;
}
-/* ANSI versions. The unicode versions support arbitrary length
- share names, but we don't support unicode yet. */
+/* ANSI versions. */
+
+#pragma pack(push, 1)
typedef struct smb_rap_share_info_0 {
- char shi0_netname[13];
+ BYTE shi0_netname[13];
} smb_rap_share_info_0_t;
typedef struct smb_rap_share_info_1 {
- char shi1_netname[13];
- char shi1_pad;
+ BYTE shi1_netname[13];
+ BYTE shi1_pad;
WORD shi1_type;
DWORD shi1_remark; /* char *shi1_remark; data offset */
} smb_rap_share_info_1_t;
typedef struct smb_rap_share_info_2 {
- char shi2_netname[13];
- char shi2_pad;
- unsigned short shi2_type;
- DWORD shi2_remark; /* char *shi2_remark; data offset */
- unsigned short shi2_permissions;
- unsigned short shi2_max_uses;
- unsigned short shi2_current_uses;
- DWORD shi2_path; /* char *shi2_path; data offset */
- unsigned short shi2_passwd[9];
- unsigned short shi2_pad2;
+ BYTE shi2_netname[13];
+ BYTE shi2_pad;
+ WORD shi2_type;
+ DWORD shi2_remark; /* char *shi2_remark; data offset */
+ WORD shi2_permissions;
+ WORD shi2_max_uses;
+ WORD shi2_current_uses;
+ DWORD shi2_path; /* char *shi2_path; data offset */
+ WORD shi2_passwd[9];
+ WORD shi2_pad2;
} smb_rap_share_info_2_t;
#define SMB_RAP_MAX_SHARES 512
smb_rap_share_info_0_t * shares;
} smb_rap_share_list_t;
+#pragma pack(pop)
+
int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
smb_rap_share_list_t * sp;
- char * name;
-
- name = dep->name;
- if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
+ if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
return 0; /* skip over '.' and '..' */
sp = (smb_rap_share_list_t *) vrockp;
- strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
+ strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
sp->shares[sp->cShare].shi0_netname[12] = 0;
sp->cShare++;
return 0;
}
+/* RAP NetShareEnumRequest */
long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
smb_tran2Packet_t *outp;
smb_rap_share_info_1_t * shares;
USHORT cshare = 0;
char * cstrp;
- char thisShare[256];
+ clientchar_t thisShare[AFSPATHMAX];
int i,j;
+ DWORD dw;
int nonrootShares;
smb_rap_share_list_t rootShares;
cm_req_t req;
osi_hyper_t thyper;
tp = p->parmsp + 1; /* skip over function number (always 0) */
- (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
- (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
+
+ {
+ clientchar_t * cdescp;
+
+ cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
+ return CM_ERROR_INVAL;
+ cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
+ return CM_ERROR_INVAL;
+ }
+
infoLevel = tp[0];
bufsize = tp[1];
return CM_ERROR_INVAL;
}
+ /* We are supposed to use the same ASCII data structure even if
+ Unicode is negotiated, which ultimately means that the share
+ names that we return must be at most 13 characters in length,
+ including the NULL terminator.
+
+ The RAP specification states that shares with names longer than
+ 12 characters should not be included in the enumeration.
+ However, since we support prefix cell references and since many
+ cell names are going to exceed 12 characters, we lie and send
+ the first 12 characters.
+ */
+
/* first figure out how many shares there are */
rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
KEY_QUERY_VALUE, &hkParam);
rootShares.cShare = 0;
rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
- cm_InitReq(&req);
+ smb_InitReq(&req);
userp = smb_GetTran2User(vcp,p);
memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
if (allSubmount) {
- strcpy( shares[cshare].shi1_netname, "all" );
+ StringCchCopyA(shares[cshare].shi1_netname,
+ lengthof(shares[cshare].shi1_netname), "all" );
shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
/* type and pad are zero already */
cshare++;
}
if (hkSubmount) {
- for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
+ for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
len = sizeof(thisShare);
- rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
- if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
- strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
+ rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
+ if (rv == ERROR_SUCCESS &&
+ cm_ClientStrLen(thisShare) &&
+ (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
+ cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
+ lengthof( shares[cshare].shi1_netname ));
shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
cshare++;
nonrootShares = cshare;
for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
- /* in case there are collisions with submounts, submounts have higher priority */
+ /* in case there are collisions with submounts, submounts have
+ higher priority */
for (j=0; j < nonrootShares; j++)
- if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
+ if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
break;
if (j < nonrootShares) {
continue;
}
- strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
+ StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
+ rootShares.shares[i].shi0_netname);
shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
cshare++;
cstrp+=REMARK_LEN;
return code;
}
+/* RAP NetShareGetInfo */
long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
smb_tran2Packet_t *outp;
unsigned short * tp;
- char * shareName;
+ clientchar_t * shareName;
BOOL shareFound = FALSE;
unsigned short infoLevel;
unsigned short bufsize;
DWORD allSubmount;
LONG rv;
long code = 0;
+ cm_scache_t *scp = NULL;
+ cm_user_t *userp;
+ cm_req_t req;
+
+ smb_InitReq(&req);
tp = p->parmsp + 1; /* skip over function number (always 1) */
- (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
- (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
- shareName = smb_ParseString( (char *) tp, (char **) &tp);
+
+ {
+ clientchar_t * cdescp;
+
+ cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
+
+ return CM_ERROR_INVAL;
+
+ cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("B13")) &&
+ cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
+ cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
+
+ return CM_ERROR_INVAL;
+ }
+ shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+
infoLevel = *tp++;
bufsize = *tp++;
else
return CM_ERROR_INVAL;
- outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
-
- if(!stricmp(shareName,"all")) {
+ if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
KEY_QUERY_VALUE, &hkParam);
if (rv == ERROR_SUCCESS) {
shareFound = TRUE;
} else {
- rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
- KEY_QUERY_VALUE, &hkSubmount);
- if (rv == ERROR_SUCCESS) {
- rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
+ return CM_ERROR_BADSMB;
+ }
+ code = cm_NameI(cm_data.rootSCachep, shareName,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
+ userp, NULL, &req, &scp);
+ if (code == 0) {
+ cm_ReleaseSCache(scp);
+ shareFound = TRUE;
+ } else {
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
+ KEY_QUERY_VALUE, &hkSubmount);
if (rv == ERROR_SUCCESS) {
- shareFound = TRUE;
+ rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
+ if (rv == ERROR_SUCCESS) {
+ shareFound = TRUE;
+ }
+ RegCloseKey(hkSubmount);
}
- RegCloseKey(hkSubmount);
}
}
- if (!shareFound) {
- smb_FreeTran2Packet(outp);
+ if (!shareFound)
return CM_ERROR_BADSHARENAME;
- }
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
memset(outp->datap, 0, totalData);
outp->parmsp[0] = 0;
if (infoLevel == 0) {
smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
- strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
- info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
+ cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
+ lengthof(info->shi0_netname));
} else if(infoLevel == SMB_INFO_STANDARD) {
smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
- strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
+ cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
/* type and pad are already zero */
} else { /* infoLevel==2 */
smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
- strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
- info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
+ cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
info->shi2_permissions = ACCESS_ALL;
info->shi2_max_uses = (unsigned short) -1;
return code;
}
+#pragma pack(push, 1)
+
typedef struct smb_rap_wksta_info_10 {
DWORD wki10_computername; /*char *wki10_computername;*/
DWORD wki10_username; /* char *wki10_username; */
DWORD wki10_langroup; /* char *wki10_langroup;*/
- unsigned char wki10_ver_major;
- unsigned char wki10_ver_minor;
+ BYTE wki10_ver_major;
+ BYTE wki10_ver_minor;
DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
} smb_rap_wksta_info_10_t;
+#pragma pack(pop)
long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
smb_user_t *uidp;
tp = p->parmsp + 1; /* Skip over function number */
- (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
- (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
+
+ {
+ clientchar_t * cdescp;
+
+ cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+ SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("WrLh")))
+ return CM_ERROR_INVAL;
+
+ cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+ SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
+ return CM_ERROR_INVAL;
+ }
+
infoLevel = *tp++;
bufsize = *tp++;
cstrp = (char *) (info + 1);
info->wki10_computername = (DWORD) (cstrp - outp->datap);
- strcpy(cstrp, smb_localNamep);
+ StringCbCopyA(cstrp, totalData, smb_localNamep);
cstrp += strlen(cstrp) + 1;
info->wki10_username = (DWORD) (cstrp - outp->datap);
if (uidp) {
lock_ObtainMutex(&uidp->mx);
if(uidp->unp && uidp->unp->name)
- strcpy(cstrp, uidp->unp->name);
+ cm_ClientStringToUtf8(uidp->unp->name, -1,
+ cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
lock_ReleaseMutex(&uidp->mx);
smb_ReleaseUID(uidp);
}
cstrp += strlen(cstrp) + 1;
info->wki10_langroup = (DWORD) (cstrp - outp->datap);
- strcpy(cstrp, "WORKGROUP");
+ StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
cstrp += strlen(cstrp) + 1;
/* TODO: Not sure what values these should take, but these work */
info->wki10_ver_minor = 1;
info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
- strcpy(cstrp, smb_ServerDomainName);
+ cm_ClientStringToUtf8(smb_ServerDomainName, -1,
+ cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
cstrp += strlen(cstrp) + 1;
info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
return code;
}
+#pragma pack(push, 1)
+
typedef struct smb_rap_server_info_0 {
- char sv0_name[16];
+ BYTE sv0_name[16];
} smb_rap_server_info_0_t;
typedef struct smb_rap_server_info_1 {
- char sv1_name[16];
- char sv1_version_major;
- char sv1_version_minor;
- unsigned long sv1_type;
- DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
+ BYTE sv1_name[16];
+ BYTE sv1_version_major;
+ BYTE sv1_version_minor;
+ DWORD sv1_type;
+ DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
} smb_rap_server_info_1_t;
+#pragma pack(pop)
+
char smb_ServerComment[] = "OpenAFS Client";
int smb_ServerCommentLen = sizeof(smb_ServerComment);
char * cstrp;
tp = p->parmsp + 1; /* Skip over function number */
- (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
- (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
+
+ {
+ clientchar_t * cdescp;
+
+ cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
+ SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("WrLh")))
+ return CM_ERROR_INVAL;
+ cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+ SMB_STRF_FORCEASCII);
+ if (cm_ClientStrCmp(cdescp, _C("B16")) ||
+ cm_ClientStrCmp(cdescp, _C("B16BBDz")))
+ return CM_ERROR_INVAL;
+ }
+
infoLevel = *tp++;
bufsize = *tp++;
if (infoLevel == 0) {
info0 = (smb_rap_server_info_0_t *) outp->datap;
cstrp = (char *) (info0 + 1);
- strcpy(info0->sv0_name, "AFS");
+ StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
} else { /* infoLevel == SMB_INFO_STANDARD */
info1 = (smb_rap_server_info_1_t *) outp->datap;
cstrp = (char *) (info1 + 1);
- strcpy(info1->sv1_name, "AFS");
+ StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
info1->sv1_type =
SMB_SV_TYPE_SERVER |
info1->sv1_version_major = 5;
info1->sv1_version_minor = 1;
- info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
+ info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
- strcpy(cstrp, smb_ServerComment);
+ StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
- cstrp += smb_ServerCommentLen;
+ cstrp += smb_ServerCommentLen / sizeof(char);
}
totalData = (DWORD)(cstrp - outp->datap);
return code;
}
+/* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
smb_tran2Packet_t *asp;
int dataCount;
int firstPacket;
long code = 0;
+ DWORD oldTime, newTime;
/* We sometimes see 0 word count. What to do? */
if (*inp->wctp == 0) {
osi_Log0(smb_logp, "Transaction2 word count = 0");
-#ifndef DJGPP
LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
-#endif /* !DJGPP */
smb_SetSMBDataLength(outp, 0);
smb_SendPacket(vcp, outp);
osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
lock_ReleaseWrite(&smb_globalLock);
+ oldTime = GetTickCount();
+
/* now dispatch it */
if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
smb_SendTran2Error(vcp, asp, outp, code);
}
+ newTime = GetTickCount();
+ if (newTime - oldTime > 45000) {
+ smb_user_t *uidp;
+ smb_fid_t *fidp;
+ clientchar_t *treepath = NULL; /* do not free */
+ clientchar_t *pathname = NULL;
+ cm_fid_t afid = {0,0,0,0,0};
+
+ uidp = smb_FindUID(vcp, asp->uid, 0);
+ smb_LookupTIDPath(vcp, asp->tid, &treepath);
+ fidp = smb_FindFID(vcp, inp->fid, 0);
+
+ if (fidp) {
+ lock_ObtainMutex(&fidp->mx);
+ if (fidp->NTopen_pathp)
+ pathname = fidp->NTopen_pathp;
+ if (fidp->scp)
+ afid = fidp->scp->fid;
+ } else {
+ if (inp->stringsp->wdata)
+ pathname = inp->stringsp->wdata;
+ }
+
+ afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
+ myCrt_2Dispatch(asp->opcode), newTime - oldTime,
+ asp->uid, uidp ? uidp->unp->name : NULL,
+ asp->pid, asp->mid, asp->tid,
+ treepath,
+ pathname,
+ afid.cell, afid.volume, afid.vnode, afid.unique);
+
+ if (fidp)
+ lock_ReleaseMutex(&fidp->mx);
+
+ if (uidp)
+ smb_ReleaseUID(uidp);
+ if (fidp)
+ smb_ReleaseFID(fidp);
+ }
+
/* free the input tran 2 packet */
smb_FreeTran2Packet(asp);
}
return 0;
}
+/* TRANS2_OPEN2 */
long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
- char *pathp;
+ clientchar_t *pathp;
smb_tran2Packet_t *outp;
long code = 0;
cm_space_t *spacep;
int initialModeBits;
smb_fid_t *fidp;
int attributes;
- char *lastNamep;
+ clientchar_t *lastNamep;
afs_uint32 dosTime;
int openFun;
int trunc;
int openAction;
int parmSlot; /* which parm we're dealing with */
long returnEALength;
- char *tidPathp;
+ clientchar_t *tidPathp;
cm_req_t req;
int created = 0;
- cm_InitReq(&req);
+ smb_InitReq(&req);
scp = NULL;
/* compute initial mode bits based on read-only flag in attributes */
initialModeBits = 0666;
- if (attributes & 1)
+ if (attributes & SMB_ATTR_READONLY)
initialModeBits &= ~0222;
- pathp = (char *) (&p->parmsp[14]);
- if (smb_StoreAnsiFilenames)
- OemToChar(pathp,pathp);
+ pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
+ SMB_STRF_ANSIPATH);
outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+ smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
- if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+ if (lastNamep &&
+ (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
+ cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
+ cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
+ cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
/* special case magic file name for receiving IOCTL requests
* (since IOCTL calls themselves aren't getting through).
*/
return 0;
}
+ if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+ clientchar_t * hexp;
+
+ hexp = cm_GetRawCharsAlloc(pathp, -1);
+ osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
+ osi_LogSaveClientString(smb_logp, hexp));
+ if (hexp)
+ free(hexp);
+#else
+ osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
+#endif
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADNTFILENAME;
+ }
+
#ifdef DEBUG_VERBOSE
{
char *hexp, *asciip;
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &scp);
if (code != 0) {
- code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &dscp);
cm_FreeSpace(spacep);
#ifdef DFS_SUPPORT
if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+ (clientchar_t*) spacep->data);
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
- if ( WANTS_DFS_PATHNAMES(p) )
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
lastNamep++;
code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
&req, &scp);
- if (code && code != CM_ERROR_NOSUCHFILE) {
+ if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
} else {
#ifdef DFS_SUPPORT
if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
- if ( WANTS_DFS_PATHNAMES(p) )
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
/* don't create if not found */
if (dscp)
cm_ReleaseSCache(dscp);
- osi_assert(scp == NULL);
+ osi_assertx(scp == NULL, "null cm_scache_t");
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
return CM_ERROR_NOSUCHFILE;
}
else {
- osi_assert(dscp != NULL && scp == NULL);
+ osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
openAction = 2; /* created file */
setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (!excl && code == CM_ERROR_EXISTS) {
/* not an exclusive create, and someone else tried
/* now all we have to do is open the file itself */
fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
+ osi_assertx(fidp, "null smb_fid_t");
cm_HoldUser(userp);
lock_ObtainMutex(&fidp->mx);
/* save a pointer to the vnode */
+ osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
fidp->scp = scp;
+ lock_ObtainWrite(&scp->rw);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseWrite(&scp->rw);
+
/* and the user */
fidp->userp = userp;
/* compute open mode */
if (openMode != 1)
- fidp->flags |= SMB_FID_OPENREAD;
+ fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
if (openMode == 1 || openMode == 2)
fidp->flags |= SMB_FID_OPENWRITE;
/* copy out remainder of the parms */
parmSlot = 0;
outp->parmsp[parmSlot++] = fidp->fid;
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainRead(&scp->rw);
if (extraInfo) {
outp->parmsp[parmSlot++] = smb_Attributes(scp);
smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
outp->parmsp[parmSlot++] = 0;
outp->parmsp[parmSlot++] = 0;
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseRead(&scp->rw);
outp->totalData = 0; /* total # of data bytes */
outp->totalParms = parmSlot * 2; /* shorts are two bytes */
return 0;
}
-long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
- osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
- return CM_ERROR_BADOP;
-}
+ unsigned short fid;
+ unsigned short infolevel;
-long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
- osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
- return CM_ERROR_BADOP;
+ infolevel = p->parmsp[0];
+ fid = p->parmsp[1];
+ osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
+
+ return CM_ERROR_BAD_LEVEL;
}
+/* TRANS2_QUERY_FS_INFORMATION */
long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
smb_tran2Packet_t *outp;
smb_tran2QFSInfo_t qi;
int responseSize;
- osi_hyper_t temp;
- static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
+ size_t sz = 0;
osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
switch (p->parmsp[0]) {
- case 1: responseSize = sizeof(qi.u.allocInfo); break;
- case 2: responseSize = sizeof(qi.u.volumeInfo); break;
- break;
- case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
- case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
- case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
- case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
- case 0x200: /* CIFS Unix Info */
- case 0x301: /* Mac FS Info */
- default:
- return CM_ERROR_INVAL;
- }
-
- outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
- switch (p->parmsp[0]) {
- case 1:
+ case SMB_INFO_ALLOCATION:
/* alloc info */
+ responseSize = sizeof(qi.u.allocInfo);
+
qi.u.allocInfo.FSID = 0;
qi.u.allocInfo.sectorsPerAllocUnit = 1;
qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
qi.u.allocInfo.bytesPerSector = 1024;
break;
- case 2:
+ case SMB_INFO_VOLUME:
/* volume info */
- qi.u.volumeInfo.vsn = 1234;
- qi.u.volumeInfo.vnCount = 4;
+ qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
+ qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
+
/* we're supposed to pad it out with zeroes to the end */
memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
- memcpy(qi.u.volumeInfo.label, "AFS", 4);
+ smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
+
+ responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
break;
- case 0x102:
+ case SMB_QUERY_FS_VOLUME_INFO:
/* FS volume info */
- memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
+ responseSize = sizeof(qi.u.FSvolumeInfo);
+
+ {
+ FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
+ memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
+ }
+
qi.u.FSvolumeInfo.vsn = 1234;
- qi.u.FSvolumeInfo.vnCount = 8;
- memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
+ qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
+ memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
+ memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
break;
- case 0x103:
+ case SMB_QUERY_FS_SIZE_INFO:
/* FS size info */
- temp.HighPart = 0;
- temp.LowPart = 0x7fffffff;
- qi.u.FSsizeInfo.totalAllocUnits = temp;
- temp.LowPart = 0x3fffffff;
- qi.u.FSsizeInfo.availAllocUnits = temp;
+ responseSize = sizeof(qi.u.FSsizeInfo);
+
+ qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
+ qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
+ qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
+ qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
qi.u.FSsizeInfo.bytesPerSector = 1024;
break;
- case 0x104:
+ case SMB_QUERY_FS_DEVICE_INFO:
/* FS device info */
- qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
+ responseSize = sizeof(qi.u.FSdeviceInfo);
+
+ qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
break;
- case 0x105:
+ case SMB_QUERY_FS_ATTRIBUTE_INFO:
/* FS attribute info */
+
/* attributes, defined in WINNT.H:
* FILE_CASE_SENSITIVE_SEARCH 0x1
* FILE_CASE_PRESERVED_NAMES 0x2
+ * FILE_UNICODE_ON_DISK 0x4
+ * FILE_VOLUME_QUOTAS 0x10
* <no name defined> 0x4000
* If bit 0x4000 is not set, Windows 95 thinks
* we can't handle long (non-8.3) names,
* despite our protestations to the contrary.
*/
qi.u.FSattributeInfo.attributes = 0x4003;
+ /* The maxCompLength is supposed to be in bytes */
+#ifdef SMB_UNICODE
+ qi.u.FSattributeInfo.attributes |= 0x04;
+#endif
qi.u.FSattributeInfo.maxCompLength = 255;
- qi.u.FSattributeInfo.FSnameLength = 6;
- memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
+ smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
+ qi.u.FSattributeInfo.FSnameLength = sz;
+
+ responseSize =
+ sizeof(qi.u.FSattributeInfo.attributes) +
+ sizeof(qi.u.FSattributeInfo.maxCompLength) +
+ sizeof(qi.u.FSattributeInfo.FSnameLength) +
+ sz;
+
break;
+
+ case SMB_INFO_UNIX: /* CIFS Unix Info */
+ case SMB_INFO_MACOS: /* Mac FS Info */
+ default:
+ return CM_ERROR_BADOP;
}
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
+
/* copy out return data, and set corresponding sizes */
outp->totalParms = 0;
outp->totalData = responseSize;
}
struct smb_ShortNameRock {
- char *maskp;
+ clientchar_t *maskp;
unsigned int vnode;
- char *shortName;
+ clientchar_t *shortName;
size_t shortNameLen;
};
osi_hyper_t *offp)
{
struct smb_ShortNameRock *rockp;
- char *shortNameEnd;
+ normchar_t normName[MAX_PATH];
+ clientchar_t *shortNameEnd;
rockp = vrockp;
+
+ if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
+ osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+ osi_LogSaveString(smb_logp, dep->name));
+ return 0;
+ }
+
/* compare both names and vnodes, though probably just comparing vnodes
* would be safe enough.
*/
- if (cm_stricmp(dep->name, rockp->maskp) != 0)
+ if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
return 0;
if (ntohl(dep->fid.vnode) != rockp->vnode)
return 0;
+
/* This is the entry */
cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
rockp->shortNameLen = shortNameEnd - rockp->shortName;
+
return CM_ERROR_STOPNOW;
-}
+}
-long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
- char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
+long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
+ clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
{
struct smb_ShortNameRock rock;
- char *lastNamep;
+ clientchar_t *lastNamep;
cm_space_t *spacep;
cm_scache_t *dscp;
int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
osi_hyper_t thyper;
spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+ smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
- code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
- reqp, &dscp);
+ code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+ caseFold, userp, tidPathp,
+ reqp, &dscp);
cm_FreeSpace(spacep);
if (code)
return code;
if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
+#ifdef DEBUG
+ DebugBreak();
+#endif
return CM_ERROR_PATH_NOT_COVERED;
}
#endif /* DFS_SUPPORT */
return code;
}
+/* TRANS2_QUERY_PATH_INFORMATION */
long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
smb_tran2Packet_t *outp;
afs_uint32 dosTime;
FILETIME ft;
unsigned short infoLevel;
- int nbytesRequired;
+ smb_tran2QPathInfo_t qpi;
+ int responseSize;
unsigned short attributes;
unsigned long extAttributes;
- char shortName[13];
- unsigned int len;
+ clientchar_t shortName[13];
+ size_t len;
cm_user_t *userp;
cm_space_t *spacep;
cm_scache_t *scp, *dscp;
+ int scp_rw_held = 0;
+ int delonclose = 0;
long code = 0;
- char *op;
- char *tidPathp;
- char *lastComp;
+ clientchar_t *pathp;
+ clientchar_t *tidPathp;
+ clientchar_t *lastComp;
cm_req_t req;
- cm_InitReq(&req);
+ smb_InitReq(&req);
infoLevel = p->parmsp[0];
if (infoLevel == SMB_INFO_IS_NAME_VALID)
- nbytesRequired = 0;
+ responseSize = 0;
else if (infoLevel == SMB_INFO_STANDARD)
- nbytesRequired = 22;
+ responseSize = sizeof(qpi.u.QPstandardInfo);
else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
- nbytesRequired = 26;
- else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
- nbytesRequired = 40;
- else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
- nbytesRequired = 24;
- else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
- nbytesRequired = 4;
+ responseSize = sizeof(qpi.u.QPeaSizeInfo);
+ else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
+ responseSize = sizeof(qpi.u.QPfileBasicInfo);
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
+ responseSize = sizeof(qpi.u.QPfileStandardInfo);
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+ responseSize = sizeof(qpi.u.QPfileEaInfo);
+ else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
+ responseSize = sizeof(qpi.u.QPfileNameInfo);
+ else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
+ responseSize = sizeof(qpi.u.QPfileAllInfo);
else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
- nbytesRequired = 30;
+ responseSize = sizeof(qpi.u.QPfileAltNameInfo);
else {
osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
return 0;
}
- osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
- osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
- outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
+ pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
+ osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
+ osi_LogSaveClientString(smb_logp, pathp));
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
if (infoLevel > 0x100)
outp->totalParms = 2;
else
outp->totalParms = 0;
- outp->totalData = nbytesRequired;
+ outp->totalData = responseSize;
/* now, if we're at infoLevel 6, we're only being asked to check
* the syntax, so we just OK things now. In particular, we're *not*
*/
if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastComp,
- (char *)(&p->parmsp[3]));
+ smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
#ifndef SPECIAL_FOLDERS
/* Make sure that lastComp is not NULL */
if (lastComp) {
- if (stricmp(lastComp, "\\desktop.ini") == 0) {
- code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
+ code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
CM_FLAG_CASEFOLD
| CM_FLAG_DIRSEARCH
| CM_FLAG_FOLLOW,
if (code == 0) {
#ifdef DFS_SUPPORT
if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
- if ( WANTS_DFS_PATHNAMES(p) )
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+ spacep->wdata);
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
code = CM_ERROR_PATH_NOT_COVERED;
else
- code = CM_ERROR_BADSHARENAME;
+ code = CM_ERROR_NOSUCHPATH;
} else
#endif /* DFS_SUPPORT */
if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
code = CM_ERROR_NOSUCHFILE;
else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
cm_buf_t *bp = buf_Find(dscp, &hzero);
- if (bp)
+ if (bp) {
buf_Release(bp);
+ bp = NULL;
+ }
else
code = CM_ERROR_NOSUCHFILE;
}
}
/* now do namei and stat, and copy out the info */
- code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
+ code = cm_NameI(cm_data.rootSCachep, pathp,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
if (code) {
#ifdef DFS_SUPPORT
if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- if ( WANTS_DFS_PATHNAMES(p) )
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
code = CM_ERROR_PATH_NOT_COVERED;
else
- code = CM_ERROR_BADSHARENAME;
+ code = CM_ERROR_NOSUCHPATH;
smb_SendTran2Error(vcp, p, opx, code);
smb_FreeTran2Packet(outp);
return 0;
}
#endif /* DFS_SUPPORT */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
+ scp_rw_held = 2;
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) goto done;
+ if (code)
+ goto done;
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ConvertWToR(&scp->rw);
+ scp_rw_held = 1;
+
+ len = 0;
+
/* now we have the status in the cache entry, and everything is locked.
* Marshall the output data.
*/
- op = outp->datap;
/* for info level 108, figure out short name */
- if (infoLevel == 0x108) {
- code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
+ if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
+ code = cm_GetShortName(pathp, userp, &req,
tidPathp, scp->fid.vnode, shortName,
- (size_t *) &len);
+ &len);
if (code) {
goto done;
}
- op = outp->datap;
- *((u_long *)op) = len * 2; op += 4;
- mbstowcs((unsigned short *)op, shortName, len);
- op += (len * 2);
+ smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
+ qpi.u.QPfileAltNameInfo.fileNameLength = len;
goto done;
}
- if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
+ else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+ smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
+ qpi.u.QPfileNameInfo.fileNameLength = len;
+
+ goto done;
+ }
+ else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
- *((u_long *)op) = dosTime; op += 4; /* creation time */
- *((u_long *)op) = dosTime; op += 4; /* access time */
- *((u_long *)op) = dosTime; op += 4; /* write time */
- *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
- *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
+ qpi.u.QPstandardInfo.creationDateTime = dosTime;
+ qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
+ qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
+ qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
+ qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
attributes = smb_Attributes(scp);
- *((u_short *)op) = attributes; op += 2; /* attributes */
+ qpi.u.QPstandardInfo.attributes = attributes;
+ qpi.u.QPstandardInfo.eaSize = 0;
}
else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- *((FILETIME *)op) = ft; op += 8; /* creation time */
- *((FILETIME *)op) = ft; op += 8; /* last access time */
- *((FILETIME *)op) = ft; op += 8; /* last write time */
- *((FILETIME *)op) = ft; op += 8; /* last change time */
+ qpi.u.QPfileBasicInfo.creationTime = ft;
+ qpi.u.QPfileBasicInfo.lastAccessTime = ft;
+ qpi.u.QPfileBasicInfo.lastWriteTime = ft;
+ qpi.u.QPfileBasicInfo.changeTime = ft;
extAttributes = smb_ExtAttributes(scp);
- *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
- *((u_long *)op) = 0; op += 4; /* don't know what this is */
+ qpi.u.QPfileBasicInfo.attributes = extAttributes;
+ qpi.u.QPfileBasicInfo.reserved = 0;
}
else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
- *((u_long *)op) = scp->linkCount; op += 4;
- *op++ = 0;
- *op++ = 0;
- *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
- *op++ = 0;
+ smb_fid_t * fidp;
+
+ lock_ReleaseRead(&scp->rw);
+ scp_rw_held = 0;
+ fidp = smb_FindFIDByScache(vcp, scp);
+
+ qpi.u.QPfileStandardInfo.allocationSize = scp->length;
+ qpi.u.QPfileStandardInfo.endOfFile = scp->length;
+ qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
+ qpi.u.QPfileStandardInfo.directory =
+ ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
+ qpi.u.QPfileStandardInfo.reserved = 0;
+
+ if (fidp) {
+ lock_ObtainMutex(&fidp->mx);
+ delonclose = fidp->flags & SMB_FID_DELONCLOSE;
+ lock_ReleaseMutex(&fidp->mx);
+ smb_ReleaseFID(fidp);
+ }
+ qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
}
else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
- memset(op, 0, 4); op += 4; /* EA size */
+ qpi.u.QPfileEaInfo.eaSize = 0;
}
-
- /* now, if we are being asked about extended attrs, return a 0 size */
- if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
- *((u_long *)op) = 0; op += 4;
+ else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+ qpi.u.QPfileAllInfo.creationTime = ft;
+ qpi.u.QPfileAllInfo.lastAccessTime = ft;
+ qpi.u.QPfileAllInfo.lastWriteTime = ft;
+ qpi.u.QPfileAllInfo.changeTime = ft;
+ extAttributes = smb_ExtAttributes(scp);
+ qpi.u.QPfileAllInfo.attributes = extAttributes;
+ qpi.u.QPfileAllInfo.allocationSize = scp->length;
+ qpi.u.QPfileAllInfo.endOfFile = scp->length;
+ qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
+ qpi.u.QPfileAllInfo.deletePending = 0;
+ qpi.u.QPfileAllInfo.directory =
+ ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
+ qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
+ qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
+ qpi.u.QPfileAllInfo.eaSize = 0;
+ qpi.u.QPfileAllInfo.accessFlags = 0;
+ qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
+ qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
+ qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
+ qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
+ qpi.u.QPfileAllInfo.mode = 0;
+ qpi.u.QPfileAllInfo.alignmentRequirement = 0;
+
+ smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
+ qpi.u.QPfileAllInfo.fileNameLength = len;
}
-
/* send and free the packets */
done:
- lock_ReleaseMutex(&scp->mx);
+ switch (scp_rw_held) {
+ case 1:
+ lock_ReleaseRead(&scp->rw);
+ break;
+ case 2:
+ lock_ReleaseWrite(&scp->rw);
+ break;
+ }
+ scp_rw_held = 0;
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- if (code == 0)
- smb_SendTran2Packet(vcp, outp, opx);
- else
+ if (code == 0) {
+ memcpy(outp->datap, &qpi, responseSize);
+ smb_SendTran2Packet(vcp, outp, opx);
+ } else {
smb_SendTran2Error(vcp, p, opx, code);
+ }
smb_FreeTran2Packet(outp);
return 0;
}
-long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+/* TRANS2_SET_PATH_INFORMATION */
+long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
+#if 0
osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
return CM_ERROR_BADOP;
-}
-
-long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
-{
- smb_tran2Packet_t *outp;
- FILETIME ft;
- unsigned long attributes;
+#else
+ long code = 0;
unsigned short infoLevel;
- int nbytesRequired;
- unsigned short fid;
+ clientchar_t * pathp;
+ smb_tran2Packet_t *outp;
+ smb_tran2QPathInfo_t *spi;
cm_user_t *userp;
- smb_fid_t *fidp;
- cm_scache_t *scp;
- char *op;
- long code = 0;
+ cm_scache_t *scp, *dscp;
cm_req_t req;
+ cm_space_t *spacep;
+ clientchar_t *tidPathp;
+ clientchar_t *lastComp;
- cm_InitReq(&req);
+ smb_InitReq(&req);
- fid = p->parmsp[0];
- fidp = smb_FindFID(vcp, fid, 0);
+ infoLevel = p->parmsp[0];
+ osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
+ if (infoLevel != SMB_INFO_STANDARD &&
+ infoLevel != SMB_INFO_QUERY_EA_SIZE &&
+ infoLevel != SMB_INFO_QUERY_ALL_EAS) {
+ osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+ p->opcode, infoLevel);
+ smb_SendTran2Error(vcp, p, opx,
+ infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
+ return 0;
+ }
+
+ pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
+
+ osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
+ osi_LogSaveClientString(smb_logp, pathp));
+
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
+ code = CM_ERROR_BADSMB;
+ goto done;
+ }
+
+ code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+ if (code == CM_ERROR_TIDIPC) {
+ /* Attempt to use a TID allocated for IPC. The client
+ * is probably looking for DCE RPC end points which we
+ * don't support OR it could be looking to make a DFS
+ * referral request.
+ */
+ osi_Log0(smb_logp, "Tran2Open received IPC TID");
+ cm_ReleaseUser(userp);
+ return CM_ERROR_NOSUCHPATH;
+ }
+
+ /*
+ * XXX Strange hack XXX
+ *
+ * As of Patch 7 (13 January 98), we are having the following problem:
+ * In NT Explorer 4.0, whenever we click on a directory, AFS gets
+ * requests to look up "desktop.ini" in all the subdirectories.
+ * This can cause zillions of timeouts looking up non-existent cells
+ * and volumes, especially in the top-level directory.
+ *
+ * We have not found any way to avoid this or work around it except
+ * to explicitly ignore the requests for mount points that haven't
+ * yet been evaluated and for directories that haven't yet been
+ * fetched.
+ */
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
+#ifndef SPECIAL_FOLDERS
+ /* Make sure that lastComp is not NULL */
+ if (lastComp) {
+ if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
+ code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+ CM_FLAG_CASEFOLD
+ | CM_FLAG_DIRSEARCH
+ | CM_FLAG_FOLLOW,
+ userp, tidPathp, &req, &dscp);
+ if (code == 0) {
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+ spacep->wdata);
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_NOSUCHPATH;
+ } else
+#endif /* DFS_SUPPORT */
+ if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
+ code = CM_ERROR_NOSUCHFILE;
+ else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
+ cm_buf_t *bp = buf_Find(dscp, &hzero);
+ if (bp) {
+ buf_Release(bp);
+ bp = NULL;
+ }
+ else
+ code = CM_ERROR_NOSUCHFILE;
+ }
+ cm_ReleaseSCache(dscp);
+ if (code) {
+ cm_FreeSpace(spacep);
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ return 0;
+ }
+ }
+ }
+ }
+#endif /* SPECIAL_FOLDERS */
+
+ cm_FreeSpace(spacep);
+ }
+
+ /* now do namei and stat, and copy out the info */
+ code = cm_NameI(cm_data.rootSCachep, pathp,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ return 0;
+ }
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
+
+ outp->totalParms = 2;
+ outp->totalData = 0;
+
+ spi = (smb_tran2QPathInfo_t *)p->datap;
+ if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
+ cm_attr_t attr;
+
+ /* lock the vnode with a callback; we need the current status
+ * to determine what the new status is, in some cases.
+ */
+ lock_ObtainWrite(&scp->rw);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_GETSTATUS
+ | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code) {
+ lock_ReleaseWrite(&scp->rw);
+ goto done;
+ }
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ /* prepare for setattr call */
+ attr.mask = CM_ATTRMASK_LENGTH;
+ attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
+ attr.length.HighPart = 0;
+
+ if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
+ smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
+ attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
+ }
+
+ if (spi->u.QPstandardInfo.attributes != 0) {
+ if ((scp->unixModeBits & 0222)
+ && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
+ /* make a writable file read-only */
+ attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+ attr.unixModeBits = scp->unixModeBits & ~0222;
+ }
+ else if ((scp->unixModeBits & 0222) == 0
+ && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
+ /* make a read-only file writable */
+ attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+ attr.unixModeBits = scp->unixModeBits | 0222;
+ }
+ }
+ lock_ReleaseRead(&scp->rw);
+
+ /* call setattr */
+ if (attr.mask)
+ code = cm_SetAttr(scp, &attr, userp, &req);
+ else
+ code = 0;
+ }
+ else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
+ /* we don't support EAs */
+ code = CM_ERROR_EAS_NOT_SUPPORTED;
+ }
+
+ done:
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if (code == 0)
+ smb_SendTran2Packet(vcp, outp, opx);
+ else
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+#endif
+}
+
+/* TRANS2_QUERY_FILE_INFORMATION */
+long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+{
+ smb_tran2Packet_t *outp;
+ FILETIME ft;
+ unsigned long attributes;
+ unsigned short infoLevel;
+ int responseSize;
+ unsigned short fid;
+ int delonclose = 0;
+ cm_user_t *userp;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
+ smb_tran2QFileInfo_t qfi;
+ long code = 0;
+ int readlock = 0;
+ cm_req_t req;
+
+ smb_InitReq(&req);
+
+ fid = p->parmsp[0];
+ fidp = smb_FindFID(vcp, fid, 0);
if (fidp == NULL) {
smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
return 0;
}
+ lock_ObtainMutex(&fidp->mx);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+ lock_ReleaseMutex(&fidp->mx);
+
infoLevel = p->parmsp[1];
if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
- nbytesRequired = 40;
+ responseSize = sizeof(qfi.u.QFbasicInfo);
else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
- nbytesRequired = 24;
+ responseSize = sizeof(qfi.u.QFstandardInfo);
else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
- nbytesRequired = 4;
+ responseSize = sizeof(qfi.u.QFeaInfo);
else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
- nbytesRequired = 6;
+ responseSize = sizeof(qfi.u.QFfileNameInfo);
else {
osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
smb_ReleaseFID(fidp);
return 0;
}
osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
- outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
if (infoLevel > 0x100)
outp->totalParms = 2;
else
outp->totalParms = 0;
- outp->totalData = nbytesRequired;
+ outp->totalData = responseSize;
userp = smb_GetTran2User(vcp, p);
if (!userp) {
}
lock_ObtainMutex(&fidp->mx);
+ delonclose = fidp->flags & SMB_FID_DELONCLOSE;
scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
+ osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
+ cm_HoldSCache(scp);
+ lock_ReleaseMutex(&fidp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
if (code)
goto done;
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ lock_ConvertWToR(&scp->rw);
+ readlock = 1;
+
/* now we have the status in the cache entry, and everything is locked.
* Marshall the output data.
*/
- op = outp->datap;
if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- *((FILETIME *)op) = ft; op += 8; /* creation time */
- *((FILETIME *)op) = ft; op += 8; /* last access time */
- *((FILETIME *)op) = ft; op += 8; /* last write time */
- *((FILETIME *)op) = ft; op += 8; /* last change time */
+ qfi.u.QFbasicInfo.creationTime = ft;
+ qfi.u.QFbasicInfo.lastAccessTime = ft;
+ qfi.u.QFbasicInfo.lastWriteTime = ft;
+ qfi.u.QFbasicInfo.lastChangeTime = ft;
attributes = smb_ExtAttributes(scp);
- *((u_long *)op) = attributes; op += 4;
- *((u_long *)op) = 0; op += 4;
+ qfi.u.QFbasicInfo.attributes = attributes;
}
else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
- *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
- *((u_long *)op) = scp->linkCount; op += 4;
- *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
- *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
- *op++ = 0;
- *op++ = 0;
+ qfi.u.QFstandardInfo.allocationSize = scp->length;
+ qfi.u.QFstandardInfo.endOfFile = scp->length;
+ qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
+ qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
+ qfi.u.QFstandardInfo.directory =
+ ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
}
else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
- *((u_long *)op) = 0; op += 4;
+ qfi.u.QFeaInfo.eaSize = 0;
}
else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
- unsigned long len;
- char *name;
+ size_t len = 0;
+ clientchar_t *name;
+ lock_ReleaseRead(&scp->rw);
+ lock_ObtainMutex(&fidp->mx);
+ lock_ObtainRead(&scp->rw);
if (fidp->NTopen_wholepathp)
name = fidp->NTopen_wholepathp;
else
- name = "\\"; /* probably can't happen */
- len = (unsigned long)strlen(name);
- outp->totalData = (len*2) + 4; /* this is actually what we want to return */
- *((u_long *)op) = len * 2; op += 4;
- mbstowcs((unsigned short *)op, name, len); op += (len * 2);
+ name = _C("\\"); /* probably can't happen */
+ lock_ReleaseMutex(&fidp->mx);
+
+ smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
+ outp->totalData = len + 4; /* this is actually what we want to return */
+ qfi.u.QFfileNameInfo.fileNameLength = len;
}
/* send and free the packets */
done:
- lock_ReleaseMutex(&scp->mx);
- lock_ReleaseMutex(&fidp->mx);
+ if (readlock)
+ lock_ReleaseRead(&scp->rw);
+ else
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_ReleaseFID(fidp);
- if (code == 0)
+ if (code == 0) {
+ memcpy(outp->datap, &qfi, responseSize);
smb_SendTran2Packet(vcp, outp, opx);
- else
+ } else {
smb_SendTran2Error(vcp, p, opx, code);
+ }
smb_FreeTran2Packet(outp);
return 0;
}
-long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+
+/* TRANS2_SET_FILE_INFORMATION */
+long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
long code = 0;
unsigned short fid;
smb_fid_t *fidp;
unsigned short infoLevel;
smb_tran2Packet_t *outp;
- cm_user_t *userp;
- cm_scache_t *scp;
+ cm_user_t *userp = NULL;
+ cm_scache_t *scp = NULL;
cm_req_t req;
- cm_InitReq(&req);
+ smb_InitReq(&req);
fid = p->parmsp[0];
fidp = smb_FindFID(vcp, fid, 0);
if (fidp == NULL) {
- smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
return 0;
}
infoLevel = p->parmsp[1];
osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
- if (infoLevel > 0x104 || infoLevel < 0x101) {
+ if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
smb_ReleaseFID(fidp);
return 0;
}
lock_ObtainMutex(&fidp->mx);
- if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+
+ if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
+ !(fidp->flags & SMB_FID_OPENDELETE)) {
+ osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
+ fidp, fidp->scp, fidp->flags);
lock_ReleaseMutex(&fidp->mx);
smb_ReleaseFID(fidp);
- smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
return 0;
}
- if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
+ if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
+ infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
&& !(fidp->flags & SMB_FID_OPENWRITE)) {
+ osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
+ fidp, fidp->scp, fidp->flags);
lock_ReleaseMutex(&fidp->mx);
smb_ReleaseFID(fidp);
- smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
return 0;
}
- lock_ReleaseMutex(&fidp->mx);
- osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
+ scp = fidp->scp;
+ osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
+ cm_HoldSCache(scp);
+ lock_ReleaseMutex(&fidp->mx);
- outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
outp->totalParms = 2;
outp->totalData = 0;
goto done;
}
- scp = fidp->scp;
-
- if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
FILETIME lastMod;
unsigned int attribute;
cm_attr_t attr;
+ smb_tran2QFileInfo_t *sfi;
- /* lock the vnode with a callback; we need the current status
+ sfi = (smb_tran2QFileInfo_t *)p->datap;
+
+ /* lock the vnode with a callback; we need the current status
* to determine what the new status is, in some cases.
*/
- lock_ObtainMutex(&fidp->mx);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_NEEDCALLBACK);
if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
goto done;
- }
+ }
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ lock_ReleaseWrite(&scp->rw);
+ lock_ObtainMutex(&fidp->mx);
+ lock_ObtainRead(&scp->rw);
/* prepare for setattr call */
attr.mask = 0;
- lastMod = *((FILETIME *)(p->datap + 16));
+ lastMod = sfi->u.QFbasicInfo.lastWriteTime;
/* when called as result of move a b, lastMod is (-1, -1).
* If the check for -1 is not present, timestamp
* of the resulting file will be 1969 (-1)
fidp->flags |= SMB_FID_MTIMESETDONE;
}
- attribute = *((u_long *)(p->datap + 32));
+ attribute = sfi->u.QFbasicInfo.attributes;
if (attribute != 0) {
if ((scp->unixModeBits & 0222)
- && (attribute & 1) != 0) {
+ && (attribute & SMB_ATTR_READONLY) != 0) {
/* make a writable file read-only */
attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
attr.unixModeBits = scp->unixModeBits & ~0222;
}
else if ((scp->unixModeBits & 0222) == 0
- && (attribute & 1) == 0) {
+ && (attribute & SMB_ATTR_READONLY) == 0) {
/* make a read-only file writable */
attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
attr.unixModeBits = scp->unixModeBits | 0222;
}
}
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseRead(&scp->rw);
lock_ReleaseMutex(&fidp->mx);
/* call setattr */
code = cm_SetAttr(scp, &attr, userp, &req);
else
code = 0;
- }
- else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
- LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
- cm_attr_t attr;
-
- attr.mask = CM_ATTRMASK_LENGTH;
- attr.length.LowPart = size.LowPart;
- attr.length.HighPart = size.HighPart;
- code = cm_SetAttr(scp, &attr, userp, &req);
- }
- else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
- if (*((char *)(p->datap))) {
+ }
+ else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
+ int delflag = *((char *)(p->datap));
+ osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
+ delflag, fidp, scp);
+ if (*((char *)(p->datap))) { /* File is Deleted */
code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
&req);
if (code == 0) {
lock_ObtainMutex(&fidp->mx);
fidp->flags |= SMB_FID_DELONCLOSE;
lock_ReleaseMutex(&fidp->mx);
+ } else {
+ osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
+ fidp, scp, code);
}
}
else {
lock_ReleaseMutex(&fidp->mx);
}
}
+ else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
+ infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
+ LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
+ cm_attr_t attr;
+
+ attr.mask = CM_ATTRMASK_LENGTH;
+ attr.length.LowPart = size.LowPart;
+ attr.length.HighPart = size.HighPart;
+ code = cm_SetAttr(scp, &attr, userp, &req);
+ }
done:
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_ReleaseFID(fidp);
if (code == 0)
- smb_SendTran2Packet(vcp, outp, op);
+ smb_SendTran2Packet(vcp, outp, opx);
else
- smb_SendTran2Error(vcp, p, op, code);
+ smb_SendTran2Error(vcp, p, opx, code);
smb_FreeTran2Packet(outp);
return 0;
}
+/* TRANS2_FSCTL */
long
smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
{
return CM_ERROR_BADOP;
}
+/* TRANS2_IOCTL2 */
long
smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
{
return CM_ERROR_BADOP;
}
+/* TRANS2_FIND_NOTIFY_FIRST */
long
smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
{
return CM_ERROR_BADOP;
}
+/* TRANS2_FIND_NOTIFY_NEXT */
long
smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
{
return CM_ERROR_BADOP;
}
+/* TRANS2_CREATE_DIRECTORY */
long
smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
{
return CM_ERROR_BADOP;
}
+/* TRANS2_SESSION_SETUP */
long
smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
{
USHORT NetworkAddressOffset;
};
+/* TRANS2_GET_DFS_REFERRAL */
long
smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
#ifdef DFS_SUPPORT
long code = 0;
int maxReferralLevel = 0;
- char requestFileName[1024] = "";
+ clientchar_t requestFileName[1024] = _C("");
+ clientchar_t referralPath[1024] = _C("");
smb_tran2Packet_t *outp = 0;
cm_user_t *userp = 0;
+ cm_scache_t *scp = 0;
+ cm_scache_t *dscp = 0;
cm_req_t req;
CPINFO CodePageInfo;
- int i, nbnLen, reqLen;
+ int i, nbnLen, reqLen, refLen;
int idx;
- cm_InitReq(&req);
+ smb_InitReq(&req);
maxReferralLevel = p->parmsp[0];
GetCPInfo(CP_ACP, &CodePageInfo);
- WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
- requestFileName, 1024, NULL, NULL);
+ cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
- osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
- maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
+ osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
+ maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
- nbnLen = strlen(cm_NetbiosName);
- reqLen = strlen(requestFileName);
+ nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
+ reqLen = (int)cm_ClientStrLen(requestFileName);
- if (reqLen == nbnLen + 5 &&
- requestFileName[0] == '\\' &&
- !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
- requestFileName[nbnLen+1] == '\\' &&
- !_strnicmp("all",&requestFileName[nbnLen+2],3))
+ if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
+ !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
+ requestFileName[nbnLen+1] == '\\')
{
- USHORT * sp;
- struct smb_v2_referral * v2ref;
- outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
-
- sp = (USHORT *)outp->datap;
- idx = 0;
- sp[idx++] = reqLen; /* path consumed */
- sp[idx++] = 1; /* number of referrals */
- sp[idx++] = 0x03; /* flags */
+ int found = 0;
+
+ if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
+ !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
+ found = 1;
+ cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
+ refLen = reqLen;
+ } else {
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
+ code = CM_ERROR_BADSMB;
+ goto done;
+ }
+
+ /*
+ * We have a requested path. Check to see if it is something
+ * we know about.
+ *
+ * But be careful because the name that we might be searching
+ * for might be a known name with the final character stripped
+ * off.
+ */
+ code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
+ userp, NULL, &req, &scp);
+ if (code == 0) {
+ /* Yes it is. */
+ found = 1;
+ cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
+ refLen = reqLen;
+ } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
+ clientchar_t temp[1024];
+ clientchar_t pathName[1024];
+ clientchar_t *lastComponent;
+ /*
+ * we have a msdfs link somewhere in the path
+ * we should figure out where in the path the link is.
+ * and return it.
+ */
+ osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
+
+ cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
+
+ do {
+ if (dscp) {
+ cm_ReleaseSCache(dscp);
+ dscp = 0;
+ }
+ if (scp) {
+ cm_ReleaseSCache(scp);
+ scp = 0;
+ }
+ smb_StripLastComponent(pathName, &lastComponent, temp);
+
+ code = cm_NameI(cm_data.rootSCachep, pathName,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, NULL, &req, &dscp);
+ if (code == 0) {
+ code = cm_NameI(dscp, ++lastComponent,
+ CM_FLAG_CASEFOLD,
+ userp, NULL, &req, &scp);
+ if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
+ break;
+ }
+ } while (code == CM_ERROR_PATH_NOT_COVERED);
+
+ /* scp should now be the DfsLink we are looking for */
+ if (scp) {
+ /* figure out how much of the input path was used */
+ reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
+
+ cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
+ referralPath, lengthof(referralPath));
+ refLen = (int)cm_ClientStrLen(referralPath);
+ found = 1;
+ }
+ } else {
+ clientchar_t shareName[MAX_PATH + 1];
+ clientchar_t *p, *q;
+ /* we may have a sharename that is a volume reference */
+
+ for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
+ {
+ *q = *p;
+ }
+ *q = '\0';
+
+ if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
+ code = cm_NameI(cm_data.rootSCachep, _C(""),
+ CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+ userp, p, &req, &scp);
+ free(p);
+
+ if (code == 0) {
+ found = 1;
+ cm_ClientStrCpy(referralPath, lengthof(referralPath),
+ requestFileName);
+ refLen = reqLen;
+ }
+ }
+ }
+ }
+
+ if (found)
+ {
+ USHORT * sp;
+ struct smb_v2_referral * v2ref;
+ outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
+
+ sp = (USHORT *)outp->datap;
+ idx = 0;
+ sp[idx++] = reqLen; /* path consumed */
+ sp[idx++] = 1; /* number of referrals */
+ sp[idx++] = 0x03; /* flags */
#ifdef DFS_VERSION_1
- sp[idx++] = 1; /* Version Number */
- sp[idx++] = reqLen + 4; /* Referral Size */
- sp[idx++] = 1; /* Type = SMB Server */
- sp[idx++] = 0; /* Do not strip path consumed */
- for ( i=0;i<=reqLen; i++ )
- sp[i+idx] = requestFileName[i];
+ sp[idx++] = 1; /* Version Number */
+ sp[idx++] = refLen + 4; /* Referral Size */
+ sp[idx++] = 1; /* Type = SMB Server */
+ sp[idx++] = 0; /* Do not strip path consumed */
+ for ( i=0;i<=refLen; i++ )
+ sp[i+idx] = referralPath[i];
#else /* DFS_VERSION_2 */
- sp[idx++] = 2; /* Version Number */
- sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
- idx += (sizeof(struct smb_v2_referral) / 2);
- v2ref = (struct smb_v2_referral *) &sp[5];
- v2ref->ServerType = 1; /* SMB Server */
- v2ref->ReferralFlags = 0x03;
- v2ref->Proximity = 0; /* closest */
- v2ref->TimeToLive = 3600; /* seconds */
- v2ref->DfsPathOffset = idx * 2;
- v2ref->DfsAlternativePathOffset = idx * 2;
- v2ref->NetworkAddressOffset = 0;
- for ( i=0;i<=reqLen; i++ )
- sp[i+idx] = requestFileName[i];
+ sp[idx++] = 2; /* Version Number */
+ sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
+ idx += (sizeof(struct smb_v2_referral) / 2);
+ v2ref = (struct smb_v2_referral *) &sp[5];
+ v2ref->ServerType = 1; /* SMB Server */
+ v2ref->ReferralFlags = 0x03;
+ v2ref->Proximity = 0; /* closest */
+ v2ref->TimeToLive = 3600; /* seconds */
+ v2ref->DfsPathOffset = idx * 2;
+ v2ref->DfsAlternativePathOffset = idx * 2;
+ v2ref->NetworkAddressOffset = 0;
+ for ( i=0;i<=refLen; i++ )
+ sp[i+idx] = referralPath[i];
#endif
+ }
} else {
- userp = smb_GetTran2User(vcp, p);
- if (!userp) {
- osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
- code = CM_ERROR_BADSMB;
- goto done;
- }
-
- /* not done yet */
code = CM_ERROR_NOSUCHPATH;
}
-
+
done:
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
if (userp)
cm_ReleaseUser(userp);
if (code == 0)
return 0;
#else /* DFS_SUPPORT */
osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
- return CM_ERROR_BADOP;
+ return CM_ERROR_NOSUCHDEVICE;
#endif /* DFS_SUPPORT */
}
+/* TRANS2_REPORT_DFS_INCONSISTENCY */
long
smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
{
return CM_ERROR_BADOP;
}
-long
-smb_ApplyV3DirListPatches(cm_scache_t *dscp,
- smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
- cm_req_t *reqp)
+static long
+smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
+ clientchar_t * tidPathp, clientchar_t * relPathp,
+ int infoLevel, cm_user_t *userp, cm_req_t *reqp)
{
long code = 0;
cm_scache_t *scp;
cm_scache_t *targetScp; /* target if scp is a symlink */
- char *dptr;
afs_uint32 dosTime;
FILETIME ft;
- int shortTemp;
unsigned short attr;
unsigned long lattr;
smb_dirListPatch_t *patchp;
smb_dirListPatch_t *npatchp;
-
- for(patchp = *dirPatchespp; patchp; patchp =
- (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
- code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
- if (code) continue;
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+ afs_uint32 rights;
+ afs_int32 mustFake = 0;
+ clientchar_t path[AFSPATHMAX];
+
+ code = cm_FindACLCache(dscp, userp, &rights);
+ if (code == -1) {
+ lock_ObtainWrite(&dscp->rw);
+ code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) {
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
+ if (code == 0)
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&dscp->rw);
+ if (code == CM_ERROR_NOACCESS) {
+ mustFake = 1;
+ code = 0;
+ }
+ }
+ if (code)
+ goto cleanup;
- dptr = patchp->dptr;
+ if (!mustFake) { /* Bulk Stat */
+ afs_uint32 count;
+ cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
+
+ memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+ for (patchp = *dirPatchespp, count=0;
+ patchp;
+ patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+ cm_scache_t *tscp = NULL;
+ int i;
+
+ code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
+ if (code == 0) {
+ if (lock_TryWrite(&tscp->rw)) {
+ /* we have an entry that we can look at */
+#ifdef AFS_FREELANCE_CLIENT
+ if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
+ code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code == 0)
+ cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ lock_ReleaseWrite(&tscp->rw);
+ cm_ReleaseSCache(tscp);
+ continue;
+ }
+#endif /* AFS_FREELANCE_CLIENT */
+ if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+ /* we have a callback on it. Don't bother
+ * fetching this stat entry, since we're happy
+ * with the info we have.
+ */
+ lock_ReleaseWrite(&tscp->rw);
+ cm_ReleaseSCache(tscp);
+ continue;
+ }
+ lock_ReleaseWrite(&tscp->rw);
+ } /* got lock */
+ cm_ReleaseSCache(tscp);
+ } /* found entry */
+
+ i = bsp->counter++;
+ bsp->fids[i].Volume = patchp->fid.volume;
+ bsp->fids[i].Vnode = patchp->fid.vnode;
+ bsp->fids[i].Unique = patchp->fid.unique;
+
+ if (bsp->counter == AFSCBMAX) {
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+ memset(bsp, 0, sizeof(cm_bulkStat_t));
+ }
+ }
+
+ if (bsp->counter > 0)
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+
+ free(bsp);
+ }
+
+ for( patchp = *dirPatchespp;
+ patchp;
+ patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+ cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
+ relPathp ? relPathp : _C(""), patchp->dep->name);
+ reqp->relPathp = path;
+ reqp->tidPathp = tidPathp;
+
+ code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+ reqp->relPathp = reqp->tidPathp = NULL;
+ if (code)
+ continue;
+
+ lock_ObtainWrite(&scp->rw);
+ if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
+ lock_ReleaseWrite(&scp->rw);
/* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
errors in the client. */
- if (infoLevel >= 0x101) {
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+ smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+
/* 1969-12-31 23:59:59 +00 */
ft.dwHighDateTime = 0x19DB200;
ft.dwLowDateTime = 0x5BB78980;
/* copy to Creation Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Last Access Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Last Write Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Change Time */
- *((FILETIME *)dptr) = ft;
- dptr += 24;
-
+ fa->creationTime = ft;
+ fa->lastAccessTime = ft;
+ fa->lastWriteTime = ft;
+ fa->lastChangeTime = ft;
+
+ switch (scp->fileType) {
+ case CM_SCACHETYPE_DIRECTORY:
+ case CM_SCACHETYPE_MOUNTPOINT:
+ case CM_SCACHETYPE_INVALID:
+ fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+ break;
+ case CM_SCACHETYPE_SYMLINK:
+ if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+ fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+ else
+ fa->extFileAttributes = 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 (mustFake && (scp->fid.vnode & 0x1))
+ fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+ else
+ fa->extFileAttributes = SMB_ATTR_NORMAL;
+ }
/* merge in hidden attribute */
if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
- *((u_long *)dptr) = SMB_ATTR_HIDDEN;
+ fa->extFileAttributes |= SMB_ATTR_HIDDEN;
}
- dptr += 4;
} else {
+ smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
/* 1969-12-31 23:59:58 +00*/
dosTime = 0xEBBFBF7D;
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* copy out creation time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* copy out access time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
-
- /* copy out mod time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 10;
+ fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
+ fa->lastAccessDateTime = fa->creationDateTime;
+ fa->lastWriteDateTime = fa->creationDateTime;
+
+ /* set the attribute */
+ switch (scp->fileType) {
+ case CM_SCACHETYPE_DIRECTORY:
+ case CM_SCACHETYPE_MOUNTPOINT:
+ case CM_SCACHETYPE_INVALID:
+ fa->attributes = SMB_ATTR_DIRECTORY;
+ break;
+ case CM_SCACHETYPE_SYMLINK:
+ if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+ fa->attributes = SMB_ATTR_DIRECTORY;
+ else
+ fa->attributes = 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.
+ * even means it is to be treated as a directory
+ * and odd means it is to be treated as a file.
+ */
+ if (mustFake && (scp->fid.vnode & 0x1))
+ fa->attributes = SMB_ATTR_DIRECTORY;
+ else
+ fa->attributes = SMB_ATTR_NORMAL;
+ }
/* merge in hidden (dot file) attribute */
if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
- attr = SMB_ATTR_HIDDEN;
- *dptr++ = attr & 0xff;
- *dptr++ = (attr >> 8) & 0xff;
+ fa->attributes |= SMB_ATTR_HIDDEN;
}
}
+
+ cm_ReleaseSCache(scp);
continue;
}
-
+
/* now watch for a symlink */
code = 0;
while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
+ cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
+ relPathp ? relPathp : _C(""), patchp->dep->name);
+ reqp->relPathp = path;
+ reqp->tidPathp = tidPathp;
code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
+ reqp->relPathp = reqp->tidPathp = NULL;
if (code == 0) {
/* we have a more accurate file to use (the
* target of the symbolic link). Otherwise,
cm_ReleaseSCache(scp);
scp = targetScp;
}
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
}
- dptr = patchp->dptr;
+ lock_ConvertWToR(&scp->rw);
+
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+ smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
- if (infoLevel >= 0x101) {
/* get filetime */
smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
- /* copy to Creation Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Last Access Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Last Write Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
-
- /* copy to Change Time */
- *((FILETIME *)dptr) = ft;
- dptr += 8;
+ fa->creationTime = ft;
+ fa->lastAccessTime = ft;
+ fa->lastWriteTime = ft;
+ fa->lastChangeTime = ft;
/* Use length for both file length and alloc length */
- *((LARGE_INTEGER *)dptr) = scp->length;
- dptr += 8;
- *((LARGE_INTEGER *)dptr) = scp->length;
- dptr += 8;
+ fa->endOfFile = scp->length;
+ fa->allocationSize = scp->length;
/* Copy attributes */
lattr = smb_ExtAttributes(scp);
- if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ if ((code == CM_ERROR_NOSUCHPATH &&
+ (scp->fileType == CM_SCACHETYPE_SYMLINK &&
+ cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
+ code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
if (lattr == SMB_ATTR_NORMAL)
lattr = SMB_ATTR_DIRECTORY;
else
else
lattr |= SMB_ATTR_HIDDEN;
}
- *((u_long *)dptr) = lattr;
- dptr += 4;
+
+ fa->extFileAttributes = lattr;
} else {
+ smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
/* get dos time */
smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
+ fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
+ fa->lastAccessDateTime = fa->creationDateTime;
+ fa->lastWriteDateTime = fa->creationDateTime;
+
+ /* copy out file length and alloc length,
+ * using the same for both
+ */
+ fa->dataSize = scp->length.LowPart;
+ fa->allocationSize = scp->length.LowPart;
+
+ /* finally copy out attributes as short */
+ attr = smb_Attributes(scp);
+ /* merge in hidden (dot file) attribute */
+ if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+ if (lattr == SMB_ATTR_NORMAL)
+ lattr = SMB_ATTR_HIDDEN;
+ else
+ lattr |= SMB_ATTR_HIDDEN;
+ }
+ fa->attributes = attr;
+ }
+
+ lock_ReleaseRead(&scp->rw);
+ cm_ReleaseSCache(scp);
+ }
+
+ /* now free the patches */
+ for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
+ npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
+ free(patchp);
+ }
+
+ /* and mark the list as empty */
+ *dirPatchespp = NULL;
+
+ cleanup:
+ return code;
+}
+
+/* smb_ReceiveTran2SearchDir implements both
+ * Tran2_Find_First and Tran2_Find_Next
+ */
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
+#define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
+#define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
+#define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
+
+/* this is an optimized handler for T2SearchDir that handles the case
+ where there are no wildcards in the search path. I.e. an
+ application is using FindFirst(Ex) to get information about a
+ single file or directory. It will attempt to do a single lookup.
+ If that fails, then smb_ReceiveTran2SearchDir() will fall back to
+ the usual mechanism.
+
+ This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
+
+ TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
+ */
+long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+{
+ int attribute;
+ long nextCookie;
+ long code = 0, code2 = 0;
+ clientchar_t *pathp = 0;
+ int maxCount;
+ smb_dirListPatch_t *dirListPatchesp;
+ smb_dirListPatch_t *curPatchp;
+ size_t orbytes; /* # of bytes in this output record */
+ size_t ohbytes; /* # of bytes, except file name */
+ size_t onbytes; /* # of bytes in name, incl. term. null */
+ cm_scache_t *scp = NULL;
+ cm_scache_t *targetscp = NULL;
+ cm_user_t *userp = NULL;
+ char *op; /* output data ptr */
+ char *origOp; /* original value of op */
+ cm_space_t *spacep; /* for pathname buffer */
+ unsigned long maxReturnData; /* max # of return data */
+ long maxReturnParms; /* max # of return parms */
+ long bytesInBuffer; /* # data bytes in the output buffer */
+ clientchar_t *maskp; /* mask part of path */
+ int infoLevel;
+ int searchFlags;
+ int eos;
+ smb_tran2Packet_t *outp; /* response packet */
+ clientchar_t *tidPathp = 0;
+ int align;
+ clientchar_t shortName[13]; /* 8.3 name if needed */
+ int NeedShortName;
+ clientchar_t *shortNameEnd;
+ cm_dirEntry_t * dep = NULL;
+ cm_req_t req;
+ char * s;
+ void * attrp = NULL;
+ smb_tran2Find_t * fp;
+
+ smb_InitReq(&req);
+
+ eos = 0;
+ osi_assertx(p->opcode == 1, "invalid opcode");
+
+ /* find first; obtain basic parameters from request */
+
+ /* note that since we are going to failover to regular
+ * processing at smb_ReceiveTran2SearchDir(), we shouldn't
+ * modify any of the input parameters here. */
+ attribute = p->parmsp[0];
+ maxCount = p->parmsp[1];
+ infoLevel = p->parmsp[3];
+ searchFlags = p->parmsp[2];
+ pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
+ nextCookie = 0;
+ maskp = cm_ClientStrRChr(pathp, '\\');
+ if (maskp == NULL)
+ maskp = pathp;
+ else
+ maskp++; /* skip over backslash */
+ /* track if this is likely to match a lot of entries */
+
+ osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
+ osi_LogSaveClientString(smb_logp, pathp),
+ osi_LogSaveClientString(smb_logp, maskp));
+
+ switch ( infoLevel ) {
+ case SMB_INFO_STANDARD:
+ s = "InfoStandard";
+ ohbytes = sizeof(fp->u.FstandardInfo);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ ohbytes = sizeof(fp->u.FeaSizeInfo);
+ s = "InfoQueryEaSize";
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ ohbytes = sizeof(fp->u.FeasFromListInfo);
+ s = "InfoQueryEasFromList";
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ s = "FindFileDirectoryInfo";
+ ohbytes = sizeof(fp->u.FfileDirectoryInfo);
+ break;
+
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ s = "FindFileFullDirectoryInfo";
+ ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ s = "FindFileNamesInfo";
+ ohbytes = sizeof(fp->u.FfileNamesInfo);
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ s = "FindFileBothDirectoryInfo";
+ ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
+ break;
+
+ default:
+ s = "unknownInfoLevel";
+ ohbytes = 0;
+ }
+
+ osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
+
+ osi_Log4(smb_logp,
+ "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
+ attribute, infoLevel, maxCount, searchFlags);
+
+ if (ohbytes == 0) {
+ osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
+ return CM_ERROR_INVAL;
+ }
+
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
+ searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
+
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+ ohbytes += 4;
+
+ dirListPatchesp = NULL;
+
+ maxReturnData = p->maxReturnData;
+ maxReturnParms = 10; /* return params for findfirst, which
+ is the only one we handle.*/
+
+ outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
+ maxReturnData);
+
+ osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
+ maxCount, osi_LogSaveClientString(smb_logp, pathp));
+
+ /* bail out if request looks bad */
+ if (!pathp) {
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADSMB;
+ }
+
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
+ smb_FreeTran2Packet(outp);
+ return CM_ERROR_BADSMB;
+ }
+
+ /* try to get the vnode for the path name next */
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->wdata, NULL, pathp);
+ code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+
+ code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+ cm_FreeSpace(spacep);
+
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+
+#ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
+ if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_NOSUCHPATH;
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+#endif /* DFS_SUPPORT */
+ osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
+
+ /* now do a single case sensitive lookup for the file in question */
+ code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
+
+ /* if a case sensitive match failed, we try a case insensitive one
+ next. */
+ if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
+ code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
+ }
+
+ if (code == 0 && targetscp->fid.vnode == 0) {
+ cm_ReleaseSCache(targetscp);
+ code = CM_ERROR_NOSUCHFILE;
+ }
+
+ if (code) {
+ /* if we can't find the directory entry, this block will
+ return CM_ERROR_NOSUCHFILE, which we will pass on to
+ smb_ReceiveTran2SearchDir(). */
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+ smb_SendTran2Error(vcp, p, opx, code);
+ code = 0;
+ }
+ smb_FreeTran2Packet(outp);
+ return code;
+ }
+
+ /* now that we have the target in sight, we proceed with filling
+ up the return data. */
+
+ op = origOp = outp->datap;
+ bytesInBuffer = 0;
+
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
+ /* skip over resume key */
+ op += 4;
+ }
+
+ fp = (smb_tran2Find_t *) op;
+
+ if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
+ && targetscp->fid.vnode != 0
+ && !cm_Is8Dot3(maskp)) {
+
+ cm_dirFid_t dfid;
+ dfid.vnode = htonl(targetscp->fid.vnode);
+ dfid.unique = htonl(targetscp->fid.unique);
+
+ cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
+ NeedShortName = 1;
+ } else {
+ NeedShortName = 0;
+ }
+
+ osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
+ htonl(targetscp->fid.vnode),
+ htonl(targetscp->fid.unique),
+ osi_LogSaveClientString(smb_logp, pathp),
+ (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
+
+ /* Eliminate entries that don't match requested attributes */
+ if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
+ smb_IsDotFile(maskp)) {
+
+ code = CM_ERROR_NOSUCHFILE;
+ osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
+ goto skip_file;
+
+ }
+
+ if (!(attribute & SMB_ATTR_DIRECTORY) &&
+ (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
+ targetscp->fileType == CM_SCACHETYPE_INVALID)) {
+
+ code = CM_ERROR_NOSUCHFILE;
+ osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
+ goto skip_file;
- /* copy out creation time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
+ }
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
+ /* add header to name & term. null */
+ onbytes = 0;
+ smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
+ orbytes = ohbytes + onbytes;
- /* copy out access time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
+ /* now, we round up the record to a 4 byte alignment, and we make
+ * sure that we have enough room here for even the aligned version
+ * (so we don't have to worry about an * overflow when we pad
+ * things out below). That's the reason for the alignment
+ * arithmetic below.
+ */
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
+ align = (4 - (orbytes & 3)) & 3;
+ else
+ align = 0;
- /* and copy out date */
- shortTemp = (dosTime>>16) & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
+ if (orbytes + align > maxReturnData) {
- /* copy out mod time */
- shortTemp = dosTime & 0xffff;
- *((u_short *)dptr) = shortTemp;
- dptr += 2;
+ /* even though this request is unlikely to succeed with a
+ failover, we do it anyway. */
+ code = CM_ERROR_NOSUCHFILE;
+ osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
+ maxReturnData);
+ goto skip_file;
+ }
- /* copy out file length and alloc length,
- * using the same for both
- */
- *((u_long *)dptr) = scp->length.LowPart;
- dptr += 4;
- *((u_long *)dptr) = scp->length.LowPart;
- dptr += 4;
+ /* this is one of the entries to use: it is not deleted and it
+ * matches the star pattern we're looking for. Put out the name,
+ * preceded by its length.
+ */
+ /* First zero everything else */
+ memset(origOp, 0, orbytes);
- /* finally copy out attributes as short */
- attr = smb_Attributes(scp);
- /* merge in hidden (dot file) attribute */
- if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
- if (lattr == SMB_ATTR_NORMAL)
- lattr = SMB_ATTR_HIDDEN;
- else
- lattr |= SMB_ATTR_HIDDEN;
- }
- *dptr++ = attr & 0xff;
- *dptr++ = (attr >> 8) & 0xff;
- }
+ onbytes = 0;
+ smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
- lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
- }
-
- /* now free the patches */
- for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
- npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
- free(patchp);
- }
-
- /* and mark the list as empty */
- *dirPatchespp = NULL;
+ switch (infoLevel) {
+ case SMB_INFO_STANDARD:
+ fp->u.FstandardInfo.fileNameLength = onbytes;
+ attrp = &fp->u.FstandardInfo.fileAttrs;
+ break;
- return code;
-}
+ case SMB_INFO_QUERY_EA_SIZE:
+ fp->u.FeaSizeInfo.fileNameLength = onbytes;
+ attrp = &fp->u.FeaSizeInfo.fileAttrs;
+ fp->u.FeaSizeInfo.eaSize = 0;
+ break;
-#ifndef USE_OLD_MATCHING
-// char table for case insensitive comparison
-char mapCaseTable[256];
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ fp->u.FeasFromListInfo.fileNameLength = onbytes;
+ attrp = &fp->u.FeasFromListInfo.fileAttrs;
+ fp->u.FeasFromListInfo.eaSize = 0;
+ break;
-VOID initUpperCaseTable(VOID)
-{
- int i;
- for (i = 0; i < 256; ++i)
- mapCaseTable[i] = toupper(i);
- // make '"' match '.'
- mapCaseTable[(int)'"'] = toupper('.');
- // make '<' match '*'
- mapCaseTable[(int)'<'] = toupper('*');
- // make '>' match '?'
- mapCaseTable[(int)'>'] = toupper('?');
-}
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ if (NeedShortName) {
+#ifdef SMB_UNICODE
+ int nchars;
-// Compare 'pattern' (containing metacharacters '*' and '?') with the file
-// name 'name'.
-// Note : this procedure works recursively calling itself.
-// Parameters
-// PSZ pattern : string containing metacharacters.
-// PSZ name : file name to be compared with 'pattern'.
-// Return value
-// BOOL : TRUE/FALSE (match/mistmatch)
-
-BOOL
-szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
-{
- PSZ pename; // points to the last 'name' character
- PSZ p;
- pename = name + strlen(name) - 1;
- while (*name) {
- switch (*pattern) {
- case '?':
- ++pattern;
- if (*name == '.')
- continue;
- ++name;
- break;
- case '*':
- ++pattern;
- if (*pattern == '\0')
- return TRUE;
- for (p = pename; p >= name; --p) {
- if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
- !casefold && (*p == *pattern)) &&
- szWildCardMatchFileName(pattern + 1, p + 1, casefold))
- return TRUE;
- } /* endfor */
- return FALSE;
- default:
- if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
- (!casefold && *name != *pattern))
- return FALSE;
- ++pattern, ++name;
- break;
- } /* endswitch */
- } /* endwhile */
+ nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
+ fp->u.FfileBothDirectoryInfo.shortName,
+ sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
+ if (nchars > 0)
+ fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
+ else
+ fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
+ fp->u.FfileBothDirectoryInfo.reserved = 0;
+#else
+ strcpy(fp->u.FfileBothDirectoryInfo.shortName,
+ shortName);
+ fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
+#endif
+ }
+ /* Fallthrough */
+
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ fp->u.FfileFullDirectoryInfo.eaSize = 0;
+ /* Fallthrough */
- /* if all we have left are wildcards, then we match */
- for (;*pattern; pattern++) {
- if (*pattern != '*' && *pattern != '?')
- return FALSE;
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
+ fp->u.FfileDirectoryInfo.fileIndex = 0;
+ attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
+ fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ fp->u.FfileNamesInfo.nextEntryOffset = 0;
+ fp->u.FfileNamesInfo.fileIndex = 0;
+ fp->u.FfileNamesInfo.fileNameLength = onbytes;
+ break;
+
+ default:
+ /* we shouldn't hit this case */
+ osi_assertx(FALSE, "Unknown query type");
}
- return TRUE;
-}
-/* do a case-folding search of the star name mask with the name in namep.
- * Return 1 if we match, otherwise 0.
- */
-int smb_V3MatchMask(char *namep, char *maskp, int flags)
-{
- char * newmask;
- int i, j, star, qmark, casefold, retval;
+ if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+ osi_assert(attrp != NULL);
- /* make sure we only match 8.3 names, if requested */
- if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
- return 0;
-
- casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
+ curPatchp = malloc(sizeof(*curPatchp));
+ osi_QAdd((osi_queue_t **) &dirListPatchesp,
+ &curPatchp->q);
+ curPatchp->dptr = attrp;
- /* optimize the pattern:
- * if there is a mixture of '?' and '*',
- * for example the sequence "*?*?*?*"
- * must be turned into the form "*"
- */
- newmask = (char *)malloc(strlen(maskp)+1);
- for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
- switch ( maskp[i] ) {
- case '?':
- case '>':
- qmark++;
- break;
- case '<':
- case '*':
- star++;
- break;
- default:
- if ( star ) {
- newmask[j++] = '*';
- } else if ( qmark ) {
- while ( qmark-- )
- newmask[j++] = '?';
- }
- newmask[j++] = maskp[i];
- star = 0;
- qmark = 0;
+ if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
+ curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
+ } else {
+ curPatchp->flags = 0;
+ }
+
+ cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
+
+ /* temp */
+ {
+ int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
+ dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
+ cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
}
+ dep->fid.vnode = targetscp->fid.vnode;
+ dep->fid.unique = targetscp->fid.unique;
+ curPatchp->dep = dep;
+ }
+
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
+ /* put out resume key */
+ *((u_long *)origOp) = 0;
}
- if ( star ) {
- newmask[j++] = '*';
- } else if ( qmark ) {
- while ( qmark-- )
- newmask[j++] = '?';
+
+ /* Adjust byte ptr and count */
+ origOp += orbytes; /* skip entire record */
+ bytesInBuffer += orbytes;
+
+ /* and pad the record out */
+ while (--align >= 0) {
+ *origOp++ = 0;
+ bytesInBuffer++;
}
- newmask[j++] = '\0';
- retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
+ /* apply the patches */
+ code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
- free(newmask);
- return retval;
-}
+ outp->parmsp[0] = 0;
+ outp->parmsp[1] = 1; /* number of names returned */
+ outp->parmsp[2] = 1; /* end of search */
+ outp->parmsp[3] = 0; /* nothing wrong with EAS */
+ outp->parmsp[4] = 0;
-#else /* USE_OLD_MATCHING */
-/* do a case-folding search of the star name mask with the name in namep.
- * Return 1 if we match, otherwise 0.
- */
-int smb_V3MatchMask(char *namep, char *maskp, int flags)
-{
- unsigned char tcp1, tcp2; /* Pattern characters */
- unsigned char tcn1; /* Name characters */
- int sawDot = 0, sawStar = 0, req8dot3 = 0;
- char *starNamep, *starMaskp;
- static char nullCharp[] = {0};
- int casefold = flags & CM_FLAG_CASEFOLD;
-
- /* make sure we only match 8.3 names, if requested */
- req8dot3 = (flags & CM_FLAG_8DOT3);
- if (req8dot3 && !cm_Is8Dot3(namep))
- return 0;
+ outp->totalParms = 10; /* in bytes */
- /* loop */
- while (1) {
- /* Next pattern character */
- tcp1 = *maskp++;
+ outp->totalData = bytesInBuffer;
- /* Next name character */
- tcn1 = *namep;
+ osi_Log0(smb_logp, "T2SDSingle done.");
- if (tcp1 == 0) {
- /* 0 - end of pattern */
- if (tcn1 == 0)
- return 1;
- else
- return 0;
- }
- else if (tcp1 == '.' || tcp1 == '"') {
- if (sawDot) {
- if (tcn1 == '.') {
- namep++;
- continue;
- } else
- return 0;
- }
- else {
- /*
- * first dot in pattern;
- * must match dot or end of name
- */
- sawDot = 1;
- if (tcn1 == 0)
- continue;
- else if (tcn1 == '.') {
- sawStar = 0;
- namep++;
- continue;
- }
- else
- return 0;
- }
- }
- else if (tcp1 == '?') {
- if (tcn1 == 0 || tcn1 == '.')
- return 0;
- namep++;
- continue;
- }
- else if (tcp1 == '>') {
- if (tcn1 != 0 && tcn1 != '.')
- namep++;
- continue;
- }
- else if (tcp1 == '*' || tcp1 == '<') {
- tcp2 = *maskp++;
- if (tcp2 == 0)
- return 1;
- else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
- while (req8dot3 && tcn1 != '.' && tcn1 != 0)
- tcn1 = *++namep;
- if (tcn1 == 0) {
- if (sawDot)
- return 0;
- else
- continue;
- }
- else {
- namep++;
- continue;
- }
- }
- else {
- /*
- * pattern character after '*' is not null or
- * period. If it is '?' or '>', we are not
- * going to understand it. If it is '*' or
- * '<', we are going to skip over it. None of
- * these are likely, I hope.
- */
- /* skip over '*' and '<' */
- while (tcp2 == '*' || tcp2 == '<')
- tcp2 = *maskp++;
-
- /* skip over characters that don't match tcp2 */
- while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
- ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
- (!casefold && tcn1 != tcp2)))
- tcn1 = *++namep;
-
- /* No match */
- if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
- return 0;
-
- /* Remember where we are */
- sawStar = 1;
- starMaskp = maskp;
- starNamep = namep;
-
- namep++;
- continue;
- }
- }
- else {
- /* tcp1 is not a wildcard */
- if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
- (!casefold && tcn1 == tcp1)) {
- /* they match */
- namep++;
- continue;
- }
- /* if trying to match a star pattern, go back */
- if (sawStar) {
- maskp = starMaskp - 2;
- namep = starNamep + 1;
- sawStar = 0;
- continue;
- }
- /* that's all */
- return 0;
- }
+ if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+ if (code)
+ smb_SendTran2Error(vcp, p, opx, code);
+ else
+ smb_SendTran2Packet(vcp, outp, opx);
+ code = 0;
}
+
+ skip_file:
+ smb_FreeTran2Packet(outp);
+ if (dep)
+ free(dep);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(targetscp);
+ cm_ReleaseUser(userp);
+
+ return code;
}
-#endif /* USE_OLD_MATCHING */
+
+/* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
int attribute;
long nextCookie;
char *tp;
long code = 0, code2 = 0;
- char *pathp;
- cm_dirEntry_t *dep;
+ clientchar_t *pathp;
+ cm_dirEntry_t *dep = 0;
int maxCount;
- smb_dirListPatch_t *dirListPatchesp;
- smb_dirListPatch_t *curPatchp;
+ smb_dirListPatch_t *dirListPatchesp = 0;
+ smb_dirListPatch_t *curPatchp = 0;
cm_buf_t *bufferp;
long temp;
- long orbytes; /* # of bytes in this output record */
- long ohbytes; /* # of bytes, except file name */
- long onbytes; /* # of bytes in name, incl. term. null */
+ size_t orbytes; /* # of bytes in this output record */
+ size_t ohbytes; /* # of bytes, except file name */
+ size_t onbytes; /* # of bytes in name, incl. term. null */
osi_hyper_t dirLength;
osi_hyper_t bufferOffset;
osi_hyper_t curOffset;
char *op; /* output data ptr */
char *origOp; /* original value of op */
cm_space_t *spacep; /* for pathname buffer */
- long maxReturnData; /* max # of return data */
- long maxReturnParms; /* max # of return parms */
+ unsigned long maxReturnData; /* max # of return data */
+ unsigned long maxReturnParms; /* max # of return parms */
long bytesInBuffer; /* # data bytes in the output buffer */
int starPattern;
- char *maskp; /* mask part of path */
+ clientchar_t *maskp; /* mask part of path */
int infoLevel;
int searchFlags;
int eos;
smb_tran2Packet_t *outp; /* response packet */
- char *tidPathp;
- int align;
- char shortName[13]; /* 8.3 name if needed */
+ clientchar_t *tidPathp;
+ unsigned int align;
+ clientchar_t shortName[13]; /* 8.3 name if needed */
int NeedShortName;
int foundInexact;
- char *shortNameEnd;
+ clientchar_t *shortNameEnd;
int fileType;
cm_fid_t fid;
cm_req_t req;
+ void * attrp;
+ char * s;
+ smb_tran2Find_t * fp;
- cm_InitReq(&req);
+ smb_InitReq(&req);
eos = 0;
if (p->opcode == 1) {
maxCount = p->parmsp[1];
infoLevel = p->parmsp[3];
searchFlags = p->parmsp[2];
- dsp = smb_NewDirSearch(1);
- dsp->attribute = attribute;
- pathp = ((char *) p->parmsp) + 12; /* points to path */
- if (smb_StoreAnsiFilenames)
- OemToChar(pathp,pathp);
+ pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
nextCookie = 0;
- maskp = strrchr(pathp, '\\');
+ maskp = cm_ClientStrRChr(pathp, '\\');
if (maskp == NULL)
maskp = pathp;
else
maskp++; /* skip over backslash */
- strcpy(dsp->mask, maskp); /* and save mask */
+
/* track if this is likely to match a lot of entries */
starPattern = smb_V3IsStarMask(maskp);
+
+#ifndef NOFINDFIRSTOPTIMIZE
+ if (!starPattern) {
+ /* if this is for a single directory or file, we let the
+ optimized routine handle it. The only error it
+ returns is CM_ERROR_NOSUCHFILE. The */
+ code = smb_T2SearchDirSingle(vcp, p, opx);
+
+ /* we only failover if we see a CM_ERROR_NOSUCHFILE */
+ if (code != CM_ERROR_NOSUCHFILE) {
+#ifdef USE_BPLUS
+ /* unless we are using the BPlusTree */
+ if (code == CM_ERROR_BPLUS_NOMATCH)
+ code = CM_ERROR_NOSUCHFILE;
+#endif /* USE_BPLUS */
+ return code;
+ }
+ }
+#endif /* NOFINDFIRSTOPTIMIZE */
+ dir_enums++;
+
+ dsp = smb_NewDirSearch(1);
+ dsp->attribute = attribute;
+ cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
}
else {
- osi_assert(p->opcode == 2);
+ osi_assertx(p->opcode == 2, "invalid opcode");
/* find next; obtain basic parameters from request or open dir file */
dsp = smb_FindDirSearch(p->parmsp[0]);
maxCount = p->parmsp[1];
starPattern = 1; /* assume, since required a Find Next */
}
+ switch ( infoLevel ) {
+ case SMB_INFO_STANDARD:
+ s = "InfoStandard";
+ ohbytes = sizeof(fp->u.FstandardInfo);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ ohbytes = sizeof(fp->u.FeaSizeInfo);
+ s = "InfoQueryEaSize";
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ ohbytes = sizeof(fp->u.FeasFromListInfo);
+ s = "InfoQueryEasFromList";
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ s = "FindFileDirectoryInfo";
+ ohbytes = sizeof(fp->u.FfileDirectoryInfo);
+ break;
+
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ s = "FindFileFullDirectoryInfo";
+ ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ s = "FindFileNamesInfo";
+ ohbytes = sizeof(fp->u.FfileNamesInfo);
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ s = "FindFileBothDirectoryInfo";
+ ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
+ break;
+
+ default:
+ s = "unknownInfoLevel";
+ ohbytes = 0;
+ }
+
+ osi_Log1(smb_logp, "T2 search dir info level: %s", s);
+
osi_Log4(smb_logp,
- "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
+ "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
attribute, infoLevel, maxCount, searchFlags);
osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
p->opcode, dsp->cookie, nextCookie);
- if (infoLevel >= 0x101)
- searchFlags &= ~4; /* no resume keys */
+ if (ohbytes == 0) {
+ osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
+ smb_ReleaseDirSearch(dsp);
+ return CM_ERROR_INVAL;
+ }
+
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
+ searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
+
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+ ohbytes += 4;
dirListPatchesp = NULL;
else
maxReturnParms = 8; /* bytes */
-#ifndef CM_CONFIG_MULTITRAN2RESPONSES
- if (maxReturnData > 6000)
- maxReturnData = 6000;
-#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
-
outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
maxReturnData);
- osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
- maxCount, osi_LogSaveString(smb_logp, pathp));
+ if (maxCount > 500)
+ maxCount = 500;
+
+ osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
+ maxCount, osi_LogSaveClientString(smb_logp, pathp));
/* bail out if request looks bad */
if (p->opcode == 1 && !pathp) {
lock_ObtainMutex(&dsp->mx);
if (dsp->scp) {
scp = dsp->scp;
+ osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
cm_HoldSCache(scp);
code = 0;
} else {
spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, NULL, pathp);
+ smb_StripLastComponent(spacep->wdata, NULL, pathp);
code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
if (code) {
cm_ReleaseUser(userp);
smb_ReleaseDirSearch(dsp);
return 0;
}
- code = cm_NameI(cm_data.rootSCachep, spacep->data,
+
+ cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
+ cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
+
+ code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &scp);
cm_FreeSpace(spacep);
if (code == 0) {
#ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- if ( WANTS_DFS_PATHNAMES(p) )
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
code = CM_ERROR_PATH_NOT_COVERED;
else
- code = CM_ERROR_BADSHARENAME;
+ code = CM_ERROR_NOSUCHPATH;
smb_SendTran2Error(vcp, p, opx, code);
smb_FreeTran2Packet(outp);
lock_ReleaseMutex(&dsp->mx);
}
#endif /* DFS_SUPPORT */
dsp->scp = scp;
+ osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
/* we need one hold for the entry we just stored into,
* and one for our own processing. When we're done
* with this function, we'll drop the one for our own
* and so we do another hold now.
*/
cm_HoldSCache(scp);
- lock_ObtainMutex(&scp->mx);
- if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
- LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
- scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
- dsp->flags |= SMB_DIRSEARCH_BULKST;
- }
- lock_ReleaseMutex(&scp->mx);
+ dsp->flags |= SMB_DIRSEARCH_BULKST;
}
}
lock_ReleaseMutex(&dsp->mx);
}
/* get the directory size */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
return code;
}
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
startsearch:
dirLength = scp->length;
bufferp = NULL;
returnedNames = 0;
bytesInBuffer = 0;
while (1) {
+ normchar_t normName[MAX_PATH]; /* Normalized name */
+ clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
+
op = origOp;
- if (searchFlags & 4)
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
/* skip over resume key */
op += 4;
+ fp = (smb_tran2Find_t *) op;
+
/* make sure that curOffset.LowPart doesn't point to the first
* 32 bytes in the 2nd through last dir page, and that it doesn't
* point at the first 13 32-byte chunks in the first dir page,
break;
}
+ /* when we have obtained as many entries as can be processed in
+ * a single Bulk Status call to the file server, apply the dir listing
+ * patches.
+ */
+ if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
+ lock_ReleaseWrite(&scp->rw);
+ code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
+ dsp->relPath, infoLevel, userp, &req);
+ lock_ObtainWrite(&scp->rw);
+ }
+ /* Then check to see if we have time left to process more entries */
+ if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
+ osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
+ break;
+ }
+
/* see if we can use the bufferp we have now; compute in which
* page the current offset would be, and check whether that's
* the offset of the buffer we have. If not, get the buffer.
buf_Release(bufferp);
bufferp = NULL;
}
- lock_ReleaseMutex(&scp->mx);
- lock_ObtainRead(&scp->bufCreateLock);
- code = buf_Get(scp, &thyper, &bufferp);
- lock_ReleaseRead(&scp->bufCreateLock);
- lock_ObtainMutex(&dsp->mx);
-
- /* now, if we're doing a star match, do bulk fetching
- * of all of the status info for files in the dir.
- */
- if (starPattern) {
- smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
- infoLevel, userp,
- &req);
- lock_ObtainMutex(&scp->mx);
- if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
- LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
- /* Don't bulk stat if risking timeout */
- int now = GetTickCount();
- if (now - req.startTime > 5000) {
- scp->bulkStatProgress = thyper;
- scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
- dsp->flags &= ~SMB_DIRSEARCH_BULKST;
- } else
- cm_TryBulkStat(scp, &thyper, userp, &req);
- }
- } else {
- lock_ObtainMutex(&scp->mx);
- }
- lock_ReleaseMutex(&dsp->mx);
+ lock_ReleaseWrite(&scp->rw);
+ code = buf_Get(scp, &thyper, &req, &bufferp);
+ lock_ObtainWrite(&scp->rw);
if (code) {
osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
break;
osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
break;
}
-
+
if (cm_HaveBuffer(scp, bufferp, 0)) {
osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
+ cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
break;
}
/* otherwise, load the buffer and try again */
code = cm_GetBuffer(scp, bufferp, NULL, userp,
&req);
+ cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
if (code) {
osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
scp, bufferp, code);
/* compute offset of cookie representing next entry */
nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
+ if (dep->fid.vnode == 0)
+ goto nextEntry; /* This entry is not in use */
+
+ if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
+ cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
+
+ osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
+ osi_LogSaveString(smb_logp, dep->name));
+ goto nextEntry;
+ }
+
/* Need 8.3 name? */
NeedShortName = 0;
- if (infoLevel == SMB_QUERY_FILE_NAME_INFO
- && dep->fid.vnode != 0
- && !cm_Is8Dot3(dep->name)) {
+ if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
+ !cm_Is8Dot3(cfileName)) {
cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
NeedShortName = 1;
}
- osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
- dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
- NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
+ osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
+ dep->fid.vnode, dep->fid.unique,
+ osi_LogSaveClientString(smb_logp, cfileName),
+ NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
/* When matching, we are using doing a case fold if we have a wildcard mask.
* If we get a non-wildcard match, it's a lookup for a specific file.
*/
- if (dep->fid.vnode != 0 &&
- (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
- (NeedShortName &&
- smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
-
+ if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
+ (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
+ {
/* Eliminate entries that don't match requested attributes */
if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
- smb_IsDotFile(dep->name)) {
+ smb_IsDotFile(cfileName)) {
osi_Log0(smb_logp, "T2 search dir skipping hidden");
goto nextEntry; /* no hidden files */
}
+
if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
{
/* We have already done the cm_TryBulkStat above */
- fid.cell = scp->fid.cell;
- fid.volume = scp->fid.volume;
- fid.vnode = ntohl(dep->fid.vnode);
- fid.unique = ntohl(dep->fid.unique);
+ cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
+ ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
fileType = cm_FindFileType(&fid);
- /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
- "has filetype %d", dep->name,
- fileType);*/
- if (fileType == CM_SCACHETYPE_DIRECTORY ||
- fileType == CM_SCACHETYPE_DFSLINK ||
- fileType == CM_SCACHETYPE_INVALID)
+ /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
+ * "has filetype %d", dep->name, fileType);
+ */
+ if ( fileType == CM_SCACHETYPE_DIRECTORY ||
+ fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ fileType == CM_SCACHETYPE_DFSLINK ||
+ fileType == CM_SCACHETYPE_INVALID)
osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
- goto nextEntry;
+ goto nextEntry;
}
/* finally check if this name will fit */
-
- /* standard dir entry stuff */
- if (infoLevel < 0x101)
- ohbytes = 23; /* pre-NT */
- else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
- ohbytes = 12; /* NT names only */
- else
- ohbytes = 64; /* NT */
-
- if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
- ohbytes += 26; /* Short name & length */
-
- if (searchFlags & 4) {
- ohbytes += 4; /* if resume key required */
- }
-
- if (infoLevel != 1
- && infoLevel != 0x101
- && infoLevel != 0x103)
- ohbytes += 4; /* EASIZE */
-
- /* add header to name & term. null */
- orbytes = onbytes + ohbytes + 1;
+ onbytes = 0;
+ smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
+ orbytes = ohbytes + onbytes;
/* now, we round up the record to a 4 byte alignment,
* and we make sure that we have enough room here for
* even the aligned version (so we don't have to worry
- * about an * overflow when we pad things out below).
+ * about an overflow when we pad things out below).
* That's the reason for the alignment arithmetic below.
*/
- if (infoLevel >= 0x101)
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
align = (4 - (orbytes & 3)) & 3;
else
align = 0;
+
if (orbytes + bytesInBuffer + align > maxReturnData) {
osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
- maxReturnData);
- break;
- }
+ maxReturnData);
+ break;
+ }
/* this is one of the entries to use: it is not deleted
* and it matches the star pattern we're looking for.
* Put out the name, preceded by its length.
*/
/* First zero everything else */
- memset(origOp, 0, ohbytes);
+ memset(origOp, 0, orbytes);
- if (infoLevel <= 0x101)
- *(origOp + ohbytes - 1) = (unsigned char) onbytes;
- else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
- *((u_long *)(op + 8)) = onbytes;
- else
- *((u_long *)(op + 60)) = onbytes;
- strcpy(origOp+ohbytes, dep->name);
- if (smb_StoreAnsiFilenames)
- CharToOem(origOp+ohbytes, origOp+ohbytes);
+ onbytes = 0;
+ smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
+
+ switch (infoLevel) {
+ case SMB_INFO_STANDARD:
+ fp->u.FstandardInfo.fileNameLength = onbytes;
+ attrp = &fp->u.FstandardInfo.fileAttrs;
+ break;
- /* Short name if requested and needed */
- if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+ case SMB_INFO_QUERY_EA_SIZE:
+ fp->u.FeaSizeInfo.fileNameLength = onbytes;
+ attrp = &fp->u.FeaSizeInfo.fileAttrs;
+ fp->u.FeaSizeInfo.eaSize = 0;
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ fp->u.FeasFromListInfo.fileNameLength = onbytes;
+ attrp = &fp->u.FeasFromListInfo.fileAttrs;
+ fp->u.FeasFromListInfo.eaSize = 0;
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
if (NeedShortName) {
- strcpy(op + 70, shortName);
- if (smb_StoreAnsiFilenames)
- CharToOem(op + 70, op + 70);
- *(op + 68) = (char)(shortNameEnd - shortName);
+#ifdef SMB_UNICODE
+ int nchars;
+
+ nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
+ fp->u.FfileBothDirectoryInfo.shortName,
+ sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
+ if (nchars > 0)
+ fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
+ else
+ fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
+ fp->u.FfileBothDirectoryInfo.reserved = 0;
+#else
+ cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
+ lengthof(fp->u.FfileBothDirectoryInfo.shortName),
+ shortName);
+ fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
+#endif
}
+ /* Fallthrough */
+
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ fp->u.FfileFullDirectoryInfo.eaSize = 0;
+ /* Fallthrough */
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
+ fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
+ attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
+ fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
+ fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
+ fp->u.FfileNamesInfo.fileNameLength = onbytes;
+ attrp = NULL;
+ break;
+
+ default:
+ /* we shouldn't hit this case */
+ osi_assertx(FALSE, "Unknown query type");
}
/* now, adjust the # of entries copied */
returnedNames++;
- /* NextEntryOffset and FileIndex */
- if (infoLevel >= 101) {
- int entryOffset = orbytes + align;
- *((u_long *)op) = entryOffset;
- *((u_long *)(op+4)) = nextEntryCookie;
- }
-
/* now we emit the attribute. This is tricky, since
* we need to really stat the file to find out what
* type of entry we've got. Right now, we're copying
* later. The replay will happen at a time when it is
* safe to unlock the directory.
*/
- if (infoLevel != 0x103) {
+ if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+ osi_assert(attrp != NULL);
curPatchp = malloc(sizeof(*curPatchp));
- osi_QAdd((osi_queue_t **) &dirListPatchesp,
- &curPatchp->q);
- curPatchp->dptr = op;
- if (infoLevel >= 0x101)
- curPatchp->dptr += 8;
+ osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
+ curPatchp->dptr = attrp;
- if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
+ if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
- }
- else
+ } else {
curPatchp->flags = 0;
+ }
- curPatchp->fid.cell = scp->fid.cell;
- curPatchp->fid.volume = scp->fid.volume;
- curPatchp->fid.vnode = ntohl(dep->fid.vnode);
- curPatchp->fid.unique = ntohl(dep->fid.unique);
+ cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
/* temp */
curPatchp->dep = dep;
}
- if (searchFlags & 4)
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
/* put out resume key */
*((u_long *)origOp) = nextEntryCookie;
bytesInBuffer += orbytes;
/* and pad the record out */
- while (--align >= 0) {
+ while (align-- > 0) {
*origOp++ = 0;
bytesInBuffer++;
}
} /* if we're including this name */
else if (!starPattern &&
!foundInexact &&
- dep->fid.vnode != 0 &&
- smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+ cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
/* We were looking for exact matches, but here's an inexact one*/
foundInexact = 1;
}
-
+
nextEntry:
/* and adjust curOffset to be where the new cookie is */
thyper.HighPart = 0;
* re-running the query.
*/
if (returnedNames == 0 && !starPattern && foundInexact) {
- osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
+ osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
starPattern = 1;
goto startsearch;
}
/* release the mutex */
- lock_ReleaseMutex(&scp->mx);
- if (bufferp)
+ lock_ReleaseWrite(&scp->rw);
+ if (bufferp) {
buf_Release(bufferp);
+ bufferp = NULL;
+ }
- /* apply and free last set of patches; if not doing a star match, this
- * will be empty, but better safe (and freeing everything) than sorry.
+ /*
+ * Finally, process whatever entries we have left.
*/
- code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
- &req);
-
+ code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
+ dsp->relPath, infoLevel, userp, &req);
+
/* now put out the final parameters */
if (returnedNames == 0)
eos = 1;
* we're supposed to close the search if we're done, and we're done,
* or if something went wrong, close the search.
*/
- /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
- if ((searchFlags & 1) || (returnedNames == 0) ||
- ((searchFlags & 2) && eos) || code != 0)
+ if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
+ (returnedNames == 0) ||
+ ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
+ code != 0)
smb_DeleteDirSearch(dsp);
+
if (code)
smb_SendTran2Error(vcp, p, opx, code);
else
return 0;
}
+/* SMB_COM_FIND_CLOSE2 */
long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
int dirHandle;
return 0;
}
+
+/* SMB_COM_FIND_NOTIFY_CLOSE */
long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
smb_SetSMBDataLength(outp, 0);
return 0;
}
+/* SMB_COM_OPEN_ANDX */
long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- char *pathp;
+ clientchar_t *pathp;
long code = 0;
cm_space_t *spacep;
int excl;
int initialModeBits;
smb_fid_t *fidp;
int attributes;
- char *lastNamep;
- afs_uint32 dosTime;
+ clientchar_t *lastNamep;
+ unsigned long dosTime;
int openFun;
int trunc;
int openMode;
int extraInfo;
int openAction;
int parmSlot; /* which parm we're dealing with */
- char *tidPathp;
+ clientchar_t *tidPathp;
cm_req_t req;
int created = 0;
- cm_InitReq(&req);
+ smb_InitReq(&req);
scp = NULL;
/* compute initial mode bits based on read-only flag in attributes */
initialModeBits = 0666;
- if (attributes & 1) initialModeBits &= ~0222;
+ if (attributes & SMB_ATTR_READONLY)
+ initialModeBits &= ~0222;
- pathp = smb_GetSMBData(inp, NULL);
- if (smb_StoreAnsiFilenames)
- OemToChar(pathp,pathp);
+ pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
+ SMB_STRF_ANSIPATH);
+ if (!pathp)
+ return CM_ERROR_BADSMB;
spacep = inp->spacep;
- smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+ smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
- if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+ if (lastNamep &&
+ (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
+ cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
+ cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
+ cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
/* special case magic file name for receiving IOCTL requests
* (since IOCTL calls themselves aren't getting through).
*/
return 0;
}
+ if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+ clientchar_t * hexp;
+
+ hexp = cm_GetRawCharsAlloc(pathp, -1);
+ osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
+ osi_LogSaveClientString(smb_logp, hexp));
+ if (hexp)
+ free(hexp);
+#else
+ osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
+#endif
+ return CM_ERROR_BADNTFILENAME;
+ }
+
#ifdef DEBUG_VERBOSE
{
char *hexp, *asciip;
#ifdef DFS_SUPPORT
if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
if (code != 0) {
- code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &dscp);
if (code) {
#ifdef DFS_SUPPORT
if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+ spacep->wdata);
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
-
/* otherwise, scp points to the parent directory. Do a lookup,
* and truncate the file if we find it, otherwise we create the
* file.
lastNamep++;
code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
&req, &scp);
- if (code && code != CM_ERROR_NOSUCHFILE) {
+ if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
return code;
return CM_ERROR_NOSUCHFILE;
}
else {
- osi_assert(dscp != NULL);
- osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
- osi_LogSaveString(smb_logp, lastNamep));
+ osi_assertx(dscp != NULL, "null cm_scache_t");
+ osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
+ osi_LogSaveClientString(smb_logp, lastNamep));
openAction = 2; /* created file */
setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (!excl && code == CM_ERROR_EXISTS) {
/* not an exclusive create, and someone else tried
/* now all we have to do is open the file itself */
fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
+ osi_assertx(fidp, "null smb_fid_t");
cm_HoldUser(userp);
lock_ObtainMutex(&fidp->mx);
/* save a pointer to the vnode */
fidp->scp = scp;
+ lock_ObtainWrite(&scp->rw);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseWrite(&scp->rw);
+ osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
/* also the user */
fidp->userp = userp;
/* compute open mode */
if (openMode != 1)
- fidp->flags |= SMB_FID_OPENREAD;
+ fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
if (openMode == 1 || openMode == 2)
fidp->flags |= SMB_FID_OPENWRITE;
/* copy out remainder of the parms */
parmSlot = 2;
smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainRead(&scp->rw);
if (extraInfo) {
smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseRead(&scp->rw);
smb_SetSMBDataLength(outp, 0);
osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
}
}
+/* SMB_COM_LOCKING_ANDX */
long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
cm_req_t req;
cm_scache_t *scp;
unsigned char LockType;
unsigned short NumberOfUnlocks, NumberOfLocks;
- long Timeout;
+ afs_uint32 Timeout;
char *op;
char *op_locks;
LARGE_INTEGER LOffset, LLength;
cm_key_t key;
unsigned int pid;
- cm_InitReq(&req);
+ smb_InitReq(&req);
fid = smb_GetSMBParm(inp, 2);
fid = smb_ChainFID(fid, inp);
return CM_ERROR_BADFD;
lock_ObtainMutex(&fidp->mx);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
if (fidp->flags & SMB_FID_IOCTL) {
osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
lock_ReleaseMutex(&fidp->mx);
smb_ReleaseFID(fidp);
return CM_ERROR_BADFD;
}
+ scp = fidp->scp;
+ osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
+ cm_HoldSCache(scp);
lock_ReleaseMutex(&fidp->mx);
/* set inp->fid so that later read calls in same msg can find fid */
userp = smb_GetUserFromVCP(vcp, inp);
- scp = fidp->scp;
-
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_GETSTATUS
NumberOfUnlocks = smb_GetSMBParm(inp, 6);
NumberOfLocks = smb_GetSMBParm(inp, 7);
- if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
- (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
-
- /* We don't support these requests. Apparently, we can safely
- not deal with them too. */
- osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
- ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
- "LOCKING_ANDX_CANCEL_LOCK":
- "LOCKING_ANDX_CHANGE_LOCKTYPE"));
- /* No need to call osi_LogSaveString since these are string
- constants.*/
+ if (!(fidp->flags & SMB_FID_OPENWRITE) &&
+ !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
+ /* somebody wants exclusive locks on a file that they only
+ opened for reading. We downgrade this to a shared lock. */
+ osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
+ LockType |= LOCKING_ANDX_SHARED_LOCK;
+ }
+ if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
+ /* AFS does not support atomic changes of lock types from read or write and vice-versa */
+ osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
code = CM_ERROR_BADOP;
goto done;
op = smb_GetSMBData(inp, NULL);
+ if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
+ /* Cancel outstanding lock requests */
+ smb_waitingLock_t * wl;
+
+ for (i=0; i<NumberOfLocks; i++) {
+ smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+ key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+ lock_ObtainWrite(&smb_globalLock);
+ for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
+ {
+ for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
+ if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
+ LargeIntegerEqualTo(wl->LLength, LLength)) {
+ wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
+ goto found_lock_request;
+ }
+ }
+ }
+ found_lock_request:
+ lock_ReleaseWrite(&smb_globalLock);
+ }
+ code = 0;
+ smb_SetSMBDataLength(outp, 0);
+ goto done;
+ }
+
+
for (i=0; i<NumberOfUnlocks; i++) {
smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
- code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
+ code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
if (code)
goto done;
code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
userp, &req, &lockp);
+ if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
+ (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
+ {
+ code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
+ userp, &req, &lockp);
+ }
+
if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
smb_waitingLock_t * wLock;
wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
- osi_assert(wlRequest != NULL);
+ osi_assertx(wlRequest != NULL, "null wlRequest");
wlRequest->vcp = vcp;
smb_HoldVC(vcp);
wlRequest->scp = scp;
+ osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
cm_HoldSCache(scp);
wlRequest->inp = smb_CopyPacket(inp);
wlRequest->outp = smb_CopyPacket(outp);
wlRequest->lockType = LockType;
- wlRequest->timeRemaining = Timeout;
+ wlRequest->msTimeout = Timeout;
+ wlRequest->start_t = osi_Time();
wlRequest->locks = NULL;
/* The waiting lock request needs to have enough
wLock = malloc(sizeof(smb_waitingLock_t));
- osi_assert(wLock != NULL);
+ osi_assertx(wLock != NULL, "null smb_waitingLock_t");
wLock->key = tkey;
wLock->LOffset = tOffset;
wLock = malloc(sizeof(smb_waitingLock_t));
- osi_assert(wLock != NULL);
+ osi_assertx(wLock != NULL, "null smb_waitingLock_t");
wLock->key = key;
wLock->LOffset = LOffset;
wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
- ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
+ ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
if(ul_code != 0) {
osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
doneSync:
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_ReleaseFID(fidp);
return code;
}
+/* SMB_COM_QUERY_INFORMATION2 */
long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
unsigned short fid;
afs_uint32 searchTime;
cm_user_t *userp;
cm_req_t req;
+ int readlock = 0;
- cm_InitReq(&req);
+ smb_InitReq(&req);
fid = smb_GetSMBParm(inp, 0);
fid = smb_ChainFID(fid, inp);
return CM_ERROR_BADFD;
lock_ObtainMutex(&fidp->mx);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
smb_ReleaseFID(fidp);
return CM_ERROR_BADFD;
}
+ scp = fidp->scp;
+ osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
+ cm_HoldSCache(scp);
lock_ReleaseMutex(&fidp->mx);
userp = smb_GetUserFromVCP(vcp, inp);
- scp = fidp->scp;
/* otherwise, stat the file */
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) goto done;
+ if (code)
+ goto done;
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ lock_ConvertWToR(&scp->rw);
+ readlock = 1;
/* decode times. We need a search time, but the response to this
* call provides the date first, not the time, as returned in the
code = 0;
done:
- lock_ReleaseMutex(&scp->mx);
+ if (readlock)
+ lock_ReleaseRead(&scp->rw);
+ else
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_ReleaseFID(fidp);
return code;
}
+/* SMB_COM_SET_INFORMATION2 */
long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
unsigned short fid;
cm_attr_t attrs;
cm_req_t req;
- cm_InitReq(&req);
+ smb_InitReq(&req);
fid = smb_GetSMBParm(inp, 0);
fid = smb_ChainFID(fid, inp);
return CM_ERROR_BADFD;
lock_ObtainMutex(&fidp->mx);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
smb_ReleaseFID(fidp);
return CM_ERROR_BADFD;
}
+ scp = fidp->scp;
+ osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
+ cm_HoldSCache(scp);
lock_ReleaseMutex(&fidp->mx);
userp = smb_GetUserFromVCP(vcp, inp);
- scp = fidp->scp;
-
/* now prepare to call cm_setattr. This message only sets various times,
* and AFS only implements mtime, and we'll set the mtime if that's
* requested. The others we'll ignore.
osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
}
}
- else code = 0;
+ else
+ code = 0;
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_ReleaseFID(fidp);
return code;
}
+/* SMB_COM_WRITE_ANDX */
+long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+ osi_hyper_t offset;
+ long count, written = 0, total_written = 0;
+ unsigned short fd;
+ unsigned pid;
+ smb_fid_t *fidp;
+ smb_t *smbp = (smb_t*) inp;
+ long code = 0;
+ cm_scache_t *scp;
+ cm_user_t *userp;
+ char *op;
+ int inDataBlockCount;
+
+ fd = smb_GetSMBParm(inp, 2);
+ count = smb_GetSMBParm(inp, 10);
+
+ offset.HighPart = 0;
+ offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
+
+ if (*inp->wctp == 14) {
+ /* we have a request with 64-bit file offsets */
+#ifdef AFS_LARGEFILES
+ offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
+#else
+ if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
+ /* uh oh */
+ osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
+ /* we shouldn't have received this op if we didn't specify
+ largefile support */
+ return CM_ERROR_BADOP;
+ }
+#endif
+ }
+
+ op = inp->data + smb_GetSMBParm(inp, 11);
+ inDataBlockCount = count;
+
+ osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
+ fd, offset.HighPart, offset.LowPart, count);
+
+ fd = smb_ChainFID(fd, inp);
+ fidp = smb_FindFID(vcp, fd, 0);
+ if (!fidp)
+ return CM_ERROR_BADFD;
+
+ lock_ObtainMutex(&fidp->mx);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ if (fidp->flags & SMB_FID_IOCTL) {
+ lock_ReleaseMutex(&fidp->mx);
+ code = smb_IoctlV3Write(fidp, vcp, inp, outp);
+ smb_ReleaseFID(fidp);
+ return code;
+ }
+
+ if (!fidp->scp) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_BADFDOP;
+ }
+
+ scp = fidp->scp;
+ cm_HoldSCache(scp);
+ lock_ReleaseMutex(&fidp->mx);
+
+ userp = smb_GetUserFromVCP(vcp, inp);
+
+ /* special case: 0 bytes transferred means there is no data
+ transferred. A slight departure from SMB_COM_WRITE where this
+ means that we are supposed to truncate the file at this
+ position. */
+ {
+ cm_key_t key;
+ LARGE_INTEGER LOffset;
+ LARGE_INTEGER LLength;
+
+ pid = smbp->pid;
+ key = cm_GenerateKey(vcp->vcID, pid, fd);
+
+ LOffset.HighPart = offset.HighPart;
+ LOffset.LowPart = offset.LowPart;
+ LLength.HighPart = 0;
+ LLength.LowPart = count;
+
+ lock_ObtainWrite(&scp->rw);
+ code = cm_LockCheckWrite(scp, LOffset, LLength, key);
+ lock_ReleaseWrite(&scp->rw);
+
+ if (code)
+ goto done;
+ }
+
+ /*
+ * Work around bug in NT client
+ *
+ * When copying a file, the NT client should first copy the data,
+ * then copy the last write time. But sometimes the NT client does
+ * these in the wrong order, so the data copies would inadvertently
+ * cause the last write time to be overwritten. We try to detect this,
+ * and don't set client mod time if we think that would go against the
+ * intention.
+ */
+ lock_ObtainMutex(&fidp->mx);
+ if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
+ scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+ scp->clientModTime = time(NULL);
+ }
+ lock_ReleaseMutex(&fidp->mx);
+
+ code = 0;
+ while ( code == 0 && count > 0 ) {
+ code = smb_WriteData(fidp, &offset, count, op, userp, &written);
+ if (code == 0 && written == 0)
+ code = CM_ERROR_PARTIALWRITE;
+
+ offset = LargeIntegerAdd(offset,
+ ConvertLongToLargeInteger(written));
+ count -= written;
+ total_written += written;
+ written = 0;
+ }
+
+ /* slots 0 and 1 are reserved for request chaining and will be
+ filled in when we return. */
+ smb_SetSMBParm(outp, 2, total_written);
+ smb_SetSMBParm(outp, 3, 0); /* reserved */
+ smb_SetSMBParm(outp, 4, 0); /* reserved */
+ smb_SetSMBParm(outp, 5, 0); /* reserved */
+ smb_SetSMBDataLength(outp, 0);
+
+ done:
+
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
+
+ return code;
+}
+
+/* SMB_COM_READ_ANDX */
long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
osi_hyper_t offset;
unsigned short fd;
unsigned pid;
smb_fid_t *fidp;
+ smb_t *smbp = (smb_t*) inp;
long code = 0;
+ cm_scache_t *scp;
cm_user_t *userp;
cm_key_t key;
char *op;
fd = smb_GetSMBParm(inp, 2);
count = smb_GetSMBParm(inp, 5);
- offset.HighPart = 0; /* too bad */
offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
- osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
- fd, offset.LowPart, count);
-
+ if (*inp->wctp == 12) {
+ /* a request with 64-bit offsets */
+#ifdef AFS_LARGEFILES
+ offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
+
+ if (LargeIntegerLessThanZero(offset)) {
+ osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
+ offset.HighPart, offset.LowPart);
+ return CM_ERROR_BADSMB;
+ }
+#else
+ if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
+ osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
+ return CM_ERROR_BADSMB;
+ } else {
+ offset.HighPart = 0;
+ }
+#endif
+ } else {
+ offset.HighPart = 0;
+ }
+
+ osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
+ fd, offset.HighPart, offset.LowPart, count);
+
fd = smb_ChainFID(fd, inp);
fidp = smb_FindFID(vcp, fd, 0);
if (!fidp) {
return CM_ERROR_BADFD;
}
- pid = ((smb_t *) inp)->pid;
+ lock_ObtainMutex(&fidp->mx);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ if (!fidp->scp) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_BADFDOP;
+ }
+
+ scp = fidp->scp;
+ cm_HoldSCache(scp);
+ lock_ReleaseMutex(&fidp->mx);
+
+ pid = smbp->pid;
key = cm_GenerateKey(vcp->vcID, pid, fd);
{
LARGE_INTEGER LOffset, LLength;
LLength.HighPart = 0;
LLength.LowPart = count;
- lock_ObtainMutex(&fidp->scp->mx);
- code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
- lock_ReleaseMutex(&fidp->scp->mx);
+ lock_ObtainWrite(&scp->rw);
+ code = cm_LockCheckRead(scp, LOffset, LLength, key);
+ lock_ReleaseWrite(&scp->rw);
}
+ cm_ReleaseSCache(scp);
if (code) {
smb_ReleaseFID(fidp);
/* set the packet data length the count of the # of bytes */
smb_SetSMBDataLength(outp, count);
-#ifndef DJGPP
code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
-#else /* DJGPP */
- code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
-#endif /* !DJGPP */
/* fix some things up */
smb_SetSMBParm(outp, 5, finalCount);
smb_SetSMBDataLength(outp, finalCount);
- smb_ReleaseFID(fidp);
-
cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
return code;
}
#define FILE_RANDOM_ACCESS 0x0800
#define FILE_DELETE_ON_CLOSE 0x1000
#define FILE_OPEN_BY_FILE_ID 0x2000
-
+#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
+#define FILE_NO_COMPRESSION 0x00008000
+#define FILE_RESERVE_OPFILTER 0x00100000
+#define FILE_OPEN_REPARSE_POINT 0x00200000
+#define FILE_OPEN_NO_RECALL 0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
+
+/* SMB_COM_NT_CREATE_ANDX */
long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- char *pathp, *realPathp;
+ clientchar_t *pathp, *realPathp;
long code = 0;
cm_space_t *spacep;
cm_user_t *userp;
cm_scache_t *scp; /* file to create or open */
cm_scache_t *targetScp; /* if scp is a symlink */
cm_attr_t setAttr;
- char *lastNamep;
- char *treeStartp;
+ clientchar_t *lastNamep;
+ clientchar_t *treeStartp;
unsigned short nameLength;
unsigned int flags;
unsigned int requestOpLock;
long fidflags;
FILETIME ft;
LARGE_INTEGER sz;
- char *tidPathp;
+ clientchar_t *tidPathp;
BOOL foundscp;
cm_req_t req;
int created = 0;
+ int prefetch = 0;
+ int checkDoneRequired = 0;
+ cm_lock_data_t *ldp = NULL;
- cm_InitReq(&req);
+ smb_InitReq(&req);
/* This code is very long and has a lot of if-then-else clauses
* scp and dscp get reused frequently and we need to ensure that
if (extAttributes & SMB_ATTR_READONLY)
initialModeBits &= ~0222;
- pathp = smb_GetSMBData(inp, NULL);
+ pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
+ NULL, SMB_STRF_ANSIPATH);
+
/* Sometimes path is not null-terminated, so we make a copy. */
- realPathp = malloc(nameLength+1);
- memcpy(realPathp, pathp, nameLength);
- realPathp[nameLength] = 0;
- if (smb_StoreAnsiFilenames)
- OemToChar(realPathp,realPathp);
+ realPathp = malloc(nameLength+sizeof(clientchar_t));
+ memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
+ realPathp[nameLength/sizeof(clientchar_t)] = 0;
spacep = inp->spacep;
- smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
+ smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
- osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
+ osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
- osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
+ osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
- if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+ if (lastNamep &&
+ (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
+ cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
+ cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
+ cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
/* special case magic file name for receiving IOCTL requests
* (since IOCTL calls themselves aren't getting through).
*/
return 0;
}
-#ifdef DEBUG_VERBOSE
- {
- char *hexp, *asciip;
- asciip = (lastNamep? lastNamep : realPathp);
- hexp = osi_HexifyString( asciip );
- DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
+ if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+ clientchar_t * hexp;
+
+ hexp = cm_GetRawCharsAlloc(realPathp, -1);
+ osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
+ osi_LogSaveClientString(smb_logp, hexp));
+ if (hexp)
free(hexp);
- }
+#else
+ osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
#endif
+ free(realPathp);
+ return CM_ERROR_BADNTFILENAME;
+ }
userp = smb_GetUserFromVCP(vcp, inp);
if (!userp) {
cm_ReleaseUser(userp);
return CM_ERROR_INVAL;
}
+
+ if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ smb_CloseFID(vcp, baseFidp, NULL, 0);
+ smb_ReleaseFID(baseFidp);
+ return CM_ERROR_NOSUCHPATH;
+ }
+
baseDirp = baseFidp->scp;
tidPathp = NULL;
}
- osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
+ osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
/* compute open mode */
fidflags = 0;
if (desiredAccess & DELETE)
fidflags |= SMB_FID_OPENDELETE;
- if (desiredAccess & AFS_ACCESS_READ)
- fidflags |= SMB_FID_OPENREAD;
+ if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
+ fidflags |= SMB_FID_OPENREAD_LISTDIR;
if (desiredAccess & AFS_ACCESS_WRITE)
fidflags |= SMB_FID_OPENWRITE;
if (createOptions & FILE_DELETE_ON_CLOSE)
fidflags |= SMB_FID_DELONCLOSE;
+ if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
+ fidflags |= SMB_FID_SEQUENTIAL;
+ if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
+ fidflags |= SMB_FID_RANDOM;
+ if (createOptions & FILE_OPEN_REPARSE_POINT)
+ osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
+ if (smb_IsExecutableFileName(lastNamep))
+ fidflags |= SMB_FID_EXECUTABLE;
/* and the share mode */
if (shareAccess & FILE_SHARE_READ)
if ( createDisp == FILE_CREATE ||
createDisp == FILE_OVERWRITE ||
createDisp == FILE_OVERWRITE_IF) {
- code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &dscp);
if (code == 0) {
#ifdef DFS_SUPPORT
if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+ spacep->wdata);
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
userp, &req, &scp);
- if (code == CM_ERROR_NOSUCHFILE) {
+ if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
if (code == 0 && realDirFlag == 1) {
userp, tidPathp, &req, &scp);
#ifdef DFS_SUPPORT
if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
/* we might have scp but not dscp */
if (dscp == NULL) {
do {
- char *tp;
+ clientchar_t *tp;
- code = cm_NameI(baseDirp, spacep->data,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, tidPathp, &req, &dscp);
+ code = cm_NameI(baseDirp, spacep->wdata,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &dscp);
#ifdef DFS_SUPPORT
if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+ spacep->wdata);
if (scp)
cm_ReleaseSCache(scp);
cm_ReleaseSCache(dscp);
free(realPathp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
- if (code &&
- (tp = strrchr(spacep->data,'\\')) &&
- (createDisp == FILE_CREATE) &&
- (realDirFlag == 1)) {
+ if (code &&
+ (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
+ (createDisp == FILE_CREATE) &&
+ (realDirFlag == 1)) {
*tp++ = 0;
treeCreate = TRUE;
- treeStartp = realPathp + (tp - spacep->data);
+ treeStartp = realPathp + (tp - spacep->wdata);
if (*tp && !smb_IsLegalFilename(tp)) {
+ cm_ReleaseUser(userp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- cm_ReleaseUser(userp);
free(realPathp);
if (scp)
cm_ReleaseSCache(scp);
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, &req, &scp);
}
- if (code && code != CM_ERROR_NOSUCHFILE) {
+ if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
if (dscp)
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
* scp is NULL.
*/
if (code == 0 && !treeCreate) {
- code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
if (code) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (dscp)
cm_ReleaseSCache(dscp);
if (scp)
free(realPathp);
return code;
}
+ checkDoneRequired = 1;
if (createDisp == FILE_CREATE) {
/* oops, file shouldn't be there */
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (dscp)
cm_ReleaseSCache(dscp);
if (scp)
code = 0;
while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
targetScp = 0;
- osi_assert(dscp != NULL);
+ osi_assertx(dscp != NULL, "null cm_scache_t");
code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
if (code == 0) {
/* we have a more accurate file to use (the
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
scp = targetScp;
- }
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+ if (code) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
+ }
}
code = cm_SetAttr(scp, &setAttr, userp, &req);
openAction = 3; /* truncated existing file */
free(realPathp);
return CM_ERROR_NOSUCHFILE;
} else if (realDirFlag == 0 || realDirFlag == -1) {
- osi_assert(dscp != NULL);
- osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
- osi_LogSaveString(smb_logp, lastNamep));
+ osi_assertx(dscp != NULL, "null cm_scache_t");
+ osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
+ osi_LogSaveClientString(smb_logp, lastNamep));
openAction = 2; /* created file */
setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
setAttr.clientModTime = time(NULL);
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
/* Not an exclusive create, and someone else tried
} /* lookup succeeded */
}
} else {
- char *tp, *pp;
- char *cp; /* This component */
+ clientchar_t *tp, *pp;
+ clientchar_t *cp; /* This component */
int clen = 0; /* length of component */
cm_scache_t *tscp1, *tscp2;
int isLast = 0;
/* create directory */
if ( !treeCreate )
treeStartp = lastNamep;
- osi_assert(dscp != NULL);
- osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
- osi_LogSaveString(smb_logp, treeStartp));
+ osi_assertx(dscp != NULL, "null cm_scache_t");
+ osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
+ osi_LogSaveClientString(smb_logp, treeStartp));
openAction = 2; /* created directory */
/* if the request is to create the root directory
* it will appear as a directory name of the nul-string
* and a code of CM_ERROR_NOSUCHFILE
*/
- if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
+ if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
code = CM_ERROR_EXISTS;
setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
setAttr.clientModTime = time(NULL);
pp = treeStartp;
- cp = spacep->data;
+ cp = spacep->wdata;
tscp1 = dscp;
cm_HoldSCache(tscp1);
tscp2 = NULL;
while (pp && *pp) {
- tp = strchr(pp, '\\');
+ tp = cm_ClientStrChr(pp, '\\');
if (!tp) {
- strcpy(cp,pp);
- clen = (int)strlen(cp);
+ cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
+ clen = (int)cm_ClientStrLen(cp);
isLast = 1; /* indicate last component. the supplied path never ends in a slash */
} else {
clen = (int)(tp - pp);
- strncpy(cp,pp,clen);
+ cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
+ pp, clen);
*(cp + clen) = 0;
tp++;
}
continue; /* the supplied path can't have consecutive slashes either , but */
/* cp is the next component to be created. */
- code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
+ code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- tscp1, cp, NULL, TRUE);
- if (code == 0 ||
- (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ tscp1, cp, NULL, TRUE);
+ if (code == 0 ||
+ (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
/* Not an exclusive create, and someone else tried
* creating it already, then we open it anyway. We
* don't bother retrying after this, since if this next
* started this call.
*/
code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
- userp, &req, &tscp2);
- }
+ userp, &req, &tscp2);
+ }
if (code)
break;
if (code) {
/* something went wrong creating or truncating the file */
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (scp)
cm_ReleaseSCache(scp);
if (dscp)
* we'll just use the symlink anyway.
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
+ if (checkDoneRequired) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ checkDoneRequired = 0;
+ }
cm_ReleaseSCache(scp);
scp = targetScp;
}
}
if (scp->fileType != CM_SCACHETYPE_FILE) {
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (dscp)
cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
/* (only applies to single component case) */
if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
if (dscp)
cm_ReleaseSCache(dscp);
/* open the file itself */
fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
+ osi_assertx(fidp, "null smb_fid_t");
/* save a reference to the user */
cm_HoldUser(userp);
LLength.HighPart = 0;
LLength.LowPart = SMB_FID_QLOCK_LENGTH;
- if (fidflags & SMB_FID_SHARE_READ) {
+ /* If we are not opening the file for writing, then we don't
+ try to get an exclusive lock. No one else should be able to
+ get an exclusive lock on the file anyway, although someone
+ else can get a shared lock. */
+ if ((fidflags & SMB_FID_SHARE_READ) ||
+ !(fidflags & SMB_FID_OPENWRITE)) {
sLockType = LOCKING_ANDX_SHARED_LOCK;
} else {
sLockType = 0;
key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
if (code) {
- /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
- smb_CloseFID(vcp, fidp, NULL, 0);
- smb_ReleaseFID(fidp);
-
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
if (dscp)
cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
+ cm_ReleaseUser(userp);
+ /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
free(realPathp);
-
return code;
}
}
+ /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
+ if (checkDoneRequired) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ checkDoneRequired = 0;
+ }
+
lock_ObtainMutex(&fidp->mx);
/* save a pointer to the vnode */
fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
+ lock_ObtainWrite(&scp->rw);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseWrite(&scp->rw);
+ osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
fidp->flags = fidflags;
/* save parent dir and pathname for delete or change notification */
if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
+ osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
fidp->flags |= SMB_FID_NTOPEN;
fidp->NTopen_dscp = dscp;
- cm_HoldSCache(dscp);
- fidp->NTopen_pathp = strdup(lastNamep);
+ dscp = NULL;
+ fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
}
fidp->NTopen_wholepathp = realPathp;
lock_ReleaseMutex(&fidp->mx);
/* out parms */
parmSlot = 2;
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainRead(&scp->rw);
smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
smb_SetSMBParmByte(outp, parmSlot,
- scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
- lock_ReleaseMutex(&scp->mx);
+ (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
smb_SetSMBDataLength(outp, 0);
- osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
- osi_LogSaveString(smb_logp, realPathp));
+ if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+ LargeIntegerGreaterThanZero(scp->length) &&
+ !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+ prefetch = 1;
+ }
+ lock_ReleaseRead(&scp->rw);
- smb_ReleaseFID(fidp);
+ if (prefetch)
+ cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
+ scp->length.LowPart, scp->length.HighPart,
+ userp);
+
+
+ osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
+ osi_LogSaveClientString(smb_logp, realPathp));
cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
/* Can't free realPathp if we get here since
fidp->NTopen_wholepathp is pointing there */
* A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
* Instead, ultimately, would like to use a subroutine for common code.
*/
+
+/* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- char *pathp, *realPathp;
+ clientchar_t *pathp, *realPathp;
long code = 0;
cm_space_t *spacep;
cm_user_t *userp;
cm_scache_t *scp; /* file to create or open */
cm_scache_t *targetScp; /* if scp is a symlink */
cm_attr_t setAttr;
- char *lastNamep;
+ clientchar_t *lastNamep;
unsigned long nameLength;
unsigned int flags;
unsigned int requestOpLock;
unsigned int extendedRespRequired;
int realDirFlag;
unsigned int desiredAccess;
-#ifdef DEBUG_VERBOSE
unsigned int allocSize;
-#endif
unsigned int shareAccess;
unsigned int extAttributes;
unsigned int createDisp;
-#ifdef DEBUG_VERBOSE
unsigned int sdLen;
-#endif
+ unsigned int eaLen;
+ unsigned int impLevel;
+ unsigned int secFlags;
unsigned int createOptions;
int initialModeBits;
unsigned short baseFid;
int parmSlot;
long fidflags;
FILETIME ft;
- char *tidPathp;
+ clientchar_t *tidPathp;
BOOL foundscp;
int parmOffset, dataOffset;
char *parmp;
char *outData;
cm_req_t req;
int created = 0;
+ int prefetch = 0;
+ cm_lock_data_t *ldp = NULL;
+ int checkDoneRequired = 0;
- cm_InitReq(&req);
+ smb_InitReq(&req);
foundscp = FALSE;
scp = NULL;
return CM_ERROR_INVAL;
baseFid = (unsigned short)lparmp[1];
desiredAccess = lparmp[2];
-#ifdef DEBUG_VERBOSE
allocSize = lparmp[3];
-#endif /* DEBUG_VERSOSE */
extAttributes = lparmp[5];
shareAccess = lparmp[6];
createDisp = lparmp[7];
createOptions = lparmp[8];
-#ifdef DEBUG_VERBOSE
sdLen = lparmp[9];
-#endif
- nameLength = lparmp[11];
-
-#ifdef DEBUG_VERBOSE
- osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
- osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
- osi_Log1(smb_logp,"... flags[%x]",flags);
-#endif
+ eaLen = lparmp[10];
+ nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
+ impLevel = lparmp[12];
+ secFlags = lparmp[13];
/* mustBeDir is never set; createOptions directory bit seems to be
* more important
* extended attributes
*/
initialModeBits = 0666;
- if (extAttributes & 1)
+ if (extAttributes & SMB_ATTR_READONLY)
initialModeBits &= ~0222;
- pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
- /* Sometimes path is not null-terminated, so we make a copy. */
- realPathp = malloc(nameLength+1);
+ pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
+ nameLength, NULL, SMB_STRF_ANSIPATH);
+ /* Sometimes path is not nul-terminated, so we make a copy. */
+ realPathp = malloc(nameLength+sizeof(clientchar_t));
memcpy(realPathp, pathp, nameLength);
- realPathp[nameLength] = 0;
- if (smb_StoreAnsiFilenames)
- OemToChar(realPathp,realPathp);
-
+ realPathp[nameLength/sizeof(clientchar_t)] = 0;
spacep = cm_GetSpace();
- smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
+ smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
+
+ osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
+ osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
+ osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
+ osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
/*
* Nothing here to handle SMB_IOCTL_FILENAME.
* Will add it if necessary.
*/
-#ifdef DEBUG_VERBOSE
- {
- char *hexp, *asciip;
- asciip = (lastNamep? lastNamep : realPathp);
- hexp = osi_HexifyString( asciip );
- DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
+ if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+ clientchar_t * hexp;
+
+ hexp = cm_GetRawCharsAlloc(realPathp, -1);
+ osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
+ osi_LogSaveClientString(smb_logp, hexp));
+ if (hexp)
free(hexp);
- }
+#else
+ osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
#endif
+ free(realPathp);
+ return CM_ERROR_BADNTFILENAME;
+ }
userp = smb_GetUserFromVCP(vcp, inp);
if (!userp) {
osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
free(realPathp);
cm_ReleaseUser(userp);
- return CM_ERROR_INVAL;
+ return CM_ERROR_BADFD;
}
+
+ if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ smb_CloseFID(vcp, baseFidp, NULL, 0);
+ smb_ReleaseFID(baseFidp);
+ return CM_ERROR_NOSUCHPATH;
+ }
+
baseDirp = baseFidp->scp;
tidPathp = NULL;
}
fidflags = 0;
if (desiredAccess & DELETE)
fidflags |= SMB_FID_OPENDELETE;
- if (desiredAccess & AFS_ACCESS_READ)
- fidflags |= SMB_FID_OPENREAD;
+ if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
+ fidflags |= SMB_FID_OPENREAD_LISTDIR;
if (desiredAccess & AFS_ACCESS_WRITE)
fidflags |= SMB_FID_OPENWRITE;
if (createOptions & FILE_DELETE_ON_CLOSE)
fidflags |= SMB_FID_DELONCLOSE;
+ if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
+ fidflags |= SMB_FID_SEQUENTIAL;
+ if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
+ fidflags |= SMB_FID_RANDOM;
+ if (createOptions & FILE_OPEN_REPARSE_POINT)
+ osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
+ if (smb_IsExecutableFileName(lastNamep))
+ fidflags |= SMB_FID_EXECUTABLE;
/* And the share mode */
if (shareAccess & FILE_SHARE_READ)
if ( createDisp == FILE_OPEN ||
createDisp == FILE_OVERWRITE ||
createDisp == FILE_OVERWRITE_IF) {
- code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &dscp);
if (code == 0) {
#ifdef DFS_SUPPORT
if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
userp, &req, &scp);
- if (code == CM_ERROR_NOSUCHFILE) {
+ if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
if (code == 0 && realDirFlag == 1) {
userp, tidPathp, &req, &scp);
#ifdef DFS_SUPPORT
if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
}
if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
/* look up parent directory */
if ( !dscp ) {
- code = cm_NameI(baseDirp, spacep->data,
+ code = cm_NameI(baseDirp, spacep->wdata,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &dscp);
#ifdef DFS_SUPPORT
if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- if ( WANTS_DFS_PATHNAMES(inp) )
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
return CM_ERROR_PATH_NOT_COVERED;
else
- return CM_ERROR_BADSHARENAME;
+ return CM_ERROR_NOSUCHPATH;
}
#endif /* DFS_SUPPORT */
} else
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, &req, &scp);
}
- if (code && code != CM_ERROR_NOSUCHFILE) {
+ if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
* scp is NULL.
*/
if (code == 0) {
- code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
- &req);
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
if (code) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (dscp)
cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
free(realPathp);
return code;
}
+ checkDoneRequired = 1;
if (createDisp == FILE_CREATE) {
/* oops, file shouldn't be there */
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (dscp)
cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
scp = targetScp;
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+ if (code) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
}
}
code = cm_SetAttr(scp, &setAttr, userp, &req);
return CM_ERROR_NOSUCHFILE;
}
else if (realDirFlag == 0 || realDirFlag == -1) {
- osi_assert(dscp != NULL);
- osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
- osi_LogSaveString(smb_logp, lastNamep));
+ osi_assertx(dscp != NULL, "null cm_scache_t");
+ osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
+ osi_LogSaveClientString(smb_logp, lastNamep));
openAction = 2; /* created file */
setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
setAttr.clientModTime = time(NULL);
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
/* Not an exclusive create, and someone else tried
}
} else {
/* create directory */
- osi_assert(dscp != NULL);
+ osi_assertx(dscp != NULL, "null cm_scache_t");
osi_Log1(smb_logp,
- "smb_ReceiveNTTranCreate creating directory %s",
- osi_LogSaveString(smb_logp, lastNamep));
+ "smb_ReceiveNTTranCreate creating directory %S",
+ osi_LogSaveClientString(smb_logp, lastNamep));
openAction = 2; /* created directory */
setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
setAttr.clientModTime = time(NULL);
- code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
+ code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
smb_NotifyChange(FILE_ACTION_ADDED,
FILE_NOTIFY_CHANGE_DIR_NAME,
if (code) {
/* something went wrong creating or truncating the file */
- if (scp)
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (scp)
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
+ if (checkDoneRequired) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ checkDoneRequired = 0;
+ }
cm_ReleaseSCache(scp);
scp = targetScp;
}
}
if (scp->fileType != CM_SCACHETYPE_FILE) {
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
}
if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
/* open the file itself */
fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
- osi_assert(fidp);
+ osi_assertx(fidp, "null smb_fid_t");
/* save a reference to the user */
cm_HoldUser(userp);
LLength.HighPart = 0;
LLength.LowPart = SMB_FID_QLOCK_LENGTH;
- if (fidflags & SMB_FID_SHARE_READ) {
+ /* Similar to what we do in handling NTCreateX. We get a
+ shared lock if we are only opening the file for reading. */
+ if ((fidflags & SMB_FID_SHARE_READ) ||
+ !(fidflags & SMB_FID_OPENWRITE)) {
sLockType = LOCKING_ANDX_SHARED_LOCK;
} else {
sLockType = 0;
key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainWrite(&scp->rw);
code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
if (code) {
- /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
- smb_CloseFID(vcp, fidp, NULL, 0);
- smb_ReleaseFID(fidp);
-
+ if (checkDoneRequired)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- free(realPathp);
-
+ /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ free(realPathp);
return CM_ERROR_SHARING_VIOLATION;
}
}
+ /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
+ if (checkDoneRequired) {
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ checkDoneRequired = 0;
+ }
+
lock_ObtainMutex(&fidp->mx);
/* save a pointer to the vnode */
fidp->scp = scp;
+ lock_ObtainWrite(&scp->rw);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseWrite(&scp->rw);
+ osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
fidp->flags = fidflags;
if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
fidp->flags |= SMB_FID_NTOPEN;
fidp->NTopen_dscp = dscp;
- cm_HoldSCache(dscp);
- fidp->NTopen_pathp = strdup(lastNamep);
+ osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
+ dscp = NULL;
+ fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
}
fidp->NTopen_wholepathp = realPathp;
lock_ReleaseMutex(&fidp->mx);
smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
smb_SetSMBDataLength(outp, 70);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainRead(&scp->rw);
outData = smb_GetSMBData(outp, NULL);
outData++; /* round to get to parmOffset */
*outData = 0; outData++; /* oplock */
*((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
*((USHORT *)outData) = 0; outData += 2; /* filetype */
*((USHORT *)outData) = 0; outData += 2; /* dev state */
- *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
+ *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
outData += 2; /* is a dir? */
- lock_ReleaseMutex(&scp->mx);
} else {
/* out parms */
parmOffset = 8*4 + 39;
smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
smb_SetSMBDataLength(outp, 105);
- lock_ObtainMutex(&scp->mx);
+ lock_ObtainRead(&scp->rw);
outData = smb_GetSMBData(outp, NULL);
outData++; /* round to get to parmOffset */
*outData = 0; outData++; /* oplock */
*((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
*((USHORT *)outData) = 0; outData += 2; /* filetype */
*((USHORT *)outData) = 0; outData += 2; /* dev state */
- *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
+ *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
outData += 1; /* is a dir? */
memset(outData,0,24); outData += 24; /* Volume ID and file ID */
*((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
*((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
- lock_ReleaseMutex(&scp->mx);
}
- osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
+ if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+ LargeIntegerGreaterThanZero(scp->length) &&
+ !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+ prefetch = 1;
+ }
+ lock_ReleaseRead(&scp->rw);
- smb_ReleaseFID(fidp);
+ if (prefetch)
+ cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
+ scp->length.LowPart, scp->length.HighPart,
+ userp);
+
+ osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
/* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
/* leave scp held since we put it in fidp->scp */
return 0;
}
+/* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
smb_packet_t *outp)
{
smb_packet_t *savedPacketp;
- ULONG filter; USHORT fid, watchtree;
+ ULONG filter;
+ USHORT fid, watchtree;
smb_fid_t *fidp;
cm_scache_t *scp;
filter = smb_GetSMBParm(inp, 19) |
(smb_GetSMBParm(inp, 20) << 16);
fid = smb_GetSMBParm(inp, 21);
- watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
+ watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
fidp = smb_FindFID(vcp, fid, 0);
if (!fidp) {
return CM_ERROR_BADFD;
}
+ lock_ObtainMutex(&fidp->mx);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ lock_ReleaseMutex(&fidp->mx);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+ scp = fidp->scp;
+ cm_HoldSCache(scp);
+ lock_ReleaseMutex(&fidp->mx);
+
+ /* Create a copy of the Directory Watch Packet to use when sending the
+ * notification if in the future a matching change is detected.
+ */
savedPacketp = smb_CopyPacket(inp);
- smb_HoldVC(vcp);
- if (savedPacketp->vcp)
- smb_ReleaseVC(savedPacketp->vcp);
- savedPacketp->vcp = vcp;
+ if (vcp != savedPacketp->vcp) {
+ smb_HoldVC(vcp);
+ if (savedPacketp->vcp)
+ smb_ReleaseVC(savedPacketp->vcp);
+ savedPacketp->vcp = vcp;
+ }
+
+ /* Add the watch to the list of events to send notifications for */
lock_ObtainMutex(&smb_Dir_Watch_Lock);
savedPacketp->nextp = smb_Directory_Watches;
smb_Directory_Watches = savedPacketp;
lock_ReleaseMutex(&smb_Dir_Watch_Lock);
- osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
- filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
-
- scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
+ osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
+ fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
+ osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
+ filter, fid, watchtree);
+ if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
+ osi_Log0(smb_logp, " Notify Change File Name");
+ if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
+ osi_Log0(smb_logp, " Notify Change Directory Name");
+ if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
+ osi_Log0(smb_logp, " Notify Change Attributes");
+ if (filter & FILE_NOTIFY_CHANGE_SIZE)
+ osi_Log0(smb_logp, " Notify Change Size");
+ if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
+ osi_Log0(smb_logp, " Notify Change Last Write");
+ if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
+ osi_Log0(smb_logp, " Notify Change Last Access");
+ if (filter & FILE_NOTIFY_CHANGE_CREATION)
+ osi_Log0(smb_logp, " Notify Change Creation");
+ if (filter & FILE_NOTIFY_CHANGE_EA)
+ osi_Log0(smb_logp, " Notify Change Extended Attributes");
+ if (filter & FILE_NOTIFY_CHANGE_SECURITY)
+ osi_Log0(smb_logp, " Notify Change Security");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
+ osi_Log0(smb_logp, " Notify Change Stream Name");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
+ osi_Log0(smb_logp, " Notify Change Stream Size");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
+ osi_Log0(smb_logp, " Notify Change Stream Write");
+
+ lock_ObtainWrite(&scp->rw);
if (watchtree)
scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
else
scp->flags |= CM_SCACHEFLAG_WATCHED;
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
smb_ReleaseFID(fidp);
outp->flags |= SMB_PACKETFLAG_NOSEND;
/* "null SID" group SID */
};
+/* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
int parmOffset, parmCount, dataOffset, dataCount;
return CM_ERROR_BUFFERTOOSMALL;
}
+/* SMB_COM_NT_TRANSACT
+
+ SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
+ */
long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
unsigned short function;
((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
switch (function) {
- case 1:
+ case 1: /* NT_TRANSACT_CREATE */
return smb_ReceiveNTTranCreate(vcp, inp, outp);
- case 2:
+ case 2: /* NT_TRANSACT_IOCTL */
osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
break;
- case 3:
+ case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
break;
- case 4:
+ case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
- case 5:
+ case 5: /* NT_TRANSACT_RENAME */
osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
break;
- case 6:
+ case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
+ case 7:
+ osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
+ break;
+ case 8:
+ osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
+ break;
}
return CM_ERROR_INVAL;
}
*
* If we don't know the file name (i.e. a callback break), filename is
* NULL, and we return a zero-length list.
+ *
+ * At present there is not a single call to smb_NotifyChange that
+ * has the isDirectParent parameter set to FALSE.
*/
void smb_NotifyChange(DWORD action, DWORD notifyFilter,
- cm_scache_t *dscp, char *filename, char *otherFilename,
+ cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
BOOL isDirectParent)
{
smb_packet_t *watch, *lastWatch, *nextWatch;
- ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
+ ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
char *outData, *oldOutData;
ULONG filter;
USHORT fid, wtree;
otherAction = FILE_ACTION_RENAMED_NEW_NAME;
}
- osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
- osi_LogSaveString(smb_logp,filename),dscp);
+ osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
+ osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
+ if (action == 0)
+ osi_Log0(smb_logp," FILE_ACTION_NONE");
+ if (action == FILE_ACTION_ADDED)
+ osi_Log0(smb_logp," FILE_ACTION_ADDED");
+ if (action == FILE_ACTION_REMOVED)
+ osi_Log0(smb_logp," FILE_ACTION_REMOVED");
+ if (action == FILE_ACTION_MODIFIED)
+ osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
+ if (action == FILE_ACTION_RENAMED_OLD_NAME)
+ osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
+ if (action == FILE_ACTION_RENAMED_NEW_NAME)
+ osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
lock_ObtainMutex(&smb_Dir_Watch_Lock);
watch = smb_Directory_Watches;
filter = smb_GetSMBParm(watch, 19)
| (smb_GetSMBParm(watch, 20) << 16);
fid = smb_GetSMBParm(watch, 21);
- wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
+ wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
+
maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
| (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
/*
- * Strange hack - bug in NT Client and NT Server that we
- * must emulate?
+ * Strange hack - bug in NT Client and NT Server that we must emulate?
*/
- if (filter == 3 && wtree)
- filter = 0x17;
+ if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
+ filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
fidp = smb_FindFID(watch->vcp, fid, 0);
if (!fidp) {
- osi_Log1(smb_logp," no fidp for fid[%d]",fid);
+ osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
lastWatch = watch;
watch = watch->nextp;
continue;
- }
- if (fidp->scp != dscp
- || (filter & notifyFilter) == 0
- || (!isDirectParent && !wtree)) {
- osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
- smb_ReleaseFID(fidp);
+ }
+
+ if (fidp->scp != dscp ||
+ fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
+ (filter & notifyFilter) == 0 ||
+ (!isDirectParent && !wtree))
+ {
+ osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
lastWatch = watch;
watch = watch->nextp;
+ smb_ReleaseFID(fidp);
continue;
}
- smb_ReleaseFID(fidp);
osi_Log4(smb_logp,
- "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
- fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
-
+ "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
+ fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
+ if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
+ osi_Log0(smb_logp, " Notify Change File Name");
+ if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
+ osi_Log0(smb_logp, " Notify Change Directory Name");
+ if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
+ osi_Log0(smb_logp, " Notify Change Attributes");
+ if (filter & FILE_NOTIFY_CHANGE_SIZE)
+ osi_Log0(smb_logp, " Notify Change Size");
+ if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
+ osi_Log0(smb_logp, " Notify Change Last Write");
+ if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
+ osi_Log0(smb_logp, " Notify Change Last Access");
+ if (filter & FILE_NOTIFY_CHANGE_CREATION)
+ osi_Log0(smb_logp, " Notify Change Creation");
+ if (filter & FILE_NOTIFY_CHANGE_EA)
+ osi_Log0(smb_logp, " Notify Change Extended Attributes");
+ if (filter & FILE_NOTIFY_CHANGE_SECURITY)
+ osi_Log0(smb_logp, " Notify Change Security");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
+ osi_Log0(smb_logp, " Notify Change Stream Name");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
+ osi_Log0(smb_logp, " Notify Change Stream Size");
+ if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
+ osi_Log0(smb_logp, " Notify Change Stream Write");
+
+ /* A watch can only be notified once. Remove it from the list */
nextWatch = watch->nextp;
if (watch == smb_Directory_Watches)
smb_Directory_Watches = nextWatch;
lastWatch->nextp = nextWatch;
/* Turn off WATCHED flag in dscp */
- lock_ObtainMutex(&dscp->mx);
+ lock_ObtainWrite(&dscp->rw);
if (wtree)
dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
else
dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
- lock_ReleaseMutex(&dscp->mx);
+ lock_ReleaseWrite(&dscp->rw);
/* Convert to response packet */
- ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+ ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+ ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
((smb_t *) watch)->wct = 0;
/* out parms */
- if (filename == NULL)
+ if (filename == NULL) {
parmCount = 0;
- else {
- nameLen = (ULONG)strlen(filename);
+ } else {
+ nameLen = (ULONG)cm_ClientStrLen(filename);
parmCount = 3*4 + nameLen*2;
parmCount = (parmCount + 3) & ~3; /* pad to 4 */
if (twoEntries) {
- otherNameLen = (ULONG)strlen(otherFilename);
+ otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
oldParmCount = parmCount;
parmCount += 3*4 + otherNameLen*2;
parmCount = (parmCount + 3) & ~3; /* pad to 4 */
smb_SetSMBDataLength(watch, parmCount + 1);
if (parmCount != 0) {
- char * p;
outData = smb_GetSMBData(watch, NULL);
outData++; /* round to get to parmOffset */
oldOutData = outData;
/* Action */
*((DWORD *)outData) = nameLen*2; outData += 4;
/* File Name Length */
- p = strdup(filename);
- if (smb_StoreAnsiFilenames)
- CharToOem(p,p);
- mbstowcs((WCHAR *)outData, p, nameLen);
- free(p);
+
+ smb_UnparseString(watch, outData, filename, NULL, 0);
/* File Name */
+
if (twoEntries) {
outData = oldOutData + oldParmCount;
*((DWORD *)outData) = 0; outData += 4;
/* Action */
*((DWORD *)outData) = otherNameLen*2;
outData += 4; /* File Name Length */
- p = strdup(otherFilename);
- if (smb_StoreAnsiFilenames)
- CharToOem(p,p);
- mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
- free(p);
+ smb_UnparseString(watch, outData, otherFilename, NULL, 0);
}
- }
+ }
/*
* If filename is null, we don't know the cause of the
smb_SendPacket(watch->vcp, watch);
smb_FreePacket(watch);
+
+ smb_ReleaseFID(fidp);
watch = nextWatch;
}
lock_ReleaseMutex(&smb_Dir_Watch_Lock);
}
+/* SMB_COM_NT_CANCEL */
long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
unsigned char *replyWctp;
fidp = smb_FindFID(vcp, fid, 0);
if (fidp) {
- osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
- fid, watchtree,
- osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
+ osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
+ fid, watchtree,
+ (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
- if (watchtree)
- scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
- else
- scp->flags &= ~CM_SCACHEFLAG_WATCHED;
- lock_ReleaseMutex(&scp->mx);
+ osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
+ if (scp) {
+ lock_ObtainWrite(&scp->rw);
+ if (watchtree)
+ scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
+ else
+ scp->flags &= ~CM_SCACHEFLAG_WATCHED;
+ lock_ReleaseWrite(&scp->rw);
+ }
smb_ReleaseFID(fidp);
} else {
osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- char *oldPathp, *newPathp;
+ clientchar_t *oldPathp, *newPathp;
long code = 0;
char * tp;
int attrs;
rename_type = smb_GetSMBParm(inp, 1);
if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
- osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
+ osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
return CM_ERROR_NOACCESS;
}
tp = smb_GetSMBData(inp, NULL);
- oldPathp = smb_ParseASCIIBlock(tp, &tp);
- if (smb_StoreAnsiFilenames)
- OemToChar(oldPathp,oldPathp);
- newPathp = smb_ParseASCIIBlock(tp, &tp);
- if (smb_StoreAnsiFilenames)
- OemToChar(newPathp,newPathp);
-
- osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
- osi_LogSaveString(smb_logp, oldPathp),
- osi_LogSaveString(smb_logp, newPathp),
- ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
+ oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+ if (!oldPathp)
+ return CM_ERROR_BADSMB;
+ newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+ if (!newPathp)
+ return CM_ERROR_BADSMB;
+
+ osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
+ osi_LogSaveClientString(smb_logp, oldPathp),
+ osi_LogSaveClientString(smb_logp, newPathp),
+ ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
if (rename_type == RENAME_FLAG_RENAME) {
code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
- } else { /* RENAME_FLAG_HARD_LINK */
+ } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
code = smb_Link(vcp,inp,oldPathp,newPathp);
- }
+ } else
+ code = CM_ERROR_BADOP;
return code;
}
void smb3_Init()
{
- lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
+ lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
}
-cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
+cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
{
smb_username_t *unp;
cm_user_t * userp;
lock_ObtainMutex(&unp->mx);
unp->userp = cm_NewUser();
lock_ReleaseMutex(&unp->mx);
- osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
+ osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
} else {
- osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
+ osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
}
userp = unp->userp;
cm_HoldUser(userp);