Fix all warnings in source3 with gcc4.3.
[ira/wip.git] / source3 / utils / smbget.c
index ab6e368c7000c381541e15b75c6850355d230f67..c062134a55eb19eab5306bee9dac66338f34b2a0 100644 (file)
@@ -5,7 +5,7 @@
 
    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"
 
 #if _FILE_OFFSET_BITS==64
 #define OFF_T_FORMAT "%lld"
+#define OFF_T_FORMAT_CAST long long
 #else
 #define OFF_T_FORMAT "%ld"
+#define OFF_T_FORMAT_CAST long
 #endif
 
-int columns = 0;
+static int columns = 0;
 
-time_t total_start_time = 0;
-off_t total_bytes = 0;
+static int debuglevel, update;
+static char *outputfile;
+
+
+static time_t total_start_time = 0;
+static off_t total_bytes = 0;
 
 #define SMB_MAXPATHLEN MAXPATHLEN
 
@@ -40,18 +45,17 @@ off_t total_bytes = 0;
 /* 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;
-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;
        if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
-               perror("ioctl");
                return 0;
        }
        return ws.ws_col;
@@ -63,20 +67,20 @@ int get_num_cols(void)
 #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 if(s > 1024) snprintf(buffer, l, "%.2fkb", 1.0 * s / 1024);
-       else snprintf(buffer, l, OFF_T_FORMAT"b", s);
+       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;
@@ -87,14 +91,18 @@ void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *
 
        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);
@@ -102,13 +110,13 @@ void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *
 
        if(workgroup)strncpy(wg, workgroup, wglen-1);
 
-       wgtmp = strndup(wg, wglen); 
-       usertmp = strndup(un, unlen);
+       wgtmp = SMB_STRNDUP(wg, wglen); 
+       usertmp = SMB_STRNDUP(un, unlen);
        if(!quiet)printf("Using workgroup %s, %s%s\n", wgtmp, *usertmp?"user ":"guest user", usertmp);
        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;
@@ -129,12 +137,14 @@ int smb_download_dir(const char *base, const char *name, int resume)
        while(*relname == '/')relname++;
        mkdir(relname, 0755);
        
-       tmpname = strdup(name);
+       tmpname = SMB_STRDUP(name);
 
        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);
@@ -194,7 +204,7 @@ int smb_download_dir(const char *base, const char *name, int resume)
        return 1;
 }
 
-char *print_time(long t)
+static char *print_time(long t)
 {
        static char buffer[100];
        int secs, mins, hours;
@@ -210,7 +220,7 @@ char *print_time(long t)
        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; 
@@ -227,19 +237,27 @@ void print_progress(const char *name, time_t start, time_t now, off_t start_pos,
        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 = strndup(name, available);
-       } else filename = strdup(name);
+               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;
@@ -299,85 +317,122 @@ int smb_download_file(const char *base, const char *name, int recursive, int res
 
        if(newpath[0] == '/')newpath++;
        
-       /* Open local file and, if necessary, resume */
-       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));
-               smbc_close(remotehandle);
-               return 0;
-       }
-       
-       fstat(localhandle, &localstat);
-
-       start_offset = localstat.st_size;
-
-       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);
-               smbc_close(remotehandle);
-               close(localhandle);
-               return 1;
-       }
-
-       if(localstat.st_size > RESUME_CHECK_OFFSET && remotestat.st_size > RESUME_CHECK_OFFSET) {
-               offset_download = localstat.st_size - RESUME_DOWNLOAD_OFFSET;
-               offset_check = localstat.st_size - RESUME_CHECK_OFFSET;
-               if(verbose)printf("Trying to start resume of %s at "OFF_T_FORMAT"\n"
-                          "At the moment "OFF_T_FORMAT" of "OFF_T_FORMAT" bytes have been retrieved\n", newpath, offset_check, 
-                          localstat.st_size, remotestat.st_size);
-       }
-
-       if(offset_check) { 
-               off_t off1, off2;
-               /* First, check all bytes from offset_check to offset_download */
-               off1 = lseek(localhandle, offset_check, SEEK_SET);
-               if(off1 < 0) {
-                       fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in local file %s\n", offset_check, newpath);
-                       smbc_close(remotehandle); close(localhandle);
+       /* 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;
                }
-
-               off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET); 
-               if(off2 < 0) {
-                       fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in remote file %s\n", offset_check, newpath);
-                       smbc_close(remotehandle); close(localhandle);
+               /* 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;
                }
-
-               if(off1 != off2) {
-                       fprintf(stderr, "Offset in local and remote files is different (local: "OFF_T_FORMAT", remote: "OFF_T_FORMAT")\n", off1, off2);
+               /* 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));
+                       smbc_close(remotehandle);
                        return 0;
                }
-
-               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);
+       
+               if (fstat(localhandle, &localstat) != 0) {
+                       fprintf(stderr, "Can't fstat %s: %s\n", newpath, strerror(errno));
+                       smbc_close(remotehandle);
+                       close(localhandle);
                        return 0;
                }
 
-               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);
-                       return 0;
+               start_offset = localstat.st_size;
+
+               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);
+                       smbc_close(remotehandle);
+                       close(localhandle);
+                       return 1;
                }
 
-               if(memcmp(checkbuf[0], checkbuf[1], RESUME_CHECK_SIZE) == 0) {
-                       if(verbose)printf("Current local and remote file appear to be the same. Starting download from offset "OFF_T_FORMAT"\n", offset_download);
-               } else {
-                       fprintf(stderr, "Local and remote file appear to be different, not doing resume for %s\n", path);
-                       smbc_close(remotehandle); close(localhandle);
-                       return 0;
+               if(localstat.st_size > RESUME_CHECK_OFFSET && remotestat.st_size > RESUME_CHECK_OFFSET) {
+                       offset_download = localstat.st_size - RESUME_DOWNLOAD_OFFSET;
+                       offset_check = localstat.st_size - RESUME_CHECK_OFFSET;
+                       if(verbose)printf("Trying to start resume of %s at "OFF_T_FORMAT"\n"
+                                  "At the moment "OFF_T_FORMAT" of "OFF_T_FORMAT" bytes have been retrieved\n",
+                               newpath, (OFF_T_FORMAT_CAST)offset_check, 
+                               (OFF_T_FORMAT_CAST)localstat.st_size,
+                               (OFF_T_FORMAT_CAST)remotestat.st_size);
+               }
+
+               if(offset_check) { 
+                       off_t off1, off2;
+                       /* First, check all bytes from offset_check to offset_download */
+                       off1 = lseek(localhandle, offset_check, SEEK_SET);
+                       if(off1 < 0) {
+                               fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in local file %s\n",
+                                       (OFF_T_FORMAT_CAST)offset_check, newpath);
+                               smbc_close(remotehandle); close(localhandle);
+                               return 0;
+                       }
+
+                       off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET); 
+                       if(off2 < 0) {
+                               fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in remote file %s\n",
+                                       (OFF_T_FORMAT_CAST)offset_check, newpath);
+                               smbc_close(remotehandle); close(localhandle);
+                               return 0;
+                       }
+
+                       if(off1 != off2) {
+                               fprintf(stderr, "Offset in local and remote files is different (local: "OFF_T_FORMAT", remote: "OFF_T_FORMAT")\n",
+                                       (OFF_T_FORMAT_CAST)off1,
+                                       (OFF_T_FORMAT_CAST)off2);
+                               return 0;
+                       }
+
+                       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);
+                               return 0;
+                       }
+
+                       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);
+                               return 0;
+                       }
+
+                       if(memcmp(checkbuf[0], checkbuf[1], RESUME_CHECK_SIZE) == 0) {
+                               if(verbose)printf("Current local and remote file appear to be the same. Starting download from offset "OFF_T_FORMAT"\n", (OFF_T_FORMAT_CAST)offset_download);
+                       } else {
+                               fprintf(stderr, "Local and remote file appear to be different, not doing resume for %s\n", path);
+                               smbc_close(remotehandle); close(localhandle);
+                               return 0;
+                       }
                }
+       } else {
+               localhandle = STDOUT_FILENO;
+               start_offset = 0;
+               offset_download = 0;
+               offset_check = 0;
        }
 
-       readbuf = 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) {
                ssize_t bytesread = smbc_read(remotehandle, readbuf, blocksize);
                if(bytesread < 0) {
-                       fprintf(stderr, "Can't read %d bytes at offset "OFF_T_FORMAT", file %s\n", blocksize, curpos, path);
-                       smbc_close(remotehandle); close(localhandle);
+                       fprintf(stderr, "Can't read %u bytes at offset "OFF_T_FORMAT", file %s\n", (unsigned int)blocksize, (OFF_T_FORMAT_CAST)curpos, path);
+                       smbc_close(remotehandle);
+                       if (localhandle != STDOUT_FILENO) close(localhandle);
                        free(readbuf);
                        return 0;
                }
@@ -385,9 +440,10 @@ int smb_download_file(const char *base, const char *name, int recursive, int res
                total_bytes += bytesread;
 
                if(write(localhandle, readbuf, bytesread) < 0) {
-                       fprintf(stderr, "Can't write %d bytes to local file %s at offset "OFF_T_FORMAT"\n", bytesread, path, curpos);
+                       fprintf(stderr, "Can't write %u bytes to local file %s at offset "OFF_T_FORMAT"\n", (unsigned int)bytesread, path, (OFF_T_FORMAT_CAST)curpos);
                        free(readbuf);
-                       smbc_close(remotehandle); close(localhandle);
+                       smbc_close(remotehandle);
+                       if (localhandle != STDOUT_FILENO) close(localhandle);
                        return 0;
                }
 
@@ -413,7 +469,7 @@ int smb_download_file(const char *base, const char *name, int recursive, int res
                fputc('\n', stderr);
        }
 
-       if(keep_permissions) {
+       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);
                        smbc_close(remotehandle);
@@ -421,12 +477,13 @@ int smb_download_file(const char *base, const char *name, int recursive, int res
                        return 0;
                }
        }
+
        smbc_close(remotehandle);
-       close(localhandle);
+       if (localhandle != STDOUT_FILENO) close(localhandle);
        return 1;
 }
 
-void clean_exit(void)
+static void clean_exit(void)
 {
        char bs[100];
        human_readable(total_bytes, bs, sizeof(bs));
@@ -434,12 +491,12 @@ void clean_exit(void)
        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;
@@ -478,7 +535,7 @@ int readrcfile(const char *name, const struct poptOption long_options[])
                                break;
                        case POPT_ARG_STRING:
                                stringdata = (char **)long_options[i].arg;
-                               *stringdata = strdup(val);
+                               *stringdata = SMB_STRDUP(val);
                                break;
                        default:
                                fprintf(stderr, "Invalid variable %s at line %d in %s\n", var, lineno, name);
@@ -498,15 +555,17 @@ int readrcfile(const char *name, const struct poptOption long_options[])
 
 int main(int argc, const char **argv)
 {
-       int resume = 0, recursive = 0;
        int c = 0;
-       int debuglevel = 0;
        const char *file = NULL;
        char *rcfile = NULL;
-       char *outputfile = 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" },        
+               {"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" },
@@ -514,6 +573,7 @@ int main(int argc, const char **argv)
                {"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" },
+               {"stdout", 'O', POPT_ARG_NONE, &send_stdout, 'O', "Write data to stdout" },
                {"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" },
@@ -525,9 +585,14 @@ int main(int argc, const char **argv)
        };
        poptContext pc;
 
+       load_case_tables();
+
        /* only read rcfile if it exists */
-       asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME"));
-       if(access(rcfile, F_OK) == 0) readrcfile(rcfile, long_options);
+       if (asprintf(&rcfile, "%s/.smbgetrc", getenv("HOME")) == -1) {
+               return 1;
+       }
+       if(access(rcfile, F_OK) == 0) 
+               readrcfile(rcfile, long_options);
        free(rcfile);
 
 #ifdef SIGWINCH
@@ -546,11 +611,23 @@ int main(int argc, const char **argv)
                case 'a':
                        username = ""; password = "";
                        break;
+               case 'e':
+                       smb_encrypt = true;
+                       break;
                }
        }
 
-       if(outputfile && recursive) {
-               fprintf(stderr, "The -o and -R options can not be used together.\n");
+       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;
+       }
+
+       if(outputfile && send_stdout) {
+               fprintf(stderr, "The -o and -O options cannot be used together.\n");
                return 1;
        }
 
@@ -559,16 +636,25 @@ int main(int argc, const char **argv)
                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);
-               else return smb_download_dir(file, "", resume);
+       while ( (file = poptGetArg(pc)) ) {
+               if (!recursive) 
+                       return smb_download_file(file, "", recursive, resume, outputfile);
+               else 
+                       return smb_download_dir(file, "", resume);
        }
 
        clean_exit();
-
+       TALLOC_FREE(frame);
        return 0;
 }