2009-07-11 02:35:08 +04:00
/*
Unix SMB / CIFS implementation .
Filename utility functions .
Copyright ( C ) Tim Prouty 2009
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
/**
* XXX : This is temporary and there should be no callers of this outside of
* this file once smb_filename is plumbed through all path based operations .
* The one legitimate caller currently is smb_fname_str_dbg ( ) , which this
* could be made static for .
*/
NTSTATUS get_full_smb_filename ( TALLOC_CTX * ctx ,
const struct smb_filename * smb_fname ,
char * * full_name )
{
if ( smb_fname - > stream_name ) {
2009-07-21 01:32:32 +04:00
/* stream_name must always be NULL if there is no stream. */
SMB_ASSERT ( smb_fname - > stream_name [ 0 ] ! = ' \0 ' ) ;
2009-07-11 02:35:08 +04:00
* full_name = talloc_asprintf ( ctx , " %s%s " , smb_fname - > base_name ,
smb_fname - > stream_name ) ;
} else {
* full_name = talloc_strdup ( ctx , smb_fname - > base_name ) ;
}
if ( ! * full_name ) {
return NT_STATUS_NO_MEMORY ;
}
return NT_STATUS_OK ;
}
/**
* There are actually legitimate callers of this such as functions that
2011-10-17 22:10:29 +04:00
* enumerate streams using the vfs_streaminfo interface and then want to
2009-07-11 02:35:08 +04:00
* operate on each stream .
*/
2013-04-11 19:01:22 +04:00
struct smb_filename * synthetic_smb_fname ( TALLOC_CTX * mem_ctx ,
const char * base_name ,
const char * stream_name ,
2016-03-19 07:19:38 +03:00
const SMB_STRUCT_STAT * psbuf ,
uint32_t flags )
2013-04-11 19:01:22 +04:00
{
struct smb_filename smb_fname_loc = { 0 , } ;
/* Setup the base_name/stream_name. */
smb_fname_loc . base_name = discard_const_p ( char , base_name ) ;
smb_fname_loc . stream_name = discard_const_p ( char , stream_name ) ;
2016-03-19 07:19:38 +03:00
smb_fname_loc . flags = flags ;
2013-04-11 19:01:22 +04:00
/* Copy the psbuf if one was given. */
if ( psbuf )
smb_fname_loc . st = * psbuf ;
2013-04-12 13:00:31 +04:00
/* Let cp_smb_filename() do the heavy lifting. */
2013-04-11 19:01:22 +04:00
return cp_smb_filename ( mem_ctx , & smb_fname_loc ) ;
}
2017-05-30 21:46:49 +03:00
/**
* Utility function used by VFS calls that must * NOT * operate
* on a stream filename , only the base_name .
*/
struct smb_filename * cp_smb_filename_nostream ( TALLOC_CTX * mem_ctx ,
const struct smb_filename * smb_fname_in )
{
struct smb_filename * smb_fname = cp_smb_filename ( mem_ctx ,
smb_fname_in ) ;
if ( smb_fname = = NULL ) {
return NULL ;
}
TALLOC_FREE ( smb_fname - > stream_name ) ;
return smb_fname ;
}
2009-07-11 02:35:08 +04:00
/**
2016-03-10 02:45:55 +03:00
* There are a few legitimate users of this .
2009-07-11 02:35:08 +04:00
*/
2013-04-12 13:06:45 +04:00
struct smb_filename * synthetic_smb_fname_split ( TALLOC_CTX * ctx ,
2016-03-10 03:00:47 +03:00
const char * fname ,
bool posix_path )
2013-04-12 13:06:45 +04:00
{
2016-03-10 02:45:55 +03:00
char * stream_name = NULL ;
2013-04-12 13:06:45 +04:00
char * base_name = NULL ;
struct smb_filename * ret ;
2016-03-10 02:45:55 +03:00
bool ok ;
2013-04-12 13:06:45 +04:00
2016-03-10 03:00:47 +03:00
if ( posix_path ) {
2016-03-10 02:45:55 +03:00
/* No stream name looked for. */
2016-03-19 07:19:38 +03:00
return synthetic_smb_fname ( ctx ,
fname ,
NULL ,
NULL ,
SMB_FILENAME_POSIX_PATH ) ;
2013-04-12 13:06:45 +04:00
}
2016-03-10 02:45:55 +03:00
ok = split_stream_filename ( ctx ,
fname ,
& base_name ,
& stream_name ) ;
if ( ! ok ) {
2013-04-12 13:06:45 +04:00
return NULL ;
}
2016-03-19 07:19:38 +03:00
ret = synthetic_smb_fname ( ctx , base_name , stream_name , NULL , 0 ) ;
2013-04-12 13:06:45 +04:00
TALLOC_FREE ( base_name ) ;
2016-03-10 02:45:55 +03:00
TALLOC_FREE ( stream_name ) ;
2013-04-12 13:06:45 +04:00
return ret ;
}
2009-07-11 02:35:08 +04:00
/**
2009-11-03 12:59:18 +03:00
* Return a string using the talloc_tos ( )
2009-07-11 02:35:08 +04:00
*/
const char * smb_fname_str_dbg ( const struct smb_filename * smb_fname )
{
char * fname = NULL ;
NTSTATUS status ;
if ( smb_fname = = NULL ) {
return " " ;
}
2009-11-03 12:59:18 +03:00
status = get_full_smb_filename ( talloc_tos ( ) , smb_fname , & fname ) ;
2009-07-11 02:35:08 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return " " ;
}
return fname ;
}
/**
2012-06-13 19:43:18 +04:00
* Return a debug string of the path name of an fsp using the talloc_tos ( ) .
2009-07-11 02:35:08 +04:00
*/
const char * fsp_str_dbg ( const struct files_struct * fsp )
{
return smb_fname_str_dbg ( fsp - > fsp_name ) ;
}
2012-06-13 19:58:54 +04:00
/**
* Create a debug string for the fnum of an fsp .
*
* This is allocated to talloc_tos ( ) or a string constant
* in certain corner cases . The returned string should
* hence not be free ' d directly but only via the talloc stack .
*/
const char * fsp_fnum_dbg ( const struct files_struct * fsp )
{
char * str ;
if ( fsp = = NULL ) {
return " fnum [fsp is NULL] " ;
}
if ( fsp - > fnum = = FNUM_FIELD_INVALID ) {
return " fnum [invalid value] " ;
}
2012-06-14 15:34:46 +04:00
str = talloc_asprintf ( talloc_tos ( ) , " fnum %llu " ,
( unsigned long long ) fsp - > fnum ) ;
2012-06-13 19:58:54 +04:00
if ( str = = NULL ) {
DEBUG ( 1 , ( " %s: talloc_asprintf failed \n " , __FUNCTION__ ) ) ;
return " fnum [talloc failed!] " ;
}
return str ;
}
2013-04-11 17:24:55 +04:00
struct smb_filename * cp_smb_filename ( TALLOC_CTX * mem_ctx ,
const struct smb_filename * in )
{
struct smb_filename * out ;
2013-09-07 02:34:44 +04:00
size_t base_len = 0 ;
size_t stream_len = 0 ;
size_t lcomp_len = 0 ;
int num = 0 ;
2013-04-11 17:24:55 +04:00
/* stream_name must always be NULL if there is no stream. */
if ( in - > stream_name ) {
SMB_ASSERT ( in - > stream_name [ 0 ] ! = ' \0 ' ) ;
}
2013-09-07 02:34:44 +04:00
if ( in - > base_name ! = NULL ) {
base_len = strlen ( in - > base_name ) + 1 ;
num + = 1 ;
}
if ( in - > stream_name ! = NULL ) {
stream_len = strlen ( in - > stream_name ) + 1 ;
num + = 1 ;
}
if ( in - > original_lcomp ! = NULL ) {
lcomp_len = strlen ( in - > original_lcomp ) + 1 ;
num + = 1 ;
}
out = talloc_pooled_object ( mem_ctx , struct smb_filename ,
num , stream_len + base_len + lcomp_len ) ;
2013-04-11 17:24:55 +04:00
if ( out = = NULL ) {
return NULL ;
}
2013-09-07 02:34:44 +04:00
ZERO_STRUCTP ( out ) ;
/*
2015-05-18 10:00:46 +03:00
* The following allocations cannot fail as we
2013-09-07 02:34:44 +04:00
* pre - allocated space for them in the out pooled
* object .
*/
2013-04-11 17:24:55 +04:00
if ( in - > base_name ! = NULL ) {
2013-09-07 02:34:44 +04:00
out - > base_name = talloc_memdup (
out , in - > base_name , base_len ) ;
2015-01-09 17:38:19 +03:00
talloc_set_name_const ( out - > base_name ,
out - > base_name ) ;
2013-04-11 17:24:55 +04:00
}
if ( in - > stream_name ! = NULL ) {
2013-09-07 02:34:44 +04:00
out - > stream_name = talloc_memdup (
out , in - > stream_name , stream_len ) ;
2015-01-09 17:38:19 +03:00
talloc_set_name_const ( out - > stream_name ,
out - > stream_name ) ;
2013-04-11 17:24:55 +04:00
}
if ( in - > original_lcomp ! = NULL ) {
2013-09-07 02:34:44 +04:00
out - > original_lcomp = talloc_memdup (
out , in - > original_lcomp , lcomp_len ) ;
2015-01-09 17:38:19 +03:00
talloc_set_name_const ( out - > original_lcomp ,
out - > original_lcomp ) ;
2013-04-11 17:24:55 +04:00
}
2016-03-18 02:20:17 +03:00
out - > flags = in - > flags ;
2013-04-11 17:24:55 +04:00
out - > st = in - > st ;
return out ;
}
2009-07-11 02:35:08 +04:00
/****************************************************************************
Simple check to determine if the filename is a stream .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_ntfs_stream_smb_fname ( const struct smb_filename * smb_fname )
{
2009-07-21 01:32:32 +04:00
/* stream_name must always be NULL if there is no stream. */
if ( smb_fname - > stream_name ) {
SMB_ASSERT ( smb_fname - > stream_name [ 0 ] ! = ' \0 ' ) ;
}
2016-03-19 07:58:20 +03:00
if ( smb_fname - > flags & SMB_FILENAME_POSIX_PATH ) {
2009-07-11 02:35:08 +04:00
return false ;
}
2009-09-18 05:34:55 +04:00
return smb_fname - > stream_name ! = NULL ;
2009-07-11 02:35:08 +04:00
}
/****************************************************************************
Returns true if the filename ' s stream = = " ::$DATA "
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_ntfs_default_stream_smb_fname ( const struct smb_filename * smb_fname )
{
if ( ! is_ntfs_stream_smb_fname ( smb_fname ) ) {
return false ;
}
2011-05-13 22:21:30 +04:00
return strcasecmp_m ( smb_fname - > stream_name , " ::$DATA " ) = = 0 ;
2009-07-11 02:35:08 +04:00
}
2013-07-10 02:50:47 +04:00
/****************************************************************************
Filter out Windows invalid EA names ( list probed from Windows 2012 ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char bad_ea_name_chars [ ] = " \" *+,/:;<=>?[ \\ ]| " ;
bool is_invalid_windows_ea_name ( const char * name )
{
int i ;
/* EA name is pulled as ascii so we can examine
individual bytes here . */
for ( i = 0 ; name [ i ] ! = 0 ; i + + ) {
int val = ( name [ i ] & 0xff ) ;
if ( val < ' ' | | strchr ( bad_ea_name_chars , val ) ) {
return true ;
}
}
return false ;
}
bool ea_list_has_invalid_name ( struct ea_list * ea_list )
{
for ( ; ea_list ; ea_list = ea_list - > next ) {
if ( is_invalid_windows_ea_name ( ea_list - > ea . name ) ) {
return true ;
}
}
return false ;
}
2016-03-10 01:56:49 +03:00
/****************************************************************************
Split an incoming name into tallocd filename and stream components .
Returns true on success , false on out of memory .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool split_stream_filename ( TALLOC_CTX * ctx ,
const char * filename_in ,
char * * filename_out ,
char * * streamname_out )
{
const char * stream_name = NULL ;
char * stream_out = NULL ;
char * file_out = NULL ;
stream_name = strchr_m ( filename_in , ' : ' ) ;
if ( stream_name ) {
stream_out = talloc_strdup ( ctx , stream_name ) ;
if ( stream_out = = NULL ) {
return false ;
}
file_out = talloc_strndup ( ctx ,
filename_in ,
PTR_DIFF ( stream_name , filename_in ) ) ;
} else {
file_out = talloc_strdup ( ctx , filename_in ) ;
}
if ( file_out = = NULL ) {
TALLOC_FREE ( stream_out ) ;
return false ;
}
if ( filename_out ) {
* filename_out = file_out ;
}
if ( streamname_out ) {
* streamname_out = stream_out ;
}
return true ;
}