case-sensitivity-20040508
authorJeffrey Altman <jaltman@mit.edu>
Sun, 9 May 2004 05:04:52 +0000 (05:04 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Sun, 9 May 2004 05:04:52 +0000 (05:04 +0000)
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.

src/WINNT/afsd/cm_access.c
src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c

index 9b6e1e3..740ec3e 100644 (file)
@@ -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;
 }
index 6194fbf..81f1f42 100644 (file)
@@ -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 */
index 81ecd22..4ed1c11 100644 (file)
@@ -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);
 
index 1f58192..423ed0a 100644 (file)
@@ -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 */
index 1af1410..9172455 100644 (file)
@@ -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 {