2007-12-07 22:28:16 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2013-07-03 18:47:05 +04:00
Tar backup command extension
Copyright ( C ) Aurélien Aptel 2013
2007-12-07 22:28:16 +03:00
1996-05-04 11:50:46 +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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1996-05-04 11:50:46 +04:00
( at your option ) any later version .
2007-12-07 22:28:16 +03:00
1996-05-04 11:50:46 +04:00
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 .
2007-12-07 22:28:16 +03:00
1996-05-04 11:50:46 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1996-05-04 11:50:46 +04:00
*/
2013-07-23 18:55:50 +04:00
/**
* # General overview of the tar extension
*
* All tar_xxx ( ) functions work on a ` struct tar ` which store most of
* the context of the backup process .
*
* The current tar context can be accessed via the global variable
2014-02-14 20:16:14 +04:00
* ` tar_ctx ` . It ' s publicly exported as an opaque handle via
* tar_get_ctx ( ) .
2013-07-23 18:55:50 +04:00
*
* A tar context is first configured through tar_parse_args ( ) which
* can be called from either the CLI ( in client . c ) or the interactive
* session ( via the cmd_tar ( ) callback ) .
*
* Once the configuration is done ( successfully ) , the context is ready
* for processing and tar_to_process ( ) returns true .
*
* The next step is to call tar_process ( ) which dispatch the
* processing to either tar_create ( ) or tar_extract ( ) , depending on
* the context .
*
* # # Archive creation
*
* tar_create ( ) creates an archive using the libarchive API then
*
* - iterates on the requested paths if the context is in inclusion
* mode with tar_create_from_list ( )
*
* - or iterates on the whole share ( starting from the current dir ) if
* in exclusion mode or if no specific path were requested
*
* The do_list ( ) function from client . c is used to list recursively
* the share . In particular it takes a DOS path mask ( eg . \ mydir \ * )
* and a callback function which will be called with each file name
* and attributes . The tar callback function is get_file_callback ( ) .
*
* The callback function checks whether the file should be skipped
* according the the configuration via tar_create_skip_path ( ) . If it ' s
* not skipped it ' s downloaded and written to the archive in
* tar_get_file ( ) .
*
* # # Archive extraction
*
* tar_extract ( ) opens the archive and iterates on each file in
* it . For each file tar_extract_skip_path ( ) checks whether it should
* be skipped according to the config . If it ' s not skipped it ' s
* uploaded on the server in tar_send_file ( ) .
*/
1996-05-04 11:50:46 +04:00
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2004-10-07 08:01:18 +04:00
# include "client/client_proto.h"
2013-07-08 20:09:47 +04:00
# include "client/clitar_proto.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2024-04-10 14:02:39 +03:00
# include "lib/util/util_file.h"
2013-08-07 18:34:22 +04:00
# ifdef HAVE_LIBARCHIVE
2013-07-05 11:51:43 +04:00
# include <archive.h>
2013-07-09 20:01:47 +04:00
# include <archive_entry.h>
2013-07-05 11:51:43 +04:00
2013-07-24 19:32:17 +04:00
/* prepend module name and line number to debug messages */
2013-07-17 18:25:34 +04:00
# define DBG(a, b) (DEBUG(a, ("tar:%-4d ", __LINE__)), DEBUG(a, b))
2013-07-09 20:01:47 +04:00
2014-02-20 22:47:50 +04:00
/* preprocessor magic to stringify __LINE__ (int) */
2013-07-24 19:32:17 +04:00
# define STR1(x) #x
# define STR2(x) STR1(x)
2013-07-18 19:06:33 +04:00
/**
* Number of byte in a block unit .
*/
# define TAR_BLOCK_UNIT 512
/**
* Default tar block size in TAR_BLOCK_UNIT .
*/
# define TAR_DEFAULT_BLOCK_SIZE 20
2013-07-09 20:01:47 +04:00
/**
* Maximum value for the blocksize field
*/
# define TAR_MAX_BLOCK_SIZE 0xffff
/**
2013-07-18 19:06:33 +04:00
* Size of the buffer used when downloading a file
2013-07-09 20:01:47 +04:00
*/
2013-07-11 02:57:40 +04:00
# define TAR_CLI_READ_SIZE 0xff00
2013-07-16 18:32:29 +04:00
# define TAR_DO_LIST_ATTR (FILE_ATTRIBUTE_DIRECTORY \
2014-02-17 18:00:43 +04:00
| FILE_ATTRIBUTE_SYSTEM \
| FILE_ATTRIBUTE_HIDDEN )
2013-07-11 02:57:40 +04:00
2013-07-11 17:56:03 +04:00
2013-07-05 20:14:50 +04:00
enum tar_operation {
2014-02-17 18:00:43 +04:00
TAR_NO_OPERATION ,
TAR_CREATE , /* c flag */
TAR_EXTRACT , /* x flag */
2013-07-05 20:14:50 +04:00
} ;
enum tar_selection {
2014-02-17 18:00:43 +04:00
TAR_NO_SELECTION ,
TAR_INCLUDE , /* I and F flag, default */
TAR_EXCLUDE , /* X flag */
2013-07-03 20:18:25 +04:00
} ;
2013-07-05 11:51:43 +04:00
struct tar {
2014-02-17 18:00:43 +04:00
TALLOC_CTX * talloc_ctx ;
/* in state that needs/can be processed? */
bool to_process ;
/* flags */
struct tar_mode {
enum tar_operation operation ; /* create, extract */
enum tar_selection selection ; /* include, exclude */
int blocksize ; /* size in TAR_BLOCK_UNIT of a tar file block */
bool hidden ; /* backup hidden file? */
bool system ; /* backup system file? */
bool incremental ; /* backup _only_ archived file? */
bool reset ; /* unset archive bit? */
bool dry ; /* don't write tar file? */
bool regex ; /* XXX: never actually using regex... */
bool verbose ; /* XXX: ignored */
} mode ;
/* nb of bytes received */
uint64_t total_size ;
/* path to tar archive name */
char * tar_path ;
/* list of path to include or exclude */
char * * path_list ;
int path_list_size ;
/* archive handle */
struct archive * archive ;
2020-01-04 23:47:59 +03:00
/* counters */
uint64_t numdir ;
uint64_t numfile ;
2013-07-05 11:51:43 +04:00
} ;
2013-07-03 20:18:25 +04:00
2013-07-23 18:55:50 +04:00
/**
* Global context imported in client . c when needed .
*
* Default options .
*/
2013-07-08 20:09:47 +04:00
struct tar tar_ctx = {
2014-02-17 18:00:43 +04:00
. mode . selection = TAR_INCLUDE ,
. mode . blocksize = TAR_DEFAULT_BLOCK_SIZE ,
. mode . hidden = true ,
. mode . system = true ,
. mode . incremental = false ,
. mode . reset = false ,
. mode . dry = false ,
. mode . regex = false ,
. mode . verbose = false ,
2013-07-05 11:51:43 +04:00
} ;
2013-07-03 20:18:25 +04:00
2013-07-23 19:39:09 +04:00
/* tar, local function */
static int tar_create ( struct tar * t ) ;
static int tar_create_from_list ( struct tar * t ) ;
static int tar_extract ( struct tar * t ) ;
2014-02-17 18:00:43 +04:00
static int tar_read_inclusion_file ( struct tar * t , const char * filename ) ;
2013-07-23 19:39:09 +04:00
static int tar_send_file ( struct tar * t , struct archive_entry * entry ) ;
static int tar_set_blocksize ( struct tar * t , int size ) ;
static int tar_set_newer_than ( struct tar * t , const char * filename ) ;
2014-02-20 22:47:50 +04:00
static NTSTATUS tar_add_selection_path ( struct tar * t , const char * path ) ;
2013-07-23 19:39:09 +04:00
static void tar_dump ( struct tar * t ) ;
2014-02-20 22:47:46 +04:00
static NTSTATUS tar_extract_skip_path ( struct tar * t ,
struct archive_entry * entry ,
bool * _skip ) ;
2013-07-24 18:48:02 +04:00
static TALLOC_CTX * tar_reset_mem_context ( struct tar * t ) ;
static void tar_free_mem_context ( struct tar * t ) ;
2014-02-20 22:47:45 +04:00
static NTSTATUS tar_create_skip_path ( struct tar * t ,
const char * fullpath ,
const struct file_info * finfo ,
bool * _skip ) ;
2013-07-23 18:55:50 +04:00
2014-02-20 22:47:47 +04:00
static NTSTATUS tar_path_in_list ( struct tar * t , const char * path ,
bool reverse , bool * _is_in_list ) ;
2013-07-09 16:27:55 +04:00
2013-07-23 19:39:09 +04:00
static int tar_get_file ( struct tar * t ,
2014-02-17 18:00:43 +04:00
const char * full_dos_path ,
struct file_info * finfo ) ;
2013-07-09 16:27:55 +04:00
2013-07-23 19:39:09 +04:00
static NTSTATUS get_file_callback ( struct cli_state * cli ,
2014-02-17 18:00:43 +04:00
struct file_info * finfo ,
const char * dir ) ;
2013-07-09 16:27:55 +04:00
2013-07-23 19:39:09 +04:00
/* utilities */
2014-02-17 18:00:43 +04:00
static char * fix_unix_path ( char * path , bool removeprefix ) ;
2014-02-20 22:47:44 +04:00
static NTSTATUS path_base_name ( TALLOC_CTX * ctx , const char * path , char * * _base ) ;
2013-07-23 19:39:09 +04:00
static const char * skip_useless_char_in_path ( const char * p ) ;
static int make_remote_path ( const char * full_path ) ;
static int max_token ( const char * str ) ;
2014-02-20 22:47:48 +04:00
static NTSTATUS is_subpath ( const char * sub , const char * full ,
bool * _subpath_match ) ;
2020-01-04 23:47:59 +03:00
/*
2014-02-14 20:16:14 +04:00
* tar_get_ctx - retrieve global tar context handle
*/
2022-10-27 09:46:39 +03:00
struct tar * tar_get_ctx ( void )
2014-02-14 20:16:14 +04:00
{
2014-02-17 18:00:43 +04:00
return & tar_ctx ;
2014-02-14 20:16:14 +04:00
}
2013-07-09 16:27:55 +04:00
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* cmd_block - interactive command to change tar blocksize
2013-07-23 18:55:50 +04:00
*
2013-07-23 19:39:09 +04:00
* Read a size from the client command line and update the current
* blocksize .
2013-07-23 18:55:50 +04:00
*/
2013-07-23 19:39:09 +04:00
int cmd_block ( void )
2013-07-17 18:25:34 +04:00
{
2014-02-17 18:00:43 +04:00
/* XXX: from client.c */
const extern char * cmd_ptr ;
char * buf ;
int err = 0 ;
bool ok ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
ok = next_token_talloc ( ctx , & cmd_ptr , & buf , NULL ) ;
if ( ! ok ) {
DBG ( 0 , ( " blocksize <n> \n " ) ) ;
err = 1 ;
goto out ;
}
ok = tar_set_blocksize ( & tar_ctx , atoi ( buf ) ) ;
if ( ok ) {
DBG ( 0 , ( " invalid blocksize \n " ) ) ;
err = 1 ;
goto out ;
}
DBG ( 2 , ( " blocksize is now %d \n " , tar_ctx . mode . blocksize ) ) ;
out :
talloc_free ( ctx ) ;
return err ;
2013-07-23 19:39:09 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* cmd_tarmode - interactive command to change tar behaviour
*
* Read one or more modes from the client command line and update the
* current tar mode .
2013-07-23 18:55:50 +04:00
*/
2013-07-23 19:39:09 +04:00
int cmd_tarmode ( void )
2013-07-09 13:41:06 +04:00
{
2014-02-17 18:00:43 +04:00
const extern char * cmd_ptr ;
char * buf ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx ;
2014-02-17 18:00:43 +04:00
struct {
const char * cmd ;
bool * p ;
bool value ;
} table [ ] = {
{ " full " , & tar_ctx . mode . incremental , false } ,
{ " inc " , & tar_ctx . mode . incremental , true } ,
{ " reset " , & tar_ctx . mode . reset , true } ,
{ " noreset " , & tar_ctx . mode . reset , false } ,
{ " system " , & tar_ctx . mode . system , true } ,
{ " nosystem " , & tar_ctx . mode . system , false } ,
{ " hidden " , & tar_ctx . mode . hidden , true } ,
{ " nohidden " , & tar_ctx . mode . hidden , false } ,
2020-01-04 23:47:59 +03:00
{ " verbose " , & tar_ctx . mode . verbose , false } ,
{ " noverbose " , & tar_ctx . mode . verbose , true } ,
2014-02-17 18:00:43 +04:00
} ;
2014-02-20 22:47:50 +04:00
ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
while ( next_token_talloc ( ctx , & cmd_ptr , & buf , NULL ) ) {
2020-12-02 13:13:11 +03:00
size_t i ;
2014-02-17 18:00:43 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( table ) ; i + + ) {
if ( strequal ( table [ i ] . cmd , buf ) ) {
* table [ i ] . p = table [ i ] . value ;
break ;
}
}
if ( i = = ARRAY_SIZE ( table ) )
2020-01-13 18:43:21 +03:00
d_printf ( " tarmode: unrecognised option %s \n " , buf ) ;
2014-02-17 18:00:43 +04:00
}
2020-01-13 18:43:21 +03:00
d_printf ( " tarmode is now %s, %s, %s, %s, %s \n " ,
2014-02-17 18:00:43 +04:00
tar_ctx . mode . incremental ? " incremental " : " full " ,
tar_ctx . mode . system ? " system " : " nosystem " ,
tar_ctx . mode . hidden ? " hidden " : " nohidden " ,
tar_ctx . mode . reset ? " reset " : " noreset " ,
2020-01-13 18:43:21 +03:00
tar_ctx . mode . verbose ? " verbose " : " noverbose " ) ;
2014-02-17 18:00:43 +04:00
talloc_free ( ctx ) ;
return 0 ;
2013-07-09 13:41:06 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* cmd_tar - interactive command to start a tar backup / restoration
*
* Check presence of argument , parse them and handle the request .
2013-07-23 18:55:50 +04:00
*/
2013-07-23 19:39:09 +04:00
int cmd_tar ( void )
2013-07-10 01:17:46 +04:00
{
2014-02-17 18:00:43 +04:00
const extern char * cmd_ptr ;
const char * flag ;
const char * * val ;
char * buf ;
int maxtok = max_token ( cmd_ptr ) ;
int i = 0 ;
int err = 0 ;
bool ok ;
int rc ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
ok = next_token_talloc ( ctx , & cmd_ptr , & buf , NULL ) ;
if ( ! ok ) {
2020-01-04 23:47:59 +03:00
d_printf ( " tar <c|x>[IXFbgvanN] [options] <tar file> [path list] \n " ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
flag = buf ;
2014-02-20 22:47:50 +04:00
val = talloc_array ( ctx , const char * , maxtok ) ;
if ( val = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
while ( next_token_talloc ( ctx , & cmd_ptr , & buf , NULL ) ) {
val [ i + + ] = buf ;
}
rc = tar_parse_args ( & tar_ctx , flag , val , i ) ;
if ( rc ! = 0 ) {
2020-01-13 18:43:21 +03:00
d_printf ( " parse_args failed \n " ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
rc = tar_process ( & tar_ctx ) ;
if ( rc ! = 0 ) {
2020-01-13 18:43:21 +03:00
d_printf ( " tar_process failed \n " ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
out :
talloc_free ( ctx ) ;
return err ;
2013-07-05 20:14:50 +04:00
}
1996-05-04 11:50:46 +04:00
2013-07-11 17:56:03 +04:00
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_parse_args - parse and set tar command line arguments
* @ flag : string pointing to tar options
* @ val : number of tar arguments
* @ valsize : table of arguments after the flags ( number of element in val )
2013-07-23 18:55:50 +04:00
*
2013-07-23 19:39:09 +04:00
* tar arguments work in a weird way . For each flag f that takes a
* value v , the user is supposed to type :
2013-07-23 18:55:50 +04:00
*
2013-07-23 19:39:09 +04:00
* on the CLI :
* - Tf1f2f3 v1 v2 v3 TARFILE PATHS . . .
*
* in the interactive session :
* tar f1f2f3 v1 v2 v3 TARFILE PATHS . . .
*
* @ flag has only flags ( eg . " f1f2f3 " ) and @ val has the arguments
* ( values ) following them ( eg . [ " v1 " , " v2 " , " v3 " , " TARFILE " , " PATH1 " ,
* " PATH2 " ] ) .
*
* There are only 2 flags that take an arg : b and N . The other flags
* just change the semantic of PATH or TARFILE .
*
* PATH can be a list of included / excluded paths , the path to a file
* containing a list of included / excluded paths to use ( F flag ) . If no
* PATH is provided , the whole share is used ( / ) .
2013-07-23 18:55:50 +04:00
*/
2014-02-17 18:00:43 +04:00
int tar_parse_args ( struct tar * t ,
const char * flag ,
const char * * val ,
int valsize )
2013-07-11 17:56:03 +04:00
{
2014-02-17 18:00:43 +04:00
TALLOC_CTX * ctx ;
bool do_read_list = false ;
/* index of next value to use */
int ival = 0 ;
int rc ;
if ( t = = NULL ) {
2020-01-13 18:43:21 +03:00
DBG_WARNING ( " Invalid tar context \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
ctx = tar_reset_mem_context ( t ) ;
2014-02-20 22:47:50 +04:00
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
/*
* Reset back some options - could be from interactive version
* all other modes are left as they are
*/
t - > mode . operation = TAR_NO_OPERATION ;
t - > mode . selection = TAR_NO_SELECTION ;
t - > mode . dry = false ;
t - > to_process = false ;
t - > total_size = 0 ;
while ( flag [ 0 ] ! = ' \0 ' ) {
switch ( flag [ 0 ] ) {
/* operation */
case ' c ' :
if ( t - > mode . operation ! = TAR_NO_OPERATION ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Tar must be followed by only one of c or x. \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
t - > mode . operation = TAR_CREATE ;
break ;
case ' x ' :
if ( t - > mode . operation ! = TAR_NO_OPERATION ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Tar must be followed by only one of c or x. \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
t - > mode . operation = TAR_EXTRACT ;
break ;
/* selection */
case ' I ' :
if ( t - > mode . selection ! = TAR_NO_SELECTION ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Only one of I,X,F must be specified \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
t - > mode . selection = TAR_INCLUDE ;
break ;
case ' X ' :
if ( t - > mode . selection ! = TAR_NO_SELECTION ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Only one of I,X,F must be specified \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
t - > mode . selection = TAR_EXCLUDE ;
break ;
case ' F ' :
if ( t - > mode . selection ! = TAR_NO_SELECTION ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Only one of I,X,F must be specified \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
t - > mode . selection = TAR_INCLUDE ;
do_read_list = true ;
break ;
/* blocksize */
case ' b ' :
if ( ival > = valsize ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Option b must be followed by a blocksize \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
if ( tar_set_blocksize ( t , atoi ( val [ ival ] ) ) ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Option b must be followed by a valid blocksize \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
ival + + ;
break ;
/* incremental mode */
case ' g ' :
t - > mode . incremental = true ;
break ;
/* newer than */
case ' N ' :
if ( ival > = valsize ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Option N must be followed by valid file name \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
if ( tar_set_newer_than ( t , val [ ival ] ) ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Error setting newer-than time \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
ival + + ;
break ;
/* reset mode */
case ' a ' :
t - > mode . reset = true ;
break ;
/* verbose */
2020-01-04 23:47:59 +03:00
case ' v ' :
2014-02-17 18:00:43 +04:00
t - > mode . verbose = true ;
break ;
/* regex match */
case ' r ' :
t - > mode . regex = true ;
break ;
/* dry run mode */
case ' n ' :
if ( t - > mode . operation ! = TAR_CREATE ) {
2020-01-13 18:43:21 +03:00
d_printf ( " n is only meaningful when creating a tar-file \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
t - > mode . dry = true ;
2020-01-13 18:43:21 +03:00
d_printf ( " dry_run set \n " ) ;
2014-02-17 18:00:43 +04:00
break ;
default :
2020-01-13 18:43:21 +03:00
d_printf ( " Unknown tar option \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
flag + + ;
}
/* no selection given? default selection is include */
if ( t - > mode . selection = = TAR_NO_SELECTION ) {
t - > mode . selection = TAR_INCLUDE ;
}
if ( valsize - ival < 1 ) {
2020-01-13 18:43:21 +03:00
d_printf ( " No tar file given. \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
/* handle TARFILE */
2014-02-20 22:47:50 +04:00
t - > tar_path = talloc_strdup ( ctx , val [ ival ] ) ;
if ( t - > tar_path = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
ival + + ;
/*
* Make sure that dbf points to stderr if we are using stdout for
* tar output
*/
if ( t - > mode . operation = = TAR_CREATE & & strequal ( t - > tar_path , " - " ) ) {
setup_logging ( " smbclient " , DEBUG_STDERR ) ;
}
/* handle PATHs... */
/* flag F -> read file list */
if ( do_read_list ) {
if ( valsize - ival ! = 1 ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Option F must be followed by exactly one filename. \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
rc = tar_read_inclusion_file ( t , val [ ival ] ) ;
if ( rc ! = 0 ) {
return 1 ;
}
ival + + ;
/* otherwise store all the PATHs on the command line */
} else {
int i ;
for ( i = ival ; i < valsize ; i + + ) {
2014-02-20 22:47:50 +04:00
NTSTATUS status ;
status = tar_add_selection_path ( t , val [ i ] ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
}
}
t - > to_process = true ;
tar_dump ( t ) ;
return 0 ;
1996-05-04 11:50:46 +04:00
}
2013-07-05 13:33:55 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_process - start processing archive
2013-07-24 18:48:02 +04:00
*
* The talloc context of the fields is freed at the end of the call .
2013-07-05 13:33:55 +04:00
*/
2013-07-23 19:39:09 +04:00
int tar_process ( struct tar * t )
2013-07-05 11:51:43 +04:00
{
2014-02-17 18:00:43 +04:00
int rc = 0 ;
if ( t = = NULL ) {
2020-01-13 18:43:21 +03:00
DBG_WARNING ( " Invalid tar context \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
switch ( t - > mode . operation ) {
case TAR_EXTRACT :
rc = tar_extract ( t ) ;
break ;
case TAR_CREATE :
rc = tar_create ( t ) ;
break ;
default :
2020-01-13 18:43:21 +03:00
DBG_WARNING ( " Invalid tar state \n " ) ;
2014-02-17 18:00:43 +04:00
rc = 1 ;
}
t - > to_process = false ;
tar_free_mem_context ( t ) ;
DBG ( 5 , ( " tar_process done, err = %d \n " , rc ) ) ;
return rc ;
2013-07-05 11:51:43 +04:00
}
2013-07-05 13:33:55 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_create - create archive and fetch files
2013-07-05 13:33:55 +04:00
*/
2013-07-23 19:39:09 +04:00
static int tar_create ( struct tar * t )
1996-05-04 11:50:46 +04:00
{
2014-02-17 18:00:43 +04:00
int r ;
int err = 0 ;
NTSTATUS status ;
const char * mask ;
2020-01-04 23:47:59 +03:00
struct timespec tp_start , tp_end ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
2020-01-04 23:47:59 +03:00
clock_gettime_mono ( & tp_start ) ;
t - > numfile = 0 ;
t - > numdir = 0 ;
2014-02-17 18:00:43 +04:00
t - > archive = archive_write_new ( ) ;
if ( ! t - > mode . dry ) {
const int bsize = t - > mode . blocksize * TAR_BLOCK_UNIT ;
r = archive_write_set_bytes_per_block ( t - > archive , bsize ) ;
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Can't use a block size of %d bytes " , bsize ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
/*
* Use PAX restricted format which is not the most
* conservative choice but has useful extensions and is widely
* supported
*/
r = archive_write_set_format_pax_restricted ( t - > archive ) ;
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Can't use pax restricted format: %s \n " ,
archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
if ( strequal ( t - > tar_path , " - " ) ) {
r = archive_write_open_fd ( t - > archive , STDOUT_FILENO ) ;
} else {
r = archive_write_open_filename ( t - > archive , t - > tar_path ) ;
}
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Can't open %s: %s \n " , t - > tar_path ,
archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out_close ;
}
}
/*
* In inclusion mode , iterate on the inclusion list
*/
if ( t - > mode . selection = = TAR_INCLUDE & & t - > path_list_size > 0 ) {
if ( tar_create_from_list ( t ) ) {
err = 1 ;
goto out_close ;
}
} else {
2014-02-20 22:47:50 +04:00
mask = talloc_asprintf ( ctx , " %s \\ * " , client_get_cur_dir ( ) ) ;
if ( mask = = NULL ) {
err = 1 ;
goto out_close ;
}
2017-10-21 01:09:38 +03:00
mask = client_clean_name ( ctx , mask ) ;
if ( mask = = NULL ) {
err = 1 ;
goto out_close ;
}
2014-02-17 18:00:43 +04:00
DBG ( 5 , ( " tar_process do_list with mask: %s \n " , mask ) ) ;
2020-12-01 10:58:14 +03:00
status = do_list ( mask , TAR_DO_LIST_ATTR , get_file_callback , true , true ) ;
2014-02-17 18:00:43 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG ( 0 , ( " do_list fail %s \n " , nt_errstr ( status ) ) ) ;
err = 1 ;
goto out_close ;
}
}
2020-01-04 23:47:59 +03:00
clock_gettime_mono ( & tp_end ) ;
d_printf ( " tar: dumped % " PRIu64 " files and % " PRIu64 " directories \n " ,
t - > numfile , t - > numdir ) ;
d_printf ( " Total bytes written: % " PRIu64 " (%.1f MiB/s) \n " ,
t - > total_size ,
t - > total_size / timespec_elapsed2 ( & tp_start , & tp_end ) / 1024 / 1024 ) ;
2014-02-17 18:00:43 +04:00
out_close :
if ( ! t - > mode . dry ) {
r = archive_write_close ( t - > archive ) ;
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Fatal: %s \n " , archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
}
out :
2015-05-28 15:55:28 +03:00
# ifdef HAVE_ARCHIVE_READ_FREE
2014-02-17 18:00:43 +04:00
archive_write_free ( t - > archive ) ;
2015-05-28 15:55:28 +03:00
# else
archive_write_finish ( t - > archive ) ;
# endif
2014-02-17 18:00:43 +04:00
talloc_free ( ctx ) ;
return err ;
1996-05-04 11:50:46 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_create_from_list - fetch from path list in include mode
2013-07-23 18:55:50 +04:00
*/
2013-07-23 19:39:09 +04:00
static int tar_create_from_list ( struct tar * t )
2013-07-10 15:16:08 +04:00
{
2014-02-17 18:00:43 +04:00
int err = 0 ;
NTSTATUS status ;
2014-02-20 22:47:44 +04:00
char * base ;
const char * path , * mask , * start_dir ;
2014-02-17 18:00:43 +04:00
int i ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
start_dir = talloc_strdup ( ctx , client_get_cur_dir ( ) ) ;
2014-02-20 22:47:50 +04:00
if ( start_dir = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
for ( i = 0 ; i < t - > path_list_size ; i + + ) {
path = t - > path_list [ i ] ;
2014-02-20 22:47:44 +04:00
base = NULL ;
status = path_base_name ( ctx , path , & base ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
err = 1 ;
goto out ;
}
2014-02-20 22:47:50 +04:00
mask = talloc_asprintf ( ctx , " %s \\ %s " ,
client_get_cur_dir ( ) , path ) ;
if ( mask = = NULL ) {
err = 1 ;
goto out ;
}
2017-10-21 01:09:38 +03:00
mask = client_clean_name ( ctx , mask ) ;
if ( mask = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
DBG ( 5 , ( " incl. path='%s', base='%s', mask='%s' \n " ,
path , base ? base : " NULL " , mask ) ) ;
if ( base ! = NULL ) {
base = talloc_asprintf ( ctx , " %s%s \\ " ,
2014-02-20 22:47:44 +04:00
client_get_cur_dir ( ) , base ) ;
if ( base = = NULL ) {
err = 1 ;
goto out ;
}
2017-10-21 01:09:38 +03:00
base = client_clean_name ( ctx , base ) ;
if ( base = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
DBG ( 5 , ( " cd '%s' before do_list \n " , base ) ) ;
client_set_cur_dir ( base ) ;
}
2020-12-01 10:58:14 +03:00
status = do_list ( mask , TAR_DO_LIST_ATTR , get_file_callback , true , true ) ;
2014-02-17 18:00:43 +04:00
if ( base ! = NULL ) {
client_set_cur_dir ( start_dir ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG ( 0 , ( " do_list failed on %s (%s) \n " , path , nt_errstr ( status ) ) ) ;
err = 1 ;
goto out ;
}
}
out :
talloc_free ( ctx ) ;
return err ;
2013-07-10 15:16:08 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* get_file_callback - do_list callback
2013-07-23 18:55:50 +04:00
*
2013-07-23 19:39:09 +04:00
* Callback for client . c do_list ( ) . Called for each file found on the
* share matching do_list mask . Recursively call do_list ( ) with itself
* as callback when the current file is a directory .
2013-07-23 18:55:50 +04:00
*/
2013-07-23 19:39:09 +04:00
static NTSTATUS get_file_callback ( struct cli_state * cli ,
2014-02-17 18:00:43 +04:00
struct file_info * finfo ,
const char * dir )
2013-07-10 15:16:08 +04:00
{
2014-02-20 22:47:45 +04:00
NTSTATUS status = NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
char * remote_name ;
2020-01-04 23:47:59 +03:00
char * old_dir = NULL ;
char * new_dir = NULL ;
2020-12-01 10:58:14 +03:00
const char * initial_dir = dir ;
2014-02-20 22:47:45 +04:00
bool skip = false ;
2020-01-04 23:47:59 +03:00
bool isdir ;
2014-02-17 18:00:43 +04:00
int rc ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2014-02-17 18:00:43 +04:00
2020-12-01 10:58:14 +03:00
remote_name = talloc_asprintf ( ctx , " %s \\ %s " , initial_dir , finfo - > name ) ;
2014-02-20 22:47:50 +04:00
if ( remote_name = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
2017-10-21 01:09:38 +03:00
remote_name = client_clean_name ( ctx , remote_name ) ;
if ( remote_name = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
2014-02-17 18:00:43 +04:00
if ( strequal ( finfo - > name , " .. " ) | | strequal ( finfo - > name , " . " ) ) {
goto out ;
}
2020-06-03 20:41:27 +03:00
isdir = finfo - > attr & FILE_ATTRIBUTE_DIRECTORY ;
2020-01-04 23:47:59 +03:00
if ( isdir ) {
old_dir = talloc_strdup ( ctx , initial_dir ) ;
new_dir = talloc_asprintf ( ctx , " %s \\ " , remote_name ) ;
if ( ( old_dir = = NULL ) | | ( new_dir = = NULL ) ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
}
status = tar_create_skip_path ( & tar_ctx ,
isdir ? new_dir : remote_name ,
finfo , & skip ) ;
2014-02-20 22:47:45 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
if ( skip ) {
2014-02-17 18:00:43 +04:00
DBG ( 5 , ( " --- %s \n " , remote_name ) ) ;
2014-02-20 22:47:45 +04:00
status = NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
goto out ;
}
2020-12-01 10:58:14 +03:00
rc = tar_get_file ( & tar_ctx , remote_name , finfo ) ;
if ( rc ! = 0 ) {
status = NT_STATUS_UNSUCCESSFUL ;
goto out ;
2014-02-17 18:00:43 +04:00
}
out :
talloc_free ( ctx ) ;
2014-02-20 22:47:45 +04:00
return status ;
2013-07-11 02:57:40 +04:00
}
2013-07-23 18:55:50 +04:00
/**
* tar_get_file - fetch a remote file to the local archive
* @ full_dos_path : path to the file to fetch
* @ finfo : attributes of the file to fetch
*/
2014-02-17 18:00:43 +04:00
static int tar_get_file ( struct tar * t ,
const char * full_dos_path ,
struct file_info * finfo )
2013-07-11 02:57:40 +04:00
{
2014-02-17 18:00:43 +04:00
extern struct cli_state * cli ;
NTSTATUS status ;
struct archive_entry * entry ;
char * full_unix_path ;
char buf [ TAR_CLI_READ_SIZE ] ;
size_t len ;
uint64_t off = 0 ;
uint16_t remote_fd = ( uint16_t ) - 1 ;
int err = 0 , r ;
2020-06-03 20:41:27 +03:00
const bool isdir = finfo - > attr & FILE_ATTRIBUTE_DIRECTORY ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
2020-01-04 23:47:59 +03:00
2014-02-20 22:47:50 +04:00
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
DBG ( 5 , ( " +++ %s \n " , full_dos_path ) ) ;
t - > total_size + = finfo - > size ;
if ( t - > mode . dry ) {
goto out ;
}
if ( t - > mode . reset ) {
/* ignore return value: server might not store DOS attributes */
set_remote_attr ( full_dos_path , FILE_ATTRIBUTE_ARCHIVE , ATTR_UNSET ) ;
}
2014-02-20 22:47:50 +04:00
full_unix_path = talloc_asprintf ( ctx , " .%s " , full_dos_path ) ;
if ( full_unix_path = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
string_replace ( full_unix_path , ' \\ ' , ' / ' ) ;
entry = archive_entry_new ( ) ;
archive_entry_copy_pathname ( entry , full_unix_path ) ;
archive_entry_set_filetype ( entry , isdir ? AE_IFDIR : AE_IFREG ) ;
archive_entry_set_atime ( entry ,
finfo - > atime_ts . tv_sec ,
finfo - > atime_ts . tv_nsec ) ;
archive_entry_set_mtime ( entry ,
finfo - > mtime_ts . tv_sec ,
finfo - > mtime_ts . tv_nsec ) ;
archive_entry_set_ctime ( entry ,
finfo - > ctime_ts . tv_sec ,
finfo - > ctime_ts . tv_nsec ) ;
archive_entry_set_perm ( entry , isdir ? 0755 : 0644 ) ;
/*
* check if we can safely cast unsigned file size to libarchive
* signed size . Very unlikely problem ( > 9 exabyte file )
*/
if ( finfo - > size > INT64_MAX ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Remote file %s too big \n " , full_dos_path ) ;
2014-02-17 18:00:43 +04:00
goto out_entry ;
}
archive_entry_set_size ( entry , ( int64_t ) finfo - > size ) ;
if ( isdir ) {
2020-01-04 23:47:59 +03:00
/* It's a directory just write a header */
r = archive_write_header ( t - > archive , entry ) ;
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Fatal: %s \n " , archive_error_string ( t - > archive ) ) ;
2020-01-04 23:47:59 +03:00
err = 1 ;
}
if ( t - > mode . verbose ) {
d_printf ( " a %s \\ \n " , full_dos_path ) ;
}
2014-02-17 18:00:43 +04:00
DBG ( 5 , ( " get_file skip dir %s \n " , full_dos_path ) ) ;
goto out_entry ;
}
status = cli_open ( cli , full_dos_path , O_RDONLY , DENY_NONE , & remote_fd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-01-04 23:47:59 +03:00
d_printf ( " %s opening remote file %s \n " ,
nt_errstr ( status ) , full_dos_path ) ;
goto out_entry ;
}
/* don't make tar file entry until after the file is open */
r = archive_write_header ( t - > archive , entry ) ;
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Fatal: %s \n " , archive_error_string ( t - > archive ) ) ;
2020-01-04 23:47:59 +03:00
err = 1 ;
2014-02-17 18:00:43 +04:00
goto out_entry ;
}
2020-01-04 23:47:59 +03:00
if ( t - > mode . verbose ) {
d_printf ( " a %s \n " , full_dos_path ) ;
}
2014-02-17 18:00:43 +04:00
do {
status = cli_read ( cli , remote_fd , buf , off , sizeof ( buf ) , & len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Error reading file %s : %s \n " ,
full_dos_path , nt_errstr ( status ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out_close ;
}
off + = len ;
r = archive_write_data ( t - > archive , buf , len ) ;
if ( r < 0 ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Fatal: %s \n " , archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out_close ;
}
} while ( off < finfo - > size ) ;
2020-01-04 23:47:59 +03:00
t - > numfile + + ;
2014-02-17 18:00:43 +04:00
out_close :
cli_close ( cli , remote_fd ) ;
out_entry :
archive_entry_free ( entry ) ;
out :
talloc_free ( ctx ) ;
return err ;
2013-07-11 02:57:40 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_extract - open archive and send files .
*/
static int tar_extract ( struct tar * t )
{
2014-02-17 18:00:43 +04:00
int err = 0 ;
int r ;
struct archive_entry * entry ;
const size_t bsize = t - > mode . blocksize * TAR_BLOCK_UNIT ;
int rc ;
t - > archive = archive_read_new ( ) ;
archive_read_support_format_all ( t - > archive ) ;
2015-05-28 15:55:28 +03:00
# ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL
2014-02-17 18:00:43 +04:00
archive_read_support_filter_all ( t - > archive ) ;
2015-05-28 15:55:28 +03:00
# endif
2014-02-17 18:00:43 +04:00
if ( strequal ( t - > tar_path , " - " ) ) {
r = archive_read_open_fd ( t - > archive , STDIN_FILENO , bsize ) ;
} else {
r = archive_read_open_filename ( t - > archive , t - > tar_path , bsize ) ;
}
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Can't open %s : %s \n " , t - > tar_path ,
archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
for ( ; ; ) {
2014-02-20 22:47:46 +04:00
NTSTATUS status ;
2016-06-07 06:42:33 +03:00
bool skip = false ;
2014-02-17 18:00:43 +04:00
r = archive_read_next_header ( t - > archive , & entry ) ;
if ( r = = ARCHIVE_EOF ) {
break ;
}
if ( r = = ARCHIVE_WARN ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Warning: %s \n " , archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
}
if ( r = = ARCHIVE_FATAL ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Fatal: %s \n " , archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
2014-02-20 22:47:46 +04:00
status = tar_extract_skip_path ( t , entry , & skip ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
err = 1 ;
goto out ;
}
if ( skip ) {
2014-02-17 18:00:43 +04:00
DBG ( 5 , ( " --- %s \n " , archive_entry_pathname ( entry ) ) ) ;
continue ;
}
DBG ( 5 , ( " +++ %s \n " , archive_entry_pathname ( entry ) ) ) ;
2020-01-04 23:47:59 +03:00
if ( t - > mode . verbose ) {
d_printf ( " x %s \n " , archive_entry_pathname ( entry ) ) ;
}
2014-02-17 18:00:43 +04:00
rc = tar_send_file ( t , entry ) ;
if ( rc ! = 0 ) {
err = 1 ;
goto out ;
}
}
out :
2015-05-28 15:55:28 +03:00
# ifdef HAVE_ARCHIVE_READ_FREE
2014-02-17 18:00:43 +04:00
r = archive_read_free ( t - > archive ) ;
2015-05-28 15:55:28 +03:00
# else
r = archive_read_finish ( t - > archive ) ;
# endif
2014-02-17 18:00:43 +04:00
if ( r ! = ARCHIVE_OK ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Can't close %s : %s \n " , t - > tar_path ,
archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
}
return err ;
2013-07-23 19:39:09 +04:00
}
/**
* tar_send_file - send @ entry to the remote server
* @ entry : current archive entry
2013-07-23 18:55:50 +04:00
*
2013-07-23 19:39:09 +04:00
* Handle the creation of the parent directories and transfer the
* entry to a new remote file .
2013-07-23 18:55:50 +04:00
*/
2013-07-23 19:39:09 +04:00
static int tar_send_file ( struct tar * t , struct archive_entry * entry )
2013-07-11 02:57:40 +04:00
{
2014-02-17 18:00:43 +04:00
extern struct cli_state * cli ;
char * dos_path ;
char * full_path ;
NTSTATUS status ;
uint16_t remote_fd = ( uint16_t ) - 1 ;
int err = 0 ;
int flags = O_RDWR | O_CREAT | O_TRUNC ;
2020-10-24 13:56:09 +03:00
mode_t filetype = archive_entry_filetype ( entry ) ;
mode_t mode = archive_entry_mode ( entry ) ;
time_t mtime = archive_entry_mtime ( entry ) ;
2014-02-17 18:00:43 +04:00
int rc ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
2014-02-20 22:47:50 +04:00
dos_path = talloc_strdup ( ctx , archive_entry_pathname ( entry ) ) ;
if ( dos_path = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
fix_unix_path ( dos_path , true ) ;
2014-02-20 22:47:50 +04:00
full_path = talloc_strdup ( ctx , client_get_cur_dir ( ) ) ;
if ( full_path = = NULL ) {
err = 1 ;
goto out ;
}
full_path = talloc_strdup_append ( full_path , dos_path ) ;
if ( full_path = = NULL ) {
err = 1 ;
goto out ;
}
2017-10-21 01:09:38 +03:00
full_path = client_clean_name ( ctx , full_path ) ;
if ( full_path = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
2020-10-24 13:56:09 +03:00
if ( filetype ! = AE_IFREG & & filetype ! = AE_IFDIR ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Skipping non-dir & non-regular file %s \n " , full_path ) ;
2014-02-17 18:00:43 +04:00
goto out ;
}
rc = make_remote_path ( full_path ) ;
if ( rc ! = 0 ) {
err = 1 ;
goto out ;
}
2020-10-24 13:56:09 +03:00
if ( filetype = = AE_IFDIR ) {
2014-02-17 18:00:43 +04:00
goto out ;
}
status = cli_open ( cli , full_path , flags , DENY_NONE , & remote_fd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Error opening remote file %s: %s \n " ,
full_path , nt_errstr ( status ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
for ( ; ; ) {
const void * buf ;
size_t len ;
off_t off ;
int r ;
r = archive_read_data_block ( t - > archive , & buf , & len , & off ) ;
if ( r = = ARCHIVE_EOF ) {
break ;
}
if ( r = = ARCHIVE_WARN ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Warning: %s \n " , archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
}
if ( r = = ARCHIVE_FATAL ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Fatal: %s \n " , archive_error_string ( t - > archive ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto close_out ;
}
status = cli_writeall ( cli , remote_fd , 0 , buf , off , len , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Error writing remote file %s: %s \n " ,
full_path , nt_errstr ( status ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto close_out ;
}
}
close_out :
status = cli_close ( cli , remote_fd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Error closing remote file %s: %s \n " ,
full_path , nt_errstr ( status ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
}
2020-10-24 13:56:09 +03:00
status = cli_setatr ( cli , full_path , mode , mtime ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2024-07-17 11:38:47 +03:00
char * timestr = timestring ( talloc_tos ( ) , mtime ) ;
d_printf ( " Error setting attributes (mode: %3o, mtime: %s) on "
" remote file %s: %s \n " ,
mode & 0777 ,
timestr ,
full_path ,
nt_errstr ( status ) ) ;
TALLOC_FREE ( timestr ) ;
2020-10-24 13:56:09 +03:00
err = 1 ;
}
2014-02-17 18:00:43 +04:00
out :
talloc_free ( ctx ) ;
return err ;
2013-07-23 19:39:09 +04:00
}
/**
* tar_add_selection_path - add a path to the path list
* @ path : path to add
*/
2014-02-20 22:47:50 +04:00
static NTSTATUS tar_add_selection_path ( struct tar * t , const char * path )
2013-07-23 19:39:09 +04:00
{
2014-02-20 22:47:50 +04:00
const char * * list ;
2014-02-17 18:00:43 +04:00
TALLOC_CTX * ctx = t - > talloc_ctx ;
if ( ! t - > path_list ) {
2014-02-20 22:47:50 +04:00
t - > path_list = str_list_make_empty ( ctx ) ;
if ( t - > path_list = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2014-02-17 18:00:43 +04:00
t - > path_list_size = 0 ;
}
2014-02-20 22:47:50 +04:00
/* cast to silence gcc const-qual warning */
list = str_list_add ( ( void * ) t - > path_list , path ) ;
if ( list = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
t - > path_list = discard_const_p ( char * , list ) ;
2014-02-17 18:00:43 +04:00
t - > path_list_size + + ;
fix_unix_path ( t - > path_list [ t - > path_list_size - 1 ] , true ) ;
2014-02-20 22:47:50 +04:00
return NT_STATUS_OK ;
2013-07-11 02:57:40 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_set_blocksize - set block size in TAR_BLOCK_UNIT
2013-07-23 18:55:50 +04:00
*/
2013-07-23 19:39:09 +04:00
static int tar_set_blocksize ( struct tar * t , int size )
2013-07-17 18:25:34 +04:00
{
2014-02-17 18:00:43 +04:00
if ( size < = 0 | | size > TAR_MAX_BLOCK_SIZE ) {
return 1 ;
}
2013-07-17 18:25:34 +04:00
2014-02-17 18:00:43 +04:00
t - > mode . blocksize = size ;
2013-07-17 18:25:34 +04:00
2014-02-17 18:00:43 +04:00
return 0 ;
2013-07-23 19:39:09 +04:00
}
2013-07-17 18:25:34 +04:00
2013-07-23 19:39:09 +04:00
/**
* tar_set_newer_than - set date threshold of saved files
* @ filename : local path to a file
*
* Only files newer than the modification time of @ filename will be
* saved .
*
* Note : this function set the global variable newer_than from
* client . c . Thus the time is not a field of the tar structure . See
* cmd_newer ( ) to change its value from an interactive session .
*/
static int tar_set_newer_than ( struct tar * t , const char * filename )
{
2014-02-17 18:00:43 +04:00
extern time_t newer_than ;
SMB_STRUCT_STAT stbuf ;
int rc ;
rc = sys_stat ( filename , & stbuf , false ) ;
if ( rc ! = 0 ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Error setting newer-than time \n " ) ;
2014-02-17 18:00:43 +04:00
return 1 ;
}
newer_than = convert_timespec_to_time_t ( stbuf . st_ex_mtime ) ;
2023-08-08 03:15:00 +03:00
DBG ( 1 , ( " Getting files newer than %s " , time_to_asc ( newer_than ) ) ) ;
2014-02-17 18:00:43 +04:00
return 0 ;
2013-07-17 18:25:34 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_read_inclusion_file - set path list from file
* @ filename : path to the list file
*
* Read and add each line of @ filename to the path list .
2013-07-23 18:55:50 +04:00
*/
2014-02-17 18:00:43 +04:00
static int tar_read_inclusion_file ( struct tar * t , const char * filename )
2013-07-11 02:57:40 +04:00
{
2014-02-17 18:00:43 +04:00
char * line ;
int err = 0 ;
2016-05-31 16:46:47 +03:00
int fd = - 1 ;
2014-02-20 22:47:50 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
fd = open ( filename , O_RDONLY ) ;
if ( fd < 0 ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Can't open inclusion file '%s': %s \n " , filename , strerror ( errno ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
for ( line = afdgets ( fd , ctx , 0 ) ;
line ! = NULL ;
line = afdgets ( fd , ctx , 0 ) ) {
2014-02-20 22:47:50 +04:00
NTSTATUS status ;
status = tar_add_selection_path ( t , line ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
}
out :
2016-05-31 16:46:47 +03:00
if ( fd ! = - 1 ) {
close ( fd ) ;
}
2014-02-17 18:00:43 +04:00
talloc_free ( ctx ) ;
return err ;
2013-07-23 19:39:09 +04:00
}
2013-07-11 02:57:40 +04:00
2013-07-23 19:39:09 +04:00
/**
2014-02-20 22:47:47 +04:00
* tar_path_in_list - check whether @ path is in the path list
2013-07-23 19:39:09 +04:00
* @ path : path to find
* @ reverse : when true also try to find path list element in @ path
2014-02-20 22:47:47 +04:00
* @ _is_in_list : set if @ path is in the path list
2013-07-23 19:39:09 +04:00
*
2014-02-20 22:47:47 +04:00
* Look at each path of the path list and set @ _is_in_list if @ path is a
2013-07-23 19:39:09 +04:00
* subpath of one of them .
*
* If you want / path to be in the path list ( path / a / , path / b / ) set
* @ reverse to true to try to match the other way around .
*/
2014-02-20 22:47:47 +04:00
static NTSTATUS tar_path_in_list ( struct tar * t , const char * path ,
bool reverse , bool * _is_in_list )
2013-07-23 19:39:09 +04:00
{
2014-02-17 18:00:43 +04:00
int i ;
const char * p ;
const char * pattern ;
if ( path = = NULL | | path [ 0 ] = = ' \0 ' ) {
2014-02-20 22:47:47 +04:00
* _is_in_list = false ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
p = skip_useless_char_in_path ( path ) ;
for ( i = 0 ; i < t - > path_list_size ; i + + ) {
bool is_in_list ;
2014-02-20 22:47:48 +04:00
NTSTATUS status ;
2014-02-17 18:00:43 +04:00
pattern = skip_useless_char_in_path ( t - > path_list [ i ] ) ;
2014-02-20 22:47:48 +04:00
status = is_subpath ( p , pattern , & is_in_list ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( reverse & & ! is_in_list ) {
status = is_subpath ( pattern , p , & is_in_list ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2014-02-17 18:00:43 +04:00
}
if ( is_in_list ) {
2014-02-20 22:47:47 +04:00
* _is_in_list = true ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
}
2014-02-20 22:47:47 +04:00
* _is_in_list = false ;
return NT_STATUS_OK ;
2013-07-10 15:16:08 +04:00
}
2007-12-19 23:59:28 +03:00
2013-07-16 21:15:48 +04:00
/**
2014-02-20 22:47:46 +04:00
* tar_extract_skip_path - check if @ entry should be skipped
2013-07-23 19:39:09 +04:00
* @ entry : current tar entry
2014-02-20 22:47:46 +04:00
* @ _skip : set true if path should be skipped , otherwise false
2013-07-16 21:15:48 +04:00
*
2013-07-23 19:39:09 +04:00
* Skip predicate for tar extraction ( archive to server ) only .
2013-07-16 21:15:48 +04:00
*/
2014-02-20 22:47:46 +04:00
static NTSTATUS tar_extract_skip_path ( struct tar * t ,
struct archive_entry * entry ,
bool * _skip )
2013-07-16 21:15:48 +04:00
{
2014-02-17 18:00:43 +04:00
const char * fullpath = archive_entry_pathname ( entry ) ;
bool in = true ;
2013-07-16 21:15:48 +04:00
2014-02-17 18:00:43 +04:00
if ( t - > path_list_size < = 0 ) {
2014-02-20 22:47:46 +04:00
* _skip = false ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
2013-07-16 21:15:48 +04:00
2014-02-17 18:00:43 +04:00
if ( t - > mode . regex ) {
in = mask_match_list ( fullpath , t - > path_list , t - > path_list_size , true ) ;
} else {
2014-02-20 22:47:47 +04:00
NTSTATUS status = tar_path_in_list ( t , fullpath , false , & in ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2014-02-17 18:00:43 +04:00
}
2013-07-16 21:15:48 +04:00
2014-02-17 18:00:43 +04:00
if ( t - > mode . selection = = TAR_EXCLUDE ) {
2014-02-20 22:47:46 +04:00
* _skip = in ;
} else {
* _skip = ! in ;
2014-02-17 18:00:43 +04:00
}
2013-07-16 21:15:48 +04:00
2014-02-20 22:47:46 +04:00
return NT_STATUS_OK ;
2013-07-16 21:15:48 +04:00
}
2013-07-08 20:09:47 +04:00
/**
2023-06-30 13:06:20 +03:00
* tar_create_skip_path - check if @ fullpath should be skipped
2013-07-23 19:39:09 +04:00
* @ fullpath : full remote path of the current file
* @ finfo : remote file attributes
2014-02-20 22:47:45 +04:00
* @ _skip : returned skip not
2013-07-08 20:09:47 +04:00
*
2013-07-23 19:39:09 +04:00
* Skip predicate for tar creation ( server to archive ) only .
2013-07-08 20:09:47 +04:00
*/
2014-02-20 22:47:45 +04:00
static NTSTATUS tar_create_skip_path ( struct tar * t ,
const char * fullpath ,
const struct file_info * finfo ,
bool * _skip )
1996-05-04 11:50:46 +04:00
{
2014-02-17 18:00:43 +04:00
/* syntaxic sugar */
2020-06-03 20:41:27 +03:00
const mode_t mode = finfo - > attr ;
2014-02-17 18:00:43 +04:00
const bool isdir = mode & FILE_ATTRIBUTE_DIRECTORY ;
const bool exclude = t - > mode . selection = = TAR_EXCLUDE ;
bool in = true ;
if ( ! isdir ) {
2015-07-27 00:02:57 +03:00
/* 1. if we don't want X and we have X, skip */
2014-02-17 18:00:43 +04:00
if ( ! t - > mode . system & & ( mode & FILE_ATTRIBUTE_SYSTEM ) ) {
2014-02-20 22:47:45 +04:00
* _skip = true ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
if ( ! t - > mode . hidden & & ( mode & FILE_ATTRIBUTE_HIDDEN ) ) {
2014-02-20 22:47:45 +04:00
* _skip = true ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
/* 2. if we only want archive and it's not, skip */
if ( t - > mode . incremental & & ! ( mode & FILE_ATTRIBUTE_ARCHIVE ) ) {
2014-02-20 22:47:45 +04:00
* _skip = true ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
}
/* 3. is it in the selection list? */
/*
* tar_create_from_list ( ) use the include list as a starting
* point , no need to check
*/
if ( ! exclude ) {
2014-02-20 22:47:45 +04:00
* _skip = false ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
/* we are now in exclude mode */
/* no matter the selection, no list => include everything */
if ( t - > path_list_size < = 0 ) {
2014-02-20 22:47:45 +04:00
* _skip = false ;
return NT_STATUS_OK ;
2014-02-17 18:00:43 +04:00
}
if ( t - > mode . regex ) {
in = mask_match_list ( fullpath , t - > path_list , t - > path_list_size , true ) ;
} else {
2014-02-20 22:47:47 +04:00
bool reverse = isdir & & ! exclude ;
NTSTATUS status = tar_path_in_list ( t , fullpath , reverse , & in ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2014-02-17 18:00:43 +04:00
}
2014-02-20 22:47:45 +04:00
* _skip = in ;
2014-02-17 18:00:43 +04:00
2014-02-20 22:47:45 +04:00
return NT_STATUS_OK ;
1996-05-04 11:50:46 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2013-07-23 19:39:09 +04:00
* tar_to_process - return true if @ t is ready to be processed
*
* @ t is ready if it properly parsed command line arguments .
2013-07-23 18:55:50 +04:00
*/
2014-02-17 18:00:43 +04:00
bool tar_to_process ( struct tar * t )
2013-07-09 20:01:47 +04:00
{
2014-02-17 18:00:43 +04:00
if ( t = = NULL ) {
2020-01-13 18:43:21 +03:00
DBG_WARNING ( " Invalid tar context \n " ) ;
2014-02-17 18:00:43 +04:00
return false ;
}
return t - > to_process ;
2013-07-23 19:39:09 +04:00
}
2013-07-09 20:01:47 +04:00
2013-07-23 19:39:09 +04:00
/**
* skip_useless_char_in_path - skip leading slashes / dots
*
* Skip leading slashes , backslashes and dot - slashes .
*/
static const char * skip_useless_char_in_path ( const char * p )
{
2014-02-17 18:00:43 +04:00
while ( p ) {
if ( * p = = ' / ' | | * p = = ' \\ ' ) {
p + + ;
}
else if ( p [ 0 ] = = ' . ' & & ( p [ 1 ] = = ' / ' | | p [ 1 ] = = ' \\ ' ) ) {
p + = 2 ;
}
else
return p ;
}
return p ;
2013-07-09 20:01:47 +04:00
}
2013-07-23 18:55:50 +04:00
/**
2014-02-20 22:47:48 +04:00
* is_subpath - check if the path @ sub is a subpath of @ full .
2013-07-23 19:39:09 +04:00
* @ sub : path to test
* @ full : container path
2014-02-20 22:47:48 +04:00
* @ _subpath_match : set true if @ sub is a subpath of @ full , otherwise false
2013-07-23 19:39:09 +04:00
*
2023-06-30 13:06:20 +03:00
* String comparison is case - insensitive .
2013-07-23 18:55:50 +04:00
*/
2014-02-20 22:47:48 +04:00
static NTSTATUS is_subpath ( const char * sub , const char * full ,
bool * _subpath_match )
1996-05-04 11:50:46 +04:00
{
2014-02-20 22:47:48 +04:00
NTSTATUS status = NT_STATUS_OK ;
2014-02-17 14:24:33 +04:00
int len = 0 ;
char * f , * s ;
2014-02-20 22:47:48 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
if ( tmp_ctx = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
2014-02-17 14:24:33 +04:00
2014-02-20 22:47:48 +04:00
f = strlower_talloc ( tmp_ctx , full ) ;
if ( f = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out_ctx_free ;
}
2014-02-17 14:24:33 +04:00
string_replace ( f , ' \\ ' , ' / ' ) ;
2014-02-20 22:47:48 +04:00
s = strlower_talloc ( tmp_ctx , sub ) ;
2016-05-31 16:44:27 +03:00
if ( s = = NULL ) {
2014-02-20 22:47:48 +04:00
status = NT_STATUS_NO_MEMORY ;
goto out_ctx_free ;
}
2014-02-17 14:24:33 +04:00
string_replace ( s , ' \\ ' , ' / ' ) ;
/* find the point where sub and full diverge */
while ( ( * f ! = ' \0 ' ) & & ( * s ! = ' \0 ' ) & & ( * f = = * s ) ) {
f + + ;
s + + ;
len + + ;
}
if ( ( * f = = ' \0 ' ) & & ( * s = = ' \0 ' ) ) {
2014-02-20 22:47:48 +04:00
* _subpath_match = true ; /* sub and full match */
goto out_ctx_free ;
2014-02-17 14:24:33 +04:00
}
if ( ( * f = = ' \0 ' ) & & ( len > 0 ) & & ( * ( f - 1 ) = = ' / ' ) ) {
/* sub diverges from full at path separator */
2014-02-20 22:47:48 +04:00
* _subpath_match = true ;
goto out_ctx_free ;
2014-02-17 14:24:33 +04:00
}
if ( ( * s = = ' \0 ' ) & & ( strcmp ( f , " / " ) = = 0 ) ) {
/* full diverges from sub with trailing slash only */
2014-02-20 22:47:48 +04:00
* _subpath_match = true ;
goto out_ctx_free ;
2014-02-17 14:24:33 +04:00
}
if ( ( * s = = ' / ' ) & & ( * f = = ' \0 ' ) ) {
/* sub diverges from full with extra path component */
2014-02-20 22:47:48 +04:00
* _subpath_match = true ;
goto out_ctx_free ;
2014-02-17 14:24:33 +04:00
}
2014-02-20 22:47:48 +04:00
* _subpath_match = false ;
2014-02-17 14:24:33 +04:00
2014-02-20 22:47:48 +04:00
out_ctx_free :
talloc_free ( tmp_ctx ) ;
out :
return status ;
1998-06-17 05:52:57 +04:00
}
2013-07-05 20:14:50 +04:00
2013-07-23 19:39:09 +04:00
/**
* make_remote_path - recursively make remote dirs
* @ full_path : full hierarchy to create
*
* Create @ full_path and each parent directories as needed .
*/
static int make_remote_path ( const char * full_path )
{
2014-02-17 18:00:43 +04:00
extern struct cli_state * cli ;
char * path ;
char * subpath ;
char * state ;
char * last_backslash ;
char * p ;
int len ;
NTSTATUS status ;
int err = 0 ;
2014-02-20 22:47:49 +04:00
TALLOC_CTX * ctx = talloc_new ( NULL ) ;
if ( ctx = = NULL ) {
return 1 ;
}
2014-02-17 18:00:43 +04:00
2014-02-20 22:47:49 +04:00
subpath = talloc_strdup ( ctx , full_path ) ;
if ( subpath = = NULL ) {
err = 1 ;
goto out ;
}
path = talloc_strdup ( ctx , full_path ) ;
if ( path = = NULL ) {
err = 1 ;
goto out ;
}
2014-02-17 18:00:43 +04:00
len = talloc_get_size ( path ) - 1 ;
last_backslash = strrchr_m ( path , ' \\ ' ) ;
if ( last_backslash = = NULL ) {
goto out ;
}
* last_backslash = 0 ;
subpath [ 0 ] = 0 ;
p = strtok_r ( path , " \\ " , & state ) ;
while ( p ! = NULL ) {
strlcat ( subpath , p , len ) ;
status = cli_chkpath ( cli , subpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
status = cli_mkdir ( cli , subpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-01-13 18:43:21 +03:00
d_printf ( " Can't mkdir %s: %s \n " , subpath , nt_errstr ( status ) ) ;
2014-02-17 18:00:43 +04:00
err = 1 ;
goto out ;
}
DBG ( 3 , ( " mkdir %s \n " , subpath ) ) ;
}
strlcat ( subpath , " \\ " , len ) ;
p = strtok_r ( NULL , " / \\ " , & state ) ;
}
out :
talloc_free ( ctx ) ;
return err ;
2013-07-23 19:39:09 +04:00
}
2013-07-05 20:14:50 +04:00
2013-07-24 18:48:02 +04:00
/**
* tar_reset_mem_context - reset talloc context associated with @ t
*
* At the start of the program the context is NULL so a new one is
* allocated . On the following runs ( interactive session only ) , simply
* free the children .
*/
static TALLOC_CTX * tar_reset_mem_context ( struct tar * t )
{
2014-02-17 18:00:43 +04:00
tar_free_mem_context ( t ) ;
2014-02-20 22:47:50 +04:00
t - > talloc_ctx = talloc_new ( NULL ) ;
2014-02-17 18:00:43 +04:00
return t - > talloc_ctx ;
2013-07-24 18:48:02 +04:00
}
/**
* tar_free_mem_context - free talloc context associated with @ t
*/
static void tar_free_mem_context ( struct tar * t )
{
2014-02-17 18:00:43 +04:00
if ( t - > talloc_ctx ) {
talloc_free ( t - > talloc_ctx ) ;
t - > talloc_ctx = NULL ;
t - > path_list_size = 0 ;
t - > path_list = NULL ;
t - > tar_path = NULL ;
}
2013-07-24 18:48:02 +04:00
}
2013-07-05 20:14:50 +04:00
2013-07-23 19:39:09 +04:00
# define XSET(v) [v] = #v
# define XTABLE(v, t) DBG(2, ("DUMP:%-20.20s = %s\n", #v, t[v]))
# define XBOOL(v) DBG(2, ("DUMP:%-20.20s = %d\n", #v, v ? 1 : 0))
# define XSTR(v) DBG(2, ("DUMP:%-20.20s = %s\n", #v, v ? v : "NULL"))
# define XINT(v) DBG(2, ("DUMP:%-20.20s = %d\n", #v, v))
# define XUINT64(v) DBG(2, ("DUMP:%-20.20s = %" PRIu64 "\n", #v, v))
2013-07-05 20:14:50 +04:00
2013-07-23 19:39:09 +04:00
/**
* tar_dump - dump tar structure on stdout
*/
static void tar_dump ( struct tar * t )
{
2014-02-17 18:00:43 +04:00
int i ;
const char * op [ ] = {
XSET ( TAR_NO_OPERATION ) ,
XSET ( TAR_CREATE ) ,
XSET ( TAR_EXTRACT ) ,
} ;
const char * sel [ ] = {
XSET ( TAR_NO_SELECTION ) ,
XSET ( TAR_INCLUDE ) ,
XSET ( TAR_EXCLUDE ) ,
} ;
XBOOL ( t - > to_process ) ;
XTABLE ( t - > mode . operation , op ) ;
XTABLE ( t - > mode . selection , sel ) ;
XINT ( t - > mode . blocksize ) ;
XBOOL ( t - > mode . hidden ) ;
XBOOL ( t - > mode . system ) ;
XBOOL ( t - > mode . incremental ) ;
XBOOL ( t - > mode . reset ) ;
XBOOL ( t - > mode . dry ) ;
XBOOL ( t - > mode . verbose ) ;
XUINT64 ( t - > total_size ) ;
XSTR ( t - > tar_path ) ;
XINT ( t - > path_list_size ) ;
for ( i = 0 ; t - > path_list & & t - > path_list [ i ] ; i + + ) {
DBG ( 2 , ( " DUMP: t->path_list[%2d] = %s \n " , i , t - > path_list [ i ] ) ) ;
}
DBG ( 2 , ( " DUMP:t->path_list @ %p (%d elem) \n " , t - > path_list , i ) ) ;
2013-07-23 19:39:09 +04:00
}
# undef XSET
# undef XTABLE
# undef XBOOL
# undef XSTR
# undef XINT
/**
* max_token - return upper limit for the number of token in @ str
*
* The result is not exact , the actual number of token might be less
* than what is returned .
*/
2014-02-17 18:00:43 +04:00
static int max_token ( const char * str )
2013-07-23 19:39:09 +04:00
{
2014-02-17 18:00:43 +04:00
const char * s ;
int nb = 0 ;
2013-07-23 19:39:09 +04:00
2014-02-17 18:00:43 +04:00
if ( str = = NULL ) {
return 0 ;
}
2013-07-05 20:14:50 +04:00
2014-02-17 18:00:43 +04:00
s = str ;
while ( s [ 0 ] ! = ' \0 ' ) {
if ( isspace ( ( int ) s [ 0 ] ) ) {
nb + + ;
}
s + + ;
}
2013-07-08 20:09:47 +04:00
2014-02-17 18:00:43 +04:00
nb + + ;
2013-07-08 20:09:47 +04:00
2014-02-17 18:00:43 +04:00
return nb ;
2013-07-23 19:39:09 +04:00
}
2013-07-11 02:57:40 +04:00
2013-07-23 19:39:09 +04:00
/**
* fix_unix_path - convert @ path to a DOS path
* @ path : path to convert
* @ removeprefix : if true , remove leading . / or / .
*/
2014-02-17 18:00:43 +04:00
static char * fix_unix_path ( char * path , bool do_remove_prefix )
2013-07-23 19:39:09 +04:00
{
2014-02-17 18:00:43 +04:00
char * from = path , * to = path ;
if ( path = = NULL | | path [ 0 ] = = ' \0 ' ) {
return path ;
}
/* remove prefix:
* . / path = > path
* / path = > path
*/
if ( do_remove_prefix ) {
/* /path */
if ( path [ 0 ] = = ' / ' | | path [ 0 ] = = ' \\ ' ) {
from + = 1 ;
}
/* ./path */
if ( path [ 1 ] ! = ' \0 ' & & path [ 0 ] = = ' . ' & & ( path [ 1 ] = = ' / ' | | path [ 1 ] = = ' \\ ' ) ) {
from + = 2 ;
}
}
/* replace / with \ */
while ( from [ 0 ] ! = ' \0 ' ) {
if ( from [ 0 ] = = ' / ' ) {
to [ 0 ] = ' \\ ' ;
} else {
to [ 0 ] = from [ 0 ] ;
}
from + + ;
to + + ;
}
to [ 0 ] = ' \0 ' ;
return path ;
2013-07-23 19:39:09 +04:00
}
/**
* path_base_name - return @ path basename
*
* If @ path doesn ' t contain any directory separator return NULL .
*/
2014-02-20 22:47:44 +04:00
static NTSTATUS path_base_name ( TALLOC_CTX * ctx , const char * path , char * * _base )
2013-07-23 19:39:09 +04:00
{
2014-02-17 18:00:43 +04:00
char * base = NULL ;
int last = - 1 ;
int i ;
for ( i = 0 ; path [ i ] ; i + + ) {
if ( path [ i ] = = ' \\ ' | | path [ i ] = = ' / ' ) {
last = i ;
}
}
if ( last > = 0 ) {
2014-02-20 22:47:44 +04:00
base = talloc_strdup ( ctx , path ) ;
if ( base = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2014-02-17 18:00:43 +04:00
base [ last ] = 0 ;
}
2014-02-20 22:47:44 +04:00
* _base = base ;
return NT_STATUS_OK ;
1996-05-04 11:50:46 +04:00
}
2013-08-07 18:34:22 +04:00
# else
2018-05-10 04:04:35 +03:00
# define NOT_IMPLEMENTED DEBUG(0, ("tar mode not compiled. build used --without-libarchive\n"))
2013-08-07 18:34:22 +04:00
int cmd_block ( void )
{
2014-02-17 18:00:43 +04:00
NOT_IMPLEMENTED ;
return 1 ;
2013-08-07 18:34:22 +04:00
}
int cmd_tarmode ( void )
{
2014-02-17 18:00:43 +04:00
NOT_IMPLEMENTED ;
return 1 ;
2013-08-07 18:34:22 +04:00
}
int cmd_tar ( void )
{
2014-02-17 18:00:43 +04:00
NOT_IMPLEMENTED ;
return 1 ;
2013-08-07 18:34:22 +04:00
}
int tar_process ( struct tar * tar )
{
2014-02-17 18:00:43 +04:00
NOT_IMPLEMENTED ;
return 1 ;
2013-08-07 18:34:22 +04:00
}
int tar_parse_args ( struct tar * tar , const char * flag , const char * * val , int valsize )
{
2014-02-17 18:00:43 +04:00
NOT_IMPLEMENTED ;
return 1 ;
2013-08-07 18:34:22 +04:00
}
bool tar_to_process ( struct tar * tar )
{
2014-02-17 18:00:43 +04:00
return false ;
2013-08-07 18:34:22 +04:00
}
2014-02-14 20:16:14 +04:00
struct tar * tar_get_ctx ( )
{
2014-02-17 18:00:43 +04:00
return NULL ;
2014-02-14 20:16:14 +04:00
}
2013-08-07 18:34:22 +04:00
# endif