From 9552283298757ca7f44643a5a26cf909e12c589f Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 6 May 2004 16:17:29 +0000 Subject: [PATCH] case-sensitivity-20040506 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 | 6 +- src/WINNT/afsd/cm_dnlc.c | 87 +++++++++++++-------- src/WINNT/afsd/cm_vnodeops.c | 22 ++++-- src/WINNT/afsd/cm_vnodeops.h | 2 +- src/WINNT/afsd/smb.c | 143 ++++++++++++++++++++++++----------- src/WINNT/afsd/smb3.c | 119 ++++++++++++++++++++++------- 6 files changed, 265 insertions(+), 114 deletions(-) diff --git a/src/WINNT/afsd/cm.h b/src/WINNT/afsd/cm.h index fe3fa4274..62fa7f88e 100644 --- a/src/WINNT/afsd/cm.h +++ b/src/WINNT/afsd/cm.h @@ -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__ */ diff --git a/src/WINNT/afsd/cm_dnlc.c b/src/WINNT/afsd/cm_dnlc.c index 57f7b5251..5bfa220be 100644 --- a/src/WINNT/afsd/cm_dnlc.c +++ b/src/WINNT/afsd/cm_dnlc.c @@ -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; diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index e96c41a42..81ecd2211 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -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 ) diff --git a/src/WINNT/afsd/cm_vnodeops.h b/src/WINNT/afsd/cm_vnodeops.h index d4667b192..dfa462422 100644 --- a/src/WINNT/afsd/cm_vnodeops.h +++ b/src/WINNT/afsd/cm_vnodeops.h @@ -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; diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 6abced05e..1f5819253 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -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); diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 44acc8dd4..48939ee2e 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -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); -- 2.39.5