case-sensitivity-20040506
authorJeffrey Altman <jaltman@mit.edu>
Thu, 6 May 2004 16:17:29 +0000 (16:17 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 6 May 2004 16:17:29 +0000 (16:17 +0000)
from asanka@mit.edu

We now strictly prefer exact case matches.  This does incur a
performance penalty because we can no longer be satisfied with an
inexact matches in cache (we make an extra trip to the server to make
sure there aren't any exact matches or pick up the extra match if
there is one).  Of course, the name lookup cache is now case
sensitive.

* cm_dnlc.c : case sensitive name lookup cache
* cm_vnodeops.{c,h} : changes to cm_Lookup to first look for exact matches,
failing which, look for inexact matches.  Also, only put a name in
the name lookup cache iff it exactly matches something on the server.
* smb.c : look for exact matches first.
* smb3.c : as above.  Also T2 Search is used by the SMB client to resolve
filenames.  Respond accordingly.

and:

* added new CM_ERROR_AMBIGUOUS_FILENAME mapped to ERROR_POTENTIAL_FILE_FOUND
  This error is not yet used but is intended for situations in which an
  AFS volume contains two files which differ only by case "Foo" and "FOO"
  and the user says "DEL foo".  Since we do not have an exact match by case
  the existing code deletes one of the two files at random.  In the future
  we want to return an error.

src/WINNT/afsd/cm.h
src/WINNT/afsd/cm_dnlc.c
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_vnodeops.h
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c

index fe3fa42..62fa7f8 100644 (file)
@@ -219,7 +219,6 @@ int RXAFS_Lookup (struct rx_connection *,
 #define CM_ERROR_EXISTS                        (CM_ERROR_BASE+11)
 #define CM_ERROR_CROSSDEVLINK          (CM_ERROR_BASE+12)
 #define CM_ERROR_BADOP                 (CM_ERROR_BASE+13)
-#define CM_ERROR_BADSMB                        (CM_ERROR_BASE+32)
 /* CM_ERROR_BADPASSWORD used to be here */
 #define CM_ERROR_NOTDIR                        (CM_ERROR_BASE+15)
 #define CM_ERROR_ISDIR                 (CM_ERROR_BASE+16)
@@ -236,9 +235,8 @@ int RXAFS_Lookup (struct rx_connection *,
 #define CM_ERROR_REMOTECONN            (CM_ERROR_BASE+27)
 #define CM_ERROR_ATSYS                 (CM_ERROR_BASE+28)
 #define CM_ERROR_NOSUCHPATH            (CM_ERROR_BASE+29)
-
 #define CM_ERROR_CLOCKSKEW             (CM_ERROR_BASE+31)
-
+#define CM_ERROR_BADSMB                        (CM_ERROR_BASE+32)
 #define CM_ERROR_ALLBUSY               (CM_ERROR_BASE+33)
 #define CM_ERROR_NOFILES               (CM_ERROR_BASE+34)
 #define CM_ERROR_PARTIALWRITE          (CM_ERROR_BASE+35)
@@ -247,5 +245,5 @@ int RXAFS_Lookup (struct rx_connection *,
 #define CM_ERROR_BUFFERTOOSMALL                (CM_ERROR_BASE+38)
 #define CM_ERROR_RENAME_IDENTICAL      (CM_ERROR_BASE+39)
 #define CM_ERROR_ALLOFFLINE             (CM_ERROR_BASE+40)
-
+#define CM_ERROR_AMBIGUOUS_FILENAME (CM_ERROR_BASE+41)
 #endif /*  __CM_H_ENV__ */
index 57f7b52..5bfa220 100644 (file)
@@ -153,7 +153,7 @@ cm_dnlcEnter ( adp, aname, avc )
     dnlcstats.enters++;
   
     for (tnc = nameHash[skey], safety=0; tnc; tnc = tnc->next, safety++ )
-       if ((tnc->dirp == adp) && (!cm_stricmp(tnc->name, aname)))
+       if ((tnc->dirp == adp) && (!strcmp(tnc->name, aname)))
            break;                              /* preexisting entry */
        else if ( tnc->next == nameHash[skey])  /* end of list */
        {
@@ -224,39 +224,55 @@ cm_dnlcLookup ( adp, sp)
     lock_ObtainRead(&cm_dnlcLock);
     dnlcstats.lookups++;            /* Is a dnlcread lock sufficient? */
 
+    ts = 0;
     tnc_begin = nameHash[skey];
     for ( tvc = (cm_scache_t *) 0, tnc = tnc_begin, safety=0; 
        tnc; tnc = tnc->next, safety++ ) 
     {
        if (tnc->dirp == adp) 
        {
+        if( cm_debugDnlc ) 
+            osi_Log1(afsd_logp,"Looking at [%s]",
+                     osi_LogSaveString(afsd_logp,tnc->name));
+
            if ( sp->caseFold )         /* case insensitive */
            {
-               match = cm_stricmp(tnc->name, aname);
-               if ( !match )   /* something matches */
-               {
-                       /* determine what type of match it is */
-                       if ( !strcmp(tnc->name, aname))
-                       {       
-                               /* exact match, do nothing */
-                       }
-                       else if ( cm_NoneUpper(tnc->name))
-                               sp->LCfound = 1;
-                       else if ( cm_NoneLower(tnc->name))
-                               sp->UCfound = 1;
-                       else    sp->NCfound = 1;
-                       tvc = tnc->vp; 
-                       break;
-               }
+            match = cm_stricmp(tnc->name, aname);
+            if ( !match )      /* something matches */
+            {
+                tvc = tnc->vp;
+                ts = tnc->name;
+
+                /* determine what type of match it is */
+                if ( !strcmp(tnc->name, aname))
+                {      
+                    /* exact match. */
+                    sp->ExactFound = 1;
+
+                    if( cm_debugDnlc )
+                        osi_Log1(afsd_logp,"DNLC found exact match [%s]",
+                                 osi_LogSaveString(afsd_logp,tnc->name));
+                    break;
+                }
+                else if ( cm_NoneUpper(tnc->name))
+                    sp->LCfound = 1;
+                else if ( cm_NoneLower(tnc->name))
+                    sp->UCfound = 1;
+                else    
+                    sp->NCfound = 1;
+                /* Don't break here. We might find an exact match yet */
+            }
            }
            else                        /* case sensitive */
            {
-               match = strcmp(tnc->name, aname);
-               if ( !match ) /* found a match */
-               {
-                       tvc = tnc->vp; 
-                       break;
-               }
+            match = strcmp(tnc->name, aname);
+            if ( !match ) /* found a match */
+            {
+                sp->ExactFound = 1;
+                tvc = tnc->vp; 
+                ts = tnc->name;
+                break;
+            }
            }
        }
        if (tnc->next == nameHash[skey]) 
@@ -276,24 +292,31 @@ cm_dnlcLookup ( adp, sp)
        }
     }
 
+    if(cm_debugDnlc && ts) {
+        osi_Log3(afsd_logp, "DNLC matched [%s] for [%s] with vnode[%ld]",
+                 osi_LogSaveString(afsd_logp,ts),
+                 osi_LogSaveString(afsd_logp,aname),
+                 (long) tvc->fid.vnode);
+    }
+
     if (!tvc) 
-       dnlcstats.misses++;     /* Is a dnlcread lock sufficient? */
+        dnlcstats.misses++;    /* Is a dnlcread lock sufficient? */
     else 
     {
-       sp->found = 1;
-       sp->fid.vnode  = tvc->fid.vnode; 
-       sp->fid.unique = tvc->fid.unique;       
+        sp->found = 1;
+        sp->fid.vnode  = tvc->fid.vnode; 
+        sp->fid.unique = tvc->fid.unique;      
     }
     lock_ReleaseRead(&cm_dnlcLock);
 
     if (tvc) {
-       lock_ObtainWrite(&cm_scacheLock);
-       tvc->refCount++;        /* scache entry held */
-       lock_ReleaseWrite(&cm_scacheLock);
+        lock_ObtainWrite(&cm_scacheLock);
+        tvc->refCount++;       /* scache entry held */
+        lock_ReleaseWrite(&cm_scacheLock);
     }
 
     if ( cm_debugDnlc && tvc ) 
-       osi_Log1(afsd_logp, "cm_dnlcLookup found %x", tvc);
+        osi_Log1(afsd_logp, "cm_dnlcLookup found %x", tvc);
     
     return tvc;
 }
@@ -355,7 +378,7 @@ cm_dnlcRemove ( adp, aname)
     for (tnc = nameHash[skey], safety=0; tnc; safety++) 
     {
        if ( (tnc->dirp == adp) && (tnc->key == key) 
-                       && !cm_stricmp(tnc->name,aname) )
+                       && !strcmp(tnc->name,aname) )
        {
            tnc->dirp = (cm_scache_t *) 0; /* now it won't match anything */
            tmp = tnc->next;
index e96c41a..81ecd22 100644 (file)
@@ -467,11 +467,17 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
        if (  retscp )                  /* if this is a lookup call */
        {
                cm_lookupSearch_t*      sp = parmp;
+        int casefold = sp->caseFold;
+
+        sp->caseFold = 0; /* we have a strong preference for exact matches */
                if ( *retscp = cm_dnlcLookup(scp, sp))  /* dnlc hit */
                {
+            sp->caseFold = casefold;
                        lock_ReleaseMutex(&scp->mx);
                        return 0;
                }
+
+        sp->caseFold = casefold;
        }       
 
        /*
@@ -659,11 +665,11 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
        osi_hyper_t *offp)
 {
        cm_lookupSearch_t *sp;
-        int match;
+    int match;
        char shortName[13];
        char *matchName;
         
-        sp = rockp;
+    sp = (cm_lookupSearch_t *) rockp;
 
        matchName = dep->name;
        if (sp->caseFold)
@@ -686,12 +692,13 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
                return 0;
 
        sp->found = 1;
+    if(!sp->caseFold) sp->ExactFound = 1;
 
        if (!sp->caseFold || matchName == shortName) {
                sp->fid.vnode = ntohl(dep->fid.vnode);
                sp->fid.unique = ntohl(dep->fid.unique);
-                return CM_ERROR_STOPNOW;
-        }
+        return CM_ERROR_STOPNOW;
+    }
 
        /*
         * If we get here, we are doing a case-insensitive search, and we
@@ -703,10 +710,11 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
        /* Exact matches are the best. */
        match = strcmp(matchName, sp->searchNamep);
        if (match == 0) {
+        sp->ExactFound = 1;
                sp->fid.vnode = ntohl(dep->fid.vnode);
                sp->fid.unique = ntohl(dep->fid.unique);
-                return CM_ERROR_STOPNOW;
-        }
+        return CM_ERROR_STOPNOW;
+    }
 
        /* Lower-case matches are next. */
        if (sp->LCfound)
@@ -1060,7 +1068,7 @@ haveFid:
     *outpScpp = tscp;
 
        /* insert scache in dnlc */
-       if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) ) {
+       if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
            /* lock the directory entry to prevent racing callback revokes */
            lock_ObtainMutex(&dscp->mx);
            if ( dscp->cbServerp && dscp->cbExpires )
index d4667b1..dfa4624 100644 (file)
@@ -33,7 +33,7 @@ typedef struct cm_lookupSearch {
         cm_fid_t fid;
         char *searchNamep;
         int found;
-        int LCfound, UCfound, NCfound;
+        int LCfound, UCfound, NCfound, ExactFound;
         int caseFold;
         int hasTilde;
 } cm_lookupSearch_t;
index 6abced0..1f58192 100644 (file)
@@ -111,6 +111,9 @@ int smb_RawBufSel[SMB_RAW_BUFS];
 char *smb_RawBufs;
 #endif /* DJGPP */
 
+#define SMB_MASKFLAG_TILDE 1
+#define SMB_MASKFLAG_CASEFOLD 2
+
 #define RAWTIMEOUT INFINITE
 
 /* for raw write */
@@ -2063,6 +2066,9 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
        else if (code == CM_ERROR_BUFFERTOOSMALL) {
                NTStatus = 0xC0000023L; /* Buffer too small */
        }
+    else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
+        NTStatus = 0xC000049CL; /* Potential file found */
+    }
        else {
                NTStatus = 0xC0982001L; /* SMB non-specific error */
        }
@@ -3886,7 +3892,7 @@ typedef struct smb_unlinkRock {
        cm_req_t *reqp;
        smb_vc_t *vcp;
        char *maskp;            /* pointer to the star pattern */
-       int hasTilde;
+       int flags;
        int any;
 } smb_unlinkRock_t;
 
@@ -3901,19 +3907,19 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
         
        rockp = vrockp;
 
-       if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
-               caseFold = CM_FLAG_CASEFOLD;
-       else 
-               caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
+    caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
+    if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
+        caseFold |= CM_FLAG_8DOT3;
 
        matchName = dep->name;
        match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
        if (!match
-           && rockp->hasTilde
+           && (rockp->flags & SMB_MASKFLAG_TILDE)
            && !cm_Is8Dot3(dep->name)) {
                cm_Gen8Dot3Name(dep, shortName, NULL);
                matchName = shortName;
-               match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
+        /* 8.3 matches are always case insensitive */
+        match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
        }
        if (match) {
                osi_Log1(smb_logp, "Unlinking %s",
@@ -3923,8 +3929,12 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
                        smb_NotifyChange(FILE_ACTION_REMOVED,
                                                         FILE_NOTIFY_CHANGE_FILE_NAME,
                                                         dscp, dep->name, NULL, TRUE);
-               if (code == 0)
+               if (code == 0) {
                        rockp->any = 1;
+            /* If we made a case sensitive exact match, we might as well quit now. */
+            if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
+                code = CM_ERROR_STOPNOW;
+        }
        }
        else code = 0;
 
@@ -3981,7 +3991,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
        rock.any = 0;
        rock.maskp = smb_FindMask(pathp);
-       rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
+       rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
         
        thyper.LowPart = 0;
        thyper.HighPart = 0;
@@ -3989,7 +3999,25 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        rock.reqp = &req;
        rock.dscp = dscp;
        rock.vcp = vcp;
-       code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
+
+    /* Now, if we aren't dealing with a wildcard match, we first try an exact 
+     * match.  If that fails, we do a case insensitve match. 
+     */
+    if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
+        !smb_IsStarMask(rock.maskp)) {
+        code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
+        if(!rock.any) {
+            thyper.LowPart = 0;
+            thyper.HighPart = 0;
+            rock.flags |= SMB_MASKFLAG_CASEFOLD;
+        }
+    }
+    if (!rock.any)
+        code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
+    
+    if (code == CM_ERROR_STOPNOW) 
+        code = 0;
 
        cm_ReleaseUser(userp);
         
@@ -4007,7 +4035,7 @@ typedef struct smb_renameRock {
        cm_req_t *reqp;         /* request struct */
        smb_vc_t *vcp;          /* virtual circuit */
        char *maskp;            /* pointer to star pattern of old file name */
-       int hasTilde;           /* star pattern might be shortname? */
+       int flags;                  /* tilde, casefold, etc */
        char *newNamep;         /* ptr to the new file's name */
 } smb_renameRock_t;
 
@@ -4021,14 +4049,13 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
         
        rockp = (smb_renameRock_t *) vrockp;
 
-       if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
-               caseFold = CM_FLAG_CASEFOLD;
-       else 
-               caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
+    caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
+    if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
+        caseFold |= CM_FLAG_8DOT3;
 
        match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
        if (!match
-           && rockp->hasTilde
+           && (rockp->flags & SMB_MASKFLAG_TILDE)
            && !cm_Is8Dot3(dep->name)) {
                cm_Gen8Dot3Name(dep, shortName, NULL);
                match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
@@ -4054,11 +4081,12 @@ long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        char *oldPathp;
        char *newPathp;
        char *tp;
-       cm_space_t *spacep;
+       cm_space_t *spacep = NULL;
        smb_renameRock_t rock;
-       cm_scache_t *oldDscp;
-       cm_scache_t *newDscp;
-       cm_scache_t *tmpscp;
+       cm_scache_t *oldDscp = NULL;
+       cm_scache_t *newDscp = NULL;
+       cm_scache_t *tmpscp= NULL;
+       cm_scache_t *tmpscp2 = NULL;
        char *oldLastNamep;
        char *newLastNamep;
        osi_hyper_t thyper;
@@ -4074,7 +4102,7 @@ long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        oldPathp = smb_ParseASCIIBlock(tp, &tp);
        newPathp = smb_ParseASCIIBlock(tp, &tp);
 
-       osi_Log2(smb_logp, "smb rename %s to %s",
+       osi_Log2(smb_logp, "smb rename [%s] to [%s]",
                         osi_LogSaveString(smb_logp, oldPathp),
                         osi_LogSaveString(smb_logp, newPathp));
 
@@ -4130,6 +4158,8 @@ long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                newLastNamep = newPathp;
        else 
                newLastNamep++;
+
+    /* TODO: The old name could be a wildcard.  The new name must not be */
        
        /* do the vnode call */
        rock.odscp = oldDscp;
@@ -4138,28 +4168,43 @@ long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        rock.reqp = &req;
        rock.vcp = vcp;
        rock.maskp = oldLastNamep;
-       rock.hasTilde = ((strchr(oldLastNamep, '~') != NULL) ? 1 : 0);
+       rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
        rock.newNamep = newLastNamep;
 
     /* Check if the file already exists; if so return error */
        code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
-       if((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
-        cm_ReleaseSCache(newDscp);
-        cm_ReleaseSCache(oldDscp);
-        cm_ReleaseUser(userp);
-        if (!code)
-            cm_ReleaseSCache(tmpscp);
+       if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
+        osi_Log2(afsd_logp, "  lookup returns %ld for [%s]", code,
+                 osi_LogSaveString(afsd_logp, newLastNamep));
         /* Check if the old and the new names differ only in case. If so return
          * success, else return CM_ERROR_EXISTS 
          */
-        if(oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
-            osi_Log0(afsd_logp, "Rename: Old and new names are the same");
-            code = 0;
+        if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
+
+            /* This would be a success only if the old file is *as same as* the new file */
+            code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
+            if (!code) {
+                if (tmpscp == tmpscp2) 
+                    code = 0;
+                else 
+                    code = CM_ERROR_EXISTS;
+                cm_ReleaseSCache(tmpscp2);
+                               tmpscp2 = NULL;
+            } else {
+                code = CM_ERROR_NOSUCHFILE;
+            }
         } else {
             /* file exist, do not rename, also fixes move */
             osi_Log0(afsd_logp, "Can't rename.  Target already exists");
             code = CM_ERROR_EXISTS;
         }
+
+               if(tmpscp != NULL)
+            cm_ReleaseSCache(tmpscp);
+        cm_ReleaseSCache(newDscp);
+        cm_ReleaseSCache(oldDscp);
+        cm_ReleaseUser(userp);
            return code; 
        }
 
@@ -4196,7 +4241,9 @@ long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                                                         NULL, TRUE);
        }
 
-       cm_ReleaseUser(userp);
+    if(tmpscp != NULL) 
+        cm_ReleaseSCache(tmpscp);
+    cm_ReleaseUser(userp);
        cm_ReleaseSCache(oldDscp);
        cm_ReleaseSCache(newDscp);
        return code;
@@ -4207,7 +4254,7 @@ typedef struct smb_rmdirRock {
        cm_user_t *userp;
        cm_req_t *reqp;
        char *maskp;            /* pointer to the star pattern */
-       int hasTilde;
+       int flags;
        int any;
 } smb_rmdirRock_t;
 
@@ -4219,12 +4266,15 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
        char shortName[13];
        char *matchName;
         
-       rockp = vrockp;
+       rockp = (smb_rmdirRock_t *) vrockp;
 
        matchName = dep->name;
-       match = (cm_stricmp(matchName, rockp->maskp) == 0);
+    if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
+        match = (cm_stricmp(matchName, rockp->maskp) == 0);
+    else
+        match = (strcmp(matchName, rockp->maskp) == 0);
        if (!match
-           && rockp->hasTilde
+           && (rockp->flags & SMB_MASKFLAG_TILDE)
            && !cm_Is8Dot3(dep->name)) {
                cm_Gen8Dot3Name(dep, shortName, NULL);
                matchName = shortName;
@@ -4290,14 +4340,21 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
        
        rock.any = 0;
        rock.maskp = lastNamep;
-       rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
+       rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
 
        thyper.LowPart = 0;
        thyper.HighPart = 0;
        rock.userp = userp;
        rock.reqp = &req;
        rock.dscp = dscp;
-       code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
+    /* First do a case sensitive match, and if that fails, do a case insensitive match */
+    code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
+    if (code == 0 && !rock.any) {
+        thyper.LowPart = 0;
+        thyper.HighPart = 0;
+        rock.flags |= SMB_MASKFLAG_CASEFOLD;
+        code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
+    }
 
        cm_ReleaseUser(userp);
         
@@ -4358,17 +4415,17 @@ int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
        char shortName[13];
        struct smb_FullNameRock *vrockp;
 
-       vrockp = rockp;
+       vrockp = (struct smb_FullNameRock *)rockp;
 
        if (!cm_Is8Dot3(dep->name)) {
                cm_Gen8Dot3Name(dep, shortName, NULL);
 
-               if (strcmp(shortName, vrockp->name) == 0) {
+               if (cm_stricmp(shortName, vrockp->name) == 0) {
                        vrockp->fullName = strdup(dep->name);
                        return CM_ERROR_STOPNOW;
                }
        }
-       if (stricmp(dep->name, vrockp->name) == 0
+       if (cm_stricmp(dep->name, vrockp->name) == 0
            && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
            && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
                vrockp->fullName = strdup(dep->name);
@@ -5269,7 +5326,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         lastNamep = pathp;
     else 
         lastNamep++;
-    code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
+    code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
     if (scp) cm_ReleaseSCache(scp);
     if (code != CM_ERROR_NOSUCHFILE) {
         if (code == 0) code = CM_ERROR_EXISTS;
@@ -5386,7 +5443,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 #endif    
 
-    code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
+    code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
     if (code && code != CM_ERROR_NOSUCHFILE) {
                cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
index 44acc8d..48939ee 100644 (file)
@@ -1053,7 +1053,7 @@ int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
        /* compare both names and vnodes, though probably just comparing vnodes
         * would be safe enough.
         */
-       if (stricmp(dep->name, rockp->maskp) != 0)
+       if (cm_stricmp(dep->name, rockp->maskp) != 0)
                return 0;
        if (ntohl(dep->fid.vnode) != rockp->vnode)
                return 0;
@@ -1755,6 +1755,7 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
        int sawDot = 0, sawStar = 0, req8dot3 = 0;
        char *starNamep, *starMaskp;
        static char nullCharp[] = {0};
+    int casefold = flags & CM_FLAG_CASEFOLD;
 
        /* make sure we only match 8.3 names, if requested */
     req8dot3 = (flags & CM_FLAG_8DOT3);
@@ -1843,8 +1844,9 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
                                        tcp2 = *maskp++;
 
                                /* skip over characters that don't match tcp2 */
-                               while (req8dot3 && tcn1 != '.' && tcn1 != 0
-                                       && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
+                               while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
+                       ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
+                         (!casefold && tcn1 != tcp2)))
                                        tcn1 = *++namep;
 
                                /* No match */
@@ -1862,7 +1864,8 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
                }
                else {
                        /* tcp1 is not a wildcard */
-                       if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
+            if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
+                (!casefold && tcn1 == tcp1)) {
                                /* they match */
                                namep++;
                                continue;
@@ -1926,6 +1929,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        int align;
        char shortName[13];             /* 8.3 name if needed */
        int NeedShortName;
+    int foundInexact;
        char *shortNameEnd;
     int fileType;
     cm_fid_t fid;
@@ -2075,6 +2079,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return code;
     }
 
+  startsearch:
     dirLength = scp->length;
     bufferp = NULL;
     bufferOffset.LowPart = bufferOffset.HighPart = 0;
@@ -2082,6 +2087,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     curOffset.LowPart = nextCookie;
        origOp = outp->datap;
 
+    foundInexact = 0;
     code = 0;
     returnedNames = 0;
     bytesInBuffer = 0;
@@ -2243,11 +2249,13 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                        NeedShortName = 1;
                }
 
-        if (dep->fid.vnode != 0
-             && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
-                 || (NeedShortName
-                      && smb_V3MatchMask(shortName, maskp,
-                                          CM_FLAG_CASEFOLD)))) {
+        /* When matching, we are using doing a case fold if we have a wildcard mask.
+         * If we get a non-wildcard match, it's a lookup for a specific file. 
+         */
+        if (dep->fid.vnode != 0 && 
+            (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
+              || (NeedShortName
+                   && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
 
             /* Eliminate entries that don't match requested attributes */
             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
@@ -2391,6 +2399,14 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             }
 
                }       /* if we're including this name */
+        else if(!NeedShortName &&
+                 !starPattern &&
+                 !foundInexact &&
+                                                       dep->fid.vnode != 0 &&
+                 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+            /* We were looking for exact matches, but here's an inexact one*/
+            foundInexact = 1;
+        }
                 
       nextEntry:
         /* and adjust curOffset to be where the new cookie is */
@@ -2399,6 +2415,17 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         curOffset = LargeIntegerAdd(thyper, curOffset);
     }          /* while copying data for dir listing */
 
+    /* If we didn't get a star pattern, we did an exact match during the first pass. 
+     * If there were no exact matches found, we fail over to inexact matches by
+     * marking the query as a star pattern (matches all case permutations), and
+     * re-running the query. 
+     */
+    if (returnedNames == 0 && !starPattern && foundInexact) {
+        osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
+        starPattern = 1;
+        goto startsearch;
+    }
+
        /* release the mutex */
        lock_ReleaseMutex(&scp->mx);
     if (bufferp) buf_Release(bufferp);
@@ -3263,17 +3290,30 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
        dscp = NULL;
        code = 0;
-       code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                       userp, tidPathp, &req, &scp);
-       if (code == 0) foundscp = TRUE;
+    /* For an exclusive create, we want to do a case sensitive match for the last component. */
+    if (createDisp == 2 || createDisp == 4) {
+        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);
+        } 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))) {
                /* 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
-        recognize.
-        */
+         * the immediate parent.  We have to work our way up realPathp until we hit something that we
+         * recognize.
+         */
 
+        if ( !dscp ) {
         while(1) {
             char *tp;
 
@@ -3299,6 +3339,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             else
                 break;
         }
+        } else
+            code = 0;
 
         if (baseFid != 0) smb_ReleaseFID(baseFidp);
 
@@ -3328,9 +3370,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
 
         if (!foundscp && !treeCreate) {
-                       code = cm_Lookup(dscp, lastNamep,
-                                        CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                                        userp, &req, &scp);
+            if(createDisp == 2 || createDisp == 4)
+                code = cm_Lookup(dscp, lastNamep,
+                                  CM_FLAG_FOLLOW, userp, &req, &scp);
+            else
+                code = cm_Lookup(dscp, lastNamep,
+                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                                 userp, &req, &scp);
                        if (code && code != CM_ERROR_NOSUCHFILE) {
                                cm_ReleaseSCache(dscp);
                                cm_ReleaseUser(userp);
@@ -3741,16 +3787,31 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
        dscp = NULL;
        code = 0;
-       code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                       userp, tidPathp, &req, &scp);
+    if (createDisp == 2 || createDisp == 4) {
+        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);
+        } 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))) {
                /* look up parent directory */
-               code = cm_NameI(baseDirp, spacep->data,
-                               CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                               userp, tidPathp, &req, &dscp);
-               cm_FreeSpace(spacep);
+        if ( !dscp ) {
+            code = cm_NameI(baseDirp, spacep->data,
+                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                             userp, tidPathp, &req, &dscp);
+        } else
+            code = 0;
+        
+        cm_FreeSpace(spacep);
 
                if (baseFid != 0) {
            smb_ReleaseFID(baseFidp);
@@ -3770,9 +3831,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
             return CM_ERROR_BADNTFILENAME;
 
                if (!foundscp) {
-                       code = cm_Lookup(dscp, lastNamep,
-                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                             userp, &req, &scp);
+            if (createDisp == 2 || createDisp == 4)
+                code = cm_Lookup(dscp, lastNamep,
+                                 CM_FLAG_FOLLOW, userp, &req, &scp);
+            else
+                code = cm_Lookup(dscp, lastNamep,
+                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                                 userp, &req, &scp);
                        if (code && code != CM_ERROR_NOSUCHFILE) {
                                cm_ReleaseSCache(dscp);
                                cm_ReleaseUser(userp);