1998-08-17 11:40:06 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
filename handling routines
Copyright ( C ) Andrew Tridgell 1992 - 1998
2000-01-27 00:25:35 +03:00
Copyright ( C ) Jeremy Allison 1999 - 200
Copyright ( C ) Ying Chen 2000
1998-08-17 11:40:06 +04:00
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 .
*/
2000-01-27 00:25:35 +03:00
/*
* New hash table stat cache code added by Ying Chen .
*/
1998-08-17 11:40:06 +04:00
# 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 )
{
1999-12-13 16:27:58 +03:00
double eff ;
if ( global_stat_cache_lookups = = 0 )
return ;
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 {
int name_len ;
2000-01-27 00:25:35 +03:00
char names [ 2 ] ; /* This is extended via malloc... */
1998-08-28 00:38:53 +04:00
} stat_cache_entry ;
2000-01-27 00:25:35 +03:00
# define INIT_STAT_CACHE_SIZE 512
static hash_table stat_cache ;
1998-08-28 00:38:53 +04:00
/****************************************************************************
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 ;
2000-01-27 00:25:35 +03:00
stat_cache_entry * found_scp ;
1998-08-28 00:38:53 +04:00
pstring orig_name ;
pstring translated_path ;
1998-09-06 05:37:14 +04:00
int namelen ;
2000-01-27 00:25:35 +03:00
hash_element * hash_elem ;
1998-09-06 05:37:14 +04:00
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 .
*/
2000-02-04 08:18:06 +03:00
if ( ( hash_elem = hash_lookup ( & stat_cache , orig_name ) ) ) {
2000-01-27 00:25:35 +03:00
found_scp = ( stat_cache_entry * ) ( hash_elem - > value ) ;
if ( strcmp ( ( found_scp - > names + found_scp - > name_len + 1 ) , translated_path ) = = 0 ) {
1998-08-28 00:38:53 +04:00
return ;
2000-01-27 00:25:35 +03:00
} else {
hash_remove ( & stat_cache , hash_elem ) ;
if ( ( scp = ( stat_cache_entry * ) malloc ( sizeof ( stat_cache_entry ) + 2 * namelen ) ) = = NULL ) {
DEBUG ( 0 , ( " stat_cache_add: Out of memory ! \n " ) ) ;
return ;
}
pstrcpy ( scp - > names , orig_name ) ;
pstrcpy ( ( scp - > names + namelen + 1 ) , translated_path ) ;
scp - > name_len = namelen ;
hash_insert ( & stat_cache , ( char * ) scp , orig_name ) ;
1998-08-28 00:38:53 +04:00
}
return ;
2000-01-27 00:25:35 +03:00
} else {
1998-08-28 00:38:53 +04:00
2000-01-27 00:25:35 +03:00
/*
* New entry .
*/
1998-08-28 00:38:53 +04:00
2000-01-27 00:25:35 +03:00
if ( ( scp = ( stat_cache_entry * ) malloc ( sizeof ( stat_cache_entry ) + 2 * namelen ) ) = = NULL ) {
DEBUG ( 0 , ( " stat_cache_add: Out of memory ! \n " ) ) ;
return ;
}
pstrcpy ( scp - > names , orig_name ) ;
pstrcpy ( scp - > names + namelen + 1 , translated_path ) ;
scp - > name_len = namelen ;
hash_insert ( & stat_cache , ( char * ) scp , orig_name ) ;
1998-08-28 00:38:53 +04:00
}
2000-01-27 00:25:35 +03:00
DEBUG ( 5 , ( " stat_cache_add: Added entry %s -> %s \n " , scp - > names , ( scp - > names + scp - > name_len + 1 ) ) ) ;
1998-08-28 00:38:53 +04:00
}
/****************************************************************************
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-02-03 08:17:25 +03:00
static BOOL stat_cache_lookup ( connection_struct * conn , 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 ;
2000-01-27 00:25:35 +03:00
char * trans_name ;
1998-09-10 04:35:10 +04:00
pstring chk_name ;
1998-09-06 05:37:14 +04:00
int namelen ;
2000-01-27 00:25:35 +03:00
hash_element * hash_elem ;
char * sp ;
1998-09-06 05:37:14 +04:00
2000-01-27 00:25:35 +03:00
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 ) ;
2000-01-27 00:25:35 +03:00
while ( 1 ) {
hash_elem = hash_lookup ( & stat_cache , chk_name ) ;
if ( hash_elem = = NULL ) {
/*
* Didn ' t find it - remove last component for next try .
*/
sp = strrchr ( chk_name , ' / ' ) ;
if ( sp ) {
* sp = ' \0 ' ;
} else {
/*
* We reached the end of the name - no match .
*/
global_stat_cache_misses + + ;
return False ;
1998-08-28 00:38:53 +04:00
}
2000-01-27 00:25:35 +03:00
if ( ( * chk_name = = ' \0 ' ) | | ( strcmp ( chk_name , " . " ) = = 0 )
| | ( strcmp ( chk_name , " .. " ) = = 0 ) ) {
global_stat_cache_misses + + ;
return False ;
}
} else {
scp = ( stat_cache_entry * ) ( hash_elem - > value ) ;
global_stat_cache_hits + + ;
trans_name = scp - > names + scp - > name_len + 1 ;
2000-02-03 08:17:25 +03:00
if ( conn - > vfs_ops . stat ( dos_to_unix ( trans_name , False ) , pst ) ! = 0 ) {
2000-01-27 00:25:35 +03:00
/* Discard this entry - it doesn't exist in the filesystem. */
hash_remove ( & stat_cache , hash_elem ) ;
return False ;
}
memcpy ( name , trans_name , scp - > name_len ) ;
* start = & name [ scp - > name_len ] ;
if ( * * start = = ' / ' )
+ + * start ;
StrnCpy ( dirpath , trans_name , name - ( * start ) ) ;
return ( namelen = = scp - > name_len ) ;
1998-08-28 00:38:53 +04:00
}
}
}
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
BOOL unix_convert ( char * name , connection_struct * conn , char * saved_last_component ,
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 ;
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 ) {
2000-01-27 00:25:35 +03:00
ZERO_STRUCTP ( pst ) ;
1998-09-05 17:24:20 +04:00
}
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 = ' _ ' ;
1999-12-13 16:27:58 +03:00
pstrcpy ( name , ( char * ) smbd_mktemp ( name2 ) ) ;
1998-08-19 05:49:34 +04:00
}
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 ) ;
2000-02-03 08:17:25 +03:00
if ( stat_cache_lookup ( conn , name , dirpath , & start , & st ) ) {
1998-08-28 00:38:53 +04:00
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
2000-02-04 02:08:24 +03:00
if ( conn - > vfs_ops . stat ( dos_to_unix ( name , False ) , & 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
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 ) & &
1999-12-13 16:27:58 +03:00
! lp_strip_dot ( ) & & ! use_mangled_map )
1998-08-17 11:40:06 +04:00
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 .
*/
2000-02-03 08:17:25 +03:00
2000-02-04 02:08:24 +03:00
if ( conn - > vfs_ops . stat ( dos_to_unix ( name , False ) , & 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 ;
2000-02-03 08:17:25 +03:00
if ( ( conn - > vfs_ops . lstat ( dos_to_unix ( name , False ) , & 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 ) ;
1999-12-13 16:27:58 +03:00
if ( ! name_map_mangle ( name2 , False , True , SNUM ( conn ) ) )
continue ;
1998-08-17 11:40:06 +04:00
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 ) ;
}
2000-01-27 00:25:35 +03:00
/*************************************************************************** **
* Initializes or clears the stat cache .
*
* Input : none .
* Output : none .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
BOOL reset_stat_cache ( void )
{
return hash_table_init ( & stat_cache , INIT_STAT_CACHE_SIZE , ( compare_function ) ( strcmp ) ) ;
} /* reset_stat_cache */