From 237ab6e5ba1e385d70601b48c89a56a409cc3050 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Sat, 22 Apr 2006 20:44:28 +0000 Subject: [PATCH] windows-insert-locking-without-afsid-20060422 This patch disables the lookup of the user's AFSID and instead solves the problem by tracking which cm_user_t created the file. If the user is unable to obtain a write lock and is the creator, then we check for the Insert bit. Otherwise, we deny access. --- src/WINNT/afsd/cm_access.c | 4 +-- src/WINNT/afsd/cm_access.h | 2 +- src/WINNT/afsd/cm_aclent.c | 4 +-- src/WINNT/afsd/cm_aclent.h | 6 ++-- src/WINNT/afsd/cm_ioctl.c | 8 +++-- src/WINNT/afsd/cm_scache.c | 11 +++--- src/WINNT/afsd/cm_scache.h | 53 ++++++++++++--------------- src/WINNT/afsd/cm_user.h | 2 ++ src/WINNT/afsd/cm_vnodeops.c | 25 +++---------- src/WINNT/afsd/smb.c | 27 +++++++++++--- src/WINNT/afsd/smb.h | 2 +- src/WINNT/afsd/smb3.c | 69 +++++++++++++++++++++++++----------- 12 files changed, 122 insertions(+), 91 deletions(-) diff --git a/src/WINNT/afsd/cm_access.c b/src/WINNT/afsd/cm_access.c index b7c50ae549..6720ec24d2 100644 --- a/src/WINNT/afsd/cm_access.c +++ b/src/WINNT/afsd/cm_access.c @@ -32,8 +32,8 @@ * can't be locked. Thus, this must always be called in a while loop to stabilize * things, since we can always lose the race condition getting to the parent vnode. */ -int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *up, long rights, - long *outRightsp) +int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *up, afs_uint32 rights, + afs_uint32 *outRightsp) { cm_scache_t *aclScp; long code; diff --git a/src/WINNT/afsd/cm_access.h b/src/WINNT/afsd/cm_access.h index 7e5933ec7b..b5f7d2af15 100644 --- a/src/WINNT/afsd/cm_access.h +++ b/src/WINNT/afsd/cm_access.h @@ -13,7 +13,7 @@ #include "cm_user.h" extern int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *up, - long rights, long *outRights); + afs_uint32 rights, afs_uint32 *outRights); extern long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *up, struct cm_req *reqp); diff --git a/src/WINNT/afsd/cm_aclent.c b/src/WINNT/afsd/cm_aclent.c index 0a1779fe7f..46799cdfca 100644 --- a/src/WINNT/afsd/cm_aclent.c +++ b/src/WINNT/afsd/cm_aclent.c @@ -68,7 +68,7 @@ static void CleanupACLEnt(cm_aclent_t * aclp) * Get an acl cache entry for a particular user and file, or return that it doesn't exist. * Called with the scp locked. */ -long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp) +long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 *rightsp) { cm_aclent_t *aclp; long retval = -1; @@ -147,7 +147,7 @@ static cm_aclent_t *GetFreeACLEnt(cm_scache_t * scp) * * The scp must be locked when this function is called. */ -long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights) +long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 rights) { register struct cm_aclent *aclp; diff --git a/src/WINNT/afsd/cm_aclent.h b/src/WINNT/afsd/cm_aclent.h index a2091124c7..61eaa6b902 100644 --- a/src/WINNT/afsd/cm_aclent.h +++ b/src/WINNT/afsd/cm_aclent.h @@ -25,7 +25,7 @@ typedef struct cm_aclent { struct cm_aclent *nextp; /* next guy same vnode */ struct cm_scache *backp; /* back ptr to vnode */ struct cm_user *userp; /* user whose access is cached */ - long randomAccess; /* watch for more rights in acl.h */ + afs_uint32 randomAccess; /* watch for more rights in acl.h */ unsigned long tgtLifetime; /* time this expires */ } cm_aclent_t; @@ -33,11 +33,11 @@ extern osi_rwlock_t cm_aclLock; extern long cm_InitACLCache(int newFile, long size); -extern long cm_FindACLCache(struct cm_scache *scp, struct cm_user *userp, long *rightsp); +extern long cm_FindACLCache(struct cm_scache *scp, struct cm_user *userp, afs_uint32 *rightsp); static cm_aclent_t *GetFreeACLEnt(cm_scache_t * scp); -extern long cm_AddACLCache(struct cm_scache *scp, struct cm_user *userp, long rights); +extern long cm_AddACLCache(struct cm_scache *scp, struct cm_user *userp, afs_uint32 rights); extern void cm_FreeAllACLEnts(struct cm_scache *scp); diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index 70b93cbe0c..151350f723 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -1896,6 +1896,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp) return code; } +#ifdef QUERY_AFSID long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid) { afs_int32 code; @@ -1970,7 +1971,7 @@ long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid) return 0; } - +#endif /* QUERY_AFSID */ long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp) { @@ -2088,11 +2089,14 @@ long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp) ucellp->kvno = ct.AuthHandle; ucellp->expirationTime = ct.EndTimestamp; ucellp->gen++; +#ifdef QUERY_AFSID ucellp->uid = ANONYMOUSID; +#endif if (uname) { StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname); - +#ifdef QUERY_AFSID cm_UsernameToId(uname, ucellp, &ucellp->uid); +#endif } ucellp->flags |= CM_UCELLFLAG_RXKAD; lock_ReleaseMutex(&userp->mx); diff --git a/src/WINNT/afsd/cm_scache.c b/src/WINNT/afsd/cm_scache.c index f80f7f775c..c2826926a2 100644 --- a/src/WINNT/afsd/cm_scache.c +++ b/src/WINNT/afsd/cm_scache.c @@ -668,12 +668,12 @@ cm_scache_t * cm_FindSCacheParent(cm_scache_t * scp) * CM_SCACHESYNC_STOREDATA_EXCL and CM_SCACHEFLAG_DATASTORING. */ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *up, cm_req_t *reqp, - long rights, long flags) + afs_uint32 rights, afs_uint32 flags) { osi_queueData_t *qdp; long code; cm_buf_t *tbufp; - long outRights; + afs_uint32 outRights; int bufLocked; /* lookup this first */ @@ -874,7 +874,8 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *up, cm_req_t *reqp, return CM_ERROR_READONLY; if (cm_HaveAccessRights(scp, up, rights, &outRights)) { - if (~outRights & rights) return CM_ERROR_NOACCESS; + if (~outRights & rights) + return CM_ERROR_NOACCESS; } else { /* we don't know the required access rights */ @@ -990,7 +991,7 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *up, cm_req_t *reqp, /* for those syncops that setup for RPCs. * Called with scache locked. */ -void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, long flags) +void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags) { osi_queueData_t *qdp; cm_buf_t *tbufp; @@ -1074,7 +1075,7 @@ void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, long flags) * started before that, can cause old info to be merged from the first call. */ void cm_MergeStatus(cm_scache_t *scp, AFSFetchStatus *statusp, AFSVolSync *volp, - cm_user_t *userp, int flags) + cm_user_t *userp, afs_uint32 flags) { // yj: i want to create some fake status for the /afs directory and the // entries under that directory diff --git a/src/WINNT/afsd/cm_scache.h b/src/WINNT/afsd/cm_scache.h index e111e18bf0..389baac19c 100644 --- a/src/WINNT/afsd/cm_scache.h +++ b/src/WINNT/afsd/cm_scache.h @@ -23,14 +23,6 @@ typedef struct cm_fid { unsigned long unique; } cm_fid_t; -#if 0 -typedef struct cm_accessCache { - osi_queue_t q; /* queue header */ - struct cm_user *userp; /* user having access rights */ - unsigned long rights; /* rights */ -} cm_accessCache_t; -#endif - /* Key used for byte range locking. Each unique key identifies a unique client per cm_scache_t for the purpose of locking. */ typedef afs_uint64 cm_key_t; @@ -94,49 +86,50 @@ typedef struct cm_prefetch { /* last region scanned for prefetching */ #define CM_SCACHE_MAGIC ('S' | 'C'<<8 | 'A'<<16 | 'C'<<24) typedef struct cm_scache { - osi_queue_t q; /* lru queue; cm_scacheLock */ + osi_queue_t q; /* lru queue; cm_scacheLock */ afs_uint32 magic; - struct cm_scache *nextp; /* next in hash; cm_scacheLock */ + struct cm_scache *nextp; /* next in hash; cm_scacheLock */ cm_fid_t fid; - afs_uint32 flags; /* flags; locked by mx */ + afs_uint32 flags; /* flags; locked by mx */ /* synchronization stuff */ - osi_mutex_t mx; /* mutex for this structure */ - osi_rwlock_t bufCreateLock; /* read-locked during buffer creation; - * write-locked to prevent buffers from - * being created during a truncate op, etc. - */ + osi_mutex_t mx; /* mutex for this structure */ + osi_rwlock_t bufCreateLock; /* read-locked during buffer creation; + * write-locked to prevent buffers from + * being created during a truncate op, etc. + */ afs_uint32 refCount; /* reference count; cm_scacheLock */ - osi_queueData_t *bufReadsp; /* queue of buffers being read */ + osi_queueData_t *bufReadsp; /* queue of buffers being read */ osi_queueData_t *bufWritesp; /* queue of buffers being written */ /* parent info for ACLs */ afs_uint32 parentVnode; /* parent vnode for ACL callbacks */ - afs_uint32 parentUnique; /* for ACL callbacks */ + afs_uint32 parentUnique; /* for ACL callbacks */ /* local modification stat */ - afs_uint32 mask; /* for clientModTime, length and - * truncPos */ + afs_uint32 mask; /* for clientModTime, length and + * truncPos */ /* file status */ afs_uint32 fileType; /* file type */ time_t clientModTime; /* mtime */ time_t serverModTime; /* at server, for concurrent call * comparisons */ - osi_hyper_t length; /* file length */ + osi_hyper_t length; /* file length */ cm_prefetch_t prefetch; /* prefetch info structure */ - afs_uint32 unixModeBits; /* unix protection mode bits */ + afs_uint32 unixModeBits; /* unix protection mode bits */ afs_uint32 linkCount; /* link count */ afs_uint32 dataVersion; /* data version */ - afs_uint32 owner; /* file owner */ - afs_uint32 group; /* file owning group */ + afs_uint32 owner; /* file owner */ + afs_uint32 group; /* file owning group */ + cm_user_t *creator; /* user, if new file */ /* pseudo file status */ - osi_hyper_t serverLength; /* length known to server */ + osi_hyper_t serverLength; /* length known to server */ /* aux file status */ - osi_hyper_t truncPos; /* file size to truncate to before - * storing data */ + osi_hyper_t truncPos; /* file size to truncate to before + * storing data */ /* symlink and mount point info */ char mountPointStringp[MOUNTPOINTLEN]; /* the string stored in a mount point; @@ -317,12 +310,12 @@ extern cm_scache_t *cm_GetNewSCache(void); extern int cm_FidCmp(cm_fid_t *, cm_fid_t *); extern long cm_SyncOp(cm_scache_t *, struct cm_buf *, struct cm_user *, - struct cm_req *, long, long); + struct cm_req *, afs_uint32, afs_uint32); -extern void cm_SyncOpDone(cm_scache_t *, struct cm_buf *, long); +extern void cm_SyncOpDone(cm_scache_t *, struct cm_buf *, afs_uint32); extern void cm_MergeStatus(cm_scache_t *, struct AFSFetchStatus *, struct AFSVolSync *, - struct cm_user *, int flags); + struct cm_user *, afs_uint32 flags); extern void cm_AFSFidFromFid(struct AFSFid *, cm_fid_t *); diff --git a/src/WINNT/afsd/cm_user.h b/src/WINNT/afsd/cm_user.h index 19013b1414..361bec1e2e 100644 --- a/src/WINNT/afsd/cm_user.h +++ b/src/WINNT/afsd/cm_user.h @@ -32,7 +32,9 @@ typedef struct cm_ucell { int iterator; /* for use as ListTokens cookie */ long flags; /* flags */ char userName[MAXKTCNAMELEN]; /* user name */ +#ifdef QUERY_AFSID afs_uint32 uid; /* User's AFS ID in this cell */ +#endif } cm_ucell_t; #define CM_UCELLFLAG_HASTIX 1 /* has Kerberos tickets */ diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 9ae2e0b80f..51f807254c 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -2270,6 +2270,7 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp, code = cm_GetSCache(&newFid, &scp, userp, reqp); if (code == 0) { lock_ObtainMutex(&scp->mx); + scp->creator = userp; /* remember who created it */ if (!cm_HaveCallback(scp)) { cm_MergeStatus(scp, &newFileStatus, &volSync, userp, 0); @@ -3434,7 +3435,8 @@ long cm_LockCheckPerms(cm_scache_t * scp, CM_SCACHESYNC_NEEDCALLBACK); if (code == CM_ERROR_NOACCESS && - lock_type == LockWrite) { + lock_type == LockWrite && + scp->creator == userp) { /* check for PRSFS_INSERT. */ cm_ucell_t * ucp; @@ -3442,25 +3444,8 @@ long cm_LockCheckPerms(cm_scache_t * scp, CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK); - if (code) { - if (code == CM_ERROR_NOACCESS) - osi_Log0(afsd_logp, "cm_LockCheckPerms user has no INSERT bits for scp"); - - goto return_code; - } - - code = CM_ERROR_NOACCESS; - - lock_ObtainMutex(&userp->mx); - for (ucp = userp->cellInfop; ucp; ucp = ucp->nextp) { - if (scp->fid.cell == ucp->cellp->cellID) { - if (scp->owner == ucp->uid) - code = 0; - - break; - } - } - lock_ReleaseMutex(&userp->mx); + if (code == CM_ERROR_NOACCESS) + osi_Log0(afsd_logp, "cm_LockCheckPerms user is creator but has no INSERT bits for scp"); } return_code: diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 115a45fe5d..977da1f658 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -5817,6 +5817,16 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp, fidp->flags &= ~SMB_FID_DELONCLOSE; } + /* if this was a newly created file, then clear the creator + * in the stat cache entry. */ + if (fidp->flags & SMB_FID_CREATED) { + lock_ObtainMutex(&fidp->scp->mx); + if (fidp->scp->creator == userp) + fidp->scp->creator = NULL; + lock_ReleaseMutex(&fidp->scp->mx); + fidp->flags &= ~SMB_FID_CREATED; + } + if (fidp->flags & SMB_FID_NTOPEN) { fidp->NTopen_dscp = NULL; fidp->NTopen_pathp = NULL; @@ -6846,6 +6856,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) afs_uint32 dosTime; char *tidPathp; cm_req_t req; + int created = 0; /* the file was new */ cm_InitReq(&req); @@ -6945,11 +6956,13 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) 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, + 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 @@ -6994,6 +7007,10 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) /* always create it open for read/write */ fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE); + /* remember that the file was newly created */ + if (created) + fidp->flags |= SMB_FID_CREATED; + /* save a pointer to the vnode */ fidp->scp = scp; /* and the user */ diff --git a/src/WINNT/afsd/smb.h b/src/WINNT/afsd/smb.h index 30a66a1c29..f25c335b09 100644 --- a/src/WINNT/afsd/smb.h +++ b/src/WINNT/afsd/smb.h @@ -358,7 +358,7 @@ typedef struct smb_fid { #define SMB_FID_OPENREAD 1 /* open for reading */ #define SMB_FID_OPENWRITE 2 /* open for writing */ -#define SMB_FID_UNUSED 4 /* free for use */ +#define SMB_FID_CREATED 4 /* a new file */ #define SMB_FID_IOCTL 8 /* a file descriptor for the * magic ioctl file */ #define SMB_FID_OPENDELETE 0x10 /* open for deletion (NT) */ diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index f7dad97b36..4dfe8ac1c4 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -2062,6 +2062,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op) long returnEALength; char *tidPathp; cm_req_t req; + int created = 0; cm_InitReq(&req); @@ -2280,11 +2281,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op) 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, + 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 @@ -2359,6 +2362,11 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op) fidp->flags |= SMB_FID_OPENREAD; 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); @@ -4515,6 +4523,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) int parmSlot; /* which parm we're dealing with */ char *tidPathp; cm_req_t req; + int created = 0; cm_InitReq(&req); @@ -4697,11 +4706,13 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) 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, + 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 @@ -4757,6 +4768,10 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) 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); @@ -5366,6 +5381,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) char *tidPathp; BOOL foundscp; cm_req_t req; + int created = 0; cm_InitReq(&req); @@ -5798,11 +5814,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) 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)) - 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, + 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 @@ -6027,6 +6045,10 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) 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)) { fidp->flags |= SMB_FID_NTOPEN; @@ -6133,6 +6155,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out ULONG *lparmp; char *outData; cm_req_t req; + int created = 0; cm_InitReq(&req); @@ -6466,11 +6489,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out 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, + 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 @@ -6627,6 +6652,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out 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;