1998-08-17 11:40:06 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
filename handling routines
Copyright ( C ) Andrew Tridgell 1992 - 1998
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
extern int DEBUGLEVEL ;
extern BOOL case_sensitive ;
extern BOOL case_preserve ;
extern BOOL short_case_preserve ;
extern fstring remote_machine ;
extern BOOL use_mangled_map ;
1998-09-05 09:07:05 +04:00
static BOOL scan_directory ( char * path , char * name , connection_struct * conn , BOOL docache ) ;
1998-08-17 11:40:06 +04:00
/****************************************************************************
1998-08-28 00:38:53 +04:00
Check if two filenames are equal .
This needs to be careful about whether we are case sensitive .
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-05 09:07:05 +04:00
static BOOL fname_equal ( char * name1 , char * name2 )
1998-08-17 11:40:06 +04:00
{
int l1 = strlen ( name1 ) ;
int l2 = strlen ( name2 ) ;
/* handle filenames ending in a single dot */
if ( l1 - l2 = = 1 & & name1 [ l1 - 1 ] = = ' . ' & & lp_strip_dot ( ) )
{
BOOL ret ;
name1 [ l1 - 1 ] = 0 ;
ret = fname_equal ( name1 , name2 ) ;
name1 [ l1 - 1 ] = ' . ' ;
return ( ret ) ;
}
if ( l2 - l1 = = 1 & & name2 [ l2 - 1 ] = = ' . ' & & lp_strip_dot ( ) )
{
BOOL ret ;
name2 [ l2 - 1 ] = 0 ;
ret = fname_equal ( name1 , name2 ) ;
name2 [ l2 - 1 ] = ' . ' ;
return ( ret ) ;
}
/* now normal filename handling */
if ( case_sensitive )
return ( strcmp ( name1 , name2 ) = = 0 ) ;
return ( strequal ( name1 , name2 ) ) ;
}
/****************************************************************************
1998-08-28 00:38:53 +04:00
Mangle the 2 nd name and check if it is then equal to the first name .
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-05 09:07:05 +04:00
static BOOL mangled_equal ( char * name1 , char * name2 )
1998-08-17 11:40:06 +04:00
{
pstring tmpname ;
if ( is_8_3 ( name2 , True ) )
return ( False ) ;
pstrcpy ( tmpname , name2 ) ;
1998-09-03 07:14:31 +04:00
mangle_name_83 ( tmpname ) ;
1998-08-17 11:40:06 +04:00
return ( strequal ( name1 , tmpname ) ) ;
}
1998-08-28 00:38:53 +04:00
/****************************************************************************
Stat cache code used in unix_convert .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int global_stat_cache_lookups ;
static int global_stat_cache_misses ;
static int global_stat_cache_hits ;
/****************************************************************************
Stat cache statistics code .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void print_stat_cache_statistics ( void )
{
1998-08-28 00:51:12 +04:00
double eff = ( 100.0 * ( double ) global_stat_cache_hits ) / ( double ) global_stat_cache_lookups ;
1998-08-28 00:38:53 +04:00
DEBUG ( 0 , ( " stat cache stats: lookups = %d, hits = %d, misses = %d, \
stat cache was % f % % effective . \ n " , global_stat_cache_lookups,
global_stat_cache_hits , global_stat_cache_misses , eff ) ) ;
}
typedef struct {
ubi_dlNode link ;
int name_len ;
pstring orig_name ;
pstring translated_name ;
} stat_cache_entry ;
# define MAX_STAT_CACHE_SIZE 50
static ubi_dlList stat_cache = { NULL , ( ubi_dlNodePtr ) & stat_cache , 0 } ;
/****************************************************************************
1998-08-29 01:46:29 +04:00
Compare a pathname to a name in the stat cache - of a given length .
Note - this code always checks that the next character in the pathname
is either a ' / ' character , or a ' \0 ' character - to ensure we only
1998-09-10 04:35:10 +04:00
match * full * pathname components . Note we don ' t need to handle case
here , if we ' re case insensitive the stat cache orig names are all upper
case .
1998-08-28 00:38:53 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-29 01:46:29 +04:00
static BOOL stat_name_equal_len ( char * stat_name , char * orig_name , int len )
1998-08-28 00:38:53 +04:00
{
1998-09-10 04:35:10 +04:00
BOOL matched = ( memcmp ( stat_name , orig_name , len ) = = 0 ) ;
1998-08-29 01:46:29 +04:00
if ( orig_name [ len ] ! = ' / ' & & orig_name [ len ] ! = ' \0 ' )
return False ;
return matched ;
1998-08-28 00:38:53 +04:00
}
/****************************************************************************
Add an entry into the stat cache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void stat_cache_add ( char * full_orig_name , char * orig_translated_path )
{
stat_cache_entry * scp ;
pstring orig_name ;
pstring translated_path ;
1998-09-06 05:37:14 +04:00
int namelen ;
if ( ! lp_stat_cache ( ) ) return ;
namelen = strlen ( orig_translated_path ) ;
1998-08-28 00:38:53 +04:00
/*
* Don ' t cache trivial valid directory entries .
*/
1998-09-19 07:34:12 +04:00
if ( ( * full_orig_name = = ' \0 ' ) | | ( strcmp ( full_orig_name , " . " ) = = 0 ) | |
( strcmp ( full_orig_name , " .. " ) = = 0 ) )
1998-08-28 00:38:53 +04:00
return ;
/*
* If we are in case insentive mode , we need to
* store names that need no translation - else , it
* would be a waste .
*/
if ( case_sensitive & & ( strcmp ( full_orig_name , orig_translated_path ) = = 0 ) )
return ;
/*
* Remove any trailing ' / ' characters from the
* translated path .
*/
pstrcpy ( translated_path , orig_translated_path ) ;
if ( translated_path [ namelen - 1 ] = = ' / ' ) {
translated_path [ namelen - 1 ] = ' \0 ' ;
namelen - - ;
}
/*
* We will only replace namelen characters
* of full_orig_name .
* StrnCpy always null terminates .
*/
StrnCpy ( orig_name , full_orig_name , namelen ) ;
1998-09-10 04:35:10 +04:00
if ( ! case_sensitive )
strupper ( orig_name ) ;
1998-08-28 00:38:53 +04:00
/*
* Check this name doesn ' t exist in the cache before we
* add it .
*/
for ( scp = ( stat_cache_entry * ) ubi_dlFirst ( & stat_cache ) ; scp ;
scp = ( stat_cache_entry * ) ubi_dlNext ( scp ) ) {
1998-09-10 04:35:10 +04:00
if ( ( strcmp ( scp - > orig_name , orig_name ) = = 0 ) & &
1998-08-28 00:38:53 +04:00
( strcmp ( scp - > translated_name , translated_path ) = = 0 ) ) {
/*
* Name does exist - promote it .
*/
if ( ( stat_cache_entry * ) ubi_dlFirst ( & stat_cache ) ! = scp ) {
ubi_dlRemThis ( & stat_cache , scp ) ;
ubi_dlAddHead ( & stat_cache , scp ) ;
}
return ;
}
}
if ( ( scp = ( stat_cache_entry * ) malloc ( sizeof ( stat_cache_entry ) ) ) = = NULL ) {
DEBUG ( 0 , ( " stat_cache_add: Out of memory ! \n " ) ) ;
return ;
}
pstrcpy ( scp - > orig_name , orig_name ) ;
pstrcpy ( scp - > translated_name , translated_path ) ;
scp - > name_len = namelen ;
ubi_dlAddHead ( & stat_cache , scp ) ;
DEBUG ( 10 , ( " stat_cache_add: Added entry %s -> %s \n " , scp - > orig_name , scp - > translated_name ) ) ;
1998-08-29 01:46:29 +04:00
if ( ubi_dlCount ( & stat_cache ) > lp_stat_cache_size ( ) ) {
1998-08-28 00:38:53 +04:00
scp = ( stat_cache_entry * ) ubi_dlRemTail ( & stat_cache ) ;
free ( ( char * ) scp ) ;
return ;
}
}
/****************************************************************************
Look through the stat cache for an entry - promote it to the top if found .
Return True if we translated ( and did a scuccessful stat on ) the entire name .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-02 00:11:54 +04:00
static BOOL stat_cache_lookup ( char * name , char * dirpath , char * * start , SMB_STRUCT_STAT * pst )
1998-08-28 00:38:53 +04:00
{
stat_cache_entry * scp ;
stat_cache_entry * longest_hit = NULL ;
1998-09-10 04:35:10 +04:00
pstring chk_name ;
1998-09-06 05:37:14 +04:00
int namelen ;
if ( ! lp_stat_cache ( ) ) return False ;
1998-08-28 00:38:53 +04:00
1998-09-06 05:37:14 +04:00
namelen = strlen ( name ) ;
1998-08-28 00:38:53 +04:00
* start = name ;
global_stat_cache_lookups + + ;
/*
* Don ' t lookup trivial valid directory entries .
*/
1998-09-19 07:34:12 +04:00
if ( ( * name = = ' \0 ' ) | | ( strcmp ( name , " . " ) = = 0 ) | | ( strcmp ( name , " .. " ) = = 0 ) ) {
1998-08-28 00:38:53 +04:00
global_stat_cache_misses + + ;
return False ;
}
1998-09-10 04:35:10 +04:00
pstrcpy ( chk_name , name ) ;
if ( ! case_sensitive )
strupper ( chk_name ) ;
1998-08-28 00:38:53 +04:00
for ( scp = ( stat_cache_entry * ) ubi_dlFirst ( & stat_cache ) ; scp ;
scp = ( stat_cache_entry * ) ubi_dlNext ( scp ) ) {
if ( scp - > name_len < = namelen ) {
1998-09-10 04:35:10 +04:00
if ( stat_name_equal_len ( scp - > orig_name , chk_name , scp - > name_len ) ) {
1998-08-28 00:38:53 +04:00
if ( ( longest_hit = = NULL ) | | ( longest_hit - > name_len < = scp - > name_len ) )
longest_hit = scp ;
}
}
}
if ( longest_hit = = NULL ) {
DEBUG ( 10 , ( " stat_cache_lookup: cache miss on %s \n " , name ) ) ;
global_stat_cache_misses + + ;
return False ;
}
global_stat_cache_hits + + ;
DEBUG ( 10 , ( " stat_cache_lookup: cache hit for name %s. %s -> %s \n " ,
name , longest_hit - > orig_name , longest_hit - > translated_name ) ) ;
/*
* longest_hit is the longest match we got in the list .
* Check it exists - if so , overwrite the original name
* and then promote it to the top .
*/
1998-09-02 00:11:54 +04:00
if ( dos_stat ( longest_hit - > translated_name , pst ) ! = 0 ) {
1998-08-28 00:38:53 +04:00
/*
* Discard this entry .
*/
ubi_dlRemThis ( & stat_cache , longest_hit ) ;
free ( ( char * ) longest_hit ) ;
return False ;
}
memcpy ( name , longest_hit - > translated_name , longest_hit - > name_len ) ;
if ( ( stat_cache_entry * ) ubi_dlFirst ( & stat_cache ) ! = longest_hit ) {
ubi_dlRemThis ( & stat_cache , longest_hit ) ;
ubi_dlAddHead ( & stat_cache , longest_hit ) ;
}
* start = & name [ longest_hit - > name_len ] ;
if ( * * start = = ' / ' )
+ + * start ;
StrnCpy ( dirpath , longest_hit - > translated_name , name - ( * start ) ) ;
return ( namelen = = longest_hit - > name_len ) ;
}
1998-08-17 11:40:06 +04:00
/****************************************************************************
This routine is called to convert names from the dos namespace to unix
namespace . It needs to handle any case conversions , mangling , format
changes etc .
We assume that we have already done a chdir ( ) to the right " root " directory
for this service .
The function will return False if some part of the name except for the last
part cannot be resolved
If the saved_last_component ! = 0 , then the unmodified last component
of the pathname is returned there . This is used in an exceptional
case in reply_mv ( so far ) . If saved_last_component = = 0 then nothing
is returned there .
The bad_path arg is set to True if the filename walk failed . This is
used to pick the correct error code to return between ENOENT and ENOTDIR
as Windows applications depend on ERRbadpath being returned if a component
of a pathname does not exist .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-19 05:49:34 +04:00
1998-08-28 00:38:53 +04:00
BOOL unix_convert ( char * name , connection_struct * conn , char * saved_last_component ,
1998-09-02 00:11:54 +04:00
BOOL * bad_path , SMB_STRUCT_STAT * pst )
1998-08-17 11:40:06 +04:00
{
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT st ;
1998-09-29 01:43:48 +04:00
char * start , * end ;
1998-08-17 11:40:06 +04:00
pstring dirpath ;
1998-08-28 00:38:53 +04:00
pstring orig_path ;
1998-08-17 11:40:06 +04:00
int saved_errno ;
1998-08-28 00:38:53 +04:00
BOOL component_was_mangled = False ;
BOOL name_has_wildcard = False ;
1998-09-08 23:21:04 +04:00
#if 0
/* Andrew's conservative code... JRA. */
1998-09-05 19:31:10 +04:00
extern char magic_char ;
1998-09-08 23:21:04 +04:00
# endif
1998-08-17 11:40:06 +04:00
1998-10-09 10:47:22 +04:00
DEBUG ( 5 , ( " unix_convert called on file \" %s \" \n " , name ) ) ;
1998-08-17 11:40:06 +04:00
* dirpath = 0 ;
* bad_path = False ;
1998-09-05 17:24:20 +04:00
if ( pst ) {
ZERO_STRUCTP ( pst ) ;
}
1998-08-17 11:40:06 +04:00
if ( saved_last_component )
* saved_last_component = 0 ;
1998-08-19 05:49:34 +04:00
/*
* Convert to basic unix format - removing \ chars and cleaning it up .
*/
1998-08-17 11:40:06 +04:00
unix_format ( name ) ;
unix_clean_name ( name ) ;
1998-08-19 05:49:34 +04:00
/*
* Names must be relative to the root of the service - trim any leading / .
* also trim trailing / ' s .
*/
1998-08-17 11:40:06 +04:00
trim_string ( name , " / " , " / " ) ;
1998-10-09 14:03:19 +04:00
/*
* If we trimmed down to a single ' \0 ' character
* then we should use the " . " directory to avoid
* searching the cache , but not if we are in a
* printing share .
*/
if ( ! * name & & ( ! conn - > printer ) ) {
name [ 0 ] = ' . ' ;
name [ 1 ] = ' \0 ' ;
}
1998-08-17 11:40:06 +04:00
/*
* Ensure saved_last_component is valid even if file exists .
*/
1998-08-19 05:49:34 +04:00
1998-08-17 11:40:06 +04:00
if ( saved_last_component ) {
end = strrchr ( name , ' / ' ) ;
if ( end )
pstrcpy ( saved_last_component , end + 1 ) ;
else
pstrcpy ( saved_last_component , name ) ;
}
if ( ! case_sensitive & &
( ! case_preserve | | ( is_8_3 ( name , False ) & & ! short_case_preserve ) ) )
strnorm ( name ) ;
1998-08-19 05:49:34 +04:00
/*
* Check if it ' s a printer file .
*/
if ( conn - > printer ) {
if ( ( ! * name ) | | strchr ( name , ' / ' ) | | ! is_8_3 ( name , True ) ) {
char * s ;
fstring name2 ;
slprintf ( name2 , sizeof ( name2 ) - 1 , " %.6s.XXXXXX " , remote_machine ) ;
/*
* Sanitise the name .
*/
for ( s = name2 ; * s ; s + + )
if ( ! issafe ( * s ) ) * s = ' _ ' ;
pstrcpy ( name , ( char * ) mktemp ( name2 ) ) ;
}
return ( True ) ;
}
1998-09-29 01:43:48 +04:00
/*
* If we trimmed down to a single ' \0 ' character
* then we will be using the " . " directory .
* As we know this is valid we can return true here .
*/
if ( ! * name )
return ( True ) ;
1998-08-28 00:38:53 +04:00
start = name ;
while ( strncmp ( start , " ./ " , 2 ) = = 0 )
start + = 2 ;
pstrcpy ( orig_path , name ) ;
if ( stat_cache_lookup ( name , dirpath , & start , & st ) ) {
if ( pst )
* pst = st ;
return True ;
}
1998-08-19 05:49:34 +04:00
/*
* stat the name - if it exists then we are all done !
*/
1998-08-17 11:40:06 +04:00
1998-09-02 00:11:54 +04:00
if ( dos_stat ( name , & st ) = = 0 ) {
1998-08-28 00:38:53 +04:00
stat_cache_add ( orig_path , name ) ;
DEBUG ( 5 , ( " conversion finished %s -> %s \n " , orig_path , name ) ) ;
if ( pst )
* pst = st ;
1998-08-17 11:40:06 +04:00
return ( True ) ;
1998-08-28 00:38:53 +04:00
}
1998-08-17 11:40:06 +04:00
saved_errno = errno ;
1998-08-28 00:38:53 +04:00
DEBUG ( 5 , ( " unix_convert begin: name = %s, dirpath = %s, start = %s \n " ,
name , dirpath , start ) ) ;
1998-08-17 11:40:06 +04:00
1998-08-19 05:49:34 +04:00
/*
* A special case - if we don ' t have any mangling chars and are case
* sensitive then searching won ' t help .
*/
1998-08-17 11:40:06 +04:00
if ( case_sensitive & & ! is_mangled ( name ) & &
! lp_strip_dot ( ) & & ! use_mangled_map & & ( saved_errno ! = ENOENT ) )
return ( False ) ;
1998-08-28 00:38:53 +04:00
if ( strchr ( start , ' ? ' ) | | strchr ( start , ' * ' ) )
name_has_wildcard = True ;
1998-09-08 23:21:04 +04:00
/*
* is_mangled ( ) was changed to look at an entire pathname , not
* just a component . JRA .
*/
if ( is_mangled ( start ) )
component_was_mangled = True ;
#if 0
/* Keep Andrew's conservative code around, just in case. JRA. */
1998-09-05 19:31:10 +04:00
/* this is an extremely conservative test for mangled names. */
if ( strchr ( start , magic_char ) )
component_was_mangled = True ;
1998-09-08 23:21:04 +04:00
# endif
1998-09-05 19:31:10 +04:00
1998-08-19 05:49:34 +04:00
/*
* Now we need to recursively match the name against the real
* directory structure .
*/
1998-08-17 11:40:06 +04:00
1998-08-19 05:49:34 +04:00
/*
* Match each part of the path name separately , trying the names
* as is first , then trying to scan the directory for matching names .
*/
1998-09-29 01:43:48 +04:00
for ( ; start ; start = ( end ? end + 1 : ( char * ) NULL ) ) {
1998-08-19 05:49:34 +04:00
/*
* Pinpoint the end of this section of the filename .
*/
1998-08-17 11:40:06 +04:00
end = strchr ( start , ' / ' ) ;
1998-08-19 05:49:34 +04:00
/*
* Chop the name at this point .
*/
if ( end )
* end = 0 ;
1998-08-17 11:40:06 +04:00
if ( saved_last_component ! = 0 )
pstrcpy ( saved_last_component , end ? end + 1 : start ) ;
1998-08-19 05:49:34 +04:00
/*
* Check if the name exists up to this point .
*/
1998-09-02 00:11:54 +04:00
if ( dos_stat ( name , & st ) = = 0 ) {
1998-08-19 05:49:34 +04:00
/*
* It exists . it must either be a directory or this must be
* the last part of the path for it to be OK .
*/
if ( end & & ! ( st . st_mode & S_IFDIR ) ) {
/*
* An intermediate part of the name isn ' t a directory .
*/
DEBUG ( 5 , ( " Not a dir %s \n " , start ) ) ;
* end = ' / ' ;
return ( False ) ;
}
1998-08-28 00:38:53 +04:00
1998-08-19 05:49:34 +04:00
} else {
pstring rest ;
* rest = 0 ;
/*
* Remember the rest of the pathname so it can be restored
* later .
*/
if ( end )
pstrcpy ( rest , end + 1 ) ;
/*
* Try to find this part of the path in the directory .
*/
1998-08-28 00:38:53 +04:00
1998-08-19 05:49:34 +04:00
if ( strchr ( start , ' ? ' ) | | strchr ( start , ' * ' ) | |
! scan_directory ( dirpath , start , conn , end ? True : False ) ) {
if ( end ) {
/*
* An intermediate part of the name can ' t be found .
*/
DEBUG ( 5 , ( " Intermediate not found %s \n " , start ) ) ;
* end = ' / ' ;
/*
* We need to return the fact that the intermediate
* name resolution failed . This is used to return an
* error of ERRbadpath rather than ERRbadfile . Some
* Windows applications depend on the difference between
* these two errors .
*/
* bad_path = True ;
return ( False ) ;
}
1998-08-17 11:40:06 +04:00
1998-08-19 05:49:34 +04:00
/*
* Just the last part of the name doesn ' t exist .
* We may need to strupper ( ) or strlower ( ) it in case
* this conversion is being used for file creation
* purposes . If the filename is of mixed case then
* don ' t normalise it .
*/
if ( ! case_preserve & & ( ! strhasupper ( start ) | | ! strhaslower ( start ) ) )
strnorm ( start ) ;
/*
* check on the mangled stack to see if we can recover the
* base of the filename .
*/
1998-08-28 00:38:53 +04:00
if ( is_mangled ( start ) ) {
1998-08-19 05:49:34 +04:00
check_mangled_cache ( start ) ;
1998-08-28 00:38:53 +04:00
}
1998-08-19 05:49:34 +04:00
DEBUG ( 5 , ( " New file %s \n " , start ) ) ;
return ( True ) ;
}
/*
* Restore the rest of the string .
*/
if ( end ) {
pstrcpy ( start + strlen ( start ) + 1 , rest ) ;
end = start + strlen ( start ) ;
}
} /* end else */
/*
* Add to the dirpath that we have resolved so far .
*/
1998-08-28 00:38:53 +04:00
if ( * dirpath )
pstrcat ( dirpath , " / " ) ;
pstrcat ( dirpath , start ) ;
/*
* Don ' t cache a name with mangled or wildcard components
* as this can change the size .
*/
if ( ! component_was_mangled & & ! name_has_wildcard )
stat_cache_add ( orig_path , dirpath ) ;
1998-08-17 11:40:06 +04:00
1998-08-19 05:49:34 +04:00
/*
* Restore the / that we wiped out earlier .
*/
if ( end )
* end = ' / ' ;
}
1998-08-17 11:40:06 +04:00
1998-08-28 00:38:53 +04:00
/*
* Don ' t cache a name with mangled or wildcard components
* as this can change the size .
*/
if ( ! component_was_mangled & & ! name_has_wildcard )
stat_cache_add ( orig_path , name ) ;
1998-08-19 05:49:34 +04:00
/*
* The name has been resolved .
*/
1998-08-28 00:38:53 +04:00
DEBUG ( 5 , ( " conversion finished %s -> %s \n " , orig_path , name ) ) ;
1998-08-17 11:40:06 +04:00
return ( True ) ;
}
/****************************************************************************
check a filename - possibly caling reducename
This is called by every routine before it allows an operation on a filename .
It does any final confirmation necessary to ensure that the filename is
a valid one for the user to access .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL check_name ( char * name , connection_struct * conn )
{
BOOL ret ;
errno = 0 ;
if ( IS_VETO_PATH ( conn , name ) ) {
DEBUG ( 5 , ( " file path name %s vetoed \n " , name ) ) ;
return ( 0 ) ;
}
ret = reduce_name ( name , conn - > connectpath , lp_widelinks ( SNUM ( conn ) ) ) ;
/* Check if we are allowing users to follow symlinks */
/* Patch from David Clerc <David.Clerc@cui.unige.ch>
University of Geneva */
# ifdef S_ISLNK
if ( ! lp_symlinks ( SNUM ( conn ) ) )
{
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT statbuf ;
if ( ( dos_lstat ( name , & statbuf ) ! = - 1 ) & &
1998-08-17 11:40:06 +04:00
( S_ISLNK ( statbuf . st_mode ) ) )
{
DEBUG ( 3 , ( " check_name: denied: file path name %s is a symlink \n " , name ) ) ;
ret = 0 ;
}
}
# endif
if ( ! ret )
DEBUG ( 5 , ( " check_name on %s failed \n " , name ) ) ;
return ( ret ) ;
}
/****************************************************************************
scan a directory to find a filename , matching without case sensitivity
If the name looks like a mangled name then try via the mangling functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-05 09:07:05 +04:00
static BOOL scan_directory ( char * path , char * name , connection_struct * conn , BOOL docache )
1998-08-17 11:40:06 +04:00
{
void * cur_dir ;
char * dname ;
BOOL mangled ;
pstring name2 ;
mangled = is_mangled ( name ) ;
/* handle null paths */
if ( * path = = 0 )
path = " . " ;
if ( docache & & ( dname = DirCacheCheck ( path , name , SNUM ( conn ) ) ) ) {
pstrcpy ( name , dname ) ;
return ( True ) ;
}
/*
* The incoming name can be mangled , and if we de - mangle it
* here it will not compare correctly against the filename ( name2 )
* read from the directory and then mangled by the name_map_mangle ( )
* call . We need to mangle both names or neither .
* ( JRA ) .
*/
if ( mangled )
mangled = ! check_mangled_cache ( name ) ;
/* open the directory */
if ( ! ( cur_dir = OpenDir ( conn , path , True ) ) )
{
DEBUG ( 3 , ( " scan dir didn't open dir [%s] \n " , path ) ) ;
return ( False ) ;
}
/* now scan for matching names */
while ( ( dname = ReadDirName ( cur_dir ) ) )
{
if ( * dname = = ' . ' & &
( strequal ( dname , " . " ) | | strequal ( dname , " .. " ) ) )
continue ;
pstrcpy ( name2 , dname ) ;
if ( ! name_map_mangle ( name2 , False , SNUM ( conn ) ) ) continue ;
if ( ( mangled & & mangled_equal ( name , name2 ) )
| | fname_equal ( name , name2 ) )
{
/* we've found the file, change it's name and return */
if ( docache ) DirCacheAdd ( path , name , dname , SNUM ( conn ) ) ;
pstrcpy ( name , dname ) ;
CloseDir ( cur_dir ) ;
return ( True ) ;
}
}
CloseDir ( cur_dir ) ;
return ( False ) ;
}