This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "includes.h"
#include "libsmbclient.h"
#define OFF_T_FORMAT_CAST long
#endif
-int columns = 0;
+static int columns = 0;
-static int _resume, _recursive, debuglevel;
+static int debuglevel, update;
static char *outputfile;
-time_t total_start_time = 0;
-off_t total_bytes = 0;
+static time_t total_start_time = 0;
+static off_t total_bytes = 0;
#define SMB_MAXPATHLEN MAXPATHLEN
/* Number of bytes to read at once */
#define SMB_DEFAULT_BLOCKSIZE 64000
-const char *username = NULL, *password = NULL, *workgroup = NULL;
-int nonprompt = 0, quiet = 0, dots = 0, keep_permissions = 0, verbose = 0, send_stdout = 0;
-int blocksize = SMB_DEFAULT_BLOCKSIZE;
+static const char *username = NULL, *password = NULL, *workgroup = NULL;
+static int nonprompt = 0, quiet = 0, dots = 0, keep_permissions = 0, verbose = 0, send_stdout = 0;
+static int blocksize = SMB_DEFAULT_BLOCKSIZE;
-int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile);
+static int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile);
-int get_num_cols(void)
+static int get_num_cols(void)
{
#ifdef TIOCGWINSZ
struct winsize ws;
#endif
}
-void change_columns(int sig)
+static void change_columns(int sig)
{
columns = get_num_cols();
}
-void human_readable(off_t s, char *buffer, int l)
+static void human_readable(off_t s, char *buffer, int l)
{
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 snprintf(buffer, l, OFF_T_FORMAT"b", (OFF_T_FORMAT_CAST)s);
}
-void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen)
+static void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen)
{
static char hasasked = 0;
char *wgtmp, *usertmp;
if(!nonprompt && !username) {
printf("Username for %s at %s [guest] ", shr, srv);
- fgets(tmp, sizeof(tmp), stdin);
+ if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
+ return;
+ }
if(tmp[strlen(tmp)-1] == '\n')tmp[strlen(tmp)-1] = '\0';
strncpy(un, tmp, unlen-1);
} else if(username) strncpy(un, username, unlen-1);
if(!nonprompt && !password) {
char *prompt, *pass;
- asprintf(&prompt, "Password for %s at %s: ", shr, srv);
+ if (asprintf(&prompt, "Password for %s at %s: ", shr, srv) == -1) {
+ return;
+ }
pass = getpass(prompt);
free(prompt);
strncpy(pw, pass, pwlen-1);
free(wgtmp); free(usertmp);
}
-int smb_download_dir(const char *base, const char *name, int resume)
+static int smb_download_dir(const char *base, const char *name, int resume)
{
char path[SMB_MAXPATHLEN];
int dirhandle;
while((dirent = smbc_readdir(dirhandle))) {
char *newname;
if(!strcmp(dirent->name, ".") || !strcmp(dirent->name, ".."))continue;
- asprintf(&newname, "%s/%s", tmpname, dirent->name);
+ if (asprintf(&newname, "%s/%s", tmpname, dirent->name) == -1) {
+ return 0;
+ }
switch(dirent->smbc_type) {
case SMBC_DIR:
smb_download_dir(base, newname, resume);
}
if(chmod(relname, remotestat.st_mode) < 0) {
- fprintf(stderr, "Unable to change mode of local dir %s to %o\n", relname, remotestat.st_mode);
+ fprintf(stderr, "Unable to change mode of local dir %s to %o\n", relname,
+ (unsigned int)remotestat.st_mode);
smbc_closedir(dirhandle);
return 0;
}
return 1;
}
-char *print_time(long t)
+static char *print_time(long t)
{
static char buffer[100];
int secs, mins, hours;
return buffer;
}
-void print_progress(const char *name, time_t start, time_t now, off_t start_pos, off_t pos, off_t total)
+static void print_progress(const char *name, time_t start, time_t now, off_t start_pos, off_t pos, off_t total)
{
double avg = 0.0;
long eta = -1;
human_readable(avg, havg, sizeof(havg));
len = asprintf(&status, "%s of %s (%.2f%%) at %s/s ETA: %s", hpos, htotal, prcnt, havg, print_time(eta));
+ if (len == -1) {
+ return;
+ }
if(columns) {
int required = strlen(name), available = columns - len - strlen("[] ");
- if(required > available) asprintf(&filename, "...%s", name + required - available + 3);
- else filename = SMB_STRNDUP(name, available);
+ if(required > available) {
+ if (asprintf(&filename, "...%s", name + required - available + 3) == -1) {
+ return;
+ }
+ } else {
+ filename = SMB_STRNDUP(name, available);
+ }
} else filename = SMB_STRDUP(name);
fprintf(stderr, "\r[%s] %s", filename, status);
free(filename); free(status);
}
-int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile) {
+static int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile) {
int remotehandle, localhandle;
time_t start_time = time(NULL);
const char *newpath;
if(newpath[0] == '/')newpath++;
- /* Open local file and, if necessary, resume */
- if(!send_stdout) {
+ /* Open local file according to the mode */
+ if(update) {
+ /* if it is up-to-date, skip */
+ if(stat(newpath, &localstat) == 0 &&
+ localstat.st_mtime >= remotestat.st_mtime) {
+ if(verbose)
+ printf("%s is up-to-date, skipping\n", newpath);
+ smbc_close(remotehandle);
+ return 0;
+ }
+ /* else open it for writing and truncate if it exists */
+ localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | O_TRUNC, 0775);
+ if(localhandle < 0) {
+ fprintf(stderr, "Can't open %s : %s\n", newpath,
+ strerror(errno));
+ smbc_close(remotehandle);
+ return 0;
+ }
+ /* no offset */
+ } 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));
return 0;
}
- fstat(localhandle, &localstat);
+ if (fstat(localhandle, &localstat) != 0) {
+ fprintf(stderr, "Can't fstat %s: %s\n", newpath, strerror(errno));
+ smbc_close(remotehandle);
+ close(localhandle);
+ return 0;
+ }
start_offset = localstat.st_size;
offset_check = 0;
}
- readbuf = SMB_MALLOC(blocksize);
+ readbuf = (char *)SMB_MALLOC(blocksize);
/* Now, download all bytes from offset_download to the end */
for(curpos = offset_download; curpos < remotestat.st_size; curpos+=blocksize) {
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, remotestat.st_mode);
+ fprintf(stderr, "Unable to change mode of local file %s to %o\n", path,
+ (unsigned int)remotestat.st_mode);
smbc_close(remotehandle);
close(localhandle);
return 0;
return 1;
}
-void clean_exit(void)
+static void clean_exit(void)
{
char bs[100];
human_readable(total_bytes, bs, sizeof(bs));
- if(!quiet)fprintf(stderr, "Downloaded %s in %lu seconds\n", bs, time(NULL) - total_start_time);
+ if(!quiet)fprintf(stderr, "Downloaded %s in %lu seconds\n", bs,
+ (unsigned long)(time(NULL) - total_start_time));
exit(0);
}
-void signal_quit(int v)
+static void signal_quit(int v)
{
clean_exit();
}
-int readrcfile(const char *name, const struct poptOption long_options[])
+static int readrcfile(const char *name, const struct poptOption long_options[])
{
FILE *fd = fopen(name, "r");
int lineno = 0, i;
int c = 0;
const char *file = NULL;
char *rcfile = NULL;
+ bool smb_encrypt = false;
+ int resume = 0, recursive = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
struct poptOption long_options[] = {
{"guest", 'a', POPT_ARG_NONE, NULL, 'a', "Work as user guest" },
- {"resume", 'r', POPT_ARG_NONE, &_resume, 0, "Automatically resume aborted files" },
- {"recursive", 'R', POPT_ARG_NONE, &_recursive, 0, "Recursively download files" },
+ {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
+ {"resume", 'r', POPT_ARG_NONE, &resume, 0, "Automatically resume aborted files" },
+ {"update", 'U', POPT_ARG_NONE, &update, 0, "Download only when remote file is newer than local file or local file is missing"},
+ {"recursive", 'R', POPT_ARG_NONE, &recursive, 0, "Recursively download files" },
{"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)" },
{"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"},
- {"rcfile", 'f', POPT_ARG_STRING, NULL, 0, "Use specified rc file"},
+ {"rcfile", 'f', POPT_ARG_STRING, NULL, 'f', "Use specified rc file"},
POPT_AUTOHELP
POPT_TABLEEND
};
poptContext pc;
+ load_case_tables();
+
/* only read rcfile if it exists */
- asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME"));
+ if (asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME")) == -1) {
+ return 1;
+ }
if(access(rcfile, F_OK) == 0)
readrcfile(rcfile, long_options);
free(rcfile);
case 'a':
username = ""; password = "";
break;
+ case 'e':
+ smb_encrypt = true;
+ break;
}
}
- if((send_stdout || outputfile) && _recursive) {
+ if((send_stdout || resume || outputfile) && update) {
+ fprintf(stderr, "The -o, -R or -O and -U options can not be used together.\n");
+ return 1;
+ }
+ if((send_stdout || outputfile) && recursive) {
fprintf(stderr, "The -o or -O and -R options can not be used together.\n");
return 1;
}
return 1;
}
+ if (smb_encrypt) {
+ SMBCCTX *smb_ctx = smbc_set_context(NULL);
+ smbc_option_set(smb_ctx,
+ CONST_DISCARD(char *, "smb_encrypt_level"),
+ "require");
+ }
+
columns = get_num_cols();
total_start_time = time(NULL);
while ( (file = poptGetArg(pc)) ) {
- if (!_recursive)
- return smb_download_file(file, "", _recursive, _resume, outputfile);
+ if (!recursive)
+ return smb_download_file(file, "", recursive, resume, outputfile);
else
- return smb_download_dir(file, "", _resume);
+ return smb_download_dir(file, "", resume);
}
clean_exit();
-
+ TALLOC_FREE(frame);
return 0;
}