2004-01-07 03:43:52 +03:00
/*
2016-01-24 13:17:20 +03:00
smbget : a wget - like utility with support for recursive downloading of
smb : // urls
2004-01-07 03:43:52 +03:00
Copyright ( C ) 2003 - 2004 Jelmer Vernooij < jelmer @ samba . org >
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
2004-01-07 03:43:52 +03:00
( at your option ) any later version .
2010-07-04 13:02:21 +04:00
2004-01-07 03:43:52 +03: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 .
2010-07-04 13:02:21 +04:00
2004-01-07 03:43:52 +03: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/>. */
2004-01-07 03:43:52 +03:00
# include "includes.h"
2011-04-26 16:58:01 +04:00
# include "system/filesys.h"
2010-08-05 12:49:53 +04:00
# include "popt_common.h"
2004-01-07 03:43:52 +03:00
# include "libsmbclient.h"
2008-03-09 15:50:56 +03:00
static int columns = 0 ;
2004-01-07 03:43:52 +03:00
2008-03-11 21:49:08 +03:00
static int debuglevel , update ;
2005-11-21 18:52:10 +03:00
static char * outputfile ;
2008-03-09 15:50:56 +03:00
static time_t total_start_time = 0 ;
static off_t total_bytes = 0 ;
2004-01-07 03:43:52 +03:00
# define SMB_MAXPATHLEN MAXPATHLEN
2016-01-24 13:17:20 +03:00
/*
* Number of bytes to read when checking whether local and remote file
* are really the same file
*/
# define RESUME_CHECK_SIZE 512
# define RESUME_DOWNLOAD_OFFSET 1024
# define RESUME_CHECK_OFFSET (RESUME_DOWNLOAD_OFFSET+RESUME_CHECK_SIZE)
2004-01-07 03:43:52 +03:00
/* Number of bytes to read at once */
2016-01-24 13:17:20 +03:00
# define SMB_DEFAULT_BLOCKSIZE 64000
2004-01-07 03:43:52 +03:00
2008-03-09 15:50:56 +03:00
static const char * username = NULL , * password = NULL , * workgroup = NULL ;
2016-01-24 13:17:20 +03:00
static int nonprompt = 0 , quiet = 0 , dots = 0 , keep_permissions = 0 ,
verbose = 0 , send_stdout = 0 ;
2016-01-24 13:45:59 +03:00
static unsigned int blocksize = SMB_DEFAULT_BLOCKSIZE ;
2004-01-07 03:43:52 +03:00
2010-07-04 13:32:50 +04:00
static int smb_download_file ( const char * base , const char * name , int recursive ,
int resume , int toplevel , char * outfile ) ;
2004-01-07 03:43:52 +03:00
2006-12-19 23:16:52 +03:00
static int get_num_cols ( void )
2004-01-07 03:43:52 +03:00
{
# ifdef TIOCGWINSZ
struct winsize ws ;
2016-01-24 13:17:20 +03:00
if ( ioctl ( STDOUT_FILENO , TIOCGWINSZ , & ws ) < 0 ) {
2004-01-07 03:43:52 +03:00
return 0 ;
}
return ws . ws_col ;
# else
# warning No support for TIOCGWINSZ
char * cols = getenv ( " COLUMNS " ) ;
2016-01-24 13:17:20 +03:00
if ( ! cols ) {
return 0 ;
}
2004-01-07 03:43:52 +03:00
return atoi ( cols ) ;
# endif
}
2006-12-19 23:16:52 +03:00
static void change_columns ( int sig )
2004-01-07 03:43:52 +03:00
{
columns = get_num_cols ( ) ;
}
2006-12-19 23:16:52 +03:00
static void human_readable ( off_t s , char * buffer , int l )
2004-01-07 03:43:52 +03:00
{
2011-04-08 00:03:49 +04:00
if ( s > 1024 * 1024 * 1024 ) {
snprintf ( buffer , l , " %.2fGB " , 1.0 * s / ( 1024 * 1024 * 1024 ) ) ;
} else if ( s > 1024 * 1024 ) {
snprintf ( buffer , l , " %.2fMB " , 1.0 * s / ( 1024 * 1024 ) ) ;
} else if ( s > 1024 ) {
snprintf ( buffer , l , " %.2fkB " , 1.0 * s / 1024 ) ;
} else {
2016-01-24 13:45:59 +03:00
snprintf ( buffer , l , " %jdb " , ( intmax_t ) s ) ;
2011-04-08 00:03:49 +04:00
}
2004-01-07 03:43:52 +03:00
}
2016-01-24 13:17:20 +03:00
static void get_auth_data ( const char * srv , const char * shr , char * wg , int wglen ,
char * un , int unlen , char * pw , int pwlen )
2004-01-07 03:43:52 +03:00
{
static char hasasked = 0 ;
2015-12-30 23:25:13 +03:00
static char * savedwg ;
static char * savedun ;
static char * savedpw ;
2004-01-07 03:43:52 +03:00
char tmp [ 128 ] ;
2015-12-30 23:25:13 +03:00
if ( hasasked ) {
strncpy ( wg , savedwg , wglen - 1 ) ;
strncpy ( un , savedun , unlen - 1 ) ;
strncpy ( pw , savedpw , pwlen - 1 ) ;
return ;
}
2004-01-07 03:43:52 +03:00
hasasked = 1 ;
2016-01-24 13:17:20 +03:00
if ( ! nonprompt & & ! username ) {
2004-01-07 03:43:52 +03:00
printf ( " Username for %s at %s [guest] " , shr , srv ) ;
2009-01-01 05:06:57 +03:00
if ( fgets ( tmp , sizeof ( tmp ) , stdin ) = = NULL ) {
return ;
}
2016-01-24 13:17:20 +03:00
if ( ( strlen ( tmp ) > 0 ) & & ( tmp [ strlen ( tmp ) - 1 ] = = ' \n ' ) ) {
tmp [ strlen ( tmp ) - 1 ] = ' \0 ' ;
2009-11-30 23:48:33 +03:00
}
2016-01-24 13:17:20 +03:00
strncpy ( un , tmp , unlen - 1 ) ;
} else if ( username ) {
strncpy ( un , username , unlen - 1 ) ;
}
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
if ( ! nonprompt & & ! password ) {
2012-11-23 17:38:14 +04:00
char * prompt ;
2016-01-24 13:17:20 +03:00
if ( asprintf ( & prompt , " Password for %s at %s: " , shr , srv ) = =
- 1 ) {
2009-01-01 05:06:57 +03:00
return ;
}
2016-01-24 13:17:20 +03:00
( void ) samba_getpass ( prompt , pw , pwlen , false , false ) ;
2004-01-07 03:43:52 +03:00
free ( prompt ) ;
2016-01-24 13:17:20 +03:00
} else if ( password ) {
strncpy ( pw , password , pwlen - 1 ) ;
}
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
if ( workgroup ) {
strncpy ( wg , workgroup , wglen - 1 ) ;
}
2004-01-07 03:43:52 +03:00
2015-12-30 23:25:13 +03:00
/* save the values found for later */
savedwg = SMB_STRDUP ( wg ) ;
savedun = SMB_STRDUP ( un ) ;
savedpw = SMB_STRDUP ( pw ) ;
2016-01-24 13:17:20 +03:00
if ( ! quiet ) {
char * wgtmp , * usertmp ;
wgtmp = SMB_STRNDUP ( wg , wglen ) ;
usertmp = SMB_STRNDUP ( un , unlen ) ;
printf ( " Using workgroup %s, %s%s \n " , wgtmp ,
* usertmp ? " user " : " guest user " , usertmp ) ;
free ( wgtmp ) ;
free ( usertmp ) ;
}
2004-01-07 03:43:52 +03:00
}
2010-01-28 21:38:24 +03:00
/* Return 1 on error, 0 on success. */
2006-12-19 23:16:52 +03:00
static int smb_download_dir ( const char * base , const char * name , int resume )
2004-01-07 03:43:52 +03:00
{
char path [ SMB_MAXPATHLEN ] ;
int dirhandle ;
struct smbc_dirent * dirent ;
const char * relname = name ;
char * tmpname ;
struct stat remotestat ;
2010-01-28 21:38:24 +03:00
int ret = 0 ;
2016-01-24 13:17:20 +03:00
snprintf ( path , SMB_MAXPATHLEN - 1 , " %s%s%s " , base ,
( base [ 0 ] & & name [ 0 ] & & name [ 0 ] ! = ' / ' & &
base [ strlen ( base ) - 1 ] ! = ' / ' ) ? " / " : " " ,
name ) ;
2004-01-07 03:43:52 +03:00
/* List files in directory and call smb_download_file on them */
dirhandle = smbc_opendir ( path ) ;
2016-01-24 13:17:20 +03:00
if ( dirhandle < 1 ) {
2010-07-04 13:32:50 +04:00
if ( errno = = ENOTDIR ) {
2016-01-24 13:17:20 +03:00
return smb_download_file ( base , name , 1 , resume , 0 ,
NULL ) ;
2010-07-04 13:32:50 +04:00
}
2016-01-24 13:17:20 +03:00
fprintf ( stderr , " Can't open directory %s: %s \n " , path ,
strerror ( errno ) ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
2016-01-24 13:17:20 +03:00
while ( * relname = = ' / ' ) {
relname + + ;
}
2004-01-07 03:43:52 +03:00
mkdir ( relname , 0755 ) ;
2010-07-04 13:02:21 +04:00
2004-12-17 00:06:33 +03:00
tmpname = SMB_STRDUP ( name ) ;
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
while ( ( dirent = smbc_readdir ( dirhandle ) ) ) {
2004-01-07 03:43:52 +03:00
char * newname ;
2016-01-24 13:17:20 +03:00
if ( ! strcmp ( dirent - > name , " . " ) | | ! strcmp ( dirent - > name , " .. " ) ) {
continue ;
}
2009-01-01 05:06:57 +03:00
if ( asprintf ( & newname , " %s/%s " , tmpname , dirent - > name ) = = - 1 ) {
2013-12-04 17:01:55 +04:00
free ( tmpname ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2009-01-01 05:06:57 +03:00
}
2016-01-24 13:17:20 +03:00
switch ( dirent - > smbc_type ) {
2004-01-07 03:43:52 +03:00
case SMBC_DIR :
2010-01-28 21:38:24 +03:00
ret = smb_download_dir ( base , newname , resume ) ;
2004-01-07 03:43:52 +03:00
break ;
case SMBC_WORKGROUP :
2010-01-28 21:38:24 +03:00
ret = smb_download_dir ( " smb:// " , dirent - > name , resume ) ;
2004-01-07 03:43:52 +03:00
break ;
case SMBC_SERVER :
2010-01-28 21:38:24 +03:00
ret = smb_download_dir ( " smb:// " , dirent - > name , resume ) ;
2004-01-07 03:43:52 +03:00
break ;
case SMBC_FILE :
2010-07-04 13:32:50 +04:00
ret = smb_download_file ( base , newname , 1 , resume , 0 ,
NULL ) ;
2004-01-07 03:43:52 +03:00
break ;
case SMBC_FILE_SHARE :
2010-01-28 21:38:24 +03:00
ret = smb_download_dir ( base , newname , resume ) ;
2004-01-07 03:43:52 +03:00
break ;
case SMBC_PRINTER_SHARE :
2016-01-24 13:17:20 +03:00
if ( ! quiet ) {
printf ( " Ignoring printer share %s \n " ,
dirent - > name ) ;
}
2004-01-07 03:43:52 +03:00
break ;
case SMBC_COMMS_SHARE :
2016-01-24 13:17:20 +03:00
if ( ! quiet ) {
printf ( " Ignoring comms share %s \n " ,
dirent - > name ) ;
}
2004-01-07 03:43:52 +03:00
break ;
2010-07-04 13:02:21 +04:00
2004-01-07 03:43:52 +03:00
case SMBC_IPC_SHARE :
2016-01-24 13:17:20 +03:00
if ( ! quiet ) {
printf ( " Ignoring ipc$ share %s \n " ,
dirent - > name ) ;
}
2004-01-07 03:43:52 +03:00
break ;
default :
2016-01-24 13:17:20 +03:00
fprintf ( stderr , " Ignoring file '%s' of type '%d' \n " ,
newname , dirent - > smbc_type ) ;
2004-01-07 03:43:52 +03:00
break ;
}
free ( newname ) ;
}
free ( tmpname ) ;
2016-01-24 13:17:20 +03:00
if ( keep_permissions ) {
if ( smbc_fstat ( dirhandle , & remotestat ) < 0 ) {
fprintf ( stderr ,
" Unable to get stats on %s on remote server \n " ,
path ) ;
2004-01-07 03:43:52 +03:00
smbc_closedir ( dirhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
2010-07-04 13:02:21 +04:00
2016-01-24 13:17:20 +03:00
if ( chmod ( relname , remotestat . st_mode ) < 0 ) {
fprintf ( stderr ,
" Unable to change mode of local dir %s to %o \n " ,
relname , ( unsigned int ) remotestat . st_mode ) ;
2004-01-07 03:43:52 +03:00
smbc_closedir ( dirhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
}
smbc_closedir ( dirhandle ) ;
2010-01-28 21:38:24 +03:00
return ret ;
2004-01-07 03:43:52 +03:00
}
2006-12-19 23:16:52 +03:00
static char * print_time ( long t )
2004-01-07 03:43:52 +03:00
{
static char buffer [ 100 ] ;
int secs , mins , hours ;
2016-01-24 13:17:20 +03:00
if ( t < - 1 ) {
2004-01-07 03:43:52 +03:00
strncpy ( buffer , " Unknown " , sizeof ( buffer ) ) ;
return buffer ;
}
secs = ( int ) t % 60 ;
mins = ( int ) t / 60 % 60 ;
hours = ( int ) t / ( 60 * 60 ) ;
2016-01-24 13:17:20 +03:00
snprintf ( buffer , sizeof ( buffer ) - 1 , " %02d:%02d:%02d " , hours , mins ,
secs ) ;
2004-01-07 03:43:52 +03:00
return buffer ;
}
2016-01-24 13:17:20 +03:00
static void print_progress ( const char * name , time_t start , time_t now ,
off_t start_pos , off_t pos , off_t total )
2004-01-07 03:43:52 +03:00
{
double avg = 0.0 ;
2016-01-24 13:17:20 +03:00
long eta = - 1 ;
2004-01-07 03:43:52 +03:00
double prcnt = 0.0 ;
char hpos [ 20 ] , htotal [ 20 ] , havg [ 20 ] ;
char * status , * filename ;
int len ;
2016-01-24 13:17:20 +03:00
if ( now - start ) {
avg = 1.0 * ( pos - start_pos ) / ( now - start ) ;
}
2004-02-14 01:09:53 +03:00
eta = ( total - pos ) / avg ;
2016-01-24 13:17:20 +03:00
if ( total ) {
prcnt = 100.0 * pos / total ;
}
2004-01-07 03:43:52 +03:00
human_readable ( pos , hpos , sizeof ( hpos ) ) ;
human_readable ( total , htotal , sizeof ( htotal ) ) ;
human_readable ( avg , havg , sizeof ( havg ) ) ;
2016-01-24 13:17:20 +03:00
len = asprintf ( & status , " %s of %s (%.2f%%) at %s/s ETA: %s " , hpos ,
htotal , prcnt , havg , print_time ( eta ) ) ;
2009-01-01 05:06:57 +03:00
if ( len = = - 1 ) {
return ;
}
2010-07-04 13:02:21 +04:00
2016-01-24 13:17:20 +03:00
if ( columns ) {
int required = strlen ( name ) ,
available = columns - len - strlen ( " [] " ) ;
if ( required > available ) {
if ( asprintf ( & filename , " ...%s " ,
name + required - available + 3 ) = = - 1 ) {
2009-01-01 05:06:57 +03:00
return ;
}
} else {
filename = SMB_STRNDUP ( name , available ) ;
}
2016-01-24 13:17:20 +03:00
} else {
filename = SMB_STRDUP ( name ) ;
}
2004-01-07 03:43:52 +03:00
fprintf ( stderr , " \r [%s] %s " , filename , status ) ;
2016-01-24 13:17:20 +03:00
free ( filename ) ;
free ( status ) ;
2004-01-07 03:43:52 +03:00
}
2010-01-28 21:38:24 +03:00
/* Return 1 on error, 0 on success. */
2010-07-04 13:32:50 +04:00
static int smb_download_file ( const char * base , const char * name , int recursive ,
int resume , int toplevel , char * outfile )
{
2004-01-07 03:43:52 +03:00
int remotehandle , localhandle ;
2010-09-09 00:29:00 +04:00
time_t start_time = time_mono ( NULL ) ;
2004-01-07 03:43:52 +03:00
const char * newpath ;
char path [ SMB_MAXPATHLEN ] ;
char checkbuf [ 2 ] [ RESUME_CHECK_SIZE ] ;
char * readbuf = NULL ;
2016-01-24 13:17:20 +03:00
off_t offset_download = 0 , offset_check = 0 , curpos = 0 ,
start_offset = 0 ;
2004-01-07 03:43:52 +03:00
struct stat localstat , remotestat ;
2016-01-24 13:17:20 +03:00
snprintf ( path , SMB_MAXPATHLEN - 1 , " %s%s%s " , base ,
( * base & & * name & & name [ 0 ] ! = ' / ' & &
base [ strlen ( base ) - 1 ] ! = ' / ' ) ? " / " : " " ,
name ) ;
2010-07-04 13:02:21 +04:00
2004-01-07 03:43:52 +03:00
remotehandle = smbc_open ( path , O_RDONLY , 0755 ) ;
2016-01-24 13:17:20 +03:00
if ( remotehandle < 0 ) {
switch ( errno ) {
case EISDIR :
if ( ! recursive ) {
fprintf ( stderr ,
" %s is a directory. Specify -R "
" to download recursively \n " ,
path ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
2010-01-28 21:38:24 +03:00
return smb_download_dir ( base , name , resume ) ;
2004-01-07 03:43:52 +03:00
case ENOENT :
2016-01-24 13:17:20 +03:00
fprintf ( stderr ,
" %s can't be found on the remote server \n " ,
path ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
case ENOMEM :
fprintf ( stderr , " Not enough memory \n " ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
case ENODEV :
2016-01-24 13:17:20 +03:00
fprintf ( stderr ,
" The share name used in %s does not exist \n " ,
path ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
case EACCES :
2016-01-24 13:17:20 +03:00
fprintf ( stderr , " You don't have enough permissions "
" to access %s \n " ,
path ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
default :
perror ( " smbc_open " ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
2016-01-24 13:17:20 +03:00
}
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
if ( smbc_fstat ( remotehandle , & remotestat ) < 0 ) {
2004-01-07 03:43:52 +03:00
fprintf ( stderr , " Can't stat %s: %s \n " , path , strerror ( errno ) ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
2016-01-24 13:17:20 +03:00
if ( outfile ) {
newpath = outfile ;
} else if ( ! name [ 0 ] ) {
2004-01-07 03:43:52 +03:00
newpath = strrchr ( base , ' / ' ) ;
2016-01-24 13:17:20 +03:00
if ( newpath ) {
newpath + + ;
} else {
newpath = base ;
}
} else {
newpath = name ;
}
2004-01-07 03:43:52 +03:00
2010-07-04 13:32:50 +04:00
if ( ! toplevel & & ( newpath [ 0 ] = = ' / ' ) ) {
newpath + + ;
}
2010-07-04 13:02:21 +04:00
2008-03-05 17:20:29 +03:00
/* Open local file according to the mode */
2016-01-24 13:17:20 +03:00
if ( update ) {
2008-03-05 17:20:29 +03:00
/* if it is up-to-date, skip */
2016-01-24 13:17:20 +03:00
if ( stat ( newpath , & localstat ) = = 0 & &
localstat . st_mtime > = remotestat . st_mtime ) {
if ( verbose ) {
2008-03-05 17:20:29 +03:00
printf ( " %s is up-to-date, skipping \n " , newpath ) ;
2016-01-24 13:17:20 +03:00
}
2008-03-05 17:20:29 +03:00
smbc_close ( remotehandle ) ;
return 0 ;
}
2008-03-05 19:30:18 +03:00
/* else open it for writing and truncate if it exists */
2016-01-24 13:17:20 +03:00
localhandle = open (
newpath , O_CREAT | O_NONBLOCK | O_RDWR | O_TRUNC , 0775 ) ;
if ( localhandle < 0 ) {
2008-03-05 17:20:29 +03:00
fprintf ( stderr , " Can't open %s : %s \n " , newpath ,
2016-01-24 13:17:20 +03:00
strerror ( errno ) ) ;
2008-03-05 17:20:29 +03:00
smbc_close ( remotehandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2008-03-05 17:20:29 +03:00
}
/* no offset */
2016-01-24 13:17:20 +03:00
} else if ( ! send_stdout ) {
localhandle = open ( newpath , O_CREAT | O_NONBLOCK | O_RDWR |
( ! resume ? O_EXCL : 0 ) ,
0755 ) ;
if ( localhandle < 0 ) {
fprintf ( stderr , " Can't open %s: %s \n " , newpath ,
strerror ( errno ) ) ;
2004-03-05 20:17:31 +03:00
smbc_close ( remotehandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-03-05 20:17:31 +03:00
}
2010-07-04 13:02:21 +04:00
2008-03-15 01:26:28 +03:00
if ( fstat ( localhandle , & localstat ) ! = 0 ) {
2016-01-24 13:17:20 +03:00
fprintf ( stderr , " Can't fstat %s: %s \n " , newpath ,
strerror ( errno ) ) ;
2008-03-15 01:26:28 +03:00
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2008-03-15 01:26:28 +03:00
}
2004-01-07 03:43:52 +03:00
2004-03-05 20:17:31 +03:00
start_offset = localstat . st_size ;
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
if ( localstat . st_size & &
localstat . st_size = = remotestat . st_size ) {
if ( verbose ) {
fprintf ( stderr , " %s is already downloaded "
" completely. \n " ,
path ) ;
} else if ( ! quiet ) {
fprintf ( stderr , " %s \n " , path ) ;
}
2004-03-05 20:17:31 +03:00
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 0 ;
2004-01-07 03:43:52 +03:00
}
2016-01-24 13:17:20 +03:00
if ( localstat . st_size > RESUME_CHECK_OFFSET & &
remotestat . st_size > RESUME_CHECK_OFFSET ) {
offset_download =
localstat . st_size - RESUME_DOWNLOAD_OFFSET ;
2004-03-05 20:17:31 +03:00
offset_check = localstat . st_size - RESUME_CHECK_OFFSET ;
2016-01-24 13:17:20 +03:00
if ( verbose ) {
2016-01-24 13:45:59 +03:00
printf ( " Trying to start resume of %s at %jd \n "
" At the moment %jd of %jd bytes have "
" been retrieved \n " ,
newpath , ( intmax_t ) offset_check ,
( intmax_t ) localstat . st_size ,
( intmax_t ) remotestat . st_size ) ;
2016-01-24 13:17:20 +03:00
}
2004-01-07 03:43:52 +03:00
}
2016-01-24 13:17:20 +03:00
if ( offset_check ) {
2004-03-05 20:17:31 +03:00
off_t off1 , off2 ;
2016-01-24 13:17:20 +03:00
/* First, check all bytes from offset_check to
* offset_download */
2004-03-05 20:17:31 +03:00
off1 = lseek ( localhandle , offset_check , SEEK_SET ) ;
2016-01-24 13:17:20 +03:00
if ( off1 < 0 ) {
2016-01-24 13:45:59 +03:00
fprintf ( stderr ,
" Can't seek to %jd in local file %s \n " ,
( intmax_t ) offset_check , newpath ) ;
2016-01-24 13:17:20 +03:00
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-03-05 20:17:31 +03:00
}
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
off2 = smbc_lseek ( remotehandle , offset_check , SEEK_SET ) ;
if ( off2 < 0 ) {
2016-01-24 13:45:59 +03:00
fprintf ( stderr ,
" Can't seek to %jd in remote file %s \n " ,
( intmax_t ) offset_check , newpath ) ;
2016-01-24 13:17:20 +03:00
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-03-05 20:17:31 +03:00
}
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
if ( off1 ! = off2 ) {
fprintf ( stderr , " Offset in local and remote "
2016-01-24 13:45:59 +03:00
" files are different "
" (local: %jd, remote: %jd) \n " ,
( intmax_t ) off1 , ( intmax_t ) off2 ) ;
2016-01-24 13:17:20 +03:00
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-03-05 20:17:31 +03:00
}
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
if ( smbc_read ( remotehandle , checkbuf [ 0 ] ,
RESUME_CHECK_SIZE ) ! = RESUME_CHECK_SIZE ) {
fprintf ( stderr , " Can't read %d bytes from "
" remote file %s \n " ,
RESUME_CHECK_SIZE , path ) ;
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-03-05 20:17:31 +03:00
}
2016-01-24 13:17:20 +03:00
if ( read ( localhandle , checkbuf [ 1 ] , RESUME_CHECK_SIZE ) ! =
RESUME_CHECK_SIZE ) {
fprintf ( stderr , " Can't read %d bytes from "
" local file %s \n " ,
RESUME_CHECK_SIZE , name ) ;
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-03-05 20:17:31 +03:00
}
2016-01-24 13:17:20 +03:00
if ( memcmp ( checkbuf [ 0 ] , checkbuf [ 1 ] ,
RESUME_CHECK_SIZE ) = = 0 ) {
if ( verbose ) {
2016-01-24 13:45:59 +03:00
printf ( " Current local and remote file "
" appear to be the same. "
" Starting download from "
" offset %jd \n " ,
( intmax_t ) offset_download ) ;
2016-01-24 13:17:20 +03:00
}
2004-03-05 20:17:31 +03:00
} else {
2016-01-24 13:17:20 +03:00
fprintf ( stderr , " Local and remote file appear "
" to be different, not "
" doing resume for %s \n " ,
path ) ;
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-03-05 20:17:31 +03:00
}
2004-01-07 03:43:52 +03:00
}
2004-03-05 20:17:31 +03:00
} else {
localhandle = STDOUT_FILENO ;
start_offset = 0 ;
offset_download = 0 ;
offset_check = 0 ;
2004-01-07 03:43:52 +03:00
}
2006-08-27 02:59:58 +04:00
readbuf = ( char * ) SMB_MALLOC ( blocksize ) ;
2010-09-10 22:56:26 +04:00
if ( ! readbuf ) {
2013-02-20 13:23:45 +04:00
if ( localhandle ! = STDOUT_FILENO ) {
close ( localhandle ) ;
}
2010-09-10 22:56:26 +04:00
return 1 ;
}
2004-01-07 03:43:52 +03:00
/* Now, download all bytes from offset_download to the end */
2016-01-24 13:17:20 +03:00
for ( curpos = offset_download ; curpos < remotestat . st_size ;
curpos + = blocksize ) {
2004-01-07 03:43:52 +03:00
ssize_t bytesread = smbc_read ( remotehandle , readbuf , blocksize ) ;
if ( bytesread < 0 ) {
2016-01-24 13:45:59 +03:00
fprintf ( stderr ,
" Can't read %u bytes at offset %jd, file %s \n " ,
blocksize , ( intmax_t ) curpos , path ) ;
2004-03-05 20:17:31 +03:00
smbc_close ( remotehandle ) ;
2016-01-24 13:17:20 +03:00
if ( localhandle ! = STDOUT_FILENO ) {
close ( localhandle ) ;
}
2004-01-07 03:43:52 +03:00
free ( readbuf ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
total_bytes + = bytesread ;
if ( write ( localhandle , readbuf , bytesread ) < 0 ) {
2016-01-24 13:45:59 +03:00
fprintf ( stderr ,
" Can't write %zd bytes to local file %s at "
" offset %jd \n " , bytesread , path ,
( intmax_t ) curpos ) ;
2004-01-07 03:43:52 +03:00
free ( readbuf ) ;
2004-03-05 20:17:31 +03:00
smbc_close ( remotehandle ) ;
2016-01-24 13:17:20 +03:00
if ( localhandle ! = STDOUT_FILENO ) {
close ( localhandle ) ;
}
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
2016-01-24 13:17:20 +03:00
if ( dots ) {
fputc ( ' . ' , stderr ) ;
} else if ( ! quiet ) {
2010-09-09 00:29:00 +04:00
print_progress ( newpath , start_time , time_mono ( NULL ) ,
2016-01-24 13:17:20 +03:00
start_offset , curpos ,
remotestat . st_size ) ;
2004-01-07 03:43:52 +03:00
}
}
free ( readbuf ) ;
2016-01-24 13:17:20 +03:00
if ( dots ) {
2004-01-07 03:43:52 +03:00
fputc ( ' \n ' , stderr ) ;
printf ( " %s downloaded \n " , path ) ;
2016-01-24 13:17:20 +03:00
} else if ( ! quiet ) {
2004-01-07 03:43:52 +03:00
int i ;
fprintf ( stderr , " \r %s " , path ) ;
2016-01-24 13:17:20 +03:00
if ( columns ) {
for ( i = strlen ( path ) ; i < columns ; i + + ) {
2004-01-07 03:43:52 +03:00
fputc ( ' ' , stderr ) ;
}
}
fputc ( ' \n ' , stderr ) ;
}
2016-01-24 13:17:20 +03:00
if ( keep_permissions & & ! send_stdout ) {
if ( fchmod ( localhandle , remotestat . st_mode ) < 0 ) {
fprintf ( stderr , " Unable to change mode of local "
" file %s to %o \n " ,
path , ( unsigned int ) remotestat . st_mode ) ;
2004-01-07 03:43:52 +03:00
smbc_close ( remotehandle ) ;
close ( localhandle ) ;
2010-01-28 21:38:24 +03:00
return 1 ;
2004-01-07 03:43:52 +03:00
}
}
2004-03-05 20:17:31 +03:00
2004-01-07 03:43:52 +03:00
smbc_close ( remotehandle ) ;
2016-01-24 13:17:20 +03:00
if ( localhandle ! = STDOUT_FILENO ) {
close ( localhandle ) ;
}
2010-01-28 21:38:24 +03:00
return 0 ;
2004-01-07 03:43:52 +03:00
}
2006-12-19 23:16:52 +03:00
static void clean_exit ( void )
2004-01-07 03:43:52 +03:00
{
char bs [ 100 ] ;
human_readable ( total_bytes , bs , sizeof ( bs ) ) ;
2016-01-24 13:17:20 +03:00
if ( ! quiet ) {
fprintf ( stderr , " Downloaded %s in %lu seconds \n " , bs ,
( unsigned long ) ( time_mono ( NULL ) - total_start_time ) ) ;
}
2004-01-07 03:43:52 +03:00
exit ( 0 ) ;
}
2006-12-19 23:16:52 +03:00
static void signal_quit ( int v )
2004-01-07 03:43:52 +03:00
{
clean_exit ( ) ;
}
2006-12-19 23:16:52 +03:00
static int readrcfile ( const char * name , const struct poptOption long_options [ ] )
2004-01-07 03:43:52 +03:00
{
FILE * fd = fopen ( name , " r " ) ;
int lineno = 0 , i ;
char var [ 101 ] , val [ 101 ] ;
char found ;
2016-01-24 13:17:20 +03:00
int * intdata ;
char * * stringdata ;
if ( ! fd ) {
2004-01-07 03:43:52 +03:00
fprintf ( stderr , " Can't open RC file %s \n " , name ) ;
return 1 ;
}
2016-01-24 13:17:20 +03:00
while ( ! feof ( fd ) ) {
2004-01-07 03:43:52 +03:00
lineno + + ;
2016-01-24 13:17:20 +03:00
if ( fscanf ( fd , " %100s %100s \n " , var , val ) < 2 ) {
fprintf ( stderr ,
" Can't parse line %d of %s, ignoring. \n " ,
lineno , name ) ;
2004-01-07 03:43:52 +03:00
continue ;
}
found = 0 ;
2016-01-24 13:17:20 +03:00
for ( i = 0 ; long_options [ i ] . shortName ; i + + ) {
if ( ! long_options [ i ] . longName ) {
continue ;
}
if ( strcmp ( long_options [ i ] . longName , var ) ) {
continue ;
}
if ( ! long_options [ i ] . arg ) {
continue ;
}
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
switch ( long_options [ i ] . argInfo ) {
2004-01-07 03:43:52 +03:00
case POPT_ARG_NONE :
intdata = ( int * ) long_options [ i ] . arg ;
2016-01-24 13:17:20 +03:00
if ( ! strcmp ( val , " on " ) ) {
* intdata = 1 ;
} else if ( ! strcmp ( val , " off " ) ) {
* intdata = 0 ;
} else {
fprintf ( stderr , " Illegal value %s for "
" %s at line %d in %s \n " ,
val , var , lineno , name ) ;
}
2004-01-07 03:43:52 +03:00
break ;
case POPT_ARG_INT :
intdata = ( int * ) long_options [ i ] . arg ;
* intdata = atoi ( val ) ;
break ;
case POPT_ARG_STRING :
stringdata = ( char * * ) long_options [ i ] . arg ;
2004-12-17 00:06:33 +03:00
* stringdata = SMB_STRDUP ( val ) ;
2004-01-07 03:43:52 +03:00
break ;
default :
2016-01-24 13:17:20 +03:00
fprintf ( stderr , " Invalid variable %s at "
" line %d in %s \n " ,
var , lineno , name ) ;
2004-01-07 03:43:52 +03:00
break ;
}
found = 1 ;
}
2016-01-24 13:17:20 +03:00
if ( ! found ) {
fprintf ( stderr ,
" Invalid variable %s at line %d in %s \n " , var ,
lineno , name ) ;
2004-01-07 03:43:52 +03:00
}
}
fclose ( fd ) ;
return 0 ;
}
int main ( int argc , const char * * argv )
{
int c = 0 ;
const char * file = NULL ;
char * rcfile = NULL ;
2008-01-05 11:51:50 +03:00
bool smb_encrypt = false ;
2008-03-11 21:49:08 +03:00
int resume = 0 , recursive = 0 ;
2007-09-04 09:39:06 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2010-01-28 21:38:24 +03:00
int ret = 0 ;
2004-01-07 03:43:52 +03:00
struct poptOption long_options [ ] = {
2016-01-24 13:17:20 +03:00
{ " guest " , ' a ' , POPT_ARG_NONE , NULL , ' a ' , " Work as user guest " } ,
2015-11-02 18:33:34 +03:00
{ " encrypt " , ' e ' , POPT_ARG_NONE , NULL , ' e ' , " Encrypt SMB transport " } ,
2008-03-11 21:49:08 +03:00
{ " resume " , ' r ' , POPT_ARG_NONE , & resume , 0 , " Automatically resume aborted files " } ,
2008-03-05 17:20:29 +03:00
{ " update " , ' U ' , POPT_ARG_NONE , & update , 0 , " Download only when remote file is newer than local file or local file is missing " } ,
2008-03-11 21:49:08 +03:00
{ " recursive " , ' R ' , POPT_ARG_NONE , & recursive , 0 , " Recursively download files " } ,
2004-01-07 03:43:52 +03:00
{ " username " , ' u ' , POPT_ARG_STRING , & username , ' u ' , " Username to use " } ,
{ " password " , ' p ' , POPT_ARG_STRING , & password , ' p ' , " Password to use " } ,
{ " workgroup " , ' w ' , POPT_ARG_STRING , & workgroup , ' w ' , " Workgroup to use (optional) " } ,
{ " nonprompt " , ' n ' , POPT_ARG_NONE , & nonprompt , ' n ' , " Don't ask anything (non-interactive) " } ,
{ " debuglevel " , ' d ' , POPT_ARG_INT , & debuglevel , ' d ' , " Debuglevel to use " } ,
{ " outputfile " , ' o ' , POPT_ARG_STRING , & outputfile , ' o ' , " Write downloaded data to specified file " } ,
2004-03-05 20:17:31 +03:00
{ " stdout " , ' O ' , POPT_ARG_NONE , & send_stdout , ' O ' , " Write data to stdout " } ,
2004-01-07 03:43:52 +03:00
{ " dots " , ' D ' , POPT_ARG_NONE , & dots , ' D ' , " Show dots as progress indication " } ,
{ " quiet " , ' q ' , POPT_ARG_NONE , & quiet , ' q ' , " Be quiet " } ,
{ " verbose " , ' v ' , POPT_ARG_NONE , & verbose , ' v ' , " Be verbose " } ,
{ " keep-permissions " , ' P ' , POPT_ARG_NONE , & keep_permissions , ' P ' , " Keep permissions " } ,
{ " blocksize " , ' b ' , POPT_ARG_INT , & blocksize , ' b ' , " Change number of bytes in a block " } ,
2009-05-15 23:02:08 +04:00
{ " rcfile " , ' f ' , POPT_ARG_STRING , NULL , ' f ' , " Use specified rc file " } ,
2004-01-07 03:43:52 +03:00
POPT_AUTOHELP
POPT_TABLEEND
} ;
poptContext pc ;
2015-03-21 22:00:06 +03:00
smb_init_locale ( ) ;
2005-12-29 01:48:54 +03:00
2004-01-07 03:43:52 +03:00
/* only read rcfile if it exists */
2009-01-01 05:06:57 +03:00
if ( asprintf ( & rcfile , " %s/.smbgetrc " , getenv ( " HOME " ) ) = = - 1 ) {
return 1 ;
}
2016-01-24 13:17:20 +03:00
if ( access ( rcfile , F_OK ) = = 0 ) {
2005-11-21 18:52:10 +03:00
readrcfile ( rcfile , long_options ) ;
2016-01-24 13:17:20 +03:00
}
2004-01-07 03:43:52 +03:00
free ( rcfile ) ;
# ifdef SIGWINCH
signal ( SIGWINCH , change_columns ) ;
# endif
signal ( SIGINT , signal_quit ) ;
signal ( SIGTERM , signal_quit ) ;
pc = poptGetContext ( argv [ 0 ] , argc , argv , long_options , 0 ) ;
2016-01-24 13:17:20 +03:00
while ( ( c = poptGetNextOpt ( pc ) ) > = 0 ) {
switch ( c ) {
2004-01-07 03:43:52 +03:00
case ' f ' :
readrcfile ( poptGetOptArg ( pc ) , long_options ) ;
break ;
case ' a ' :
2016-01-24 13:17:20 +03:00
username = " " ;
password = " " ;
2004-01-07 03:43:52 +03:00
break ;
2008-01-05 11:51:50 +03:00
case ' e ' :
smb_encrypt = true ;
break ;
2004-01-07 03:43:52 +03:00
}
}
2016-01-24 13:17:20 +03:00
if ( ( send_stdout | | resume | | outputfile ) & & update ) {
fprintf ( stderr , " The -o, -R or -O and -U options can not be "
" used together. \n " ) ;
2008-03-05 17:20:29 +03:00
return 1 ;
}
2016-01-24 13:17:20 +03:00
if ( ( send_stdout | | outputfile ) & & recursive ) {
fprintf ( stderr , " The -o or -O and -R options can not be "
" used together. \n " ) ;
2004-03-05 20:17:31 +03:00
return 1 ;
}
2016-01-24 13:17:20 +03:00
if ( outputfile & & send_stdout ) {
fprintf ( stderr , " The -o and -O options can not be "
" used together. \n " ) ;
2004-01-07 03:43:52 +03:00
return 1 ;
}
2016-01-24 13:17:20 +03:00
if ( smbc_init ( get_auth_data , debuglevel ) < 0 ) {
2004-01-07 03:43:52 +03:00
fprintf ( stderr , " Unable to initialize libsmbclient \n " ) ;
return 1 ;
}
2008-01-05 11:51:50 +03:00
if ( smb_encrypt ) {
SMBCCTX * smb_ctx = smbc_set_context ( NULL ) ;
smbc_option_set ( smb_ctx ,
2016-01-24 13:17:20 +03:00
discard_const_p ( char , " smb_encrypt_level " ) ,
" require " ) ;
2008-01-05 11:51:50 +03:00
}
2010-07-04 13:02:21 +04:00
2004-01-07 03:43:52 +03:00
columns = get_num_cols ( ) ;
2010-09-09 00:29:00 +04:00
total_start_time = time_mono ( NULL ) ;
2004-01-07 03:43:52 +03:00
2016-01-24 13:17:20 +03:00
while ( ( file = poptGetArg ( pc ) ) ) {
if ( ! recursive ) {
ret = smb_download_file ( file , " " , recursive , resume , 1 ,
outputfile ) ;
} else {
2010-01-28 21:38:24 +03:00
ret = smb_download_dir ( file , " " , resume ) ;
2016-01-24 13:17:20 +03:00
}
2004-01-07 03:43:52 +03:00
}
2007-09-04 09:39:06 +04:00
TALLOC_FREE ( frame ) ;
2016-01-24 13:17:20 +03:00
if ( ret = = 0 ) {
2010-01-28 21:38:24 +03:00
clean_exit ( ) ;
}
return ret ;
2004-01-07 03:43:52 +03:00
}