From: Jeffrey Altman Date: Sun, 9 May 2004 05:04:52 +0000 (+0000) Subject: case-sensitivity-20040508 X-Git-Tag: openafs-devel-1_3_64~14 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=98bcba19235a6ff40ba9c3dd1bf4054a870d8a20 case-sensitivity-20040508 Correct the number of parameters to cm_Lookup calls in smb_ReceiveNTCreateX and smb_ReceiveNTTranCreate. Also, do not allow directories to be created if there are any files with names that differ only by case. Miscellaneous reformatting. --- diff --git a/src/WINNT/afsd/cm_access.c b/src/WINNT/afsd/cm_access.c index 9b6e1e3..740ec3e 100644 --- a/src/WINNT/afsd/cm_access.c +++ b/src/WINNT/afsd/cm_access.c @@ -118,43 +118,43 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *up, { long code; cm_fid_t tfid; - cm_scache_t *aclScp; + cm_scache_t *aclScp; /* pretty easy: just force a pass through the fetch status code */ osi_Log2(afsd_logp, "GetAccess scp %x user %x", scp, up); - /* first, start by finding out whether we have a directory or something + /* first, start by finding out whether we have a directory or something * else, so we can find what object's ACL we need. - */ - code = cm_SyncOp(scp, NULL, up, reqp, 0, CM_SCACHESYNC_GETSTATUS - | CM_SCACHESYNC_NEEDCALLBACK); + */ + code = cm_SyncOp(scp, NULL, up, reqp, 0, CM_SCACHESYNC_GETSTATUS + | CM_SCACHESYNC_NEEDCALLBACK); - if (code) return code; + if (code) return code; - if (scp->fileType != CM_SCACHETYPE_DIRECTORY) { + if (scp->fileType != CM_SCACHETYPE_DIRECTORY) { /* not a dir, use parent dir's acl */ tfid.cell = scp->fid.cell; - tfid.volume = scp->fid.volume; - tfid.vnode = scp->parentVnode; - tfid.unique = scp->parentUnique; + tfid.volume = scp->fid.volume; + tfid.vnode = scp->parentVnode; + tfid.unique = scp->parentUnique; lock_ReleaseMutex(&scp->mx); code = cm_GetSCache(&tfid, &aclScp, up, reqp); - if (code) { + if (code) { lock_ObtainMutex(&scp->mx); - return code; - } + return code; + } osi_Log1(afsd_logp, "GetAccess parent %x", aclScp); lock_ObtainMutex(&aclScp->mx); - code = cm_GetCallback(aclScp, up, reqp, 1); - lock_ReleaseMutex(&aclScp->mx); - cm_ReleaseSCache(aclScp); - lock_ObtainMutex(&scp->mx); - } - else { + code = cm_GetCallback(aclScp, up, reqp, 1); + lock_ReleaseMutex(&aclScp->mx); + cm_ReleaseSCache(aclScp); + lock_ObtainMutex(&scp->mx); + } + else { code = cm_GetCallback(scp, up, reqp, 1); - } + } return code; } diff --git a/src/WINNT/afsd/cm_callback.c b/src/WINNT/afsd/cm_callback.c index 6194fbf..81f1f42 100644 --- a/src/WINNT/afsd/cm_callback.c +++ b/src/WINNT/afsd/cm_callback.c @@ -747,14 +747,15 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp, struct cm_req *reqp, long flags) { long code; - cm_conn_t *connp; - AFSFetchStatus afsStatus; - AFSVolSync volSync; - AFSCallBack callback; - AFSFid tfid; - cm_callbackRequest_t cbr; - int mustCall; - long sflags; + cm_conn_t *connp; + AFSFetchStatus afsStatus; + AFSVolSync volSync; + AFSCallBack callback; + AFSFid tfid; + cm_callbackRequest_t cbr; + int mustCall; + long sflags; + cm_fid_t sfid; #ifdef AFS_FREELANCE_CLIENT // yj @@ -762,14 +763,14 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp, // specially. We need to fetch the status by calling // cm_MergeStatus and mark that cm_fakeDirCallback is 2 if (cm_freelanceEnabled && - scp->fid.cell==0x1 && + scp->fid.cell==0x1 && scp->fid.volume==0x20000001 && scp->fid.unique==0x1 && scp->fid.vnode==0x1) { // Start by indicating that we're in the process // of fetching the callback - lock_ObtainMutex(&cm_Freelance_Lock); + lock_ObtainMutex(&cm_Freelance_Lock); cm_fakeGettingCallback = 1; lock_ReleaseMutex(&cm_Freelance_Lock); @@ -798,41 +799,42 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp, while (1) { if (!mustCall && cm_HaveCallback(scp)) return 0; - /* turn off mustCall, since it has now forced us past the check above */ - mustCall = 0; + /* turn off mustCall, since it has now forced us past the check above */ + mustCall = 0; - /* otherwise, we have to make an RPC to get the status */ + /* otherwise, we have to make an RPC to get the status */ sflags = CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK; - cm_SyncOp(scp, NULL, NULL, NULL, 0, sflags); - cm_StartCallbackGrantingCall(scp, &cbr); + cm_SyncOp(scp, NULL, NULL, NULL, 0, sflags); + cm_StartCallbackGrantingCall(scp, &cbr); + sfid = scp->fid; lock_ReleaseMutex(&scp->mx); /* now make the RPC */ osi_Log1(afsd_logp, "CALL FetchStatus vp %x", (long) scp); - do { - code = cm_Conn(&scp->fid, userp, reqp, &connp); - if (code) continue; + do { + code = cm_Conn(&sfid, userp, reqp, &connp); + if (code) continue; - code = RXAFS_FetchStatus(connp->callp, &tfid, - &afsStatus, &callback, &volSync); + code = RXAFS_FetchStatus(connp->callp, &tfid, + &afsStatus, &callback, &volSync); - } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, - &cbr, code)); - code = cm_MapRPCError(code, reqp); + } while (cm_Analyze(connp, userp, reqp, &sfid, &volSync, + &cbr, code)); + code = cm_MapRPCError(code, reqp); osi_Log0(afsd_logp, "CALL FetchStatus DONE"); lock_ObtainMutex(&scp->mx); - cm_SyncOpDone(scp, NULL, sflags); + cm_SyncOpDone(scp, NULL, sflags); if (code == 0) { - cm_EndCallbackGrantingCall(scp, &cbr, &callback, 0); - cm_MergeStatus(scp, &afsStatus, &volSync, userp, 0); - } - else - cm_EndCallbackGrantingCall(NULL, NULL, NULL, 0); - - /* now check to see if we got an error */ - if (code) return code; - } + cm_EndCallbackGrantingCall(scp, &cbr, &callback, 0); + cm_MergeStatus(scp, &afsStatus, &volSync, userp, 0); + } + else + cm_EndCallbackGrantingCall(NULL, NULL, NULL, 0); + + /* now check to see if we got an error */ + if (code) return code; + } } /* called periodically by cm_daemon to shut down use of expired callbacks */ diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 81ecd22..4ed1c11 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -434,37 +434,37 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp, osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp, cm_scache_t **retscp) { - char *tp; - long code; - cm_dirEntry_t *dep; - cm_buf_t *bufferp; - long temp; - osi_hyper_t dirLength; - osi_hyper_t bufferOffset; - osi_hyper_t curOffset; - osi_hyper_t thyper; - long entryInDir; - long entryInBuffer; + char *tp; + long code; + cm_dirEntry_t *dep; + cm_buf_t *bufferp; + long temp; + osi_hyper_t dirLength; + osi_hyper_t bufferOffset; + osi_hyper_t curOffset; + osi_hyper_t thyper; + long entryInDir; + long entryInBuffer; cm_pageHeader_t *pageHeaderp; - int slotInPage; - long nextEntryCookie; - int numDirChunks; /* # of 32 byte dir chunks in this entry */ + int slotInPage; + long nextEntryCookie; + int numDirChunks; /* # of 32 byte dir chunks in this entry */ - /* get the directory size */ + /* get the directory size */ lock_ObtainMutex(&scp->mx); - code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP, - CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP, + CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); if (code) { lock_ReleaseMutex(&scp->mx); - return code; - } + return code; + } - if (scp->fileType != CM_SCACHETYPE_DIRECTORY) { + if (scp->fileType != CM_SCACHETYPE_DIRECTORY) { lock_ReleaseMutex(&scp->mx); return CM_ERROR_NOTDIR; - } + } - if ( retscp ) /* if this is a lookup call */ + if (retscp) /* if this is a lookup call */ { cm_lookupSearch_t* sp = parmp; int casefold = sp->caseFold; @@ -484,163 +484,163 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp, * XXX We only get the length once. It might change when we drop the * lock. */ - dirLength = scp->length; + dirLength = scp->length; lock_ReleaseMutex(&scp->mx); - bufferp = NULL; - bufferOffset.LowPart = bufferOffset.HighPart = 0; + bufferp = NULL; + bufferOffset.LowPart = bufferOffset.HighPart = 0; if (startOffsetp) - curOffset = *startOffsetp; + curOffset = *startOffsetp; else { - curOffset.HighPart = 0; - curOffset.LowPart = 0; - } + curOffset.HighPart = 0; + curOffset.LowPart = 0; + } - while (1) { + while (1) { /* make sure that curOffset.LowPart doesn't point to the first - * 32 bytes in the 2nd through last dir page, and that it + * 32 bytes in the 2nd through last dir page, and that it * doesn't point at the first 13 32-byte chunks in the first * dir page, since those are dir and page headers, and don't * contain useful information. - */ + */ temp = curOffset.LowPart & (2048-1); - if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) { - /* we're in the first page */ - if (temp < 13*32) temp = 13*32; + if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) { + /* we're in the first page */ + if (temp < 13*32) temp = 13*32; } else { /* we're in a later dir page */ - if (temp < 32) temp = 32; - } + if (temp < 32) temp = 32; + } - /* make sure the low order 5 bits are zero */ - temp &= ~(32-1); + /* make sure the low order 5 bits are zero */ + temp &= ~(32-1); - /* now put temp bits back ito curOffset.LowPart */ - curOffset.LowPart &= ~(2048-1); - curOffset.LowPart |= temp; + /* now put temp bits back ito curOffset.LowPart */ + curOffset.LowPart &= ~(2048-1); + curOffset.LowPart |= temp; - /* check if we've passed the dir's EOF */ - if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) + /* check if we've passed the dir's EOF */ + if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break; - /* see if we can use the bufferp we have now; compute in which - * page the current offset would be, and check whether that's + /* see if we can use the bufferp we have now; compute in which + * page the current offset would be, and check whether that's * the offset of the buffer we have. If not, get the buffer. */ - thyper.HighPart = curOffset.HighPart; - thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1); - if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) { + thyper.HighPart = curOffset.HighPart; + thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1); + if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) { /* wrong buffer */ - if (bufferp) { + if (bufferp) { lock_ReleaseMutex(&bufferp->mx); - buf_Release(bufferp); - bufferp = NULL; + buf_Release(bufferp); + bufferp = NULL; } lock_ObtainRead(&scp->bufCreateLock); - code = buf_Get(scp, &thyper, &bufferp); + code = buf_Get(scp, &thyper, &bufferp); lock_ReleaseRead(&scp->bufCreateLock); lock_ObtainMutex(&bufferp->mx); - if (code) break; - bufferOffset = thyper; + if (code) break; + bufferOffset = thyper; - /* now get the data in the cache */ - while (1) { - lock_ObtainMutex(&scp->mx); + /* now get the data in the cache */ + while (1) { + lock_ObtainMutex(&scp->mx); code = cm_SyncOp(scp, bufferp, userp, reqp, - PRSFS_LOOKUP, - CM_SCACHESYNC_NEEDCALLBACK - | CM_SCACHESYNC_READ - | CM_SCACHESYNC_BUFLOCKED); + PRSFS_LOOKUP, + CM_SCACHESYNC_NEEDCALLBACK + | CM_SCACHESYNC_READ + | CM_SCACHESYNC_BUFLOCKED); if (code) { lock_ReleaseMutex(&scp->mx); break; } - if (cm_HaveBuffer(scp, bufferp, 1)) { + if (cm_HaveBuffer(scp, bufferp, 1)) { lock_ReleaseMutex(&scp->mx); break; } - /* otherwise, load the buffer and try again */ - lock_ReleaseMutex(&bufferp->mx); - code = cm_GetBuffer(scp, bufferp, NULL, userp, - reqp); - lock_ReleaseMutex(&scp->mx); - lock_ObtainMutex(&bufferp->mx); - if (code) break; - } - if (code) { + /* otherwise, load the buffer and try again */ + lock_ReleaseMutex(&bufferp->mx); + code = cm_GetBuffer(scp, bufferp, NULL, userp, + reqp); + lock_ReleaseMutex(&scp->mx); + lock_ObtainMutex(&bufferp->mx); + if (code) break; + } + if (code) { lock_ReleaseMutex(&bufferp->mx); buf_Release(bufferp); - bufferp = NULL; - break; + bufferp = NULL; + break; } - } /* if (wrong buffer) ... */ + } /* if (wrong buffer) ... */ - /* now we have the buffer containing the entry we're interested - * in; copy it out if it represents a non-deleted entry. - */ + /* now we have the buffer containing the entry we're interested + * 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 & (buf_bufferSize - 1); /* page header will help tell us which entries are free. Page * header can change more often than once per buffer, since * AFS 3 dir page size may be less than (but not more than) a * buffer package buffer. - */ + */ /* only look intra-buffer */ temp = curOffset.LowPart & (buf_bufferSize - 1); - temp &= ~(2048 - 1); /* turn off intra-page bits */ + temp &= ~(2048 - 1); /* turn off intra-page bits */ pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp); /* now determine which entry we're looking at in the page. If * it is free (there's a free bitmap at the start of the dir), * we should skip these 32 bytes. - */ - slotInPage = (entryInDir & 0x7e0) >> 5; - if (!(pageHeaderp->freeBitmap[slotInPage>>3] - & (1 << (slotInPage & 0x7)))) { + */ + slotInPage = (entryInDir & 0x7e0) >> 5; + if (!(pageHeaderp->freeBitmap[slotInPage>>3] + & (1 << (slotInPage & 0x7)))) { /* this entry is free */ - numDirChunks = 1; /* only skip this guy */ - goto nextEntry; - } + numDirChunks = 1; /* only skip this guy */ + goto nextEntry; + } tp = bufferp->datap + entryInBuffer; - dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */ + dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */ - /* while we're here, compute the next entry's location, too, + /* while we're here, compute the next entry's location, too, * since we'll need it when writing out the cookie into the * dir listing stream. - */ + */ numDirChunks = cm_NameEntries(dep->name, NULL); - /* compute the offset of the cookie representing the next entry */ - nextEntryCookie = curOffset.LowPart + /* compute the offset of the cookie representing the next entry */ + nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks); - if (dep->fid.vnode != 0) { + if (dep->fid.vnode != 0) { /* this is one of the entries to use: it is not deleted */ code = (*funcp)(scp, dep, parmp, &curOffset); - if (code) break; + if (code) break; } /* if we're including this name */ -nextEntry: - /* and adjust curOffset to be where the new cookie is */ + nextEntry: + /* and adjust curOffset to be where the new cookie is */ thyper.HighPart = 0; - thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks; - curOffset = LargeIntegerAdd(thyper, curOffset); - } /* while copying data for dir listing */ + thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks; + curOffset = LargeIntegerAdd(thyper, curOffset); + } /* while copying data for dir listing */ /* release the mutex */ - if (bufferp) { + if (bufferp) { lock_ReleaseMutex(&bufferp->mx); - buf_Release(bufferp); + buf_Release(bufferp); } - return code; + return code; } int cm_NoneUpper(char *s) @@ -673,7 +673,7 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp, matchName = dep->name; if (sp->caseFold) - match = cm_stricmp(matchName, sp->searchNamep); + match = cm_stricmp(matchName, sp->searchNamep); else match = strcmp(matchName, sp->searchNamep); diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 1f58192..423ed0a 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -2067,7 +2067,11 @@ void smb_MapNTError(long code, unsigned long *NTStatusp) NTStatus = 0xC0000023L; /* Buffer too small */ } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) { - NTStatus = 0xC000049CL; /* Potential file found */ +#ifdef COMMENT + NTStatus = 0xC000049CL; /* Potential file found */ +#else + NTStatus = 0xC0000035L; /* Object name collision */ +#endif } else { NTStatus = 0xC0982001L; /* SMB non-specific error */ diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 1af1410..9172455 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -3247,7 +3247,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) | (smb_GetSMBOffsetParm(inp, 20, 1) << 16); /* mustBeDir is never set; createOptions directory bit seems to be - * more important + * more important */ if (createOptions & 1) realDirFlag = 1; @@ -3357,22 +3357,33 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) dscp = NULL; code = 0; /* For an exclusive create, we want to do a case sensitive match for the last component. */ - if (createDisp == 2 || createDisp == 4) { + if (createDisp == 2 || createDisp == 4 || createDisp == 5) { code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &dscp); - if(code == 0) { + if (code == 0) { code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW, - userp, tidPathp, &req, &scp); + userp, &req, &scp); + if (code == CM_ERROR_NOSUCHFILE) { + code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, + CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp); + if (code == 0 && realDirFlag == 1) { + cm_ReleaseSCache(scp); + cm_ReleaseSCache(dscp); + cm_ReleaseUser(userp); + free(realPathp); + return CM_ERROR_EXISTS; + } + } } else dscp = NULL; } else { code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp); } - - if (code == 0) foundscp = TRUE; - if (code != 0 - || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) { + if (code == 0) + 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* * the immediate parent. We have to work our way up realPathp until we hit something that we @@ -3380,35 +3391,37 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) */ if ( !dscp ) { - while(1) { - char *tp; + while (1) { + char *tp; - code = cm_NameI(baseDirp, spacep->data, + code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &dscp); - if (code && - (tp = strrchr(spacep->data,'\\')) && - (createDisp == 2) && - (realDirFlag == 1)) { - *tp++ = 0; - treeCreate = TRUE; - treeStartp = realPathp + (tp - spacep->data); - - if (*tp && !smb_IsLegalFilename(tp)) { - if(baseFid != 0) smb_ReleaseFID(baseFidp); - cm_ReleaseUser(userp); - free(realPathp); - return CM_ERROR_BADNTFILENAME; + if (code && + (tp = strrchr(spacep->data,'\\')) && + (createDisp == 2) && + (realDirFlag == 1)) { + *tp++ = 0; + treeCreate = TRUE; + treeStartp = realPathp + (tp - spacep->data); + + if (*tp && !smb_IsLegalFilename(tp)) { + if(baseFid != 0) + smb_ReleaseFID(baseFidp); + cm_ReleaseUser(userp); + free(realPathp); + return CM_ERROR_BADNTFILENAME; + } } + else + break; } - else - break; - } } else code = 0; - if (baseFid != 0) smb_ReleaseFID(baseFidp); + if (baseFid != 0) + smb_ReleaseFID(baseFidp); if (code) { osi_Log0(smb_logp,"NTCreateX parent not found"); @@ -3417,7 +3430,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return code; } - if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) { + if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) { /* A file exists where we want a directory. */ cm_ReleaseSCache(dscp); cm_ReleaseUser(userp); @@ -3425,8 +3438,10 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return CM_ERROR_EXISTS; } - if (!lastNamep) lastNamep = realPathp; - else lastNamep++; + if (!lastNamep) + lastNamep = realPathp; + else + lastNamep++; if (!smb_IsLegalFilename(lastNamep)) { cm_ReleaseSCache(dscp); @@ -3452,7 +3467,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) } } else { - if (baseFid != 0) smb_ReleaseFID(baseFidp); + if (baseFid != 0) + smb_ReleaseFID(baseFidp); } /* if we get here, if code is 0, the file exists and is represented by @@ -3853,12 +3869,23 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out dscp = NULL; code = 0; - if (createDisp == 2 || createDisp == 4) { + if (createDisp == 2 || createDisp == 4 || createDisp == 5) { code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &dscp); if (code == 0) { code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW, - userp, tidPathp, &req, &scp); + userp, &req, &scp); + if (code == CM_ERROR_NOSUCHFILE) { + code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, + CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp); + if (code == 0 && realDirFlag == 1) { + cm_ReleaseSCache(scp); + cm_ReleaseSCache(dscp); + cm_ReleaseUser(userp); + free(realPathp); + return CM_ERROR_EXISTS; + } + } } else dscp = NULL; } else {