#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 <osi.h>
#include "afsd.h"
+#include <WINNT\afsreg.h>
#include "smb.h"
/* protected by the smb_globalLock */
smb_tran2Packet_t *smb_tran2AssemblyQueuep;
+const char **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)
cm_user_t *up = NULL;
uidp = smb_FindUID(vcp, inp->uid, 0);
- if (!uidp) return NULL;
+ if (!uidp)
+ return NULL;
- lock_ObtainMutex(&uidp->mx);
- if (uidp->unp) {
- up = uidp->unp->userp;
- cm_HoldUser(up);
- }
- lock_ReleaseMutex(&uidp->mx);
+ up = smb_GetUserFromUID(uidp);
smb_ReleaseUID(uidp);
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 char *name)
+{
+ int i, j, len;
+
+ if ( smb_ExecutableExtensions == NULL || name == NULL)
+ return 0;
+
+ len = strlen(name);
+
+ for ( i=0; smb_ExecutableExtensions[i]; i++) {
+ j = len - strlen(smb_ExecutableExtensions[i]);
+ if (_stricmp(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
unsigned long attrs;
if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
- scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_INVALID)
{
attrs = SMB_ATTR_DIRECTORY;
#ifdef SPECIAL_FOLDERS
attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
#endif /* SPECIAL_FOLDERS */
+ } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
} else
attrs = 0;
/*
*/
#ifdef notdef
if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
+ attrs |= SMB_ATTR_READONLY; /* Read-only */
+#else
+ if ((scp->unixModeBits & 0222) == 0)
+ attrs |= SMB_ATTR_READONLY; /* Read-only */
#endif
- if ((scp->unixModeBits & 0222) == 0)
- attrs |= SMB_ATTR_READONLY; /* Read-only */
if (attrs == 0)
attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
char tc;
while (tc = *maskp++)
- if (tc == '?' || tc == '*')
+ if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
return 1;
return 0;
}
return inp;
}
-/*DEBUG do not checkin*/
void OutputDebugF(char * format, ...) {
va_list args;
int len;
for (i=0;i<len;i++) {
if(!(i%16)) {
if(i) {
- osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
- strcat(buf,"\n");
+ osi_Log0(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
+ strcat(buf,"\r\n");
OutputDebugString(buf);
}
sprintf(buf,"%5x",i);
buf[j] = (k>32 && k<127)?k:'.';
}
if(i) {
- osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
- strcat(buf,"\n");
+ osi_Log0(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
+ strcat(buf,"\r\n");
OutputDebugString(buf);
}
}
-/**/
#define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
+
void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
SECURITY_STATUS status, istatus;
CredHandle creds = {0,0};
&creds,
&expiry);
- if (status != SEC_E_OK) {
+ if (status != SEC_E_OK) {
/* Really bad. We return an empty security blob */
OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
goto nes_0;
lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
- lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
+ 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);
- lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
+ lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
size = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerNameW(lmAuth.workstationW, &size);
- lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
+ lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
lmAuth.tgroups.Groups[0].Sid = NULL;
lmAuth.tgroups.Groups[0].Attributes = 0;
- lmAuth.tsource.SourceIdentifier.HighPart = 0;
- lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
+ lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
+ lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
nts = LsaLogonUser( smb_lsaHandle,
"aLimits,
&ntsEx);
+ if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
+ 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);
return 0;
}
-/* When using SMB auth, all SMB sessions have to pass through here first to
- * authenticate the user.
- * Caveat: If not use the SMB auth the protocol does not require 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.
+/* When using SMB auth, all SMB sessions have to pass through here
+ * first to authenticate the user.
+ *
+ * Caveat: If not using SMB auth, the protocol does not require
+ * 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.
*/
long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
smb_user_t *uidp;
unsigned short newUid;
unsigned long caps = 0;
- cm_user_t *userp;
smb_username_t *unp;
char *s1 = " ";
long code = 0;
uidp = smb_FindUserByNameThisSession(vcp, usern);
if (uidp) { /* already there, so don't create a new one */
unp = uidp->unp;
- userp = unp->userp;
- newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
- osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
- osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
+ newUid = uidp->userID;
+ osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
+ vcp->lana,vcp->lsn,newUid);
smb_ReleaseUID(uidp);
}
else {
- /* do a global search for the username/machine name pair */
+ cm_user_t *userp;
+
+ /* do a global search for the username/machine name pair */
unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
+ lock_ObtainMutex(&unp->mx);
+ if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
+ /* clear the afslogon flag so that the tickets can now
+ * be freed when the refCount returns to zero.
+ */
+ unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
+ }
+ lock_ReleaseMutex(&unp->mx);
/* Create a new UID and cm_user_t structure */
userp = unp->userp;
if (!userp)
userp = cm_NewUser();
- lock_ObtainMutex(&vcp->mx);
+ cm_HoldUserVCRef(userp);
+ lock_ObtainMutex(&vcp->mx);
if (!vcp->uidCounter)
vcp->uidCounter++; /* handle unlikely wraparounds */
newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
lock_ReleaseMutex(&unp->mx);
uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
- lock_ObtainMutex(&uidp->mx);
- uidp->unp = unp;
- osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
- osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],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 */
{
smb_user_t *uidp;
- /* don't get tokens from this VC */
- vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-
- inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
-
/* find the tree and free it */
uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
- /* TODO: smb_ReleaseUID() ? */
if (uidp) {
- char *s1 = NULL, *s2 = NULL;
+ smb_username_t * unp;
- if (s2 == NULL) s2 = " ";
- if (s1 == NULL) {s1 = s2; s2 = " ";}
-
- osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
- osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
+ osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
+ osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
lock_ObtainMutex(&uidp->mx);
uidp->flags |= SMB_USERFLAG_DELETE;
- /*
+ /*
* it doesn't get deleted right away
* because the vcp points to it
*/
+ unp = uidp->unp;
lock_ReleaseMutex(&uidp->mx);
+
+#ifdef COMMENT
+ /* we can't do this. we get logoff messages prior to a session
+ * disconnect even though it doesn't mean the user is logging out.
+ * we need to create a new pioctl and EventLogoff handler to set
+ * SMB_USERNAMEFLAG_LOGOFF.
+ */
+ if (unp && smb_LogoffTokenTransfer) {
+ lock_ObtainMutex(&unp->mx);
+ unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
+ unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
+ lock_ReleaseMutex(&unp->mx);
+ }
+#endif
+
+ smb_ReleaseUID(uidp);
}
else
osi_Log0(smb_logp, "SMB3 user logoffX");
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 shareName[AFSPATHMAX];
char *sharePath;
int shareFound;
char *tp;
char *pathp;
char *passwordp;
char *servicep;
- cm_user_t *userp;
+ cm_user_t *userp = NULL;
int ipc = 0;
osi_Log0(smb_logp, "SMB3 receive tree connect");
#endif
}
- userp = smb_GetUser(vcp, inp);
+ uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+ if (uidp)
+ userp = smb_GetUserFromUID(uidp);
lock_ObtainMutex(&vcp->mx);
newTid = vcp->tidCounter++;
tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
if (!ipc) {
- uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+ if (!strcmp(shareName, "*."))
+ strcpy(shareName, "all");
shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
- if (uidp)
- smb_ReleaseUID(uidp);
if (!shareFound) {
+ if (uidp)
+ smb_ReleaseUID(uidp);
smb_ReleaseTID(tidp);
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
+ (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
(policy << 2));
}
} else {
smb_SetSMBParm(outp, 2, 0);
sharePath = NULL;
}
+ if (uidp)
+ smb_ReleaseUID(uidp);
lock_ObtainMutex(&tidp->mx);
tidp->userp = userp;
((smb_t *)inp)->tid = newTid;
tp = smb_GetSMBData(outp, NULL);
if (!ipc) {
- /* XXX - why is this a drive letter? - jaltman */
+ /* XXX - why is this a drive letter? */
*tp++ = 'A';
*tp++ = ':';
*tp++ = 0;
- smb_SetSMBDataLength(outp, 3);
+ *tp++ = 'A';
+ *tp++ = 'F';
+ *tp++ = 'S';
+ *tp++ = 0;
+ smb_SetSMBDataLength(outp, 7);
} else {
strcpy(tp, "IPC");
smb_SetSMBDataLength(outp, 4);
tp = malloc(sizeof(*tp));
memset(tp, 0, sizeof(*tp));
- tp->vcp = NULL;
+ smb_HoldVC(vcp);
+ tp->vcp = vcp;
tp->curData = tp->curParms = 0;
tp->totalData = totalData;
tp->totalParms = totalParms;
return tp;
}
-/* free a tran2 packet; must be called with smb_globalLock held */
+/* free a tran2 packet */
void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
{
- if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
+ if (t2p->vcp) {
+ smb_ReleaseVC(t2p->vcp);
+ t2p->vcp = NULL;
+ }
if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
if (t2p->parmsp)
free(t2p->parmsp);
smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
- smbp->flg2 |= SMB_FLAGS2_ERR_STATUS;
+ smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
}
else {
smbp->rcls = errClass;
/* We sometimes see 0 word count. What to do? */
if (*inp->wctp == 0) {
-#ifndef DJGPP
- HANDLE h;
- char *ptbuf[1];
-
- osi_Log0(smb_logp, "TRANSACTION word count = 0");
-
- h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
- ptbuf[0] = "Transaction2 word count = 0";
- ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
- 1, inp->ncb_length, ptbuf, inp);
- DeregisterEventSource(h);
-#else /* DJGPP */
- osi_Log0(smb_logp, "TRANSACTION word count = 0");
-#endif /* !DJGPP */
+ osi_Log0(smb_logp, "Transaction2 word count = 0");
+ LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
smb_SetSMBDataLength(outp, 0);
smb_SendPacket(vcp, outp);
rapOp = asp->parmsp[0];
if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
- osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
- osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
+ osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
+ osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
}
else {
- osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
- osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
+ osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
code = CM_ERROR_BADOP;
}
}
/* free the input tran 2 packet */
- lock_ObtainWrite(&smb_globalLock);
smb_FreeTran2Packet(asp);
- lock_ReleaseWrite(&smb_globalLock);
}
else if (firstPacket) {
/* the first packet in a multi-packet request, we need to send an
int outDataTotal; /* total data bytes */
int code = 0;
DWORD rv;
- DWORD allSubmount;
- USHORT nShares;
- DWORD nRegShares;
- DWORD nSharesRet;
+ DWORD allSubmount = 0;
+ USHORT nShares = 0;
+ DWORD nRegShares = 0;
+ DWORD nSharesRet = 0;
HKEY hkParam;
HKEY hkSubmount = NULL;
smb_rap_share_info_1_t * shares;
USHORT cshare = 0;
char * cstrp;
- char thisShare[256];
+ char thisShare[AFSPATHMAX];
int i,j;
+ DWORD dw;
int nonrootShares;
smb_rap_share_list_t rootShares;
cm_req_t req;
}
/* first figure out how many shares there are */
- rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
KEY_QUERY_VALUE, &hkParam);
if (rv == ERROR_SUCCESS) {
len = sizeof(allSubmount);
RegCloseKey (hkParam);
}
- rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
0, KEY_QUERY_VALUE, &hkSubmount);
if (rv == ERROR_SUCCESS) {
rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
thyper.HighPart = 0;
thyper.LowPart = 0;
- cm_HoldSCache(cm_rootSCachep);
- cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
- cm_ReleaseSCache(cm_rootSCachep);
+ cm_HoldSCache(cm_data.rootSCachep);
+ cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
+ cm_ReleaseSCache(cm_data.rootSCachep);
cm_ReleaseUser(userp);
- nShares = rootShares.cShare + nRegShares + allSubmount;
+ nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
#define REMARK_LEN 1
outParmsTotal = 8; /* 4 dwords */
if (allSubmount) {
strcpy( shares[cshare].shi1_netname, "all" );
- shares[cshare].shi1_remark = cstrp - outp->datap;
+ shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
/* type and pad are zero already */
cshare++;
cstrp+=REMARK_LEN;
}
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);
+ rv = RegEnumValue(hkSubmount, dw, 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);
shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
- shares[cshare].shi1_remark = cstrp - outp->datap;
+ shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
cshare++;
cstrp+=REMARK_LEN;
}
}
strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
- shares[cshare].shi1_remark = cstrp - outp->datap;
+ shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
cshare++;
cstrp+=REMARK_LEN;
}
outp->parmsp[2] = cshare;
outp->parmsp[3] = nShares;
- outp->totalData = cstrp - outp->datap;
+ outp->totalData = (int)(cstrp - outp->datap);
outp->totalParms = outParmsTotal;
smb_SendTran2Packet(vcp, outp, op);
outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
- if(!stricmp(shareName,"all")) {
- rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
+ if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
+ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
KEY_QUERY_VALUE, &hkParam);
if (rv == ERROR_SUCCESS) {
len = sizeof(allSubmount);
shareFound = TRUE;
} else {
- rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
+ 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);
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);
info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
- info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
+ 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;
- info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
+ info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
info->shi2_permissions = ACCESS_ALL;
info->shi2_max_uses = (unsigned short) -1;
- info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
+ info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
}
outp->totalData = totalData;
cstrp += smb_ServerCommentLen;
}
- totalData = cstrp - outp->datap;
+ totalData = (DWORD)(cstrp - outp->datap);
outp->totalData = min(bufsize,totalData); /* actual data size */
outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
outp->parmsp[2] = totalData;
/* We sometimes see 0 word count. What to do? */
if (*inp->wctp == 0) {
-#ifndef DJGPP
- HANDLE h;
- char *ptbuf[1];
-
- osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
-
- h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
- ptbuf[0] = "Transaction2 word count = 0";
- ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
- 1, inp->ncb_length, ptbuf, inp);
- DeregisterEventSource(h);
-#else /* DJGPP */
- osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
-#endif /* !DJGPP */
+ osi_Log0(smb_logp, "Transaction2 word count = 0");
+ LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
smb_SetSMBDataLength(outp, 0);
smb_SendPacket(vcp, outp);
/* now dispatch it */
if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
- osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
- osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
+ osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
}
else {
- osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
- osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
+ osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
code = CM_ERROR_BADOP;
}
}
/* free the input tran 2 packet */
- lock_ObtainWrite(&smb_globalLock);
smb_FreeTran2Packet(asp);
- lock_ReleaseWrite(&smb_globalLock);
}
else if (firstPacket) {
/* the first packet in a multi-packet request, we need to send an
smb_fid_t *fidp;
int attributes;
char *lastNamep;
- time_t dosTime;
+ afs_uint32 dosTime;
int openFun;
int trunc;
int openMode;
long returnEALength;
char *tidPathp;
cm_req_t req;
+ int created = 0;
cm_InitReq(&req);
/* 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 = (char *) (&p->parmsp[14]);
if (smb_StoreAnsiFilenames)
/* copy out remainder of the parms */
parmSlot = 0;
- outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
+ outp->parmsp[parmSlot++] = fidp->fid;
if (extraInfo) {
- outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
- outp->parmsp[parmSlot] = 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
- outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
- outp->parmsp[parmSlot] = openMode; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
- outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
+ outp->parmsp[parmSlot++] = 0; /* attrs */
+ outp->parmsp[parmSlot++] = 0; /* mod time */
+ outp->parmsp[parmSlot++] = 0;
+ outp->parmsp[parmSlot++] = 0; /* len */
+ outp->parmsp[parmSlot++] = 0x7fff;
+ outp->parmsp[parmSlot++] = openMode;
+ outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
+ outp->parmsp[parmSlot++] = 0; /* IPC junk */
}
/* and the final "always present" stuff */
- outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
+ outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
/* next write out the "unique" ID */
- outp->parmsp[parmSlot] = 0x1234; parmSlot++;
- outp->parmsp[parmSlot] = 0x5678; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
+ outp->parmsp[parmSlot++] = 0x1234;
+ outp->parmsp[parmSlot++] = 0x5678;
+ outp->parmsp[parmSlot++] = 0;
if (returnEALength) {
- outp->parmsp[parmSlot] = 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
+ outp->parmsp[parmSlot++] = 0;
+ outp->parmsp[parmSlot++] = 0;
}
outp->totalData = 0;
code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
if (code == CM_ERROR_TIDIPC) {
- /* Attempt to use TID allocated for IPC. The client is
- probably trying to locate DCE RPC end points, which
- we don't support. */
+ /* 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");
+#ifndef DFS_SUPPORT
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
return CM_ERROR_NOSUCHPATH;
+#endif
}
dscp = NULL;
- code = cm_NameI(cm_rootSCachep, pathp,
+ code = cm_NameI(cm_data.rootSCachep, pathp,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &scp);
if (code != 0) {
- code = cm_NameI(cm_rootSCachep, spacep->data,
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &dscp);
cm_FreeSpace(spacep);
return code;
}
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ smb_FreeTran2Packet(outp);
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#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);
smb_FreeTran2Packet(outp);
return code;
}
- }
- else {
+ } 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) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+
+ /* macintosh is expensive to program for it */
cm_FreeSpace(spacep);
}
if (code == 0) {
code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
if (code) {
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
if (excl) {
/* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
else
openAction = 1; /* found existing file */
}
- else if (!(openFun & SMB_ATTR_DIRECTORY)) {
+ else if (!(openFun & 0x10)) {
/* don't create if not found */
- if (dscp) cm_ReleaseSCache(dscp);
- osi_assert(scp == NULL);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ 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);
code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
&req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (!excl && code == CM_ERROR_EXISTS) {
+ if (code == 0) {
+ created = 1;
+ if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ 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
* creating it already, then we open it anyway. We
* don't bother retrying after this, since if this next
}
/* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
if (code) {
/* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
+ if (scp)
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_FreeTran2Packet(outp);
return code;
code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
if (code == 0) {
/* we have a more accurate file to use (the
- * target of the symbolic link). Otherwise,
- * we'll just use the symlink anyway.
- */
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
cm_ReleaseSCache(scp);
/* 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_ObtainMutex(&scp->mx);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseMutex(&scp->mx);
+
+ /* and the user */
+ fidp->userp = userp;
/* compute open mode */
- if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
+ if (openMode != 1)
+ fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
if (openMode == 1 || openMode == 2)
fidp->flags |= SMB_FID_OPENWRITE;
+ /* remember that the file was newly created */
+ if (created)
+ fidp->flags |= SMB_FID_CREATED;
+
+ lock_ReleaseMutex(&fidp->mx);
+
smb_ReleaseFID(fidp);
cm_Open(scp, 0, userp);
/* copy out remainder of the parms */
parmSlot = 0;
- outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
+ outp->parmsp[parmSlot++] = fidp->fid;
lock_ObtainMutex(&scp->mx);
if (extraInfo) {
- outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
+ outp->parmsp[parmSlot++] = smb_Attributes(scp);
smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
- outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
- outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
- outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
- parmSlot++;
- outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
- parmSlot++;
- outp->parmsp[parmSlot] = openMode; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
- outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
+ outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
+ outp->parmsp[parmSlot++] = openMode;
+ outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
+ outp->parmsp[parmSlot++] = 0; /* IPC junk */
}
/* and the final "always present" stuff */
- outp->parmsp[parmSlot] = openAction; parmSlot++;
+ outp->parmsp[parmSlot++] = openAction;
/* next write out the "unique" ID */
- outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
- outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
+ outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
+ outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
+ outp->parmsp[parmSlot++] = 0;
if (returnEALength) {
- outp->parmsp[parmSlot] = 0; parmSlot++;
- outp->parmsp[parmSlot] = 0; parmSlot++;
+ outp->parmsp[parmSlot++] = 0;
+ outp->parmsp[parmSlot++] = 0;
}
lock_ReleaseMutex(&scp->mx);
outp->totalData = 0; /* total # of data 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;
}
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};
+ static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 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;
- 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;
+ case SMB_INFO_ALLOCATION:
+ responseSize = sizeof(qi.u.allocInfo);
+ break;
+ case SMB_INFO_VOLUME:
+ responseSize = sizeof(qi.u.volumeInfo);
+ break;
+ case SMB_QUERY_FS_VOLUME_INFO:
+ responseSize = sizeof(qi.u.FSvolumeInfo);
+ break;
+ case SMB_QUERY_FS_SIZE_INFO:
+ responseSize = sizeof(qi.u.FSsizeInfo);
+ break;
+ case SMB_QUERY_FS_DEVICE_INFO:
+ responseSize = sizeof(qi.u.FSdeviceInfo);
+ break;
+ case SMB_QUERY_FS_ATTRIBUTE_INFO:
+ responseSize = sizeof(qi.u.FSattributeInfo);
+ 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);
switch (p->parmsp[0]) {
- case 1:
+ case SMB_INFO_ALLOCATION:
/* alloc info */
qi.u.allocInfo.FSID = 0;
qi.u.allocInfo.sectorsPerAllocUnit = 1;
qi.u.allocInfo.bytesPerSector = 1024;
break;
- case 2:
+ case SMB_INFO_VOLUME:
/* volume info */
qi.u.volumeInfo.vsn = 1234;
qi.u.volumeInfo.vnCount = 4;
memcpy(qi.u.volumeInfo.label, "AFS", 4);
break;
- case 0x102:
+ case SMB_QUERY_FS_VOLUME_INFO:
/* FS volume info */
- memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
+ memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
qi.u.FSvolumeInfo.vsn = 1234;
qi.u.FSvolumeInfo.vnCount = 8;
- memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
+ memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
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;
+ 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 */
+ 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_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;
- qi.u.FSattributeInfo.maxCompLength = 255;
- qi.u.FSattributeInfo.FSnameLength = 6;
- memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
+ qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
+ qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
+ memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
break;
}
spacep = cm_GetSpace();
smb_StripLastComponent(spacep->data, &lastNamep, pathp);
- code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
+ code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
reqp, &dscp);
cm_FreeSpace(spacep);
- if (code) return code;
+ if (code)
+ return code;
+
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ DebugBreak();
+ return CM_ERROR_PATH_NOT_COVERED;
+ }
+#endif /* DFS_SUPPORT */
if (!lastNamep) lastNamep = pathp;
else lastNamep++;
long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
smb_tran2Packet_t *outp;
- time_t dosTime;
+ 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];
cm_user_t *userp;
cm_space_t *spacep;
cm_scache_t *scp, *dscp;
+ int scp_mx_held = 0;
+ int delonclose = 0;
long code = 0;
- char *op;
+ char *pathp;
char *tidPathp;
char *lastComp;
cm_req_t 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;
}
+
+ pathp = (char *)(&p->parmsp[3]);
+ if (smb_StoreAnsiFilenames)
+ OemToChar(pathp,pathp);
osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
- osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
+ osi_LogSaveString(smb_logp, pathp));
- 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;
/* 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->data, &lastComp, pathp);
#ifndef SPECIAL_FOLDERS
/* Make sure that lastComp is not NULL */
if (lastComp) {
if (stricmp(lastComp, "\\desktop.ini") == 0) {
- code = cm_NameI(cm_rootSCachep, spacep->data,
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
CM_FLAG_CASEFOLD
| CM_FLAG_DIRSEARCH
| CM_FLAG_FOLLOW,
userp, tidPathp, &req, &dscp);
if (code == 0) {
- if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
- && !dscp->mountRootFidp)
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_BADSHARENAME;
+ } 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_rootSCachep, (char *)(&p->parmsp[3]),
+ code = cm_NameI(cm_data.rootSCachep, pathp,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
if (code) {
return 0;
}
+#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) || pnc )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_BADSHARENAME;
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+#endif /* DFS_SUPPORT */
+
lock_ObtainMutex(&scp->mx);
+ scp_mx_held = 1;
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);
/* 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);
if (code) {
goto done;
}
- op = outp->datap;
- *((u_long *)op) = len * 2; op += 4;
- mbstowcs((unsigned short *)op, shortName, len);
- op += (len * 2);
+ qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
+ mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
goto done;
}
- if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
+ else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+ len = strlen(lastComp);
+ qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
+ mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
+
+ 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 = 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_ReleaseMutex(&scp->mx);
+ scp_mx_held = 0;
+ 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;
+ len = strlen(lastComp);
+ qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
+ mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
}
-
/* send and free the packets */
done:
- lock_ReleaseMutex(&scp->mx);
+ if (scp_mx_held)
+ lock_ReleaseMutex(&scp->mx);
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)
+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;
+ smb_fid_t *fidp;
unsigned short infoLevel;
- int nbytesRequired;
- unsigned short fid;
+ char * 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;
+ char *tidPathp;
+ char *lastComp;
cm_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;
- }
-
- infoLevel = p->parmsp[1];
- 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;
- else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
- nbytesRequired = 6;
- else {
+ 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, CM_ERROR_INVAL);
- smb_ReleaseFID(fidp);
+ smb_SendTran2Error(vcp, p, opx,
+ infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
return 0;
}
- osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
- outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
-
- if (infoLevel > 0x100)
- outp->totalParms = 2;
- else
- outp->totalParms = 0;
- outp->totalData = nbytesRequired;
+ pathp = (char *)(&p->parmsp[3]);
+ if (smb_StoreAnsiFilenames)
+ OemToChar(pathp,pathp);
+ osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
+ osi_LogSaveString(smb_logp, pathp));
userp = smb_GetTran2User(vcp, p);
if (!userp) {
- osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
+ osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
code = CM_ERROR_BADSMB;
goto done;
}
- scp = fidp->scp;
- lock_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, &req, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code)
- 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;
+ }
- /* now we have the status in the cache entry, and everything is locked.
- * Marshall the output data.
- */
- op = outp->datap;
+ /*
+ * 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) {
- 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 */
- attributes = smb_ExtAttributes(scp);
- *((u_long *)op) = attributes; op += 4;
- *((u_long *)op) = 0; op += 4;
- }
- 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;
- }
- else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
- *((u_long *)op) = 0; op += 4;
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->data, &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,
+ 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->data);
+ if ( WANTS_DFS_PATHNAMES(p) || pnc )
+ code = CM_ERROR_PATH_NOT_COVERED;
+ else
+ code = CM_ERROR_BADSHARENAME;
+ } 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);
}
- else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+
+ /* 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;
+ }
+
+ fidp = smb_FindFIDByScache(vcp, scp);
+ if (!fidp) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ return 0;
+ }
+
+ lock_ObtainMutex(&fidp->mx);
+ if (!(fidp->flags & SMB_FID_OPENWRITE)) {
+ lock_ReleaseMutex(&fidp->mx);
+ cm_ReleaseSCache(scp);
+ smb_ReleaseFID(fidp);
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
+ return 0;
+ }
+ lock_ReleaseMutex(&fidp->mx);
+
+ 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_ObtainMutex(&scp->mx);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_GETSTATUS
+ | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code) {
+ lock_ReleaseMutex(&scp->mx);
+ goto done;
+ }
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ lock_ReleaseMutex(&scp->mx);
+ lock_ObtainMutex(&fidp->mx);
+ lock_ObtainMutex(&scp->mx);
+
+ /* 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;
+ fidp->flags |= SMB_FID_MTIMESETDONE;
+ }
+
+ 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_ReleaseMutex(&scp->mx);
+ lock_ReleaseMutex(&fidp->mx);
+
+ /* 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);
+ smb_ReleaseFID(fidp);
+ if (code == 0)
+ smb_SendTran2Packet(vcp, outp, opx);
+ else
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+#endif
+}
+
+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;
+ cm_req_t req;
+
+ cm_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;
+ }
+
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+
+ infoLevel = p->parmsp[1];
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
+ responseSize = sizeof(qfi.u.QFbasicInfo);
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
+ responseSize = sizeof(qfi.u.QFstandardInfo);
+ else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+ responseSize = sizeof(qfi.u.QFeaInfo);
+ else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
+ 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_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, responseSize);
+
+ if (infoLevel > 0x100)
+ outp->totalParms = 2;
+ else
+ outp->totalParms = 0;
+ outp->totalData = responseSize;
+
+ userp = smb_GetTran2User(vcp, p);
+ if (!userp) {
+ osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
+ code = CM_ERROR_BADSMB;
+ goto done;
+ }
+
+ lock_ObtainMutex(&fidp->mx);
+ delonclose = fidp->flags & SMB_FID_DELONCLOSE;
+ scp = fidp->scp;
+ osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
+ cm_HoldSCache(scp);
+ lock_ReleaseMutex(&fidp->mx);
+ lock_ObtainMutex(&scp->mx);
+ 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);
+
+ /* now we have the status in the cache entry, and everything is locked.
+ * Marshall the output data.
+ */
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+ qfi.u.QFbasicInfo.creationTime = ft;
+ qfi.u.QFbasicInfo.lastAccessTime = ft;
+ qfi.u.QFbasicInfo.lastWriteTime = ft;
+ qfi.u.QFbasicInfo.lastChangeTime = ft;
+ attributes = smb_ExtAttributes(scp);
+ qfi.u.QFbasicInfo.attributes = attributes;
+ }
+ else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+ 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) {
+ qfi.u.QFeaInfo.eaSize = 0;
+ }
+ else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
unsigned long len;
char *name;
+ lock_ReleaseMutex(&scp->mx);
+ lock_ObtainMutex(&fidp->mx);
+ lock_ObtainMutex(&scp->mx);
if (fidp->NTopen_wholepathp)
name = fidp->NTopen_wholepathp;
else
name = "\\"; /* probably can't happen */
- len = 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);
+ lock_ReleaseMutex(&fidp->mx);
+ len = (unsigned long)strlen(name);
+ outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
+ qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
+ mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
}
/* send and free the packets */
done:
lock_ReleaseMutex(&scp->mx);
+ 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)
+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);
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;
+ }
+
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
return 0;
}
infoLevel = p->parmsp[1];
- osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
- if (infoLevel > 0x104 || infoLevel < 0x101) {
+ osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
+ 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;
}
- if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
- smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+ lock_ObtainMutex(&fidp->mx);
+ 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, 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)) {
- smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+ 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, opx, CM_ERROR_NOACCESS);
return 0;
}
- 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(&scp->mx);
CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_NEEDCALLBACK);
if (code) {
- lock_ReleaseMutex(&scp->mx);
+ lock_ReleaseMutex(&scp->mx);
goto done;
- }
+ }
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ lock_ReleaseMutex(&scp->mx);
+ lock_ObtainMutex(&fidp->mx);
+ lock_ObtainMutex(&scp->mx);
/* 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)
if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
- smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
- &lastMod);
+ smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
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_ReleaseMutex(&fidp->mx);
/* call setattr */
if (attr.mask)
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)
+ 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 {
code = 0;
+ lock_ObtainMutex(&fidp->mx);
fidp->flags &= ~SMB_FID_DELONCLOSE;
+ 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;
return CM_ERROR_BADOP;
}
+struct smb_v2_referral {
+ USHORT ServerType;
+ USHORT ReferralFlags;
+ ULONG Proximity;
+ ULONG TimeToLive;
+ USHORT DfsPathOffset;
+ USHORT DfsAlternativePathOffset;
+ USHORT NetworkAddressOffset;
+};
+
long
-smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
{
/* This is a UNICODE only request (bit15 of Flags2) */
/* The TID must be IPC$ */
/* ServerType = 0; indicates the next server should be queried for the file */
/* ReferralFlags = 0x01; PathConsumed characters should be stripped */
/* Node = UnicodeString of UNC path of the next share name */
+#ifdef DFS_SUPPORT
+ long code = 0;
+ int maxReferralLevel = 0;
+ char requestFileName[1024] = "";
+ char referralPath[1024] = "";
+ 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, refLen;
+ int idx;
+
+ cm_InitReq(&req);
+
+ maxReferralLevel = p->parmsp[0];
+
+ GetCPInfo(CP_ACP, &CodePageInfo);
+ WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
+ requestFileName, 1024, NULL, NULL);
+
+ osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
+ maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
+
+ nbnLen = strlen(cm_NetbiosName);
+ reqLen = strlen(requestFileName);
+
+ if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
+ !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
+ requestFileName[nbnLen+1] == '\\')
+ {
+ int found = 0;
+
+ if (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
+ !_strnicmp("*.",&requestFileName[nbnLen+2],2))
+ {
+ found = 1;
+ strcpy(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.
+ */
+ code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, NULL, &req, &scp);
+ if (code == 0) {
+ /* Yes it is. */
+ found = 1;
+ strcpy(referralPath, requestFileName);
+ refLen = reqLen;
+ } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
+ char temp[1024];
+ char pathName[1024];
+ char *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);
+
+ strcpy(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 = nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent);
+
+ strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
+ refLen = strlen(referralPath);
+ found = 1;
+ }
+ } else {
+ char shareName[MAX_PATH + 1];
+ char *p, *q;
+ /* we may have a sharename that is a volume reference */
- osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
+ 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, "",
+ CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+ userp, p, &req, &scp);
+ free(p);
+
+ if (code == 0) {
+ found = 1;
+ strcpy(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++] = 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<=refLen; i++ )
+ sp[i+idx] = referralPath[i];
+#endif
+ }
+ } else {
+ code = CM_ERROR_NOSUCHPATH;
+ }
+
+ done:
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ if (userp)
+ cm_ReleaseUser(userp);
+ if (code == 0)
+ smb_SendTran2Packet(vcp, outp, op);
+ else
+ smb_SendTran2Error(vcp, p, op, code);
+ if (outp)
+ smb_FreeTran2Packet(outp);
+
+ return 0;
+#else /* DFS_SUPPORT */
+ osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
return CM_ERROR_BADOP;
+#endif /* DFS_SUPPORT */
}
long
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,
+ char * tidPathp, char * 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;
- time_t dosTime;
+ afs_uint32 dosTime;
FILETIME ft;
int shortTemp;
unsigned short attr;
unsigned long lattr;
smb_dirListPatch_t *patchp;
smb_dirListPatch_t *npatchp;
-
+ afs_uint32 rights;
+ afs_int32 mustFake = 0;
+ char path[AFSPATHMAX];
+
+ code = cm_FindACLCache(dscp, userp, &rights);
+ if (code == 0 && !(rights & PRSFS_READ))
+ mustFake = 1;
+ else if (code == -1) {
+ lock_ObtainMutex(&dscp->mx);
+ code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseMutex(&dscp->mx);
+ if (code == CM_ERROR_NOACCESS) {
+ mustFake = 1;
+ code = 0;
+ }
+ }
+ if (code)
+ return code;
+
for(patchp = *dirPatchespp; patchp; patchp =
(smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
- code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
- if (code) continue;
+ snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", 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_ObtainMutex(&scp->mx);
- code = cm_SyncOp(scp, NULL, userp, reqp, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code) {
+ if (mustFake == 0)
+ code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (mustFake || code) {
lock_ReleaseMutex(&scp->mx);
- cm_ReleaseSCache(scp);
dptr = patchp->dptr;
/* 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) {
/* 1969-12-31 23:59:59 +00 */
ft.dwHighDateTime = 0x19DB200;
ft.dwLowDateTime = 0x5BB78980;
*((FILETIME *)dptr) = ft;
dptr += 24;
+ switch (scp->fileType) {
+ case CM_SCACHETYPE_DIRECTORY:
+ case CM_SCACHETYPE_MOUNTPOINT:
+ case CM_SCACHETYPE_SYMLINK:
+ case CM_SCACHETYPE_INVALID:
+ *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+ 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))
+ *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+ else
+ *((u_long *)dptr) = SMB_ATTR_NORMAL;
+
+ }
/* merge in hidden attribute */
if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
- *((u_long *)dptr) = SMB_ATTR_HIDDEN;
+ *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
}
dptr += 4;
} else {
*((u_short *)dptr) = shortTemp;
dptr += 10;
+ /* set the attribute */
+ switch (scp->fileType) {
+ case CM_SCACHETYPE_DIRECTORY:
+ case CM_SCACHETYPE_MOUNTPOINT:
+ case CM_SCACHETYPE_SYMLINK:
+ case CM_SCACHETYPE_INVALID:
+ attr = SMB_ATTR_DIRECTORY;
+ default:
+ attr = 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;
+ attr |= SMB_ATTR_HIDDEN;
}
+ *dptr++ = attr & 0xff;
+ *dptr++ = (attr >> 8) & 0xff;
}
+
+ cm_ReleaseSCache(scp);
continue;
}
-
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
/* now watch for a symlink */
code = 0;
while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
lock_ReleaseMutex(&scp->mx);
+ snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", 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,
dptr = patchp->dptr;
- if (infoLevel >= 0x101) {
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
/* get filetime */
smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
/* Copy attributes */
lattr = smb_ExtAttributes(scp);
+ if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
+ code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ if (lattr == SMB_ATTR_NORMAL)
+ lattr = SMB_ATTR_DIRECTORY;
+ else
+ lattr |= SMB_ATTR_DIRECTORY;
+ }
/* merge in hidden (dot file) attribute */
- if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
- lattr |= SMB_ATTR_HIDDEN;
+ if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+ if (lattr == SMB_ATTR_NORMAL)
+ lattr = SMB_ATTR_HIDDEN;
+ else
+ lattr |= SMB_ATTR_HIDDEN;
+ }
*((u_long *)dptr) = lattr;
dptr += 4;
- }
- else {
+ } else {
/* get dos time */
smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
/* finally copy out attributes as short */
attr = smb_Attributes(scp);
/* merge in hidden (dot file) attribute */
- if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
- attr |= SMB_ATTR_HIDDEN;
+ 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;
}
return code;
}
-#ifndef USE_OLD_MATCHING
// char table for case insensitive comparison
char mapCaseTable[256];
// BOOL : TRUE/FALSE (match/mistmatch)
BOOL
-szWildCardMatchFileName(PSZ pattern, PSZ name)
+szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
{
PSZ pename; // points to the last 'name' character
PSZ p;
while (*name) {
switch (*pattern) {
case '?':
- if (*name == '.')
- return FALSE;
- ++pattern, ++name;
+ ++pattern;
+ if (*name == '.')
+ continue;
+ ++name;
break;
case '*':
++pattern;
if (*pattern == '\0')
return TRUE;
for (p = pename; p >= name; --p) {
- if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
- szWildCardMatchFileName(pattern + 1, p + 1))
+ if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
+ !casefold && (*p == *pattern)) &&
+ szWildCardMatchFileName(pattern + 1, p + 1, casefold))
return TRUE;
} /* endfor */
return FALSE;
default:
- if (mapCaseTable[*name] != mapCaseTable[*pattern])
+ if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
+ (!casefold && *name != *pattern))
return FALSE;
++pattern, ++name;
break;
} /* endswitch */
} /* endwhile */
- if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
- return TRUE;
- else
- return FALSE;
+ /* if all we have left are wildcards, then we match */
+ for (;*pattern; pattern++) {
+ if (*pattern != '*' && *pattern != '?')
+ return FALSE;
+ }
+ return TRUE;
}
/* do a case-folding search of the star name mask with the name in namep.
int smb_V3MatchMask(char *namep, char *maskp, int flags)
{
char * newmask;
- int i, j, star, qmark, retval;
+ int i, j, star, qmark, casefold, retval;
/* 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;
+
/* optimize the pattern:
* if there is a mixture of '?' and '*',
* for example the sequence "*?*?*?*"
}
newmask[j++] = '\0';
- retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
+ retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
free(newmask);
return retval;
}
-#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.
+
+/* smb_ReceiveTran2SearchDir implements both
+ * Tran2_Find_First and Tran2_Find_Next
*/
-int smb_V3MatchMask(char *namep, char *maskp, int flags)
+#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.
+ */
+long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
- 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;
+ int attribute;
+ long nextCookie;
+ long code = 0, code2 = 0;
+ char *pathp = 0;
+ int maxCount;
+ smb_dirListPatch_t *dirListPatchesp;
+ smb_dirListPatch_t *curPatchp;
+ long orbytes; /* # of bytes in this output record */
+ long ohbytes; /* # of bytes, except file name */
+ long 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 */
+ long maxReturnData; /* max # of return data */
+ long maxReturnParms; /* max # of return parms */
+ long bytesInBuffer; /* # data bytes in the output buffer */
+ char *maskp; /* mask part of path */
+ int infoLevel;
+ int searchFlags;
+ int eos;
+ smb_tran2Packet_t *outp; /* response packet */
+ char *tidPathp = 0;
+ int align;
+ char shortName[13]; /* 8.3 name if needed */
+ int NeedShortName;
+ char *shortNameEnd;
+ cm_dirEntry_t * dep = NULL;
+ cm_req_t req;
+ char * s;
- /* make sure we only match 8.3 names, if requested */
- req8dot3 = (flags & CM_FLAG_8DOT3);
- if (req8dot3 && !cm_Is8Dot3(namep))
+ cm_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 = ((char *) p->parmsp) + 12; /* points to path */
+ nextCookie = 0;
+ maskp = strrchr(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_LogSaveString(smb_logp, pathp),
+ osi_LogSaveString(smb_logp, maskp));
+
+ switch ( infoLevel ) {
+ case SMB_INFO_STANDARD:
+ s = "InfoStandard";
+ break;
+ case SMB_INFO_QUERY_EA_SIZE:
+ s = "InfoQueryEaSize";
+ break;
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ s = "InfoQueryEasFromList";
+ break;
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ s = "FindFileDirectoryInfo";
+ break;
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ s = "FindFileFullDirectoryInfo";
+ break;
+ case SMB_FIND_FILE_NAMES_INFO:
+ s = "FindFileNamesInfo";
+ break;
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ s = "FindFileBothDirectoryInfo";
+ break;
+ default:
+ s = "unknownInfoLevel";
+ }
+
+ 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 (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+ 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 */
+
+ dirListPatchesp = NULL;
+
+ maxReturnData = p->maxReturnData;
+ maxReturnParms = 10; /* return params for findfirst, which
+ is the only one we handle.*/
+
+#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, "T2SDSingle search dir count %d [%s]",
+ maxCount, osi_LogSaveString(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->data, 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;
+ }
- /* loop */
- while (1) {
- /* Next pattern character */
- tcp1 = *maskp++;
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+ cm_FreeSpace(spacep);
- /* Next name character */
- tcn1 = *namep;
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
- 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;
- }
+#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_BADSHARENAME;
+ 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;
+ }
+
+ 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_Gen8Dot3NameInt(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_LogSaveString(smb_logp, pathp),
+ NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
+
+ /* 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;
+
+ }
+
+ /* Check if the name will fit */
+ if (infoLevel < 0x101)
+ ohbytes = 23; /* pre-NT */
+ else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
+ ohbytes = 12; /* NT names only */
+ else
+ ohbytes = 64; /* NT */
+
+ if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
+ ohbytes += 26; /* Short name & length */
+
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
+ ohbytes += 4; /* if resume key required */
+ }
+
+ if (infoLevel != SMB_INFO_STANDARD
+ && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
+ && infoLevel != SMB_FIND_FILE_NAMES_INFO)
+ ohbytes += 4; /* EASIZE */
+
+ /* add header to name & term. null */
+ onbytes = strlen(maskp);
+ orbytes = ohbytes + onbytes + 1;
+
+ /* 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;
+
+ if (orbytes + align > maxReturnData) {
+
+ /* 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;
+ }
+
+ /* 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);
+
+ if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
+ *(origOp + ohbytes - 1) = (unsigned char) onbytes;
+ else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
+ *((u_long *)(op + 8)) = onbytes;
+ else
+ *((u_long *)(op + 60)) = onbytes;
+ strcpy(origOp+ohbytes, maskp);
+ if (smb_StoreAnsiFilenames)
+ CharToOem(origOp+ohbytes, origOp+ohbytes);
+
+ /* Short name if requested and needed */
+ if (infoLevel == 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);
}
- 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;
+ }
+
+ /* NextEntryOffset and FileIndex */
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+ int entryOffset = orbytes + align;
+ *((u_long *)op) = 0;
+ *((u_long *)(op+4)) = 0;
+ }
+
+ if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+ curPatchp = malloc(sizeof(*curPatchp));
+ osi_QAdd((osi_queue_t **) &dirListPatchesp,
+ &curPatchp->q);
+ curPatchp->dptr = op;
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
+ curPatchp->dptr += 8;
+
+ if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
+ curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
+ } else {
+ curPatchp->flags = 0;
}
+
+ curPatchp->fid.cell = targetscp->fid.cell;
+ curPatchp->fid.volume = targetscp->fid.volume;
+ curPatchp->fid.vnode = targetscp->fid.vnode;
+ curPatchp->fid.unique = targetscp->fid.unique;
+
+ /* temp */
+ dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+strlen(maskp));
+ strcpy(dep->name, maskp);
+ 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;
+ }
+
+ /* Adjust byte ptr and count */
+ origOp += orbytes; /* skip entire record */
+ bytesInBuffer += orbytes;
+
+ /* and pad the record out */
+ while (--align >= 0) {
+ *origOp++ = 0;
+ bytesInBuffer++;
+ }
+
+ /* apply the patches */
+ code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->data, infoLevel, userp, &req);
+
+ 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;
+
+ outp->totalParms = 10; /* in bytes */
+
+ outp->totalData = bytesInBuffer;
+
+ osi_Log0(smb_logp, "T2SDSingle done.");
+
+ 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);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(targetscp);
+ cm_ReleaseUser(userp);
+
+ return code;
}
-#endif /* USE_OLD_MATCHING */
+
long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
int attribute;
long nextCookie;
char *tp;
- long code = 0;
+ long code = 0, code2 = 0;
char *pathp;
- cm_dirEntry_t *dep;
+ 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 */
int fileType;
cm_fid_t fid;
cm_req_t req;
+ char * s;
cm_InitReq(&req);
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);
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
+ dir_enums++;
+
+ dsp = smb_NewDirSearch(1);
+ dsp->attribute = attribute;
+ strcpy(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]);
- if (!dsp)
- return CM_ERROR_BADFD;
- attribute = dsp->attribute;
maxCount = p->parmsp[1];
infoLevel = p->parmsp[2];
+ nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
searchFlags = p->parmsp[5];
+ if (!dsp) {
+ osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
+ p->parmsp[0], nextCookie);
+ return CM_ERROR_BADFD;
+ }
+ attribute = dsp->attribute;
pathp = NULL;
- nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
maskp = dsp->mask;
starPattern = 1; /* assume, since required a Find Next */
}
+ switch ( infoLevel ) {
+ case SMB_INFO_STANDARD:
+ s = "InfoStandard";
+ break;
+ case SMB_INFO_QUERY_EA_SIZE:
+ s = "InfoQueryEaSize";
+ break;
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ s = "InfoQueryEasFromList";
+ break;
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ s = "FindFileDirectoryInfo";
+ break;
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ s = "FindFileFullDirectoryInfo";
+ break;
+ case SMB_FIND_FILE_NAMES_INFO:
+ s = "FindFileNamesInfo";
+ break;
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ s = "FindFileBothDirectoryInfo";
+ break;
+ default:
+ s = "unknownInfoLevel";
+ }
+
+ 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_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
- p->opcode, nextCookie);
+ osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
+ p->opcode, dsp->cookie, nextCookie);
+
+ if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+ osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
+ smb_ReleaseDirSearch(dsp);
+ return CM_ERROR_INVAL;
+ }
- if (infoLevel >= 0x101)
- searchFlags &= ~4; /* no resume keys */
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
+ searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
dirListPatchesp = NULL;
outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
maxReturnData);
- osi_Log1(smb_logp, "T2 receive search dir %s",
- osi_LogSaveString(smb_logp, pathp));
+ osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
+ maxCount, osi_LogSaveString(smb_logp, pathp));
/* bail out if request looks bad */
if (p->opcode == 1 && !pathp) {
return CM_ERROR_BADSMB;
}
- osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
- nextCookie, dsp->cookie);
+ osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
+ dsp->cookie, nextCookie, attribute);
userp = smb_GetTran2User(vcp, p);
if (!userp) {
- osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
+ osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
smb_ReleaseDirSearch(dsp);
smb_FreeTran2Packet(outp);
return CM_ERROR_BADSMB;
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 {
+ } else {
spacep = cm_GetSpace();
smb_StripLastComponent(spacep->data, NULL, pathp);
code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
if (code) {
- lock_ReleaseMutex(&dsp->mx);
cm_ReleaseUser(userp);
smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
smb_FreeTran2Packet(outp);
+ lock_ReleaseMutex(&dsp->mx);
smb_DeleteDirSearch(dsp);
smb_ReleaseDirSearch(dsp);
return 0;
}
- code = cm_NameI(cm_rootSCachep, spacep->data,
+
+ strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
+ strcpy(dsp->relPath, spacep->data);
+
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &scp);
cm_FreeSpace(spacep);
if (code == 0) {
- if (dsp->scp != 0)
- cm_ReleaseSCache(dsp->scp);
+#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_BADSHARENAME;
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ lock_ReleaseMutex(&dsp->mx);
+ smb_DeleteDirSearch(dsp);
+ smb_ReleaseDirSearch(dsp);
+ return 0;
+ }
+#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
dsp->flags |= SMB_DIRSEARCH_BULKST;
}
lock_ReleaseMutex(&scp->mx);
- }
+ }
}
lock_ReleaseMutex(&dsp->mx);
if (code) {
return code;
}
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
startsearch:
dirLength = scp->length;
bufferp = NULL;
bytesInBuffer = 0;
while (1) {
op = origOp;
- if (searchFlags & 4)
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
/* skip over resume key */
op += 4;
/* check if we've passed the dir's EOF */
if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
+ osi_Log0(smb_logp, "T2 search dir passed eof");
eos = 1;
break;
}
* the dir entry, since we'll need to check its size.
*/
if (returnedNames >= maxCount) {
+ osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
+ returnedNames, maxCount);
break;
}
* the offset of the buffer we have. If not, get the buffer.
*/
thyper.HighPart = curOffset.HighPart;
- thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
+ thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
/* wrong buffer */
if (bufferp) {
* of all of the status info for files in the dir.
*/
if (starPattern) {
- smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
- infoLevel, userp,
- &req);
+ code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, 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 = GetCurrentTime();
- if (now - req.startTime > 5000) {
+ DWORD now = GetTickCount();
+ if (now - req.startTime > RDRtimeout * 1000) {
scp->bulkStatProgress = thyper;
scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
dsp->flags &= ~SMB_DIRSEARCH_BULKST;
} else
- cm_TryBulkStat(scp, &thyper, userp, &req);
+ code = cm_TryBulkStat(scp, &thyper, userp, &req);
}
} else {
lock_ObtainMutex(&scp->mx);
}
lock_ReleaseMutex(&dsp->mx);
- if (code)
+ if (code) {
+ osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
break;
+ }
bufferOffset = thyper;
PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_READ);
- if (code) break;
-
- if (cm_HaveBuffer(scp, bufferp, 0)) break;
+ if (code) {
+ osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
+ break;
+ }
+
+ cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
+ if (cm_HaveBuffer(scp, bufferp, 0)) {
+ osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
+ break;
+ }
/* otherwise, load the buffer and try again */
code = cm_GetBuffer(scp, bufferp, NULL, userp,
&req);
- if (code) break;
+ if (code) {
+ osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
+ scp, bufferp, code);
+ break;
+ }
}
if (code) {
buf_Release(bufferp);
* in; copy it out if it represents a non-deleted entry.
*/
entryInDir = curOffset.LowPart & (2048-1);
- entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
+ entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
/* page header will help tell us which entries are free. Page
* header can change more often than once per buffer, since
* a buffer package buffer.
*/
/* only look intra-buffer */
- temp = curOffset.LowPart & (buf_bufferSize - 1);
+ temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
temp &= ~(2048 - 1); /* turn off intra-page bits */
pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
/* 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 */
+
/* 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(dep->name)) {
cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
NeedShortName = 1;
}
+ osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
+ dep->fid.vnode, dep->fid.unique,
+ osi_LogSaveString(smb_logp, dep->name),
+ NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
+
/* 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 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
+ (NeedShortName && smb_V3MatchMask(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(dep->name)) {
+ 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.vnode = ntohl(dep->fid.vnode);
fid.unique = 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)
- goto nextEntry;
+ /* 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;
}
/* 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)
+ else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
ohbytes = 12; /* NT names only */
else
ohbytes = 64; /* NT */
- if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
+ if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
ohbytes += 26; /* Short name & length */
- if (searchFlags & 4) {
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
ohbytes += 4; /* if resume key required */
}
- if (infoLevel != 1
- && infoLevel != 0x101
- && infoLevel != 0x103)
+ if ( infoLevel != SMB_INFO_STANDARD &&
+ infoLevel != SMB_FIND_FILE_DIRECTORY_INFO &&
+ infoLevel != SMB_FIND_FILE_NAMES_INFO)
ohbytes += 4; /* EASIZE */
/* add header to name & term. null */
/* 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)
- break;
+ if (orbytes + bytesInBuffer + align > maxReturnData) {
+ osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
+ maxReturnData);
+ break;
+ }
/* this is one of the entries to use: it is not deleted
* and it matches the star pattern we're looking for.
/* First zero everything else */
memset(origOp, 0, ohbytes);
- if (infoLevel <= 0x101)
+ if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
*(origOp + ohbytes - 1) = (unsigned char) onbytes;
- else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+ else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
*((u_long *)(op + 8)) = onbytes;
else
*((u_long *)(op + 60)) = onbytes;
CharToOem(origOp+ohbytes, origOp+ohbytes);
/* Short name if requested and needed */
- if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+ if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
if (NeedShortName) {
strcpy(op + 70, shortName);
if (smb_StoreAnsiFilenames)
CharToOem(op + 70, op + 70);
- *(op + 68) = shortNameEnd - shortName;
+ *(op + 68) = (char)(shortNameEnd - shortName);
}
}
returnedNames++;
/* NextEntryOffset and FileIndex */
- if (infoLevel >= 101) {
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
int entryOffset = orbytes + align;
*((u_long *)op) = entryOffset;
*((u_long *)(op+4)) = nextEntryCookie;
* 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) {
curPatchp = malloc(sizeof(*curPatchp));
- osi_QAdd((osi_queue_t **) &dirListPatchesp,
- &curPatchp->q);
+ osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
curPatchp->dptr = op;
- if (infoLevel >= 0x101)
+ if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
curPatchp->dptr += 8;
if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
curPatchp->dep = dep;
}
- if (searchFlags & 4)
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
/* put out resume key */
*((u_long *)origOp) = nextEntryCookie;
bytesInBuffer++;
}
} /* if we're including this name */
- else if (!NeedShortName &&
- !starPattern &&
- !foundInexact &&
- dep->fid.vnode != 0 &&
- smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+ else if (!starPattern &&
+ !foundInexact &&
+ smb_V3MatchMask(dep->name, 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) buf_Release(bufferp);
+ 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.
*/
- 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;
+ if (returnedNames == 0)
+ eos = 1;
if (p->opcode == 1) {
/* find first */
outp->parmsp[0] = (unsigned short) dsp->cookie;
/* return # of bytes in the buffer */
outp->totalData = bytesInBuffer;
- osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
- returnedNames, code);
-
/* Return error code if unsuccessful on first request */
if (code == 0 && p->opcode == 1 && returnedNames == 0)
code = CM_ERROR_NOSUCHFILE;
+ osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
+ p->opcode, dsp->cookie, returnedNames, code);
+
/* if we're supposed to close the search after this request, or if
* 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 {
+ else
smb_SendTran2Packet(vcp, outp, opx);
- }
+
smb_FreeTran2Packet(outp);
smb_ReleaseDirSearch(dsp);
cm_ReleaseSCache(scp);
smb_fid_t *fidp;
int attributes;
char *lastNamep;
- time_t dosTime;
+ afs_uint32 dosTime;
int openFun;
int trunc;
int openMode;
int parmSlot; /* which parm we're dealing with */
char *tidPathp;
cm_req_t req;
+ int created = 0;
cm_InitReq(&req);
scp = NULL;
- extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
- openFun = smb_GetSMBParm(inp, 8); /* open function */
+ extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
+ openFun = smb_GetSMBParm(inp, 8); /* open function */
excl = ((openFun & 3) == 0);
- trunc = ((openFun & 3) == 2); /* truncate it */
+ trunc = ((openFun & 3) == 2); /* truncate it */
openMode = (smb_GetSMBParm(inp, 3) & 0x7);
- openAction = 0; /* tracks what we did */
+ openAction = 0; /* tracks what we did */
attributes = smb_GetSMBParm(inp, 5);
dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
- /* compute initial mode bits based on read-only flag in attributes */
+ /* 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)
free(hexp);
}
#endif
- userp = smb_GetUser(vcp, inp);
+ userp = smb_GetUserFromVCP(vcp, inp);
dscp = NULL;
code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
cm_ReleaseUser(userp);
return CM_ERROR_NOSUCHPATH;
}
- code = cm_NameI(cm_rootSCachep, pathp,
+ code = cm_NameI(cm_data.rootSCachep, pathp,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &scp);
+
+#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) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+
if (code != 0) {
- code = cm_NameI(cm_rootSCachep, spacep->data,
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
userp, tidPathp, &req, &dscp);
-
if (code) {
cm_ReleaseUser(userp);
return code;
}
-
+
+#ifdef DFS_SUPPORT
+ if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+ int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#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.
*/
- if (!lastNamep) lastNamep = pathp;
- else lastNamep++;
+ if (!lastNamep)
+ lastNamep = pathp;
+ else
+ lastNamep++;
code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
&req, &scp);
- if (code && code != CM_ERROR_NOSUCHFILE) {
- cm_ReleaseSCache(dscp);
+ if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+ cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
return code;
}
if (excl) {
/* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
return CM_ERROR_EXISTS;
}
else openAction = 1; /* found existing file */
}
- else if (!(openFun & 0x10)) {
+ else if (!(openFun & SMB_ATTR_DIRECTORY)) {
/* don't create if not found */
if (dscp) cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
return CM_ERROR_NOSUCHFILE;
}
else {
- osi_assert(dscp != NULL);
+ osi_assertx(dscp != NULL, "null cm_scache_t");
osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
osi_LogSaveString(smb_logp, lastNamep));
openAction = 2; /* created file */
smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
&req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (!excl && code == CM_ERROR_EXISTS) {
+ if (code == 0) {
+ created = 1;
+ if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ 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
* creating it already, then we open it anyway. We
* don't bother retrying after this, since if this next
}
/* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
if (code) {
/* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
+ if (scp)
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
return code;
}
/* 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_ObtainMutex(&scp->mx);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseMutex(&scp->mx);
+ 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;
+ if (openMode != 1)
+ fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
if (openMode == 1 || openMode == 2)
fidp->flags |= SMB_FID_OPENWRITE;
+ /* remember if the file was newly created */
+ if (created)
+ fidp->flags |= SMB_FID_CREATED;
+
+ lock_ReleaseMutex(&fidp->mx);
smb_ReleaseFID(fidp);
cm_Open(scp, 0, userp);
return 0;
}
+static void smb_GetLockParams(unsigned char LockType,
+ char ** buf,
+ unsigned int * ppid,
+ LARGE_INTEGER * pOffset,
+ LARGE_INTEGER * pLength)
+{
+ if (LockType & LOCKING_ANDX_LARGE_FILES) {
+ /* Large Files */
+ *ppid = *((USHORT *) *buf);
+ pOffset->HighPart = *((LONG *)(*buf + 4));
+ pOffset->LowPart = *((DWORD *)(*buf + 8));
+ pLength->HighPart = *((LONG *)(*buf + 12));
+ pLength->LowPart = *((DWORD *)(*buf + 16));
+ *buf += 20;
+ }
+ else {
+ /* Not Large Files */
+ *ppid = *((USHORT *) *buf);
+ pOffset->HighPart = 0;
+ pOffset->LowPart = *((DWORD *)(*buf + 2));
+ pLength->HighPart = 0;
+ pLength->LowPart = *((DWORD *)(*buf + 6));
+ *buf += 10;
+ }
+}
+
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;
- unsigned long Timeout;
+ long Timeout;
char *op;
+ char *op_locks;
LARGE_INTEGER LOffset, LLength;
- smb_waitingLock_t *waitingLock;
- void *lockp;
+ smb_waitingLockRequest_t *wlRequest = NULL;
+ cm_file_lock_t *lockp;
long code = 0;
int i;
+ cm_key_t key;
+ unsigned int pid;
cm_InitReq(&req);
fid = smb_ChainFID(fid, inp);
fidp = smb_FindFID(vcp, fid, 0);
- if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+ if (!fidp)
+ return CM_ERROR_BADFD;
+
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ lock_ObtainMutex(&fidp->mx);
+ 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 */
inp->fid = fid;
- userp = smb_GetUser(vcp, inp);
+ userp = smb_GetUserFromVCP(vcp, inp);
- scp = fidp->scp;
lock_ObtainMutex(&scp->mx);
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_LOCK);
- if (code) goto doneSync;
-
- LockType = smb_GetSMBParm(inp, 3) & 0xff;
- Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
- NumberOfUnlocks = smb_GetSMBParm(inp, 6);
- NumberOfLocks = smb_GetSMBParm(inp, 7);
-
- op = smb_GetSMBData(inp, NULL);
-
- for (i=0; i<NumberOfUnlocks; i++) {
- if (LockType & 0x10) {
- /* Large Files */
- LOffset.HighPart = *((LONG *)(op + 4));
- LOffset.LowPart = *((DWORD *)(op + 8));
- LLength.HighPart = *((LONG *)(op + 12));
- LLength.LowPart = *((DWORD *)(op + 16));
- op += 20;
- }
- else {
- /* Not Large Files */
- LOffset.HighPart = 0;
- LOffset.LowPart = *((DWORD *)(op + 2));
- LLength.HighPart = 0;
- LLength.LowPart = *((DWORD *)(op + 6));
- op += 10;
- }
- if (LargeIntegerNotEqualToZero(LOffset))
- continue;
- /* Do not check length -- length check done in cm_Unlock */
-
- code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
- if (code) goto done;
- }
-
- for (i=0; i<NumberOfLocks; i++) {
- if (LockType & 0x10) {
- /* Large Files */
- LOffset.HighPart = *((LONG *)(op + 4));
- LOffset.LowPart = *((DWORD *)(op + 8));
- LLength.HighPart = *((LONG *)(op + 12));
- LLength.LowPart = *((DWORD *)(op + 16));
- op += 20;
- }
- else {
- /* Not Large Files */
- LOffset.HighPart = 0;
- LOffset.LowPart = *((DWORD *)(op + 2));
- LLength.HighPart = 0;
- LLength.LowPart = *((DWORD *)(op + 6));
- op += 10;
- }
- if (LargeIntegerNotEqualToZero(LOffset))
- continue;
- if (LargeIntegerLessThan(LOffset, scp->length))
- continue;
-
- code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
- userp, &req, &lockp);
- if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
- /* Put on waiting list */
- waitingLock = malloc(sizeof(smb_waitingLock_t));
- waitingLock->vcp = vcp;
- waitingLock->inp = smb_CopyPacket(inp);
- waitingLock->outp = smb_CopyPacket(outp);
- waitingLock->timeRemaining = Timeout;
- waitingLock->lockp = lockp;
- lock_ObtainWrite(&smb_globalLock);
- osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
- &waitingLock->q);
- osi_Wakeup((long) &smb_allWaitingLocks);
- lock_ReleaseWrite(&smb_globalLock);
- /* don't send reply immediately */
- outp->flags |= SMB_PACKETFLAG_NOSEND;
+ if (code) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
+ goto doneSync;
+ }
+
+ LockType = smb_GetSMBParm(inp, 3) & 0xff;
+ Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
+ NumberOfUnlocks = smb_GetSMBParm(inp, 6);
+ NumberOfLocks = smb_GetSMBParm(inp, 7);
+
+ 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_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.*/
+
+ code = CM_ERROR_BADOP;
+ goto done;
+
+ }
+
+ op = smb_GetSMBData(inp, NULL);
+
+ 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);
+
+ if (code)
+ goto done;
+ }
+
+ op_locks = op;
+
+ for (i=0; i<NumberOfLocks; i++) {
+ smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+ key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+ 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;
+
+ /* Put on waiting list */
+ if(wlRequest == NULL) {
+ int j;
+ char * opt;
+ cm_key_t tkey;
+ LARGE_INTEGER tOffset, tLength;
+
+ wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
+
+ 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->locks = NULL;
+
+ /* The waiting lock request needs to have enough
+ information to undo all the locks in the request.
+ We do the following to store info about locks that
+ have already been granted. Sure, we can get most
+ of the info from the packet, but the packet doesn't
+ hold the result of cm_Lock call. In practice we
+ only receive packets with one or two locks, so we
+ are only wasting a few bytes here and there and
+ only for a limited period of time until the waiting
+ lock times out or is freed. */
+
+ for(opt = op_locks, j=i; j > 0; j--) {
+ smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
+
+ tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+ wLock = malloc(sizeof(smb_waitingLock_t));
+
+ osi_assertx(wLock != NULL, "null smb_waitingLock_t");
+
+ wLock->key = tkey;
+ wLock->LOffset = tOffset;
+ wLock->LLength = tLength;
+ wLock->lockp = NULL;
+ wLock->state = SMB_WAITINGLOCKSTATE_DONE;
+ osi_QAdd((osi_queue_t **) &wlRequest->locks,
+ &wLock->q);
+ }
}
- if (code) break;
- }
- if (code) {
- /* release any locks acquired before the failure */
+ wLock = malloc(sizeof(smb_waitingLock_t));
+
+ osi_assertx(wLock != NULL, "null smb_waitingLock_t");
+
+ wLock->key = key;
+ wLock->LOffset = LOffset;
+ wLock->LLength = LLength;
+ wLock->lockp = lockp;
+ wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
+ osi_QAdd((osi_queue_t **) &wlRequest->locks,
+ &wLock->q);
+
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
+ wLock);
+
+ code = 0;
+ continue;
+ }
+
+ if (code) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
+ break;
+ }
}
- else
+
+ if (code) {
+
+ /* Since something went wrong with the lock number i, we now
+ have to go ahead and release any locks acquired before the
+ failure. All locks before lock number i (of which there
+ are i of them) have either been successful or are waiting.
+ Either case requires calling cm_Unlock(). */
+
+ /* And purge the waiting lock */
+ if(wlRequest != NULL) {
+ smb_waitingLock_t * wl;
+ smb_waitingLock_t * wlNext;
+ long ul_code;
+
+ for(wl = wlRequest->locks; wl; wl = wlNext) {
+
+ wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
+
+ ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
+
+ if(ul_code != 0) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
+ } else {
+ osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
+ }
+
+ osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
+ free(wl);
+
+ }
+
+ smb_ReleaseVC(wlRequest->vcp);
+ cm_ReleaseSCache(wlRequest->scp);
+ smb_FreePacket(wlRequest->inp);
+ smb_FreePacket(wlRequest->outp);
+
+ free(wlRequest);
+
+ wlRequest = NULL;
+ }
+
+ } else {
+
+ if (wlRequest != NULL) {
+
+ lock_ObtainWrite(&smb_globalLock);
+ osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
+ &wlRequest->q);
+ osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
+ lock_ReleaseWrite(&smb_globalLock);
+
+ /* don't send reply immediately */
+ outp->flags |= SMB_PACKETFLAG_NOSEND;
+ }
+
smb_SetSMBDataLength(outp, 0);
+ }
+
done:
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
doneSync:
lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_ReleaseFID(fidp);
smb_fid_t *fidp;
cm_scache_t *scp;
long code = 0;
- time_t searchTime;
+ afs_uint32 searchTime;
cm_user_t *userp;
cm_req_t req;
fid = smb_ChainFID(fid, inp);
fidp = smb_FindFID(vcp, fid, 0);
- if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+ if (!fidp)
+ return CM_ERROR_BADFD;
+
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ lock_ObtainMutex(&fidp->mx);
+ 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_GetUser(vcp, inp);
+ userp = smb_GetUserFromVCP(vcp, inp);
- scp = fidp->scp;
/* otherwise, stat the file */
lock_ObtainMutex(&scp->mx);
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);
/* decode times. We need a search time, but the response to this
* call provides the date first, not the time, as returned in the
done:
lock_ReleaseMutex(&scp->mx);
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
smb_ReleaseFID(fidp);
return code;
smb_fid_t *fidp;
cm_scache_t *scp;
long code = 0;
- time_t searchTime;
+ afs_uint32 searchTime;
time_t unixTime;
cm_user_t *userp;
cm_attr_t attrs;
cm_InitReq(&req);
- fid = smb_GetSMBParm(inp, 0);
- fid = smb_ChainFID(fid, inp);
-
- fidp = smb_FindFID(vcp, fid, 0);
- if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
- return CM_ERROR_BADFD;
+ fid = smb_GetSMBParm(inp, 0);
+ fid = smb_ChainFID(fid, inp);
+
+ fidp = smb_FindFID(vcp, fid, 0);
+ if (!fidp)
+ return CM_ERROR_BADFD;
+
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ lock_ObtainMutex(&fidp->mx);
+ 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);
+
+
+ /* 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.
+ */
+ searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
+
+ if (searchTime != 0) {
+ smb_UnixTimeFromSearchTime(&unixTime, searchTime);
+
+ if ( unixTime != -1 ) {
+ attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
+ attrs.clientModTime = unixTime;
+ code = cm_SetAttr(scp, &attrs, userp, &req);
+
+ osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
+ } else {
+ osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
+ }
+ }
+ else
+ code = 0;
+
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
+ return code;
+}
+
+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;
+ long code = 0;
+ 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;
+
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ lock_ObtainMutex(&fidp->mx);
+ if (fidp->flags & SMB_FID_IOCTL) {
+ lock_ReleaseMutex(&fidp->mx);
+ code = smb_IoctlV3Write(fidp, vcp, inp, outp);
+ smb_ReleaseFID(fidp);
+ return code;
+ }
+ 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;
+ cm_scache_t * scp;
+
+ pid = ((smb_t *) inp)->pid;
+ key = cm_GenerateKey(vcp->vcID, pid, fd);
+
+ LOffset.HighPart = offset.HighPart;
+ LOffset.LowPart = offset.LowPart;
+ LLength.HighPart = 0;
+ LLength.LowPart = count;
+
+ scp = fidp->scp;
+ lock_ObtainMutex(&scp->mx);
+ code = cm_LockCheckWrite(scp, LOffset, LLength, key);
+ lock_ReleaseMutex(&scp->mx);
+
+ if (code)
+ goto done;
}
-
- userp = smb_GetUser(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.
+
+ /*
+ * 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.
*/
- searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
-
- if (searchTime != 0) {
- smb_UnixTimeFromSearchTime(&unixTime, searchTime);
+ lock_ObtainMutex(&fidp->mx);
+ if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
+ fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+ fidp->scp->clientModTime = time(NULL);
+ }
+ lock_ReleaseMutex(&fidp->mx);
- if ( unixTime != -1 ) {
- attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
- attrs.clientModTime = unixTime;
- code = cm_SetAttr(scp, &attrs, userp, &req);
+ 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;
- osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
- } else {
- osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
- }
+ offset = LargeIntegerAdd(offset,
+ ConvertLongToLargeInteger(written));
+ count -= written;
+ total_written += written;
+ written = 0;
}
- else code = 0;
+ done_writing:
+
+ /* 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_ReleaseUser(userp);
smb_ReleaseFID(fidp);
+
return code;
}
-
long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
osi_hyper_t offset;
- long count, finalCount;
+ long count;
+ long finalCount = 0;
unsigned short fd;
+ unsigned pid;
smb_fid_t *fidp;
long code = 0;
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;
}
+
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ pid = ((smb_t *) inp)->pid;
+ key = cm_GenerateKey(vcp->vcID, pid, fd);
+ {
+ LARGE_INTEGER LOffset, LLength;
+ cm_scache_t *scp;
+
+ LOffset.HighPart = offset.HighPart;
+ LOffset.LowPart = offset.LowPart;
+ LLength.HighPart = 0;
+ LLength.LowPart = count;
+
+ scp = fidp->scp;
+ lock_ObtainMutex(&scp->mx);
+ code = cm_LockCheckRead(scp, LOffset, LLength, key);
+ lock_ReleaseMutex(&scp->mx);
+ }
+
+ if (code) {
+ smb_ReleaseFID(fidp);
+ return code;
+ }
+
/* set inp->fid so that later read calls in same msg can find fid */
inp->fid = fd;
+ lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
- return smb_IoctlV3Read(fidp, vcp, inp, outp);
+ lock_ReleaseMutex(&fidp->mx);
+ code = smb_IoctlV3Read(fidp, vcp, inp, outp);
+ smb_ReleaseFID(fidp);
+ return code;
}
-
- userp = smb_GetUser(vcp, inp);
+ lock_ReleaseMutex(&fidp->mx);
+
+ userp = smb_GetUserFromVCP(vcp, inp);
/* 0 and 1 are reserved for request chaining, were setup by our caller,
* and will be further filled in after we return.
/* 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_OVERWRITE 4 // (open & truncate, but do not create)
#define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
+/* Flags field */
+#define REQUEST_OPLOCK 2
+#define REQUEST_BATCH_OPLOCK 4
+#define OPEN_DIRECTORY 8
+#define EXTENDED_RESPONSE_REQUIRED 0x10
+
+/* CreateOptions field. */
+#define FILE_DIRECTORY_FILE 0x0001
+#define FILE_WRITE_THROUGH 0x0002
+#define FILE_SEQUENTIAL_ONLY 0x0004
+#define FILE_NON_DIRECTORY_FILE 0x0040
+#define FILE_NO_EA_KNOWLEDGE 0x0200
+#define FILE_EIGHT_DOT_THREE_ONLY 0x0400
+#define FILE_RANDOM_ACCESS 0x0800
+#define FILE_DELETE_ON_CLOSE 0x1000
+#define FILE_OPEN_BY_FILE_ID 0x2000
+
long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
char *pathp, *realPathp;
unsigned int requestOpLock;
unsigned int requestBatchOpLock;
unsigned int mustBeDir;
+ unsigned int extendedRespRequired;
unsigned int treeCreate;
int realDirFlag;
unsigned int desiredAccess;
unsigned int extAttributes;
unsigned int createDisp;
unsigned int createOptions;
+ unsigned int shareAccess;
int initialModeBits;
unsigned short baseFid;
smb_fid_t *baseFidp;
char *tidPathp;
BOOL foundscp;
cm_req_t req;
+ int created = 0;
+ cm_lock_data_t *ldp = NULL;
cm_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
+ * we don't lose a reference. Start by ensuring that they are NULL.
+ */
+ scp = NULL;
+ dscp = NULL;
treeCreate = FALSE;
foundscp = FALSE;
- scp = NULL;
nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
flags = smb_GetSMBOffsetParm(inp, 3, 1)
| (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
- requestOpLock = flags & 0x02;
- requestBatchOpLock = flags & 0x04;
- mustBeDir = flags & 0x08;
+ requestOpLock = flags & REQUEST_OPLOCK;
+ requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
+ mustBeDir = flags & OPEN_DIRECTORY;
+ extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
/*
* Why all of a sudden 32-bit FID?
| (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
| (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
+ shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
+ | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
| (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
/* mustBeDir is never set; createOptions directory bit seems to be
* more important
*/
- if (createOptions & 1)
+ if (createOptions & FILE_DIRECTORY_FILE)
realDirFlag = 1;
- else if (createOptions & 0x40)
+ else if (createOptions & FILE_NON_DIRECTORY_FILE)
realDirFlag = 0;
else
realDirFlag = -1;
* extended attributes
*/
initialModeBits = 0666;
- if (extAttributes & 1)
+ if (extAttributes & SMB_ATTR_READONLY)
initialModeBits &= ~0222;
pathp = smb_GetSMBData(inp, NULL);
osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
- osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
+ osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
/* special case magic file name for receiving IOCTL requests
free(hexp);
}
#endif
- userp = smb_GetUser(vcp, inp);
+
+ userp = smb_GetUserFromVCP(vcp, inp);
if (!userp) {
osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
free(realPathp);
}
if (baseFid == 0) {
- baseDirp = cm_rootSCachep;
+ baseFidp = NULL;
+ baseDirp = cm_data.rootSCachep;
code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->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. */
+ * don't support OR it could be looking to make a DFS
+ * referral request.
+ */
osi_Log0(smb_logp, "NTCreateX received IPC TID");
+#ifndef DFS_SUPPORT
free(realPathp);
cm_ReleaseUser(userp);
return CM_ERROR_NOSUCHFILE;
+#endif /* DFS_SUPPORT */
}
- }
- else {
+ } else {
baseFidp = smb_FindFID(vcp, baseFid, 0);
if (!baseFidp) {
osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
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;
}
if (desiredAccess & DELETE)
fidflags |= SMB_FID_OPENDELETE;
if (desiredAccess & AFS_ACCESS_READ)
- fidflags |= SMB_FID_OPENREAD;
+ fidflags |= SMB_FID_OPENREAD_LISTDIR;
if (desiredAccess & AFS_ACCESS_WRITE)
fidflags |= SMB_FID_OPENWRITE;
-
- dscp = NULL;
+ 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 (smb_IsExecutableFileName(lastNamep))
+ fidflags |= SMB_FID_EXECUTABLE;
+
+ /* and the share mode */
+ if (shareAccess & FILE_SHARE_READ)
+ fidflags |= SMB_FID_SHARE_READ;
+ if (shareAccess & FILE_SHARE_WRITE)
+ fidflags |= SMB_FID_SHARE_WRITE;
+
+ osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
code = 0;
+
/* For an exclusive create, we want to do a case sensitive match for the last component. */
if ( createDisp == FILE_CREATE ||
createDisp == FILE_OVERWRITE ||
code = cm_NameI(baseDirp, spacep->data, 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->data);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#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) {
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
return CM_ERROR_EXISTS;
}
}
- } else
- dscp = NULL;
+ }
+ /* we have both scp and dscp */
} else {
code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
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) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+ /* we might have scp but not dscp */
}
- if (code == 0)
- foundscp = TRUE;
+ if (scp)
+ foundscp = TRUE;
+
if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
/* look up parent directory */
/* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
* recognize.
*/
- if ( !dscp ) {
- while (1) {
+ /* we might or might not have scp */
+
+ if (dscp == NULL) {
+ do {
char *tp;
code = cm_NameI(baseDirp, spacep->data,
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->data);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
+
if (code &&
(tp = strrchr(spacep->data,'\\')) &&
(createDisp == FILE_CREATE) &&
treeStartp = realPathp + (tp - spacep->data);
if (*tp && !smb_IsLegalFilename(tp)) {
- if (baseFid != 0)
- smb_ReleaseFID(baseFidp);
cm_ReleaseUser(userp);
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
free(realPathp);
+ if (scp)
+ cm_ReleaseSCache(scp);
return CM_ERROR_BADNTFILENAME;
}
+ code = 0;
+ }
+ } while (dscp == NULL && code == 0);
+ } else
+ code = 0;
+
+ /* we might have scp and we might have dscp */
+
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
+
+ if (code) {
+ osi_Log0(smb_logp,"NTCreateX parent not found");
+ if (scp)
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
+
+ if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
+ /* A file exists where we want a directory. */
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_EXISTS;
+ }
+
+ if (!lastNamep)
+ lastNamep = realPathp;
+ else
+ lastNamep++;
+
+ if (!smb_IsLegalFilename(lastNamep)) {
+ if (scp)
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_BADNTFILENAME;
+ }
+
+ if (!foundscp && !treeCreate) {
+ if ( createDisp == FILE_CREATE ||
+ createDisp == FILE_OVERWRITE ||
+ createDisp == FILE_OVERWRITE_IF)
+ {
+ code = cm_Lookup(dscp, lastNamep,
+ CM_FLAG_FOLLOW, userp, &req, &scp);
+ } else {
+ code = cm_Lookup(dscp, lastNamep,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ }
+ if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
+ }
+ /* we have scp and dscp */
+ } else {
+ /* we have scp but not dscp */
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
+ }
+
+ /* if we get here, if code is 0, the file exists and is represented by
+ * scp. Otherwise, we have to create it. The dir may be represented
+ * by dscp, or we may have found the file directly. If code is non-zero,
+ * scp is NULL.
+ */
+ if (code == 0 && !treeCreate) {
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+ if (code) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
+
+ if (createDisp == FILE_CREATE) {
+ /* oops, file shouldn't be there */
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_EXISTS;
+ }
+
+ if ( createDisp == FILE_OVERWRITE ||
+ createDisp == FILE_OVERWRITE_IF) {
+
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ targetScp = 0;
+ 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
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ 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) {
+ 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 */
+ }
+ else
+ openAction = 1; /* found existing file */
+
+ } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
+ /* don't create if not found */
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return CM_ERROR_NOSUCHFILE;
+ } else if (realDirFlag == 0 || realDirFlag == -1) {
+ osi_assertx(dscp != NULL, "null cm_scache_t");
+ osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
+ osi_LogSaveString(smb_logp, lastNamep));
+ openAction = 2; /* created file */
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ setAttr.clientModTime = time(NULL);
+ code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
+ if (code == 0) {
+ created = 1;
+ if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ 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
+ * creating it already, then we open it anyway. We
+ * don't bother retrying after this, since if this next
+ * fails, that means that the file was deleted after we
+ * started this call.
+ */
+ code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
+ userp, &req, &scp);
+ if (code == 0) {
+ if (createDisp == FILE_OVERWRITE_IF) {
+ setAttr.mask = CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = 0;
+ setAttr.length.HighPart = 0;
+
+ /* now watch for a symlink */
+ code = 0;
+ while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ targetScp = 0;
+ code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+ if (code == 0) {
+ /* we have a more accurate file to use (the
+ * target of the symbolic link). Otherwise,
+ * we'll just use the symlink anyway.
+ */
+ osi_Log2(smb_logp, "symlink vp %x to vp %x",
+ scp, targetScp);
+ cm_ReleaseSCache(scp);
+ scp = targetScp;
+ }
+ }
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
}
- else
- break;
- }
- } else
- code = 0;
-
- if (baseFid != 0)
- smb_ReleaseFID(baseFidp);
-
- if (code) {
- osi_Log0(smb_logp,"NTCreateX parent not found");
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
+ } /* lookup succeeded */
}
+ } else {
+ char *tp, *pp;
+ char *cp; /* This component */
+ int clen = 0; /* length of component */
+ cm_scache_t *tscp1, *tscp2;
+ int isLast = 0;
- if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
- /* A file exists where we want a directory. */
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_EXISTS;
- }
+ /* create directory */
+ if ( !treeCreate )
+ treeStartp = lastNamep;
+ osi_assertx(dscp != NULL, "null cm_scache_t");
+ osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
+ osi_LogSaveString(smb_logp, treeStartp));
+ openAction = 2; /* created directory */
- if (!lastNamep)
- lastNamep = realPathp;
- else
- lastNamep++;
+ /* 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 || code == CM_ERROR_BPLUS_NOMATCH))
+ code = CM_ERROR_EXISTS;
- if (!smb_IsLegalFilename(lastNamep)) {
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_BADNTFILENAME;
- }
+ setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+ setAttr.clientModTime = time(NULL);
- if (!foundscp && !treeCreate) {
- if ( createDisp == FILE_CREATE ||
- createDisp == FILE_OVERWRITE ||
- createDisp == FILE_OVERWRITE_IF)
- {
- code = cm_Lookup(dscp, lastNamep,
- CM_FLAG_FOLLOW, userp, &req, &scp);
+ pp = treeStartp;
+ cp = spacep->data;
+ tscp1 = dscp;
+ cm_HoldSCache(tscp1);
+ tscp2 = NULL;
+
+ while (pp && *pp) {
+ tp = strchr(pp, '\\');
+ if (!tp) {
+ strcpy(cp,pp);
+ clen = (int)strlen(cp);
+ isLast = 1; /* indicate last component. the supplied path never ends in a slash */
} else {
- code = cm_Lookup(dscp, lastNamep,
- CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- }
- if (code && code != CM_ERROR_NOSUCHFILE) {
- cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
- }
- }
- else {
- if (baseFid != 0)
- smb_ReleaseFID(baseFidp);
- }
-
- /* if we get here, if code is 0, the file exists and is represented by
- * scp. Otherwise, we have to create it. The dir may be represented
- * by dscp, or we may have found the file directly. If code is non-zero,
- * scp is NULL.
- */
- if (code == 0 && !treeCreate) {
- if (createDisp == FILE_CREATE) {
- /* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return CM_ERROR_EXISTS;
+ clen = (int)(tp - pp);
+ strncpy(cp,pp,clen);
+ *(cp + clen) = 0;
+ tp++;
}
+ pp = tp;
- if ( createDisp == FILE_OVERWRITE ||
- createDisp == FILE_OVERWRITE_IF) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
- /* now watch for a symlink */
- code = 0;
- while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
- targetScp = 0;
- code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
- if (code == 0) {
- /* we have a more accurate file to use (the
- * target of the symbolic link). Otherwise,
- * we'll just use the symlink anyway.
- */
- osi_Log2(smb_logp, "symlink vp %x to vp %x",
- scp, targetScp);
- cm_ReleaseSCache(scp);
- scp = targetScp;
- }
- }
- code = cm_SetAttr(scp, &setAttr, userp, &req);
- openAction = 3; /* truncated existing file */
- }
- else
- openAction = 1; /* found existing file */
+ if (clen == 0)
+ continue; /* the supplied path can't have consecutive slashes either , but */
- code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
- &req);
- if (code) {
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseSCache(scp);
- cm_ReleaseUser(userp);
- free(realPathp);
- return code;
- }
- }
- else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
- /* don't create if not found */
- if (dscp) cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
- 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));
- openAction = 2; /* created file */
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- setAttr.clientModTime = time(NULL);
- code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
- &req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+ /* cp is the next component to be created. */
+ code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
+ if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (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
* fails, that means that the file was deleted after we
* started this call.
*/
- code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- if (code == 0) {
- if (createDisp == FILE_OVERWRITE_IF) {
- setAttr.mask = CM_ATTRMASK_LENGTH;
- setAttr.length.LowPart = 0;
- setAttr.length.HighPart = 0;
-
- /* now watch for a symlink */
- code = 0;
- while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
- targetScp = 0;
- code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
- if (code == 0) {
- /* we have a more accurate file to use (the
- * target of the symbolic link). Otherwise,
- * we'll just use the symlink anyway.
- */
- osi_Log2(smb_logp, "symlink vp %x to vp %x",
- scp, targetScp);
- cm_ReleaseSCache(scp);
- scp = targetScp;
- }
- }
- code = cm_SetAttr(scp, &setAttr, userp, &req);
- }
- } /* lookup succeeded */
- }
- }
- else {
- char *tp, *pp;
- char *cp; /* This component */
- int clen = 0; /* length of component */
- cm_scache_t *tscp;
- 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));
- openAction = 2; /* created directory */
-
- setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
- setAttr.clientModTime = time(NULL);
-
- pp = treeStartp;
- cp = spacep->data;
- tscp = dscp;
-
- while (pp && *pp) {
- tp = strchr(pp, '\\');
- if (!tp) {
- strcpy(cp,pp);
- clen = strlen(cp);
- isLast = 1; /* indicate last component. the supplied path never ends in a slash */
- }
- else {
- clen = tp - pp;
- strncpy(cp,pp,clen);
- *(cp + clen) = 0;
- tp++;
- }
- pp = tp;
-
- if (clen == 0)
- continue; /* the supplied path can't have consecutive slashes either , but */
-
- /* cp is the next component to be created. */
- code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
- if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- tscp, 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
- * fails, that means that the file was deleted after we
- * started this call.
- */
- code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
- userp, &req, &scp);
- }
- if (code) break;
+ code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
+ userp, &req, &tscp2);
+ }
+ if (code)
+ break;
- if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
- cm_ReleaseSCache(tscp);
- tscp = scp; /* Newly created directory will be next parent */
- }
+ if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
+ cm_ReleaseSCache(tscp1);
+ tscp1 = tscp2; /* Newly created directory will be next parent */
+ /* the hold is transfered to tscp1 from tscp2 */
}
+ }
- /*
- * if we get here and code == 0, then scp is the last directory created, and tscp is the
- * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
- */
- dscp = tscp;
- }
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ dscp = tscp1;
+ if (scp)
+ cm_ReleaseSCache(scp);
+ scp = tscp2;
+ /*
+ * if we get here and code == 0, then scp is the last directory created, and dscp is the
+ * parent of scp.
+ */
+ }
if (code) {
/* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
- if (dscp) cm_ReleaseSCache(dscp);
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
return code;
* target of the symbolic link). Otherwise,
* we'll just use the symlink anyway.
*/
- osi_Log2(smb_logp, "symlink vp %x to vp %x",
- scp, targetScp);
+ osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
scp = targetScp;
}
}
if (scp->fileType != CM_SCACHETYPE_FILE) {
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
/* (only applies to single component case) */
if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
return CM_ERROR_NOTDIR;
/* 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);
+ fidp->userp = userp;
+
+ /* If we are restricting sharing, we should do so with a suitable
+ share lock. */
+ if (scp->fileType == CM_SCACHETYPE_FILE &&
+ !(fidflags & SMB_FID_SHARE_WRITE)) {
+ cm_key_t key;
+ LARGE_INTEGER LOffset, LLength;
+ int sLockType;
+
+ LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+ LOffset.LowPart = SMB_FID_QLOCK_LOW;
+ LLength.HighPart = 0;
+ LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+ /* If we are not opening the file for writing, then we don't
+ try to get an exclusive lock. Noone 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);
+ code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+ lock_ReleaseMutex(&scp->mx);
+
+ if (code) {
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ cm_ReleaseSCache(scp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ 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 (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+
+ lock_ObtainMutex(&fidp->mx);
/* save a pointer to the vnode */
- fidp->scp = scp;
+ fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
+ lock_ObtainMutex(&scp->mx);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseMutex(&scp->mx);
+ osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
fidp->flags = fidflags;
+ /* remember if the file was newly created */
+ if (created)
+ fidp->flags |= SMB_FID_CREATED;
+
/* 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);
+ dscp = NULL;
fidp->NTopen_pathp = strdup(lastNamep);
}
fidp->NTopen_wholepathp = realPathp;
+ lock_ReleaseMutex(&fidp->mx);
/* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp) {
+ cm_ReleaseSCache(dscp);
+ dscp = NULL;
+ }
+
cm_Open(scp, 0, userp);
/* set inp->fid so that later read calls in same msg can find fid */
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);
+ if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+ LargeIntegerGreaterThanZero(fidp->scp->length) &&
+ !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+ cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
+ fidp->scp->length.LowPart, fidp->scp->length.HighPart,
+ userp);
+ }
+ lock_ReleaseMutex(&scp->mx);
+
osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
osi_LogSaveString(smb_logp, realPathp));
- smb_ReleaseFID(fidp);
-
cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
- /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
+ /* Can't free realPathp if we get here since
+ fidp->NTopen_wholepathp is pointing there */
/* leave scp held since we put it in fidp->scp */
return 0;
unsigned int desiredAccess;
#ifdef DEBUG_VERBOSE
unsigned int allocSize;
- unsigned int shareAccess;
#endif
+ unsigned int shareAccess;
unsigned int extAttributes;
unsigned int createDisp;
#ifdef DEBUG_VERBOSE
ULONG *lparmp;
char *outData;
cm_req_t req;
+ int created = 0;
+ cm_lock_data_t *ldp = NULL;
cm_InitReq(&req);
lparmp = (ULONG *) parmp;
flags = lparmp[0];
- requestOpLock = flags & 0x02;
- requestBatchOpLock = flags & 0x04;
- mustBeDir = flags & 0x08;
- extendedRespRequired = flags & 0x10;
+ requestOpLock = flags & REQUEST_OPLOCK;
+ requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
+ mustBeDir = flags & OPEN_DIRECTORY;
+ extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
/*
* Why all of a sudden 32-bit FID?
allocSize = lparmp[3];
#endif /* DEBUG_VERSOSE */
extAttributes = lparmp[5];
-#ifdef DEBUG_VEROSE
shareAccess = lparmp[6];
-#endif
createDisp = lparmp[7];
createOptions = lparmp[8];
#ifdef DEBUG_VERBOSE
/* mustBeDir is never set; createOptions directory bit seems to be
* more important
*/
- if (createOptions & 1)
+ if (createOptions & FILE_DIRECTORY_FILE)
realDirFlag = 1;
- else if (createOptions & 0x40)
+ else if (createOptions & FILE_NON_DIRECTORY_FILE)
realDirFlag = 0;
else
realDirFlag = -1;
* extended attributes
*/
initialModeBits = 0666;
- if (extAttributes & 1)
+ if (extAttributes & SMB_ATTR_READONLY)
initialModeBits &= ~0222;
pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
}
#endif
- userp = smb_GetUser(vcp, inp);
+ userp = smb_GetUserFromVCP(vcp, inp);
if (!userp) {
osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
free(realPathp);
}
if (baseFid == 0) {
- baseDirp = cm_rootSCachep;
+ baseFidp = NULL;
+ baseDirp = cm_data.rootSCachep;
code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
- if(code == CM_ERROR_TIDIPC) {
- /* Attempt to use TID allocated for IPC. The client is
- * probably trying to locate DCE RPC endpoints, which we
- * don't support. */
+ 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, "NTTranCreate received IPC TID");
+#ifndef DFS_SUPPORT
free(realPathp);
cm_ReleaseUser(userp);
return CM_ERROR_NOSUCHPATH;
+#endif
}
- }
- else {
+ } else {
baseFidp = smb_FindFID(vcp, baseFid, 0);
if (!baseFidp) {
- osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
+ 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;
}
if (desiredAccess & DELETE)
fidflags |= SMB_FID_OPENDELETE;
if (desiredAccess & AFS_ACCESS_READ)
- fidflags |= SMB_FID_OPENREAD;
+ 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 (smb_IsExecutableFileName(lastNamep))
+ fidflags |= SMB_FID_EXECUTABLE;
+
+ /* And the share mode */
+ if (shareAccess & FILE_SHARE_READ)
+ fidflags |= SMB_FID_SHARE_READ;
+ if (shareAccess & FILE_SHARE_WRITE)
+ fidflags |= SMB_FID_SHARE_WRITE;
dscp = NULL;
code = 0;
code = cm_NameI(baseDirp, spacep->data, 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->data);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#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) {
cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
return CM_ERROR_EXISTS;
}
}
} else {
code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
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) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
}
if (code == 0)
foundscp = TRUE;
- if (code != 0
- || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
+
+ if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
/* look up parent directory */
if ( !dscp ) {
code = cm_NameI(baseDirp, spacep->data,
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->data);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ if (baseFidp)
+ smb_ReleaseFID(baseFidp);
+ if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+ return CM_ERROR_PATH_NOT_COVERED;
+ else
+ return CM_ERROR_BADSHARENAME;
+ }
+#endif /* DFS_SUPPORT */
} else
code = 0;
cm_FreeSpace(spacep);
- if (baseFid != 0) {
+ if (baseFidp)
smb_ReleaseFID(baseFidp);
- baseFidp = 0;
- }
if (code) {
cm_ReleaseUser(userp);
return code;
}
- if (!lastNamep) lastNamep = realPathp;
- else lastNamep++;
+ if (!lastNamep)
+ lastNamep = realPathp;
+ else
+ lastNamep++;
if (!smb_IsLegalFilename(lastNamep))
return CM_ERROR_BADNTFILENAME;
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);
return code;
}
}
- }
- else {
- if (baseFid != 0) {
+ } else {
+ if (baseFidp)
smb_ReleaseFID(baseFidp);
- baseFidp = 0;
- }
cm_FreeSpace(spacep);
}
* 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) {
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
if (createDisp == FILE_CREATE) {
/* oops, file shouldn't be there */
- if (dscp) cm_ReleaseSCache(dscp);
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
*/
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) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
}
}
code = cm_SetAttr(scp, &setAttr, userp, &req);
}
else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
/* don't create if not found */
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_ReleaseUser(userp);
free(realPathp);
return CM_ERROR_NOSUCHFILE;
}
else if (realDirFlag == 0 || realDirFlag == -1) {
- osi_assert(dscp != NULL);
+ osi_assertx(dscp != NULL, "null cm_scache_t");
osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
osi_LogSaveString(smb_logp, lastNamep));
openAction = 2; /* created file */
setAttr.clientModTime = time(NULL);
code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
&req);
- if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
- smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- dscp, lastNamep, NULL, TRUE);
- if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
+ if (code == 0) {
+ created = 1;
+ if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ 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
* creating it already, then we open it anyway. We
* don't bother retrying after this, since if this next
}
} /* lookup succeeded */
}
- }
- else {
+ } 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));
if (code) {
/* something went wrong creating or truncating the file */
- if (scp) cm_ReleaseSCache(scp);
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (scp)
+ cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
return code;
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
scp = targetScp;
}
}
if (scp->fileType != CM_SCACHETYPE_FILE) {
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
}
if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+ if (ldp)
+ 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);
+ fidp->userp = userp;
+
+ /* If we are restricting sharing, we should do so with a suitable
+ share lock. */
+ if (scp->fileType == CM_SCACHETYPE_FILE &&
+ !(fidflags & SMB_FID_SHARE_WRITE)) {
+ cm_key_t key;
+ LARGE_INTEGER LOffset, LLength;
+ int sLockType;
+
+ LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+ LOffset.LowPart = SMB_FID_QLOCK_LOW;
+ LLength.HighPart = 0;
+ LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+ /* 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);
+ code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+ lock_ReleaseMutex(&scp->mx);
+
+ if (code) {
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ cm_ReleaseSCache(scp);
+ 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 CM_ERROR_SHARING_VIOLATION;
+ }
+ }
+
+ /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ lock_ObtainMutex(&fidp->mx);
/* save a pointer to the vnode */
fidp->scp = scp;
+ lock_ObtainMutex(&scp->mx);
+ scp->flags |= CM_SCACHEFLAG_SMB_FID;
+ lock_ReleaseMutex(&scp->mx);
+ osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
fidp->flags = fidflags;
+ /* remember if the file was newly created */
+ if (created)
+ fidp->flags |= SMB_FID_CREATED;
+
/* save parent dir and pathname for deletion or change notification */
if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
fidp->flags |= SMB_FID_NTOPEN;
fidp->NTopen_dscp = dscp;
- cm_HoldSCache(dscp);
+ osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
+ dscp = NULL;
fidp->NTopen_pathp = strdup(lastNamep);
}
fidp->NTopen_wholepathp = realPathp;
+ lock_ReleaseMutex(&fidp->mx);
/* we don't need this any longer */
- if (dscp) cm_ReleaseSCache(dscp);
+ if (dscp)
+ cm_ReleaseSCache(dscp);
cm_Open(scp, 0, userp);
*((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 {
*((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 */
lock_ReleaseMutex(&scp->mx);
}
- osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
+ lock_ObtainMutex(&scp->mx);
+ if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+ LargeIntegerGreaterThanZero(fidp->scp->length) &&
+ !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+ cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
+ fidp->scp->length.LowPart, fidp->scp->length.HighPart,
+ userp);
+ }
+ lock_ReleaseMutex(&scp->mx);
- smb_ReleaseFID(fidp);
+ 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 */
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;
}
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
+ /* 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;
+
+ /* 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;
+ osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
+ fidp, scp, osi_LogSaveString(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_ObtainMutex(&scp->mx);
if (watchtree)
scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
switch (function) {
- case 6:
- return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
- case 4:
- return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
case 1:
return smb_ReceiveNTTranCreate(vcp, inp, outp);
- default:
- return CM_ERROR_INVAL;
+ case 2:
+ osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
+ break;
+ case 3:
+ osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
+ break;
+ case 4:
+ return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
+ case 5:
+ osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
+ break;
+ case 6:
+ return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
}
+ 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,
BOOL twoEntries = FALSE;
ULONG otherNameLen, oldParmCount = 0;
DWORD otherAction;
- smb_vc_t *vcp;
smb_fid_t *fidp;
/* Get ready for rename within directory */
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_LogSaveString(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);
- vcp = watch->vcp;
/*
- * 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(vcp, fid, 0);
+ 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);
+ }
+
+ 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);
smb_ReleaseFID(fidp);
lastWatch = watch;
watch = watch->nextp;
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));
-
+ 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;
lock_ReleaseMutex(&dscp->mx);
/* Convert to response packet */
- ((smb_t *) watch)->reb = 0x80;
+ ((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)
parmCount = 0;
else {
- nameLen = strlen(filename);
+ nameLen = (ULONG)strlen(filename);
parmCount = 3*4 + nameLen*2;
parmCount = (parmCount + 3) & ~3; /* pad to 4 */
if (twoEntries) {
- otherNameLen = strlen(otherFilename);
+ otherNameLen = (ULONG)strlen(otherFilename);
oldParmCount = parmCount;
parmCount += 3*4 + otherNameLen*2;
parmCount = (parmCount + 3) & ~3; /* pad to 4 */
((smb_t *) watch)->errLow = 0;
((smb_t *) watch)->errHigh = 0;
/* Set NT Status codes flag */
- ((smb_t *) watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
+ ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
}
- smb_SendPacket(vcp, watch);
- smb_ReleaseVC(vcp);
+ smb_SendPacket(watch->vcp, watch);
smb_FreePacket(watch);
watch = nextWatch;
}
osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
scp = fidp->scp;
+ osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
lock_ObtainMutex(&scp->mx);
if (watchtree)
scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
((smb_t *)watch)->reh = 0x1;
((smb_t *)watch)->errLow = 0;
((smb_t *)watch)->errHigh = 0xC0;
- ((smb_t *)watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
+ ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
smb_SendPacket(vcp, watch);
- if (watch->vcp)
- smb_ReleaseVC(watch->vcp);
smb_FreePacket(watch);
return 0;
}
{
char *oldPathp, *newPathp;
long code = 0;
- cm_user_t *userp;
char * tp;
int attrs;
int rename_type;
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;
}
lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
}
-cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
+cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
{
- /*int newUid;*/
smb_username_t *unp;
+ cm_user_t * userp;
- unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
+ unp = smb_FindUserByName(usern, machine, flags);
if (!unp->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_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
+ osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(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_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);
- }
- return unp->userp;
+ }
+ userp = unp->userp;
+ cm_HoldUser(userp);
+ smb_ReleaseUsername(unp);
+ return userp;
}