2012-05-03 21:39:53 +04:00
/*
* $ Id : media_harmony . c , v 1.1 2007 / 11 / 06 10 : 07 : 22 stuart_hc Exp $
*
* Samba VFS module supporting multiple AVID clients sharing media .
*
* Copyright ( C ) 2005 Philip de Nier < philipn @ users . sourceforge . net >
* Copyright ( C ) 2012 Andrew Klaassen < clawsoon @ yahoo . com >
*
* 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 . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA .
*/
/*
* Media Harmony is a Samba VFS module that allows multiple AVID
* clients to share media . Each client sees their own copy of the
* AVID msmMMOB . mdb and msmFMID . pmr files and Creating directories .
*
* Add this module to the vfs objects option in your Samba share
* configuration .
* eg .
*
* [ avid_win ]
* path = / video
* vfs objects = media_harmony
* . . .
*
* It is recommended that you separate out Samba shares for Mac
* and Windows clients , and add the following options to the shares
* for Windows clients ( NOTE : replace @ with * ) :
*
* veto files = / . DS_Store / . _ @ / . Trash @ / . Spotlight @ / . hidden / . hotfiles @ / . vol /
* delete veto files = yes
*
* This prevents hidden files from Mac clients interfering with Windows
* clients . If you find any more problem hidden files then add them to
* the list .
*
*
* Andrew Klaassen , 2012 - 03 - 14
* To prevent Avid clients from interrupting each other ( via Avid ' s habit
* of launching a database refresh whenever it notices an mtime update
* on media directories , i . e . whenever one editor adds new material to a
* shared share ) , I ' ve added code that causes stat information for anything
* directly under " Avid MediaFile/MXF " to be taken from
* dirname_clientaddr_clientuser if it exists . These files ~ aren ' t ~
* hidden , unlike the client - suffixed database files .
*
* For example , stat information for
* Avid MediaFiles / MXF / 1
* will come from
* Avid MediaFiles / MXF / 1 _192 .168 .1 .10 _dave
* for dave working on 192.168 .1 .10 , but will come from
* Avid MediaFile / MXF / 1 _192 .168 .1 .11 _susan
* for susan working on 192.168 .1 .11 . If those alternate
* directories don ' t exist , the user will get the actual directory ' s stat
* info . When an editor wants to force a database refresh , they update
* the mtime on " their " file . This will cause Avid
* on that client to see an updated mtime for " Avid MediaFiles/MXF/1 " ,
* which will trigger an Avid database refresh just for that editor .
*
*
* Notes :
* - This module is designed to work with AVID editing applications that
* look in the Avid MediaFiles or OMFI MediaFiles directory for media .
* It is not designed to work as expected in all circumstances for
* general use . For example : it is possibly to open client specific
* files such as msmMMOB . mdb_192 .168 .1 .10 _userx even though is doesn ' t
* show up in a directory listing .
*
*/
# include "includes.h"
# include "system/filesys.h"
# include "smbd/smbd.h"
# include "../smbd/globals.h"
# include "auth.h"
# include "../lib/tsocket/tsocket.h"
# define MH_INFO_DEBUG 10
# define MH_ERR_DEBUG 0
static const char * MDB_FILENAME = " msmMMOB.mdb " ;
static const size_t MDB_FILENAME_LEN = 11 ;
static const char * PMR_FILENAME = " msmFMID.pmr " ;
static const size_t PMR_FILENAME_LEN = 11 ;
static const char * CREATING_DIRNAME = " Creating " ;
static const size_t CREATING_DIRNAME_LEN = 8 ;
static const char * AVID_MEDIAFILES_DIRNAME = " Avid MediaFiles " ;
static const size_t AVID_MEDIAFILES_DIRNAME_LEN = 15 ;
static const char * OMFI_MEDIAFILES_DIRNAME = " OMFI MediaFiles " ;
static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15 ;
static const char * APPLE_DOUBLE_PREFIX = " ._ " ;
static const size_t APPLE_DOUBLE_PREFIX_LEN = 2 ;
static const char * AVID_MXF_DIRNAME = " Avid MediaFiles/MXF " ;
static const size_t AVID_MXF_DIRNAME_LEN = 19 ;
static int vfs_mh_debug_level = DBGC_VFS ;
/* supplements the directory list stream */
typedef struct mh_dirinfo_struct
{
DIR * dirstream ;
char * dirpath ;
char * clientPath ;
bool isInMediaFiles ;
char * clientMDBFilename ;
char * clientPMRFilename ;
char * clientCreatingDirname ;
} mh_dirinfo_struct ;
/* Add "_<ip address>_<user name>" suffix to path or filename.
*
* Success : return 0
* Failure : set errno , path NULL , return - 1
*/
static int alloc_append_client_suffix ( vfs_handle_struct * handle ,
char * * path )
{
int status = 0 ;
char * raddr = NULL ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with *path '%s' \n " , * path ) ) ;
2012-05-03 21:39:53 +04:00
raddr = tsocket_address_inet_addr_string (
handle - > conn - > sconn - > remote_address , talloc_tos ( ) ) ;
if ( raddr = = NULL )
{
errno = ENOMEM ;
status = - 1 ;
goto err ;
}
/* talloc_asprintf_append uses talloc_realloc, which
* frees original ' path ' memory so we don ' t have to .
*/
* path = talloc_asprintf_append ( * path , " _%s_%s " ,
raddr ,
handle - > conn - > session_info - > unix_info - > sanitized_username ) ;
if ( * path = = NULL )
{
DEBUG ( MH_ERR_DEBUG , ( " alloc_append_client_suffix "
" out of memory \n " ) ) ;
errno = ENOMEM ;
status = - 1 ;
goto err ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with *path '%s' \n " , * path ) ) ;
err :
TALLOC_FREE ( raddr ) ;
return status ;
}
/* Returns True if the file or directory begins with the appledouble
* prefix .
*/
static bool is_apple_double ( const char * fname )
{
bool ret = False ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with fname '%s' \n " , fname ) ) ;
2012-05-03 21:39:53 +04:00
if ( strncmp ( APPLE_DOUBLE_PREFIX , fname , APPLE_DOUBLE_PREFIX_LEN )
= = 0 )
{
ret = True ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with ret '%s' \n " ,
ret = = True ? " True " : " False " ) ) ;
return ret ;
}
static bool starts_with_media_dir ( const char * media_dirname ,
size_t media_dirname_len , const char * path )
{
bool ret = False ;
2014-09-11 15:22:52 +04:00
const char * path_start ;
2012-05-03 21:39:53 +04:00
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with media_dirname '%s' "
" path '%s' \n " , media_dirname , path ) ) ;
2012-05-03 21:39:53 +04:00
/* Sometimes Samba gives us "./OMFI MediaFiles". */
if ( strncmp ( path , " ./ " , 2 ) = = 0 )
{
path_start = & path [ 2 ] ;
}
else {
path_start = path ;
}
if ( strncmp ( media_dirname , path_start , media_dirname_len ) = = 0
& &
(
path_start [ media_dirname_len ] = = ' \0 '
| |
path_start [ media_dirname_len ] = = ' / '
)
)
{
ret = True ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with ret '%s' \n " ,
ret = = True ? " True " : " False " ) ) ;
return ret ;
}
/*
* Returns True if the file or directory referenced by the path is below
* the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME directory
* The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME are assumed to
* be in the root directory , which is generally a safe assumption
* in the fixed - path world of Avid .
*/
static bool is_in_media_files ( const char * path )
{
bool ret = False ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with path '%s' \n " , path ) ) ;
2012-05-03 21:39:53 +04:00
if (
starts_with_media_dir ( AVID_MEDIAFILES_DIRNAME ,
AVID_MEDIAFILES_DIRNAME_LEN , path )
| |
starts_with_media_dir ( OMFI_MEDIAFILES_DIRNAME ,
OMFI_MEDIAFILES_DIRNAME_LEN , path )
)
{
ret = True ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with ret '%s' \n " ,
ret = = True ? " True " : " False " ) ) ;
return ret ;
}
/*
* Returns depth of path under media directory . Deals with the
* occasional . . . . / . and . . . . / . . paths that get passed to stat .
*
* Assumes is_in_media_files has already been called and has returned
* true for the path ; if it hasn ' t , this function will likely crash
* and burn .
*
* Not foolproof ; something like " Avid MediaFiles/MXF/../foo/1 "
* would fool it . Haven ' t seen paths like that getting to the
* stat function yet , so ignoring that possibility for now .
*/
static int depth_from_media_dir ( const char * media_dirname ,
size_t media_dirname_len , const char * path )
{
int transition_count = 0 ;
2014-09-11 15:22:52 +04:00
const char * path_start ;
const char * pathPtr ;
2012-05-03 21:39:53 +04:00
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with media_dirname '%s' "
" path '%s' \n " , media_dirname , path ) ) ;
2012-05-03 21:39:53 +04:00
/* Sometimes Samba gives us "./OMFI MediaFiles". */
if ( strncmp ( path , " ./ " , 2 ) = = 0 )
{
path_start = & path [ 2 ] ;
}
else {
path_start = path ;
}
if ( path_start [ media_dirname_len ] = = ' \0 ' )
{
goto out ;
}
pathPtr = & path_start [ media_dirname_len + 1 ] ;
while ( 1 )
{
if ( * pathPtr = = ' \0 ' | | * pathPtr = = ' / ' )
{
if (
* ( pathPtr - 1 ) = = ' . '
& &
* ( pathPtr - 2 ) = = ' . '
& &
* ( pathPtr - 3 ) = = ' / '
)
{
transition_count - - ;
}
else if (
!
(
* ( pathPtr - 1 ) = = ' / '
| |
(
* ( pathPtr - 1 ) = = ' . '
& &
* ( pathPtr - 2 ) = = ' / '
)
)
)
{
transition_count + + ;
}
}
if ( * pathPtr = = ' \0 ' )
{
break ;
}
pathPtr + + ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with transition_count '%i' \n " ,
transition_count ) ) ;
out :
return transition_count ;
}
/* Identifies MDB and PMR files at end of path. */
static bool is_avid_database (
char * path ,
size_t path_len ,
const char * avid_db_filename ,
const size_t avid_db_filename_len )
{
bool ret = False ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with path '%s', "
" avid_db_filename '%s', "
" path_len '%i', "
" avid_db_filename_len '%i' \n " ,
path , avid_db_filename ,
2012-09-05 12:15:48 +04:00
( int ) path_len , ( int ) avid_db_filename_len ) ) ;
2012-08-31 16:10:02 +04:00
2012-05-03 21:39:53 +04:00
if (
path_len > avid_db_filename_len
& &
strcmp ( & path [ path_len - avid_db_filename_len ] ,
avid_db_filename ) = = 0
& &
(
path [ path_len - avid_db_filename_len - 1 ] = = ' / '
| |
2014-09-11 15:22:52 +04:00
( path_len > avid_db_filename_len
2012-05-03 21:39:53 +04:00
+ APPLE_DOUBLE_PREFIX_LEN
& &
path [ path_len - avid_db_filename_len
- APPLE_DOUBLE_PREFIX_LEN - 1 ] = = ' / '
& &
is_apple_double ( & path [ path_len
- avid_db_filename_len
2014-09-11 15:22:52 +04:00
- APPLE_DOUBLE_PREFIX_LEN ] ) )
2012-05-03 21:39:53 +04:00
)
)
{
ret = True ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with ret '%s' \n " ,
ret = = True ? " True " : " False " ) ) ;
return ret ;
}
/* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
* CREATING_SUBDIRNAME .
*
* Caller must free newPath .
*
* Success : return 0
* Failure : set errno , newPath NULL , return - 1
*/
static int alloc_get_client_path ( vfs_handle_struct * handle ,
TALLOC_CTX * ctx ,
const char * path ,
char * * newPath )
{
/* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
* directory in path - potentially in middle of path
* - with suffixed name .
*/
int status = 0 ;
char * pathPtr ;
2012-08-31 16:10:02 +04:00
size_t intermPathLen ;
DEBUG ( MH_INFO_DEBUG , ( " Entering with path '%s' \n " , path ) ) ;
2012-05-03 21:39:53 +04:00
* newPath = talloc_strdup ( ctx , path ) ;
if ( * newPath = = NULL )
{
DEBUG ( MH_ERR_DEBUG , ( " alloc_get_client_path ENOMEM #1 \n " ) ) ;
errno = ENOMEM ;
status = - 1 ;
goto out ;
}
DEBUG ( MH_INFO_DEBUG , ( " newPath #1 %s \n " , * newPath ) ) ;
if (
( pathPtr = strstr ( path , CREATING_DIRNAME ) ) ! = NULL
& &
(
* ( pathPtr + CREATING_DIRNAME_LEN ) = = ' \0 '
| |
* ( pathPtr + CREATING_DIRNAME_LEN ) = = ' / '
)
& &
(
2014-09-11 15:22:52 +04:00
( pathPtr - path > 0
2012-05-03 21:39:53 +04:00
& &
2014-09-11 15:22:52 +04:00
* ( pathPtr - 1 ) = = ' / ' )
2012-05-03 21:39:53 +04:00
| |
2014-09-11 15:22:52 +04:00
( pathPtr - path > APPLE_DOUBLE_PREFIX_LEN
2012-05-03 21:39:53 +04:00
& &
* ( pathPtr - APPLE_DOUBLE_PREFIX_LEN - 1 ) = = ' / '
& &
2014-09-11 15:22:52 +04:00
is_apple_double ( pathPtr - APPLE_DOUBLE_PREFIX_LEN ) )
2012-05-03 21:39:53 +04:00
)
)
{
/* Insert client suffix into path. */
( * newPath ) [ pathPtr - path + CREATING_DIRNAME_LEN ] = ' \0 ' ;
DEBUG ( MH_INFO_DEBUG , ( " newPath #2 %s \n " , * newPath ) ) ;
2012-08-29 15:37:05 +04:00
if ( ( status = alloc_append_client_suffix ( handle , newPath ) ) )
2012-05-03 21:39:53 +04:00
{
goto out ;
}
DEBUG ( MH_INFO_DEBUG , ( " newPath #3 %s \n " , * newPath ) ) ;
* newPath = talloc_strdup_append ( * newPath ,
pathPtr + CREATING_DIRNAME_LEN ) ;
if ( * newPath = = NULL )
{
DEBUG ( MH_ERR_DEBUG , ( " alloc_get_client_path "
" ENOMEM #2 \n " ) ) ;
errno = ENOMEM ;
status = - 1 ;
goto out ;
}
DEBUG ( MH_INFO_DEBUG , ( " newPath #4 %s \n " , * newPath ) ) ;
}
/* replace /MDB_FILENAME or /PMR_FILENAME or /._MDB_FILENAME
* or / . _PMR_FILENAME at newPath end with suffixed name .
*/
2012-08-31 16:10:02 +04:00
intermPathLen = strlen ( * newPath ) ;
2012-05-03 21:39:53 +04:00
if (
is_avid_database ( * newPath , intermPathLen ,
MDB_FILENAME , MDB_FILENAME_LEN )
| |
is_avid_database ( * newPath , intermPathLen ,
PMR_FILENAME , PMR_FILENAME_LEN )
)
{
DEBUG ( MH_INFO_DEBUG , ( " newPath #5 %s \n " , * newPath ) ) ;
2012-08-29 15:37:05 +04:00
if ( ( status = alloc_append_client_suffix ( handle , newPath ) ) )
2012-05-03 21:39:53 +04:00
{
goto out ;
}
DEBUG ( MH_INFO_DEBUG , ( " newPath #6 %s \n " , * newPath ) ) ;
}
out :
/* newPath must be freed in caller. */
DEBUG ( MH_INFO_DEBUG , ( " Leaving with *newPath '%s' \n " , * newPath ) ) ;
return status ;
}
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int alloc_get_client_smb_fname ( struct vfs_handle_struct * handle ,
TALLOC_CTX * ctx ,
const struct smb_filename * smb_fname ,
struct smb_filename * * clientFname )
{
int status = 0 ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with smb_fname->base_name '%s' \n " ,
smb_fname - > base_name ) ) ;
2014-09-11 15:33:42 +04:00
* clientFname = cp_smb_filename ( ctx , smb_fname ) ;
if ( ( * clientFname ) = = NULL ) {
2012-05-03 21:39:53 +04:00
DEBUG ( MH_ERR_DEBUG , ( " alloc_get_client_smb_fname "
" NTERR \n " ) ) ;
2013-04-11 18:14:05 +04:00
errno = ENOMEM ;
2012-05-03 21:39:53 +04:00
status = - 1 ;
goto err ;
}
2012-08-29 15:37:05 +04:00
if ( ( status = alloc_get_client_path ( handle , ctx ,
2012-05-03 21:39:53 +04:00
smb_fname - > base_name ,
2012-08-29 15:37:05 +04:00
& ( * clientFname ) - > base_name ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with (*clientFname)->base_name "
" '%s' \n " , ( * clientFname ) - > base_name ) ) ;
err :
return status ;
}
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int alloc_set_client_dirinfo_path ( struct vfs_handle_struct * handle ,
TALLOC_CTX * ctx ,
char * * path ,
const char * avid_db_filename )
{
int status = 0 ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with avid_db_filename '%s' \n " ,
avid_db_filename ) ) ;
2012-05-03 21:39:53 +04:00
if ( ( * path = talloc_strdup ( ctx , avid_db_filename ) ) = = NULL )
{
DEBUG ( MH_ERR_DEBUG , ( " alloc_set_client_dirinfo_path "
" ENOMEM \n " ) ) ;
errno = ENOMEM ;
status = - 1 ;
goto err ;
}
2012-08-29 15:37:05 +04:00
if ( ( status = alloc_append_client_suffix ( handle , path ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
DEBUG ( MH_INFO_DEBUG , ( " Leaving with *path '%s' \n " , * path ) ) ;
err :
return status ;
}
/*
* Replace mtime on clientFname with mtime from client - suffixed
* equivalent , if it exists .
*
* Success : return 0
* Failure : set errno , return - 1
*/
static int set_fake_mtime ( vfs_handle_struct * handle ,
TALLOC_CTX * ctx ,
struct smb_filename * * clientFname ,
int ( * statFn ) ( const char * , SMB_STRUCT_STAT * , bool ) )
{
int status = 0 ;
2012-08-31 16:10:02 +04:00
char * statPath ;
SMB_STRUCT_STAT fakeStat ;
int copy_len ;
DEBUG ( MH_INFO_DEBUG , ( " Entering with (*clientFname)->base_name "
" '%s', (*clientFname)->st.st_ex_mtime %s " ,
( * clientFname ) - > base_name ,
ctime ( & ( ( * clientFname ) - > st . st_ex_mtime . tv_sec ) ) ) ) ;
2012-05-03 21:39:53 +04:00
if (
depth_from_media_dir ( AVID_MXF_DIRNAME ,
AVID_MXF_DIRNAME_LEN ,
( * clientFname ) - > base_name )
! = 1
& &
depth_from_media_dir ( OMFI_MEDIAFILES_DIRNAME ,
OMFI_MEDIAFILES_DIRNAME_LEN ,
( * clientFname ) - > base_name )
! = 0
)
{
goto out ;
}
2012-08-31 16:10:02 +04:00
copy_len = strlen ( ( * clientFname ) - > base_name ) ;
2012-05-03 21:39:53 +04:00
/* Hack to deal with occasional "Avid MediaFiles/MXF/1/." paths.
* We know we ' re under a media dir , so paths are at least 2 chars
* long .
*/
if ( ( * clientFname ) - > base_name [ copy_len - 1 ] = = ' . ' & &
( * clientFname ) - > base_name [ copy_len - 2 ] = = ' / ' )
{
copy_len - = 2 ;
}
2012-08-29 15:37:05 +04:00
if ( ( ( statPath = talloc_strndup ( ctx ,
( * clientFname ) - > base_name , copy_len ) ) = = NULL ) )
2012-05-03 21:39:53 +04:00
{
errno = ENOMEM ;
status = - 1 ;
goto err ;
}
2012-08-29 15:37:05 +04:00
if ( ( status = alloc_append_client_suffix ( handle , & statPath ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
DEBUG ( MH_INFO_DEBUG , ( " Fake stat'ing '%s' \n " , statPath ) ) ;
if ( statFn ( statPath , & fakeStat ,
2014-02-04 06:09:02 +04:00
lp_fake_directory_create_times ( SNUM ( handle - > conn ) ) ) )
2012-05-03 21:39:53 +04:00
{
/* This can fail for legitimate reasons - i.e. the
* fakeStat directory doesn ' t exist , which is okay
* - so we don ' t set status . But if it does fail ,
* we need to skip over the mtime assignment .
*/
goto err ;
}
DEBUG ( MH_INFO_DEBUG , ( " Setting fake mtime from '%s' \n " , statPath ) ) ;
( * clientFname ) - > st . st_ex_mtime = fakeStat . st_ex_mtime ;
err :
TALLOC_FREE ( statPath ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with (*clientFname)->base_name "
" '%s', (*clientFname)->st.st_ex_mtime %s " ,
( * clientFname ) - > base_name ,
ctime ( & ( ( * clientFname ) - > st . st_ex_mtime . tv_sec ) ) ) ) ;
return status ;
}
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_statvfs ( struct vfs_handle_struct * handle ,
2017-06-03 01:26:06 +03:00
const struct smb_filename * smb_fname ,
2012-05-03 21:39:53 +04:00
struct vfs_statvfs_struct * statbuf )
{
int status ;
2017-06-03 01:26:06 +03:00
struct smb_filename * clientFname = NULL ;
2012-08-31 16:10:02 +04:00
2017-06-03 01:26:06 +03:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with path '%s' \n " ,
smb_fname - > base_name ) ) ;
2012-05-03 21:39:53 +04:00
2017-06-03 01:26:06 +03:00
if ( ! is_in_media_files ( smb_fname - > base_name ) )
2012-05-03 21:39:53 +04:00
{
2017-06-03 01:26:06 +03:00
status = SMB_VFS_NEXT_STATVFS ( handle , smb_fname , statbuf ) ;
2012-05-03 21:39:53 +04:00
goto out ;
}
2017-06-03 01:26:06 +03:00
status = alloc_get_client_smb_fname ( handle ,
talloc_tos ( ) ,
smb_fname ,
& clientFname ) ;
if ( status ! = 0 ) {
2012-05-03 21:39:53 +04:00
goto err ;
}
2017-06-03 01:26:06 +03:00
status = SMB_VFS_NEXT_STATVFS ( handle , clientFname , statbuf ) ;
2012-05-03 21:39:53 +04:00
err :
2017-06-03 01:26:06 +03:00
TALLOC_FREE ( clientFname ) ;
2012-05-03 21:39:53 +04:00
out :
2017-06-03 01:26:06 +03:00
DEBUG ( MH_INFO_DEBUG , ( " Leaving with path '%s' \n " ,
smb_fname - > base_name ) ) ;
2012-05-03 21:39:53 +04:00
return status ;
}
static int alloc_set_client_dirinfo ( vfs_handle_struct * handle ,
const char * fname ,
struct mh_dirinfo_struct * * dirInfo )
{
int status = 0 ;
2012-08-31 16:10:02 +04:00
char * clientPath ;
TALLOC_CTX * ctx ;
DEBUG ( MH_INFO_DEBUG , ( " Entering with fname '%s' \n " , fname ) ) ;
2012-05-03 21:39:53 +04:00
* dirInfo = talloc ( NULL , struct mh_dirinfo_struct ) ;
if ( * dirInfo = = NULL )
{
goto err ;
}
( * dirInfo ) - > dirpath = talloc_strdup ( * dirInfo , fname ) ;
if ( ( * dirInfo ) - > dirpath = = NULL )
{
goto err ;
}
if ( ! is_in_media_files ( fname ) )
{
( * dirInfo ) - > clientPath = NULL ;
( * dirInfo ) - > clientMDBFilename = NULL ;
( * dirInfo ) - > clientPMRFilename = NULL ;
( * dirInfo ) - > clientCreatingDirname = NULL ;
( * dirInfo ) - > isInMediaFiles = False ;
goto out ;
}
( * dirInfo ) - > isInMediaFiles = True ;
if ( alloc_set_client_dirinfo_path ( handle ,
* dirInfo ,
& ( ( * dirInfo ) - > clientMDBFilename ) ,
MDB_FILENAME ) )
{
goto err ;
}
if ( alloc_set_client_dirinfo_path ( handle ,
* dirInfo ,
& ( ( * dirInfo ) - > clientPMRFilename ) ,
PMR_FILENAME ) )
{
goto err ;
}
if ( alloc_set_client_dirinfo_path ( handle ,
* dirInfo ,
& ( ( * dirInfo ) - > clientCreatingDirname ) ,
CREATING_DIRNAME ) )
{
goto err ;
}
2012-08-31 16:10:02 +04:00
clientPath = NULL ;
ctx = talloc_tos ( ) ;
2012-05-03 21:39:53 +04:00
if ( alloc_get_client_path ( handle , ctx ,
fname ,
& clientPath ) )
{
goto err ;
}
( * dirInfo ) - > clientPath = talloc_strdup ( * dirInfo , clientPath ) ;
if ( ( * dirInfo ) - > clientPath = = NULL )
{
goto err ;
}
TALLOC_FREE ( clientPath ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with (*dirInfo)->dirpath '%s', "
" (*dirInfo)->clientPath '%s' \n " ,
( * dirInfo ) - > dirpath ,
( * dirInfo ) - > clientPath ) ) ;
return status ;
err :
DEBUG ( MH_ERR_DEBUG , ( " Failing with fname '%s' \n " , fname ) ) ;
TALLOC_FREE ( * dirInfo ) ;
status = - 1 ;
errno = ENOMEM ;
return status ;
}
static DIR * mh_fdopendir ( vfs_handle_struct * handle ,
files_struct * fsp ,
const char * mask ,
2015-05-03 06:11:02 +03:00
uint32_t attr )
2012-05-03 21:39:53 +04:00
{
2012-12-10 16:35:27 +04:00
struct mh_dirinfo_struct * dirInfo = NULL ;
2012-05-03 21:39:53 +04:00
DIR * dirstream ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with fsp->fsp_name->base_name '%s' \n " ,
fsp - > fsp_name - > base_name ) ) ;
2012-05-03 21:39:53 +04:00
dirstream = SMB_VFS_NEXT_FDOPENDIR ( handle , fsp , mask , attr ) ;
if ( ! dirstream )
{
goto err ;
}
if ( alloc_set_client_dirinfo ( handle , fsp - > fsp_name - > base_name ,
& dirInfo ) )
{
goto err ;
}
dirInfo - > dirstream = dirstream ;
if ( ! dirInfo - > isInMediaFiles ) {
goto out ;
}
if ( set_fake_mtime ( handle , fsp , & ( fsp - > fsp_name ) , sys_stat ) )
{
goto err ;
}
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with dirInfo->dirpath '%s', "
" dirInfo->clientPath '%s', "
" fsp->fsp_name->st.st_ex_mtime %s " ,
dirInfo - > dirpath ,
dirInfo - > clientPath ,
ctime ( & ( fsp - > fsp_name - > st . st_ex_mtime . tv_sec ) ) ) ) ;
/* Success is freed in closedir. */
return ( DIR * ) dirInfo ;
err :
/* Failure is freed here. */
DEBUG ( MH_ERR_DEBUG , ( " Failing with fsp->fsp_name->base_name '%s' \n " ,
fsp - > fsp_name - > base_name ) ) ;
TALLOC_FREE ( dirInfo ) ;
return NULL ;
}
/*
* skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
* directory , skip other client ' s suffixed MDB_FILENAME and PMR_FILENAME
* filenames and CREATING_DIRNAME directory , replace this client ' s
* suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
* directory with non suffixed .
*
* Success : return dirent
* End of data : return NULL
* Failure : set errno , return NULL
*/
static struct dirent * mh_readdir ( vfs_handle_struct * handle ,
2020-11-22 15:57:27 +03:00
struct files_struct * dirfsp ,
DIR * dirp ,
SMB_STRUCT_STAT * sbuf )
2012-05-03 21:39:53 +04:00
{
mh_dirinfo_struct * dirInfo = ( mh_dirinfo_struct * ) dirp ;
2012-08-31 16:10:02 +04:00
struct dirent * d = NULL ;
int skip ;
2012-05-03 21:39:53 +04:00
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_readdir \n " ) ) ;
2012-05-03 21:39:53 +04:00
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " dirInfo->dirpath '%s', "
" dirInfo->clientPath '%s', "
" dirInfo->isInMediaFiles '%s', "
" dirInfo->clientMDBFilename '%s', "
" dirInfo->clientPMRFilename '%s', "
" dirInfo->clientCreatingDirname '%s' \n " ,
dirInfo - > dirpath ,
dirInfo - > clientPath ,
dirInfo - > isInMediaFiles ? " True " : " False " ,
dirInfo - > clientMDBFilename ,
dirInfo - > clientPMRFilename ,
dirInfo - > clientCreatingDirname ) ) ;
2012-05-03 21:39:53 +04:00
if ( ! dirInfo - > isInMediaFiles )
{
2020-11-22 15:57:27 +03:00
d = SMB_VFS_NEXT_READDIR ( handle , dirfsp , dirInfo - > dirstream , sbuf ) ;
2012-05-03 21:39:53 +04:00
goto out ;
}
do
{
2012-08-31 16:10:02 +04:00
const char * dname ;
bool isAppleDouble ;
2012-05-03 21:39:53 +04:00
skip = False ;
2020-11-22 15:57:27 +03:00
d = SMB_VFS_NEXT_READDIR ( handle , dirfsp , dirInfo - > dirstream , sbuf ) ;
2012-05-03 21:39:53 +04:00
if ( d = = NULL )
{
break ;
}
/* ignore apple double prefix for logic below */
if ( is_apple_double ( d - > d_name ) )
{
dname = & d - > d_name [ APPLE_DOUBLE_PREFIX_LEN ] ;
isAppleDouble = True ;
}
else
{
dname = d - > d_name ;
isAppleDouble = False ;
}
/* skip Avid-special files with no client suffix */
if (
strcmp ( dname , MDB_FILENAME ) = = 0
| |
strcmp ( dname , PMR_FILENAME ) = = 0
| |
strcmp ( dname , CREATING_DIRNAME ) = = 0
)
{
skip = True ;
}
/* chop client suffix off this client's suffixed files */
else if ( strcmp ( dname , dirInfo - > clientMDBFilename ) = = 0 )
{
if ( isAppleDouble )
{
d - > d_name [ MDB_FILENAME_LEN
+ APPLE_DOUBLE_PREFIX_LEN ] = ' \0 ' ;
}
else
{
d - > d_name [ MDB_FILENAME_LEN ] = ' \0 ' ;
}
}
else if ( strcmp ( dname , dirInfo - > clientPMRFilename ) = = 0 )
{
if ( isAppleDouble )
{
d - > d_name [ PMR_FILENAME_LEN
+ APPLE_DOUBLE_PREFIX_LEN ] = ' \0 ' ;
}
else
{
d - > d_name [ PMR_FILENAME_LEN ] = ' \0 ' ;
}
}
else if ( strcmp ( dname , dirInfo - > clientCreatingDirname )
= = 0 )
{
if ( isAppleDouble )
{
d - > d_name [ CREATING_DIRNAME_LEN
+ APPLE_DOUBLE_PREFIX_LEN ] = ' \0 ' ;
}
else
{
d - > d_name [ CREATING_DIRNAME_LEN ] = ' \0 ' ;
}
}
/*
* Anything that starts as an Avid - special file
* that ' s made it this far should be skipped . This
* is different from the original behaviour , which
* only skipped other client ' s suffixed files .
*/
else if (
strncmp ( MDB_FILENAME , dname ,
MDB_FILENAME_LEN ) = = 0
| |
strncmp ( PMR_FILENAME , dname ,
PMR_FILENAME_LEN ) = = 0
| |
strncmp ( CREATING_DIRNAME , dname ,
CREATING_DIRNAME_LEN ) = = 0
)
{
skip = True ;
}
}
while ( skip ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving mh_readdir \n " ) ) ;
return d ;
}
/*
* Success : no success result defined .
* Failure : no failure result defined .
*/
static void mh_seekdir ( vfs_handle_struct * handle ,
DIR * dirp ,
long offset )
{
DEBUG ( MH_INFO_DEBUG , ( " Entering and leaving mh_seekdir \n " ) ) ;
2012-08-07 21:16:40 +04:00
SMB_VFS_NEXT_SEEKDIR ( handle ,
2012-05-03 21:39:53 +04:00
( ( mh_dirinfo_struct * ) dirp ) - > dirstream , offset ) ;
}
/*
* Success : return long
* Failure : no failure result defined .
*/
static long mh_telldir ( vfs_handle_struct * handle ,
DIR * dirp )
{
DEBUG ( MH_INFO_DEBUG , ( " Entering and leaving mh_telldir \n " ) ) ;
return SMB_VFS_NEXT_TELLDIR ( handle ,
( ( mh_dirinfo_struct * ) dirp ) - > dirstream ) ;
}
/*
* Success : no success result defined .
* Failure : no failure result defined .
*/
static void mh_rewinddir ( vfs_handle_struct * handle ,
DIR * dirp )
{
DEBUG ( MH_INFO_DEBUG , ( " Entering and leaving mh_rewinddir \n " ) ) ;
2012-08-07 21:16:40 +04:00
SMB_VFS_NEXT_REWINDDIR ( handle ,
2012-05-03 21:39:53 +04:00
( ( mh_dirinfo_struct * ) dirp ) - > dirstream ) ;
}
2019-09-05 20:26:53 +03:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_mkdirat ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
mode_t mode )
{
int status ;
struct smb_filename * clientFname = NULL ;
const char * path = smb_fname - > base_name ;
2020-12-14 17:35:22 +03:00
struct smb_filename * full_fname = NULL ;
2019-09-05 20:26:53 +03:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with path '%s' \n " , path ) ) ;
if ( ! is_in_media_files ( path ) ) {
status = SMB_VFS_NEXT_MKDIRAT ( handle ,
dirfsp ,
smb_fname ,
mode ) ;
goto out ;
}
2020-12-14 17:35:22 +03:00
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
return - 1 ;
}
2019-09-05 20:26:53 +03:00
status = alloc_get_client_smb_fname ( handle ,
talloc_tos ( ) ,
2020-12-14 17:35:22 +03:00
full_fname ,
2019-09-05 20:26:53 +03:00
& clientFname ) ;
if ( status ! = 0 ) {
goto err ;
}
status = SMB_VFS_NEXT_MKDIRAT ( handle ,
2020-12-14 17:35:22 +03:00
handle - > conn - > cwd_fsp ,
2019-09-05 20:26:53 +03:00
clientFname ,
mode ) ;
err :
2020-12-14 17:35:22 +03:00
TALLOC_FREE ( full_fname ) ;
2019-09-05 20:26:53 +03:00
TALLOC_FREE ( clientFname ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with path '%s' \n " , path ) ) ;
return status ;
}
2012-05-03 21:39:53 +04:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_closedir ( vfs_handle_struct * handle ,
DIR * dirp )
{
DIR * realdirp = ( ( mh_dirinfo_struct * ) dirp ) - > dirstream ;
2012-08-31 16:10:02 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_closedir \n " ) ) ;
2012-05-03 21:39:53 +04:00
// Will this talloc_free destroy realdirp?
TALLOC_FREE ( dirp ) ;
DEBUG ( MH_INFO_DEBUG , ( " Leaving mh_closedir \n " ) ) ;
return SMB_VFS_NEXT_CLOSEDIR ( handle , realdirp ) ;
}
2020-05-20 22:43:26 +03:00
/*
* Success : return non - negative file descriptor
* Failure : set errno , return - 1
*/
static int mh_openat ( struct vfs_handle_struct * handle ,
const struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
files_struct * fsp ,
2022-06-03 16:53:29 +03:00
const struct vfs_open_how * how )
2020-05-20 22:43:26 +03:00
{
int ret ;
struct smb_filename * clientFname ;
TALLOC_CTX * ctx ;
DEBUG ( MH_INFO_DEBUG , ( " Entering with smb_fname->base_name '%s' \n " ,
smb_fname - > base_name ) ) ;
if ( ! is_in_media_files ( smb_fname - > base_name ) ) {
ret = SMB_VFS_NEXT_OPENAT ( handle ,
dirfsp ,
smb_fname ,
fsp ,
2022-06-03 16:53:29 +03:00
how ) ;
2020-05-20 22:43:26 +03:00
goto out ;
}
clientFname = NULL ;
ctx = talloc_tos ( ) ;
if ( alloc_get_client_smb_fname ( handle , ctx , smb_fname , & clientFname ) ) {
ret = - 1 ;
goto err ;
}
/*
* What about fsp - > fsp_name ? We also have to get correct stat info into
* fsp and smb_fname for DB files , don ' t we ?
*/
DEBUG ( MH_INFO_DEBUG , ( " Leaving with smb_fname->base_name '%s' "
" smb_fname->st.st_ex_mtime %s "
" fsp->fsp_name->st.st_ex_mtime %s " ,
smb_fname - > base_name ,
ctime ( & ( smb_fname - > st . st_ex_mtime . tv_sec ) ) ,
ctime ( & ( fsp - > fsp_name - > st . st_ex_mtime . tv_sec ) ) ) ) ;
2022-06-03 16:53:29 +03:00
ret = SMB_VFS_NEXT_OPENAT ( handle , dirfsp , clientFname , fsp , how ) ;
2020-05-20 22:43:26 +03:00
err :
TALLOC_FREE ( clientFname ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with smb_fname->base_name '%s' \n " ,
smb_fname - > base_name ) ) ;
return ret ;
}
2012-05-03 21:39:53 +04:00
/*
* Success : return non - negative file descriptor
* Failure : set errno , return - 1
*/
static NTSTATUS mh_create_file ( vfs_handle_struct * handle ,
struct smb_request * req ,
2021-11-23 14:29:17 +03:00
struct files_struct * dirfsp ,
2012-05-03 21:39:53 +04:00
struct smb_filename * smb_fname ,
uint32_t access_mask ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options ,
uint32_t file_attributes ,
uint32_t oplock_request ,
2019-08-07 23:00:11 +03:00
const struct smb2_lease * lease ,
2012-05-03 21:39:53 +04:00
uint64_t allocation_size ,
uint32_t private_flags ,
struct security_descriptor * sd ,
struct ea_list * ea_list ,
files_struct * * result_fsp ,
2014-11-26 16:12:51 +03:00
int * pinfo ,
const struct smb2_create_blobs * in_context_blobs ,
struct smb2_create_blobs * out_context_blobs )
2012-05-03 21:39:53 +04:00
{
NTSTATUS status ;
2012-08-31 16:10:02 +04:00
struct smb_filename * clientFname ;
TALLOC_CTX * ctx ;
2012-05-03 21:39:53 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with smb_fname->base_name '%s' \n " ,
smb_fname - > base_name ) ) ;
if ( ! is_in_media_files ( smb_fname - > base_name ) )
{
status = SMB_VFS_NEXT_CREATE_FILE (
handle ,
req ,
2021-11-23 14:29:17 +03:00
dirfsp ,
2012-05-03 21:39:53 +04:00
smb_fname ,
access_mask ,
share_access ,
create_disposition ,
create_options ,
file_attributes ,
oplock_request ,
2013-08-21 17:56:14 +04:00
lease ,
2012-05-03 21:39:53 +04:00
allocation_size ,
private_flags ,
sd ,
ea_list ,
result_fsp ,
2014-11-26 16:12:51 +03:00
pinfo ,
in_context_blobs ,
out_context_blobs ) ;
2012-05-03 21:39:53 +04:00
goto out ;
}
2012-08-31 16:10:02 +04:00
clientFname = NULL ;
ctx = talloc_tos ( ) ;
2012-05-03 21:39:53 +04:00
if ( alloc_get_client_smb_fname ( handle , ctx ,
smb_fname ,
& clientFname ) )
{
status = map_nt_error_from_unix ( errno ) ;
goto err ;
}
/* This only creates files, so we don't have to worry about
* our fake directory stat ' ing here .
*/
// But we still need to route stat calls for DB files
// properly, right?
status = SMB_VFS_NEXT_CREATE_FILE (
handle ,
req ,
2021-11-23 14:29:17 +03:00
dirfsp ,
2012-05-03 21:39:53 +04:00
clientFname ,
access_mask ,
share_access ,
create_disposition ,
create_options ,
file_attributes ,
oplock_request ,
2013-08-21 17:56:14 +04:00
lease ,
2012-05-03 21:39:53 +04:00
allocation_size ,
private_flags ,
sd ,
ea_list ,
result_fsp ,
2014-11-26 16:12:51 +03:00
pinfo ,
in_context_blobs ,
out_context_blobs ) ;
2012-05-03 21:39:53 +04:00
err :
TALLOC_FREE ( clientFname ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with smb_fname->base_name '%s' "
" smb_fname->st.st_ex_mtime %s "
" fsp->fsp_name->st.st_ex_mtime %s " ,
smb_fname - > base_name ,
ctime ( & ( smb_fname - > st . st_ex_mtime . tv_sec ) ) ,
( * result_fsp ) & & VALID_STAT ( ( * result_fsp ) - > fsp_name - > st ) ?
ctime ( & ( ( * result_fsp ) - > fsp_name - > st . st_ex_mtime . tv_sec ) ) :
" No fsp time \n " ) ) ;
return status ;
}
/*
* Success : return 0
* Failure : set errno , return - 1
*/
2019-08-10 01:03:06 +03:00
static int mh_renameat ( vfs_handle_struct * handle ,
files_struct * srcfsp ,
const struct smb_filename * smb_fname_src ,
files_struct * dstfsp ,
const struct smb_filename * smb_fname_dst )
{
2021-06-17 20:47:42 +03:00
int status = - 1 ;
struct smb_filename * full_fname_src = NULL ;
struct smb_filename * full_fname_dst = NULL ;
struct smb_filename * srcClientFname = NULL ;
struct smb_filename * dstClientFname = NULL ;
2019-08-10 01:03:06 +03:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with "
" smb_fname_src->base_name '%s', "
" smb_fname_dst->base_name '%s' \n " ,
smb_fname_src - > base_name ,
smb_fname_dst - > base_name ) ) ;
if ( ! is_in_media_files ( smb_fname_src - > base_name )
& &
! is_in_media_files ( smb_fname_dst - > base_name ) )
{
status = SMB_VFS_NEXT_RENAMEAT ( handle ,
srcfsp ,
smb_fname_src ,
dstfsp ,
smb_fname_dst ) ;
goto out ;
}
2021-06-17 20:47:42 +03:00
full_fname_src = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
srcfsp ,
smb_fname_src ) ;
if ( full_fname_src = = NULL ) {
errno = ENOMEM ;
goto out ;
}
full_fname_dst = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dstfsp ,
smb_fname_dst ) ;
if ( full_fname_dst = = NULL ) {
errno = ENOMEM ;
goto out ;
}
2019-08-10 01:03:06 +03:00
2021-06-17 20:47:42 +03:00
if ( ( status = alloc_get_client_smb_fname ( handle ,
talloc_tos ( ) ,
full_fname_src ,
2019-08-10 01:03:06 +03:00
& srcClientFname ) ) )
{
goto err ;
}
2021-06-17 20:47:42 +03:00
if ( ( status = alloc_get_client_smb_fname ( handle ,
talloc_tos ( ) ,
full_fname_dst ,
2019-08-10 01:03:06 +03:00
& dstClientFname ) ) )
{
goto err ;
}
status = SMB_VFS_NEXT_RENAMEAT ( handle ,
2021-06-17 20:47:42 +03:00
srcfsp - > conn - > cwd_fsp ,
2019-08-10 01:03:06 +03:00
srcClientFname ,
2021-06-17 20:47:42 +03:00
dstfsp - > conn - > cwd_fsp ,
2019-08-10 01:03:06 +03:00
dstClientFname ) ;
err :
2021-06-17 20:47:42 +03:00
TALLOC_FREE ( full_fname_src ) ;
TALLOC_FREE ( full_fname_dst ) ;
2019-08-10 01:03:06 +03:00
TALLOC_FREE ( dstClientFname ) ;
TALLOC_FREE ( srcClientFname ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with smb_fname_src->base_name '%s', "
" smb_fname_dst->base_name '%s' \n " ,
smb_fname_src - > base_name ,
smb_fname_dst - > base_name ) ) ;
return status ;
}
2012-05-03 21:39:53 +04:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_stat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
{
int status = 0 ;
2012-08-31 16:10:02 +04:00
struct smb_filename * clientFname ;
TALLOC_CTX * ctx ;
DEBUG ( MH_INFO_DEBUG , ( " Entering with smb_fname->base_name '%s' \n " ,
smb_fname - > base_name ) ) ;
2012-05-03 21:39:53 +04:00
if ( ! is_in_media_files ( smb_fname - > base_name ) )
{
status = SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
goto out ;
}
2012-08-31 16:10:02 +04:00
clientFname = NULL ;
ctx = talloc_tos ( ) ;
2012-05-03 21:39:53 +04:00
2012-08-29 15:37:05 +04:00
if ( ( status = alloc_get_client_smb_fname ( handle , ctx ,
2012-05-03 21:39:53 +04:00
smb_fname ,
2012-08-29 15:37:05 +04:00
& clientFname ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
DEBUG ( MH_INFO_DEBUG , ( " Stat'ing clientFname->base_name '%s' \n " ,
clientFname - > base_name ) ) ;
2012-08-29 15:37:05 +04:00
if ( ( status = SMB_VFS_NEXT_STAT ( handle , clientFname ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
2012-08-29 15:37:05 +04:00
if ( ( status = set_fake_mtime ( handle , ctx , & clientFname , sys_stat ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
/* Unlike functions with const smb_filename, we have to
* modify smb_fname itself to pass our info back up .
*/
DEBUG ( MH_INFO_DEBUG , ( " Setting smb_fname '%s' stat "
" from clientFname '%s' \n " ,
smb_fname - > base_name ,
clientFname - > base_name ) ) ;
smb_fname - > st = clientFname - > st ;
err :
TALLOC_FREE ( clientFname ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with smb_fname->st.st_ex_mtime %s " ,
ctime ( & ( smb_fname - > st . st_ex_mtime . tv_sec ) ) ) ) ;
return status ;
}
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_lstat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
{
int status = 0 ;
2012-08-31 16:10:02 +04:00
struct smb_filename * clientFname ;
TALLOC_CTX * ctx ;
DEBUG ( MH_INFO_DEBUG , ( " Entering with smb_fname->base_name '%s' \n " ,
smb_fname - > base_name ) ) ;
2012-05-03 21:39:53 +04:00
if ( ! is_in_media_files ( smb_fname - > base_name ) )
{
status = SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
goto out ;
}
2012-08-31 16:10:02 +04:00
clientFname = NULL ;
ctx = talloc_tos ( ) ;
2012-05-03 21:39:53 +04:00
2012-08-29 15:37:05 +04:00
if ( ( status = alloc_get_client_smb_fname ( handle , ctx ,
2012-05-03 21:39:53 +04:00
smb_fname ,
2012-08-29 15:37:05 +04:00
& clientFname ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
2012-08-29 15:37:05 +04:00
if ( ( status = SMB_VFS_NEXT_LSTAT ( handle , clientFname ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
2012-08-29 15:37:05 +04:00
if ( ( status = set_fake_mtime ( handle , ctx , & clientFname , sys_lstat ) ) )
2012-05-03 21:39:53 +04:00
{
goto err ;
}
/* Unlike functions with const smb_filename, we have to
* modify smb_fname itself to pass our info back up .
*/
smb_fname - > st = clientFname - > st ;
err :
TALLOC_FREE ( clientFname ) ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with smb_fname->st.st_ex_mtime %s " ,
ctime ( & ( smb_fname - > st . st_ex_mtime . tv_sec ) ) ) ) ;
return status ;
}
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_fstat ( vfs_handle_struct * handle ,
files_struct * fsp , SMB_STRUCT_STAT * sbuf )
{
2012-08-31 16:10:02 +04:00
int status = 0 ;
2012-05-03 21:39:53 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering with fsp->fsp_name->base_name "
" '%s' \n " , fsp_str_dbg ( fsp ) ) ) ;
2012-08-29 15:37:05 +04:00
if ( ( status = SMB_VFS_NEXT_FSTAT ( handle , fsp , sbuf ) ) )
2012-05-03 21:39:53 +04:00
{
goto out ;
}
if ( fsp - > fsp_name = = NULL
| | ! is_in_media_files ( fsp - > fsp_name - > base_name ) )
{
goto out ;
}
2012-08-29 15:37:05 +04:00
if ( ( status = mh_stat ( handle , fsp - > fsp_name ) ) )
2012-05-03 21:39:53 +04:00
{
goto out ;
}
* sbuf = fsp - > fsp_name - > st ;
out :
DEBUG ( MH_INFO_DEBUG , ( " Leaving with fsp->fsp_name->st.st_ex_mtime "
" %s " ,
2012-12-17 18:36:32 +04:00
fsp - > fsp_name ! = NULL ?
ctime ( & ( fsp - > fsp_name - > st . st_ex_mtime . tv_sec ) ) :
" 0 " ) ) ;
2012-05-03 21:39:53 +04:00
return status ;
}
2019-09-12 21:51:09 +03:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_unlinkat ( vfs_handle_struct * handle ,
struct files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
int flags )
{
int status ;
2021-01-20 17:02:54 +03:00
struct smb_filename * full_fname = NULL ;
2019-09-12 21:51:09 +03:00
struct smb_filename * clientFname ;
TALLOC_CTX * ctx ;
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_unlinkat \n " ) ) ;
if ( ! is_in_media_files ( smb_fname - > base_name ) ) {
status = SMB_VFS_NEXT_UNLINKAT ( handle ,
dirfsp ,
smb_fname ,
flags ) ;
goto out ;
}
clientFname = NULL ;
ctx = talloc_tos ( ) ;
2021-01-20 17:02:54 +03:00
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
return - 1 ;
}
2019-09-12 21:51:09 +03:00
if ( ( status = alloc_get_client_smb_fname ( handle , ctx ,
2021-01-20 17:02:54 +03:00
full_fname ,
2019-09-12 21:51:09 +03:00
& clientFname ) ) ) {
goto err ;
}
status = SMB_VFS_NEXT_UNLINKAT ( handle ,
2021-01-20 17:02:54 +03:00
dirfsp - > conn - > cwd_fsp ,
2019-09-12 21:51:09 +03:00
clientFname ,
flags ) ;
err :
2021-01-20 17:02:54 +03:00
TALLOC_FREE ( full_fname ) ;
2019-09-12 21:51:09 +03:00
TALLOC_FREE ( clientFname ) ;
out :
return status ;
}
2012-05-03 21:39:53 +04:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_lchown ( vfs_handle_struct * handle ,
2016-03-04 01:34:57 +03:00
const struct smb_filename * smb_fname ,
2012-05-03 21:39:53 +04:00
uid_t uid ,
gid_t gid )
{
int status ;
2016-03-04 01:34:57 +03:00
struct smb_filename * clientFname = NULL ;
2012-05-03 21:39:53 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_lchown \n " ) ) ;
2016-03-04 01:34:57 +03:00
if ( ! is_in_media_files ( smb_fname - > base_name ) )
2012-05-03 21:39:53 +04:00
{
2016-03-04 01:34:57 +03:00
status = SMB_VFS_NEXT_LCHOWN ( handle , smb_fname , uid , gid ) ;
2012-05-03 21:39:53 +04:00
goto out ;
}
2016-03-04 01:34:57 +03:00
status = alloc_get_client_smb_fname ( handle ,
talloc_tos ( ) ,
smb_fname ,
& clientFname ) ;
if ( status ! = 0 ) {
2012-05-03 21:39:53 +04:00
goto err ;
}
2016-03-04 01:34:57 +03:00
status = SMB_VFS_NEXT_LCHOWN ( handle , clientFname , uid , gid ) ;
2012-05-03 21:39:53 +04:00
err :
2016-03-04 01:34:57 +03:00
TALLOC_FREE ( clientFname ) ;
2012-05-03 21:39:53 +04:00
out :
return status ;
}
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_chdir ( vfs_handle_struct * handle ,
2017-06-29 21:29:33 +03:00
const struct smb_filename * smb_fname )
2012-05-03 21:39:53 +04:00
{
int status ;
2017-06-29 21:29:33 +03:00
struct smb_filename * clientFname = NULL ;
2012-05-03 21:39:53 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_chdir \n " ) ) ;
2017-06-29 21:29:33 +03:00
if ( ! is_in_media_files ( smb_fname - > base_name ) ) {
status = SMB_VFS_NEXT_CHDIR ( handle , smb_fname ) ;
2012-05-03 21:39:53 +04:00
goto out ;
}
2017-06-29 21:29:33 +03:00
status = alloc_get_client_smb_fname ( handle ,
talloc_tos ( ) ,
smb_fname ,
& clientFname ) ;
if ( status ! = 0 ) {
2012-05-03 21:39:53 +04:00
goto err ;
}
2017-06-29 21:29:33 +03:00
status = SMB_VFS_NEXT_CHDIR ( handle , clientFname ) ;
2012-05-03 21:39:53 +04:00
err :
2017-06-29 21:29:33 +03:00
TALLOC_FREE ( clientFname ) ;
2012-05-03 21:39:53 +04:00
out :
return status ;
}
2019-08-30 23:51:50 +03:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_symlinkat ( vfs_handle_struct * handle ,
2020-04-30 20:30:50 +03:00
const struct smb_filename * link_contents ,
2019-08-30 23:51:50 +03:00
struct files_struct * dirfsp ,
const struct smb_filename * new_smb_fname )
{
int status = - 1 ;
2021-01-25 23:26:14 +03:00
struct smb_filename * full_fname = NULL ;
2020-04-30 20:30:50 +03:00
struct smb_filename * new_link_target = NULL ;
2019-08-30 23:51:50 +03:00
struct smb_filename * newclientFname = NULL ;
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_symlinkat \n " ) ) ;
2021-01-25 23:26:14 +03:00
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
new_smb_fname ) ;
if ( full_fname = = NULL ) {
status = - 1 ;
goto err ;
}
2020-04-30 20:30:50 +03:00
if ( ! is_in_media_files ( link_contents - > base_name ) & &
2021-01-25 23:26:14 +03:00
! is_in_media_files ( full_fname - > base_name ) ) {
2019-08-30 23:51:50 +03:00
status = SMB_VFS_NEXT_SYMLINKAT ( handle ,
link_contents ,
dirfsp ,
new_smb_fname ) ;
goto out ;
}
2020-04-30 20:30:50 +03:00
if ( ( status = alloc_get_client_smb_fname ( handle , talloc_tos ( ) ,
2019-08-30 23:51:50 +03:00
link_contents ,
2020-04-30 20:30:50 +03:00
& new_link_target ) ) ) {
2019-08-30 23:51:50 +03:00
goto err ;
}
if ( ( status = alloc_get_client_smb_fname ( handle , talloc_tos ( ) ,
2021-01-25 23:26:14 +03:00
full_fname ,
2019-08-30 23:51:50 +03:00
& newclientFname ) ) ) {
goto err ;
}
status = SMB_VFS_NEXT_SYMLINKAT ( handle ,
2020-04-30 20:30:50 +03:00
new_link_target ,
2021-01-25 23:26:14 +03:00
handle - > conn - > cwd_fsp ,
2019-08-30 23:51:50 +03:00
newclientFname ) ;
err :
2020-04-30 20:30:50 +03:00
TALLOC_FREE ( new_link_target ) ;
2019-08-30 23:51:50 +03:00
TALLOC_FREE ( newclientFname ) ;
out :
2021-01-25 23:26:14 +03:00
TALLOC_FREE ( full_fname ) ;
2019-08-30 23:51:50 +03:00
return status ;
}
2019-08-23 00:24:49 +03:00
/*
* Success : return byte count
* Failure : set errno , return - 1
*/
static int mh_readlinkat ( vfs_handle_struct * handle ,
2020-10-13 16:19:30 +03:00
const struct files_struct * dirfsp ,
2019-08-23 00:24:49 +03:00
const struct smb_filename * smb_fname ,
char * buf ,
size_t bufsiz )
{
int status ;
2021-02-11 22:05:28 +03:00
struct smb_filename * full_fname = NULL ;
2019-08-23 00:24:49 +03:00
struct smb_filename * clientFname = NULL ;
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_readlinkat \n " ) ) ;
2021-02-11 22:05:28 +03:00
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
status = - 1 ;
goto err ;
}
if ( ! is_in_media_files ( full_fname - > base_name ) ) {
2019-08-23 00:24:49 +03:00
status = SMB_VFS_NEXT_READLINKAT ( handle ,
dirfsp ,
smb_fname ,
buf ,
bufsiz ) ;
goto out ;
}
if ( ( status = alloc_get_client_smb_fname ( handle , talloc_tos ( ) ,
2021-02-11 22:05:28 +03:00
full_fname ,
2019-08-23 00:24:49 +03:00
& clientFname ) ) ) {
goto err ;
}
status = SMB_VFS_NEXT_READLINKAT ( handle ,
2021-02-11 22:05:28 +03:00
handle - > conn - > cwd_fsp ,
2019-08-23 00:24:49 +03:00
clientFname ,
buf ,
bufsiz ) ;
err :
TALLOC_FREE ( clientFname ) ;
out :
2021-02-11 22:05:28 +03:00
TALLOC_FREE ( full_fname ) ;
2019-08-23 00:24:49 +03:00
return status ;
}
2019-08-17 01:57:15 +03:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_linkat ( vfs_handle_struct * handle ,
files_struct * srcfsp ,
const struct smb_filename * old_smb_fname ,
files_struct * dstfsp ,
const struct smb_filename * new_smb_fname ,
int flags )
{
int status ;
2021-02-03 23:36:27 +03:00
struct smb_filename * old_full_fname = NULL ;
2019-08-17 01:57:15 +03:00
struct smb_filename * oldclientFname = NULL ;
2021-02-03 23:36:27 +03:00
struct smb_filename * new_full_fname = NULL ;
2019-08-17 01:57:15 +03:00
struct smb_filename * newclientFname = NULL ;
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_linkat \n " ) ) ;
2021-02-03 23:36:27 +03:00
old_full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
srcfsp ,
old_smb_fname ) ;
if ( old_full_fname = = NULL ) {
status = - 1 ;
goto err ;
}
new_full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dstfsp ,
new_smb_fname ) ;
if ( new_full_fname = = NULL ) {
status = - 1 ;
goto err ;
}
if ( ! is_in_media_files ( old_full_fname - > base_name ) & &
! is_in_media_files ( new_full_fname - > base_name ) ) {
TALLOC_FREE ( old_full_fname ) ;
TALLOC_FREE ( new_full_fname ) ;
2019-08-17 01:57:15 +03:00
status = SMB_VFS_NEXT_LINKAT ( handle ,
srcfsp ,
old_smb_fname ,
dstfsp ,
new_smb_fname ,
flags ) ;
goto out ;
}
if ( ( status = alloc_get_client_smb_fname ( handle , talloc_tos ( ) ,
2021-02-03 23:36:27 +03:00
old_full_fname ,
2019-08-17 01:57:15 +03:00
& oldclientFname ) ) ) {
goto err ;
}
if ( ( status = alloc_get_client_smb_fname ( handle , talloc_tos ( ) ,
2021-02-03 23:36:27 +03:00
new_full_fname ,
2019-08-17 01:57:15 +03:00
& newclientFname ) ) ) {
goto err ;
}
status = SMB_VFS_NEXT_LINKAT ( handle ,
2021-02-03 23:36:27 +03:00
handle - > conn - > cwd_fsp ,
2019-08-17 01:57:15 +03:00
oldclientFname ,
2021-02-03 23:36:27 +03:00
handle - > conn - > cwd_fsp ,
2019-08-17 01:57:15 +03:00
newclientFname ,
flags ) ;
err :
2021-02-03 23:36:27 +03:00
TALLOC_FREE ( old_full_fname ) ;
TALLOC_FREE ( new_full_fname ) ;
2019-08-17 01:57:15 +03:00
TALLOC_FREE ( newclientFname ) ;
TALLOC_FREE ( oldclientFname ) ;
out :
return status ;
}
2019-08-21 02:55:55 +03:00
/*
* Success : return 0
* Failure : set errno , return - 1
*/
static int mh_mknodat ( vfs_handle_struct * handle ,
files_struct * dirfsp ,
const struct smb_filename * smb_fname ,
mode_t mode ,
SMB_DEV_T dev )
{
int status ;
2021-01-20 22:56:36 +03:00
struct smb_filename * full_fname = NULL ;
2019-08-21 02:55:55 +03:00
struct smb_filename * clientFname = NULL ;
TALLOC_CTX * ctx ;
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_mknodat \n " ) ) ;
2021-01-20 22:56:36 +03:00
full_fname = full_path_from_dirfsp_atname ( talloc_tos ( ) ,
dirfsp ,
smb_fname ) ;
if ( full_fname = = NULL ) {
status = - 1 ;
goto err ;
}
if ( ! is_in_media_files ( full_fname - > base_name ) ) {
2019-08-21 02:55:55 +03:00
status = SMB_VFS_NEXT_MKNODAT ( handle ,
dirfsp ,
smb_fname ,
mode ,
dev ) ;
goto out ;
}
ctx = talloc_tos ( ) ;
if ( ( status = alloc_get_client_smb_fname ( handle , ctx ,
2021-01-20 22:56:36 +03:00
full_fname ,
2019-08-21 02:55:55 +03:00
& clientFname ) ) ) {
goto err ;
}
status = SMB_VFS_NEXT_MKNODAT ( handle ,
2021-01-20 22:56:36 +03:00
handle - > conn - > cwd_fsp ,
2019-08-21 02:55:55 +03:00
clientFname ,
mode ,
dev ) ;
err :
TALLOC_FREE ( clientFname ) ;
out :
2021-01-20 22:56:36 +03:00
TALLOC_FREE ( full_fname ) ;
2019-08-21 02:55:55 +03:00
return status ;
}
2012-05-03 21:39:53 +04:00
/*
* Success : return path pointer
* Failure : set errno , return NULL pointer
*/
2017-06-30 21:32:59 +03:00
static struct smb_filename * mh_realpath ( vfs_handle_struct * handle ,
TALLOC_CTX * ctx ,
const struct smb_filename * smb_fname )
2012-05-03 21:39:53 +04:00
{
2017-06-30 21:32:59 +03:00
struct smb_filename * result_fname = NULL ;
struct smb_filename * clientFname = NULL ;
2012-05-03 21:39:53 +04:00
DEBUG ( MH_INFO_DEBUG , ( " Entering mh_realpath \n " ) ) ;
2017-06-30 21:32:59 +03:00
if ( ! is_in_media_files ( smb_fname - > base_name ) ) {
return SMB_VFS_NEXT_REALPATH ( handle , ctx , smb_fname ) ;
2012-05-03 21:39:53 +04:00
}
2017-06-30 21:32:59 +03:00
if ( alloc_get_client_smb_fname ( handle , ctx ,
smb_fname ,
& clientFname ) ! = 0 ) {
2012-05-03 21:39:53 +04:00
goto err ;
}
2017-06-30 21:32:59 +03:00
result_fname = SMB_VFS_NEXT_REALPATH ( handle , ctx , clientFname ) ;
2012-05-03 21:39:53 +04:00
err :
2017-06-30 21:32:59 +03:00
TALLOC_FREE ( clientFname ) ;
return result_fname ;
2012-05-03 21:39:53 +04:00
}
/* Ignoring get_real_filename function because the default
* doesn ' t do anything .
*/
/*
* Success : return 0
* Failure : set errno , return - 1
* In this case , " name " is an attr name .
*/
/* VFS operations structure */
static struct vfs_fn_pointers vfs_mh_fns = {
/* Disk operations */
. statvfs_fn = mh_statvfs ,
/* Directory operations */
. fdopendir_fn = mh_fdopendir ,
. readdir_fn = mh_readdir ,
. seekdir_fn = mh_seekdir ,
. telldir_fn = mh_telldir ,
. rewind_dir_fn = mh_rewinddir ,
2019-09-05 20:26:53 +03:00
. mkdirat_fn = mh_mkdirat ,
2012-05-03 21:39:53 +04:00
. closedir_fn = mh_closedir ,
/* File operations */
2020-05-20 22:43:26 +03:00
. openat_fn = mh_openat ,
2012-05-03 21:39:53 +04:00
. create_file_fn = mh_create_file ,
2019-08-10 01:03:06 +03:00
. renameat_fn = mh_renameat ,
2012-05-03 21:39:53 +04:00
. stat_fn = mh_stat ,
. lstat_fn = mh_lstat ,
. fstat_fn = mh_fstat ,
2019-09-12 21:51:09 +03:00
. unlinkat_fn = mh_unlinkat ,
2012-05-03 21:39:53 +04:00
. lchown_fn = mh_lchown ,
. chdir_fn = mh_chdir ,
2019-08-30 23:51:50 +03:00
. symlinkat_fn = mh_symlinkat ,
2019-08-23 00:24:49 +03:00
. readlinkat_fn = mh_readlinkat ,
2019-08-17 01:57:15 +03:00
. linkat_fn = mh_linkat ,
2019-08-21 02:55:55 +03:00
. mknodat_fn = mh_mknodat ,
2012-05-03 21:39:53 +04:00
. realpath_fn = mh_realpath ,
/* EA operations. */
2018-03-13 10:14:53 +03:00
. getxattrat_send_fn = vfs_not_implemented_getxattrat_send ,
. getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv ,
2012-05-03 21:39:53 +04:00
/* aio operations */
} ;
2017-12-16 01:32:12 +03:00
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_media_harmony_init ( TALLOC_CTX * ctx )
2012-05-03 21:39:53 +04:00
{
NTSTATUS ret = smb_register_vfs ( SMB_VFS_INTERFACE_VERSION ,
" media_harmony " , & vfs_mh_fns ) ;
if ( ! NT_STATUS_IS_OK ( ret ) )
{
goto out ;
}
vfs_mh_debug_level = debug_add_class ( " media_harmony " ) ;
if ( vfs_mh_debug_level = = - 1 ) {
vfs_mh_debug_level = DBGC_VFS ;
DEBUG ( 1 , ( " media_harmony_init: Couldn't register custom "
" debugging class. \n " ) ) ;
} else {
DEBUG ( 3 , ( " media_harmony_init: Debug class number of "
" 'media_harmony': %d \n " ,
vfs_mh_debug_level ) ) ;
}
out :
return ret ;
}