#include <afs/param.h>
#include <afs/stds.h>
-#ifndef DJGPP
#include <windows.h>
#include <ntstatus.h>
#define SECURITY_WIN32
#include <security.h>
#include <lmaccess.h>
-#endif /* !DJGPP */
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
/* We sometimes see 0 word count. What to do? */
if (*inp->wctp == 0) {
osi_Log0(smb_logp, "Transaction2 word count = 0");
-#ifndef DJGPP
LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
-#endif /* !DJGPP */
smb_SetSMBDataLength(outp, 0);
smb_SendPacket(vcp, outp);
char * cstrp;
char thisShare[256];
int i,j;
+ DWORD dw;
int nonrootShares;
smb_rap_share_list_t rootShares;
cm_req_t req;
}
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 */
/* We sometimes see 0 word count. What to do? */
if (*inp->wctp == 0) {
osi_Log0(smb_logp, "Transaction2 word count = 0");
-#ifndef DJGPP
LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
-#endif /* !DJGPP */
smb_SetSMBDataLength(outp, 0);
smb_SendPacket(vcp, outp);
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (!excl && code == CM_ERROR_EXISTS) {
/* not an exclusive create, and someone else tried
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;
+ fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
if (openMode == 1 || openMode == 2)
fidp->flags |= SMB_FID_OPENWRITE;
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;
- 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]);
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 SMB_QUERY_FS_SIZE_INFO:
* we can't handle long (non-8.3) names,
* despite our protestations to the contrary.
*/
- qi.u.FSattributeInfo.attributes = 0x4013;
- qi.u.FSattributeInfo.maxCompLength = 255;
- qi.u.FSattributeInfo.FSnameLength = 6;
- memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
+ qi.u.FSattributeInfo.attributes = 0x4003;
+ qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
+ qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
+ memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
break;
}
cm_user_t *userp;
cm_space_t *spacep;
cm_scache_t *scp, *dscp;
- smb_fid_t *fidp;
- unsigned short fid;
+ int scp_mx_held = 0;
int delonclose = 0;
long code = 0;
char *pathp;
cm_InitReq(&req);
- fid = p->parmsp[0];
- fidp = smb_FindFID(vcp, fid, 0);
- if (fidp) {
- lock_ObtainMutex(&fidp->mx);
- delonclose = fidp->flags & SMB_FID_DELONCLOSE;
- lock_ReleaseMutex(&fidp->mx);
- smb_ReleaseFID(fidp);
- fidp = NULL;
- }
-
infoLevel = p->parmsp[0];
if (infoLevel == SMB_INFO_IS_NAME_VALID)
responseSize = 0;
else {
osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
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.
goto done;
}
- qpi.u.QPfileAltNameInfo.fileNameLength = len * 2;
- mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len);
+ qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
+ mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
goto done;
}
else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
len = strlen(lastComp);
- qpi.u.QPfileNameInfo.fileNameLength = len * 2;
- mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len);
+ qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
+ mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
goto done;
}
qpi.u.QPfileBasicInfo.changeTime = ft;
extAttributes = smb_ExtAttributes(scp);
qpi.u.QPfileBasicInfo.attributes = extAttributes;
+ qpi.u.QPfileBasicInfo.reserved = 0;
}
else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+ 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.deletePending = (delonclose ? 1 : 0);
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) {
qpi.u.QPfileEaInfo.eaSize = 0;
qpi.u.QPfileAllInfo.mode = 0;
qpi.u.QPfileAllInfo.alignmentRequirement = 0;
len = strlen(lastComp);
- qpi.u.QPfileAllInfo.fileNameLength = len * 2;
- mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len);
+ 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) {
return CM_ERROR_BADOP;
#else
long code = 0;
- unsigned short fid;
smb_fid_t *fidp;
unsigned short infoLevel;
+ char * pathp;
smb_tran2Packet_t *outp;
smb_tran2QPathInfo_t *spi;
cm_user_t *userp;
- cm_scache_t *scp;
+ 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];
- osi_Log2(smb_logp,"ReceiveTran2SetPathInfo type 0x%x fid %d", infoLevel, fid);
+ 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, CM_ERROR_BAD_LEVEL);
+ return 0;
+ }
+
+ 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,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
+ code = CM_ERROR_BADSMB;
+ goto done;
+ }
+
+ code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+ if (code == CM_ERROR_TIDIPC) {
+ /* Attempt to use a TID allocated for IPC. The client
+ * is probably looking for DCE RPC end points which we
+ * don't support OR it could be looking to make a DFS
+ * referral request.
+ */
+ osi_Log0(smb_logp, "Tran2Open received IPC TID");
+ cm_ReleaseUser(userp);
+ return CM_ERROR_NOSUCHPATH;
+ }
+
+ /*
+ * XXX Strange hack XXX
+ *
+ * As of Patch 7 (13 January 98), we are having the following problem:
+ * In NT Explorer 4.0, whenever we click on a directory, AFS gets
+ * requests to look up "desktop.ini" in all the subdirectories.
+ * This can cause zillions of timeouts looking up non-existent cells
+ * and volumes, especially in the top-level directory.
+ *
+ * We have not found any way to avoid this or work around it except
+ * to explicitly ignore the requests for mount points that haven't
+ * yet been evaluated and for directories that haven't yet been
+ * fetched.
+ */
+ if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+ spacep = cm_GetSpace();
+ smb_StripLastComponent(spacep->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) {
+ if ( WANTS_DFS_PATHNAMES(p) )
+ 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);
+ else
+ code = CM_ERROR_NOSUCHFILE;
+ }
+ cm_ReleaseSCache(dscp);
+ if (code) {
+ cm_FreeSpace(spacep);
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ return 0;
+ }
+ }
+ }
+ }
+#endif /* SPECIAL_FOLDERS */
+
+ cm_FreeSpace(spacep);
+ }
+
+ /* now do namei and stat, and copy out the info */
+ code = cm_NameI(cm_data.rootSCachep, pathp,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ return 0;
+ }
+
+ 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;
}
-
- scp = fidp->scp;
- cm_HoldSCache(scp);
lock_ReleaseMutex(&fidp->mx);
outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
outp->totalParms = 2;
outp->totalData = 0;
- userp = smb_GetTran2User(vcp, p);
- if (!userp) {
- osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
- code = CM_ERROR_BADSMB;
- goto done;
- }
-
spi = (smb_tran2QPathInfo_t *)p->datap;
if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
cm_attr_t attr;
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_NEEDCALLBACK);
- lock_ReleaseMutex(&scp->mx);
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);
else {
osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
p->opcode, infoLevel);
- smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
smb_ReleaseFID(fidp);
return 0;
}
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);
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.
*/
name = "\\"; /* probably can't happen */
lock_ReleaseMutex(&fidp->mx);
len = (unsigned long)strlen(name);
- outp->totalData = (len*2) + 4; /* this is actually what we want to return */
- qfi.u.QFfileNameInfo.fileNameLength = len * 2;
- mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len);
+ 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 */
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);
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, opx, CM_ERROR_BADOP);
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
smb_ReleaseFID(fidp);
return 0;
}
lock_ObtainMutex(&fidp->mx);
- if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
+ 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);
if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
&& !(fidp->flags & SMB_FID_OPENWRITE)) {
+ osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
+ fidp, fidp->scp, fidp->flags);
lock_ReleaseMutex(&fidp->mx);
smb_ReleaseFID(fidp);
smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
}
scp = fidp->scp;
+ osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
cm_HoldSCache(scp);
lock_ReleaseMutex(&fidp->mx);
code = cm_SyncOp(scp, NULL, userp, &req, 0,
CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_NEEDCALLBACK);
- lock_ReleaseMutex(&scp->mx);
- if (code)
+ 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);
code = 0;
}
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);
lock_ObtainMutex(&fidp->mx);
fidp->flags |= SMB_FID_DELONCLOSE;
lock_ReleaseMutex(&fidp->mx);
+ } else {
+ osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
+ fidp, scp, code);
}
}
else {
lock_ReleaseMutex(&fidp->mx);
}
}
- else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO) {
+ 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.length.HighPart = size.HighPart;
code = cm_SetAttr(scp, &attr, userp, &req);
}
- else if (infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
- unsigned short size = *((unsigned short *)(p->datap));
- cm_attr_t attr;
-
- attr.mask = CM_ATTRMASK_LENGTH;
- attr.length.HighPart = 0;
- attr.length.LowPart = size;
- code = cm_SetAttr(scp, &attr, userp, &req);
- }
done:
cm_ReleaseSCache(scp);
unsigned long lattr;
smb_dirListPatch_t *patchp;
smb_dirListPatch_t *npatchp;
-
+ afs_uint32 rights;
+ afs_int32 mustFake = 0;
+
+ 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;
+ code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+ 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;
*((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:
+ *((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) {
}
#endif /* USE_OLD_MATCHING */
+/* smb_ReceiveTran2SearchDir implements both
+ * Tran2_Find_First and Tran2_Find_Next
+ */
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
+#define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
+#define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
+#define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
+
+/* this is an optimized handler for T2SearchDir that handles the case
+ where there are no wildcards in the search path. I.e. an
+ application is using FindFirst(Ex) to get information about a
+ single file or directory. It will attempt to do a single lookup.
+ If that fails, then smb_ReceiveTran2SearchDir() will fall back to
+ the usual mechanism.
+
+ This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
+ */
+long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+{
+ int attribute;
+ long nextCookie;
+ long code = 0, code2 = 0;
+ char *pathp;
+ 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;
+ int align;
+ char shortName[13]; /* 8.3 name if needed */
+ int NeedShortName;
+ char *shortNameEnd;
+ cm_req_t req;
+ char * s;
+
+ cm_InitReq(&req);
+
+ eos = 0;
+ osi_assert(p->opcode == 1);
+
+ /* 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, "T2 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;
+ }
+
+ code = cm_NameI(cm_data.rootSCachep, spacep->data,
+ CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+ userp, tidPathp, &req, &scp);
+ cm_FreeSpace(spacep);
+
+ if (code) {
+ cm_ReleaseUser(userp);
+ smb_SendTran2Error(vcp, p, opx, code);
+ smb_FreeTran2Packet(outp);
+ return 0;
+ }
+
+#ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
+ if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if ( WANTS_DFS_PATHNAMES(p) )
+ 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,"smb_ReceiveTran2SearchDir scp 0x%p", scp);
+ lock_ObtainMutex(&scp->mx);
+ if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
+ LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
+ scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
+ }
+ lock_ReleaseMutex(&scp->mx);
+
+ /* 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_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) {
+ 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);
+ }
+ }
+
+ /* 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 */
+ curPatchp->dep = NULL;
+ }
+
+ 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, 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) {
+ if (code)
+ smb_SendTran2Error(vcp, p, opx, code);
+ else
+ smb_SendTran2Packet(vcp, outp, opx);
+ code = 0;
+ }
+
+ skip_file:
+ smb_FreeTran2Packet(outp);
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(targetscp);
+ cm_ReleaseUser(userp);
+
+ return code;
+}
+
+
long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
{
int attribute;
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) {
+ return code;
+ }
+ }
+#endif
+
+ dsp = smb_NewDirSearch(1);
+ dsp->attribute = attribute;
+ strcpy(dsp->mask, maskp); /* and save mask */
}
else {
osi_assert(p->opcode == 2);
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 >= SMB_FIND_FILE_DIRECTORY_INFO)
- searchFlags &= ~4; /* no resume keys */
+ searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
dirListPatchesp = NULL;
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 {
}
#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
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;
if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
/* Don't bulk stat if risking timeout */
- int now = GetTickCount();
+ DWORD now = GetTickCount();
if (now - req.startTime > RDRtimeout) {
scp->bulkStatProgress = thyper;
scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
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;
"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");
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 */
}
curPatchp->dep = dep;
}
- if (searchFlags & 4)
+ if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
/* put out resume key */
*((u_long *)origOp) = nextEntryCookie;
* 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)
+ 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.
* 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
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (!excl && code == CM_ERROR_EXISTS) {
/* not an exclusive create, and someone else tried
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;
+ fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
if (openMode == 1 || openMode == 2)
fidp->flags |= SMB_FID_OPENWRITE;
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);
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)) {
code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
userp, &req, &lockp);
+ if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
+ (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
+ {
+ code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
+ userp, &req, &lockp);
+ }
+
if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
smb_waitingLock_t * wLock;
wlRequest->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);
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);
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
* searchTime variable. So we take the high-order bits first.
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);
code = 0;
while ( code == 0 && count > 0 ) {
-#ifndef DJGPP
code = smb_WriteData(fidp, &offset, count, op, userp, &written);
-#else /* DJGPP */
- code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
-#endif /* !DJGPP */
if (code == 0 && written == 0)
code = CM_ERROR_PARTIALWRITE;
smb_SetSMBDataLength(outp, 0);
done:
- smb_ReleaseFID(fidp);
cm_ReleaseUser(userp);
+ smb_ReleaseFID(fidp);
return code;
}
/* 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;
}
BOOL foundscp;
cm_req_t req;
int created = 0;
+ cm_lock_data_t *ldp = NULL;
cm_InitReq(&req);
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;
/* and the share mode */
if (shareAccess & FILE_SHARE_READ)
treeStartp = realPathp + (tp - spacep->data);
if (*tp && !smb_IsLegalFilename(tp)) {
+ cm_ReleaseUser(userp);
if (baseFidp)
smb_ReleaseFID(baseFidp);
- cm_ReleaseUser(userp);
free(realPathp);
if (scp)
cm_ReleaseSCache(scp);
* scp is NULL.
*/
if (code == 0 && !treeCreate) {
- code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
if (code) {
if (dscp)
cm_ReleaseSCache(dscp);
if (createDisp == FILE_CREATE) {
/* oops, file shouldn't be there */
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (dscp)
cm_ReleaseSCache(dscp);
if (scp)
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
scp = targetScp;
- }
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+ if (code) {
+ 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 */
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
/* Not an exclusive create, and someone else tried
if (code) {
/* something went wrong creating or truncating the file */
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (scp)
cm_ReleaseSCache(scp);
if (dscp)
* we'll just use the symlink anyway.
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
+ if (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);
/* (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);
LLength.HighPart = 0;
LLength.LowPart = SMB_FID_QLOCK_LENGTH;
- if (fidflags & SMB_FID_SHARE_READ) {
+ /* If we are not opening the file for writing, then we don't
+ try to get an exclusive lock. 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;
lock_ReleaseMutex(&scp->mx);
if (code) {
- /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
- smb_CloseFID(vcp, fidp, NULL, 0);
- smb_ReleaseFID(fidp);
-
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
if (dscp)
cm_ReleaseSCache(dscp);
- cm_ReleaseUser(userp);
+ cm_ReleaseUser(userp);
+ /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
free(realPathp);
-
return code;
}
}
+ /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+
lock_ObtainMutex(&fidp->mx);
/* save a pointer to the vnode */
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;
/* 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;
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 */
char *outData;
cm_req_t req;
int created = 0;
+ cm_lock_data_t *ldp = NULL;
cm_InitReq(&req);
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;
/* And the share mode */
if (shareAccess & FILE_SHARE_READ)
* 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 (createDisp == FILE_CREATE) {
/* oops, file shouldn't be there */
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
if (dscp)
cm_ReleaseSCache(dscp);
cm_ReleaseSCache(scp);
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
scp = targetScp;
+ code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+ if (code) {
+ if (dscp)
+ cm_ReleaseSCache(dscp);
+ if (scp)
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ free(realPathp);
+ return code;
+ }
}
}
code = cm_SetAttr(scp, &setAttr, userp, &req);
created = 1;
if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(FILE_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
dscp, lastNamep, NULL, TRUE);
} else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
/* Not an exclusive create, and someone else tried
if (code) {
/* something went wrong creating or truncating the file */
- if (scp)
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+ if (scp)
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
free(realPathp);
*/
osi_Log2(smb_logp, "symlink vp %x to vp %x",
scp, targetScp);
+ if (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);
LLength.HighPart = 0;
LLength.LowPart = SMB_FID_QLOCK_LENGTH;
- if (fidflags & SMB_FID_SHARE_READ) {
+ /* Similar to what we do in handling NTCreateX. We get a
+ shared lock if we are only opening the file for reading. */
+ if ((fidflags & SMB_FID_SHARE_READ) ||
+ !(fidflags & SMB_FID_OPENWRITE)) {
sLockType = LOCKING_ANDX_SHARED_LOCK;
} else {
sLockType = 0;
lock_ReleaseMutex(&scp->mx);
if (code) {
- /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
- smb_CloseFID(vcp, fidp, NULL, 0);
- smb_ReleaseFID(fidp);
-
+ if (ldp)
+ cm_CheckNTOpenDone(scp, userp, &req, &ldp);
cm_ReleaseSCache(scp);
cm_ReleaseUser(userp);
- free(realPathp);
-
+ /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ free(realPathp);
return CM_ERROR_SHARING_VIOLATION;
}
}
+ /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
+ if (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;
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;
osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
- smb_ReleaseFID(fidp);
-
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;
}
+ /* 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;
*
* 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,
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);
/*
- * Strange hack - bug in NT Client and NT Server that we
- * must emulate?
+ * Strange hack - bug in NT Client and NT Server that we must emulate?
*/
- if (filter == 3 && wtree)
- filter = 0x17;
+ if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
+ filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
fidp = smb_FindFID(watch->vcp, fid, 0);
if (!fidp) {
- osi_Log1(smb_logp," no fidp for fid[%d]",fid);
+ osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
lastWatch = watch;
watch = watch->nextp;
continue;
if (fidp->scp != dscp
|| (filter & notifyFilter) == 0
|| (!isDirectParent && !wtree)) {
- osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
+ 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;
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;
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;
}