syncing up with HEAD. Seems to be a lot of differences creeping in
[vlendec/samba-autobuild/.git] / source3 / client / client.c
index dbd5ab8d52c0965c9014d8da5dbbcc3e02735221..f25ed1623b0d96c865620a5ffecf90b9f2f86856 100644 (file)
@@ -1,9 +1,8 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0.
+   Unix SMB/CIFS implementation.
    SMB client
    Copyright (C) Andrew Tridgell 1994-1998
-   Copyright (C) Simo Sorce 2001
+   Copyright (C) Simo Sorce 2001-2002
    
    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
@@ -23,7 +22,7 @@
 #define NO_SYSLOG
 
 #include "includes.h"
-
+#include "../client/client_proto.h"
 #ifndef REGISTER
 #define REGISTER 0
 #endif
@@ -35,7 +34,7 @@ extern BOOL in_client;
 extern BOOL AllowDebugChange;
 static int port = 0;
 pstring cur_dir = "\\";
-pstring cd_path = "";
+static pstring cd_path = "";
 static pstring service;
 static pstring desthost;
 extern pstring global_myname;
@@ -62,9 +61,9 @@ static int cmd_help(void);
 #define FID_UNUSED (0xFFFF)
 
 time_t newer_than = 0;
-int archive_level = 0;
+static int archive_level = 0;
 
-BOOL translation = False;
+static BOOL translation = False;
 
 static BOOL have_ip;
 
@@ -75,36 +74,39 @@ extern BOOL tar_reset;
 /* clitar bits end */
  
 
-mode_t myumask = 0755;
+static mode_t myumask = 0755;
 
-BOOL prompt = True;
+static BOOL prompt = True;
 
-int printmode = 1;
+static int printmode = 1;
 
 static BOOL recurse = False;
 BOOL lowercase = False;
 
-struct in_addr dest_ip;
+static struct in_addr dest_ip;
 
 #define SEPARATORS " \t\n\r"
 
-BOOL abort_mget = True;
+static BOOL abort_mget = True;
 
-pstring fileselection = "";
+static pstring fileselection = "";
 
 extern file_info def_finfo;
 
 /* timing globals */
 int get_total_size = 0;
 int get_total_time_ms = 0;
-int put_total_size = 0;
-int put_total_time_ms = 0;
+static int put_total_size = 0;
+static int put_total_time_ms = 0;
 
 /* totals globals */
 static double dir_total;
 
 #define USENMB
 
+/* some forward declarations */
+static struct cli_state *do_connect(const char *server, const char *share);
+
 /****************************************************************************
 write to a local file with CR/LF->LF translation if appropriate. return the 
 number taken from the buffer. This may not equal the number written.
@@ -305,7 +307,7 @@ static BOOL do_this_one(file_info *finfo)
 
        if (*fileselection && 
            !mask_match(finfo->name,fileselection,False)) {
-               DEBUG(3,("match_match %s failed\n", finfo->name));
+               DEBUG(3,("mask_match %s failed\n", finfo->name));
                return False;
        }
 
@@ -647,15 +649,16 @@ static int cmd_du(void)
 /****************************************************************************
   get a file from rname to lname
   ****************************************************************************/
-static int do_get(char *rname,char *lname)
+static int do_get(char *rname, char *lname, BOOL reget)
 {  
-       int handle=0,fnum;
+       int handle = 0, fnum;
        BOOL newhandle = False;
        char *data;
        struct timeval tp_start;
        int read_size = io_bufsize;
        uint16 attr;
        size_t size;
+       off_t start = 0;
        off_t nread = 0;
        int rc = 0;
 
@@ -675,7 +678,18 @@ static int do_get(char *rname,char *lname)
        if(!strcmp(lname,"-")) {
                handle = fileno(stdout);
        } else {
-               handle = sys_open(lname,O_WRONLY|O_CREAT|O_TRUNC,0644);
+               if (reget) {
+                       handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
+                       if (handle >= 0) {
+                               start = sys_lseek(handle, 0, SEEK_END);
+                               if (start == -1) {
+                                       d_printf("Error seeking local file\n");
+                                       return 1;
+                               }
+                       }
+               } else {
+                       handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+               }
                newhandle = True;
        }
        if (handle < 0) {
@@ -693,7 +707,7 @@ static int do_get(char *rname,char *lname)
        }
 
        DEBUG(2,("getting file %s of size %.0f as %s ", 
-                lname, (double)size, lname));
+                rname, (double)size, lname));
 
        if(!(data = (char *)malloc(read_size))) { 
                d_printf("malloc fail for size %d\n", read_size);
@@ -702,7 +716,7 @@ static int do_get(char *rname,char *lname)
        }
 
        while (1) {
-               int n = cli_read(cli, fnum, data, nread, read_size);
+               int n = cli_read(cli, fnum, data, nread + start, read_size);
 
                if (n <= 0) break;
  
@@ -715,7 +729,7 @@ static int do_get(char *rname,char *lname)
                nread += n;
        }
 
-       if (nread < size) {
+       if (nread + start < size) {
                DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
                            rname, (long)nread));
 
@@ -780,7 +794,7 @@ static int cmd_get(void)
        
        next_token_nr(NULL,lname,NULL,sizeof(lname));
        
-       return do_get(rname, lname);
+       return do_get(rname, lname, False);
 }
 
 
@@ -814,7 +828,7 @@ static void do_mget(file_info *finfo)
        if (!(finfo->mode & aDIR)) {
                pstrcpy(rname,cur_dir);
                pstrcat(rname,finfo->name);
-               do_get(rname,finfo->name);
+               do_get(rname, finfo->name, False);
                return;
        }
 
@@ -878,7 +892,7 @@ static int cmd_more(void)
        }
        dos_clean_name(rname);
 
-       rc = do_get(rname,lname);
+       rc = do_get(rname, lname, False);
 
        pager=getenv("PAGER");
 
@@ -1044,19 +1058,31 @@ static int cmd_altname(void)
 /****************************************************************************
   put a single file
   ****************************************************************************/
-static int do_put(char *rname,char *lname)
+static int do_put(char *rname, char *lname, BOOL reput)
 {
        int fnum;
        XFILE *f;
-       int nread=0;
-       char *buf=NULL;
-       int maxwrite=io_bufsize;
+       int start = 0;
+       int nread = 0;
+       char *buf = NULL;
+       int maxwrite = io_bufsize;
        int rc = 0;
        
        struct timeval tp_start;
        GetTimeOfDay(&tp_start);
 
-       fnum = cli_open(cli, rname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+       if (reput) {
+               fnum = cli_open(cli, rname, O_RDWR|O_CREAT, DENY_NONE);
+               if (fnum >= 0) {
+                       if (!cli_qfileinfo(cli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
+                           !cli_getattrE(cli, fnum, NULL, &start, NULL, NULL, NULL)) {
+                               d_printf("getattrib: %s\n",cli_errstr(cli));
+                               return 1;
+                       }
+               }
+       } else {
+               fnum = cli_open(cli, rname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+       }
   
        if (fnum == -1) {
                d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
@@ -1064,12 +1090,21 @@ static int do_put(char *rname,char *lname)
        }
 
        /* allow files to be piped into smbclient
-          jdblair 24.jun.98 */
+          jdblair 24.jun.98
+
+          Note that in this case this function will exit(0) rather
+          than returning. */
        if (!strcmp(lname, "-")) {
                f = x_stdin;
                /* size of file is not known */
        } else {
                f = x_fopen(lname,O_RDONLY, 0);
+               if (f && reput) {
+                       if (x_tseek(f, start, SEEK_SET) == -1) {
+                               d_printf("Error seeking local file\n");
+                               return 1;
+                       }
+               }
        }
 
        if (!f) {
@@ -1099,7 +1134,7 @@ static int do_put(char *rname,char *lname)
                        break;
                }
 
-               ret = cli_write(cli, fnum, 0, buf, nread, n);
+               ret = cli_write(cli, fnum, 0, buf, nread + start, n);
 
                if (n != ret) {
                        d_printf("Error writing file: %s\n", cli_errstr(cli));
@@ -1118,7 +1153,10 @@ static int do_put(char *rname,char *lname)
        }
 
        
-       x_fclose(f);
+       if (f != x_stdin) {
+               x_fclose(f);
+       }
+
        SAFE_FREE(buf);
 
        {
@@ -1184,7 +1222,7 @@ static int cmd_put(void)
                }
        }
 
-       return do_put(rname,lname);
+       return do_put(rname, lname, False);
 }
 
 /*************************************
@@ -1343,7 +1381,7 @@ static int cmd_mput(void)
                                /* if (!recurse) continue; */
                                
                                SAFE_FREE(quest);
-                               asprintf(&quest, "Put directory %s? ", lname);
+                               if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
                                if (prompt && !yesno(quest)) { /* No */
                                        /* Skip the directory */
                                        lname[strlen(lname)-1] = '/';
@@ -1351,7 +1389,7 @@ static int cmd_mput(void)
                                                break;              
                                } else { /* Yes */
                                        SAFE_FREE(rname);
-                                       asprintf(&rname, "%s%s", cur_dir, lname);
+                                       if(asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
                                        dos_format(rname);
                                        if (!cli_chkpath(cli, rname) && 
                                            !do_mkdir(rname)) {
@@ -1365,18 +1403,18 @@ static int cmd_mput(void)
                                continue;
                        } else {
                                SAFE_FREE(quest);
-                               asprintf(&quest,"Put file %s? ", lname);
+                               if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
                                if (prompt && !yesno(quest)) /* No */
                                        continue;
                                
                                /* Yes */
                                SAFE_FREE(rname);
-                               asprintf(&rname, "%s%s", cur_dir, lname);
+                               if (asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
                        }
 
                        dos_format(rname);
 
-                       do_put(rname, lname);
+                       do_put(rname, lname, False);
                }
                free_file_list(file_list);
                SAFE_FREE(quest);
@@ -1448,7 +1486,7 @@ static int cmd_print(void)
                slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)sys_getpid());
        }
 
-       return do_put(rname, lname);
+       return do_put(rname, lname, False);
 }
 
 
@@ -1858,8 +1896,8 @@ static int cmd_printmode(void)
 }
 
 /****************************************************************************
-do the lcd command
-****************************************************************************/
+ do the lcd command
+ ****************************************************************************/
 static int cmd_lcd(void)
 {
        fstring buf;
@@ -1873,8 +1911,70 @@ static int cmd_lcd(void)
 }
 
 /****************************************************************************
-list a share name
-****************************************************************************/
+ get a file restarting at end of local file
+ ****************************************************************************/
+static int cmd_reget(void)
+{
+       pstring local_name;
+       pstring remote_name;
+       char *p;
+
+       pstrcpy(remote_name, cur_dir);
+       pstrcat(remote_name, "\\");
+       
+       p = remote_name + strlen(remote_name);
+       
+       if (!next_token_nr(NULL, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
+               d_printf("reget <filename>\n");
+               return 1;
+       }
+       pstrcpy(local_name, p);
+       dos_clean_name(remote_name);
+       
+       next_token_nr(NULL, local_name, NULL, sizeof(local_name));
+       
+       return do_get(remote_name, local_name, True);
+}
+
+/****************************************************************************
+ put a file restarting at end of local file
+ ****************************************************************************/
+static int cmd_reput(void)
+{
+       pstring local_name;
+       pstring remote_name;
+       fstring buf;
+       char *p = buf;
+       SMB_STRUCT_STAT st;
+       
+       pstrcpy(remote_name, cur_dir);
+       pstrcat(remote_name, "\\");
+  
+       if (!next_token_nr(NULL, p, NULL, sizeof(buf))) {
+               d_printf("reput <filename>\n");
+               return 1;
+       }
+       pstrcpy(local_name, p);
+  
+       if (!file_exist(local_name, &st)) {
+               d_printf("%s does not exist\n", local_name);
+               return 1;
+       }
+
+       if (next_token_nr(NULL, p, NULL, sizeof(buf)))
+               pstrcat(remote_name, p);
+       else
+               pstrcat(remote_name, local_name);
+       
+       dos_clean_name(remote_name);
+
+       return do_put(remote_name, local_name, True);
+}
+
+
+/****************************************************************************
+ list a share name
+ ****************************************************************************/
 static void browse_fn(const char *name, uint32 m, 
                       const char *comment, void *state)
 {
@@ -1956,7 +2056,7 @@ static BOOL list_servers(char *wk_grp)
  *       field is NULL, and NULL in that field is used in process_tok()
  *       (below) to indicate the end of the list.  crh
  */
-struct
+static struct
 {
   char *name;
   int (*fn)(void);
@@ -1965,7 +2065,6 @@ struct
 } commands[] = 
 {
   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
-  {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
   {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
@@ -2002,7 +2101,9 @@ struct
   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
+  {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
@@ -2010,6 +2111,9 @@ struct
   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
+  
+  /* Yes, this must be here, see crh's comment above. */
+  {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
   {"",NULL,NULL,{COMPL_NONE,COMPL_NONE}}
 };
 
@@ -2076,6 +2180,14 @@ static int process_command_string(char *cmd)
        char *ptr;
        int rc = 0;
 
+       /* establish the connection if not already */
+       
+       if (!cli) {
+               cli = do_connect(desthost, service);
+               if (!cli)
+                       return 0;
+       }
+       
        while (cmd[0] != '\0')    {
                char *p;
                fstring tok;
@@ -2165,7 +2277,7 @@ static void readline_callback(void)
 
        timeout.tv_sec = 0;
        timeout.tv_usec = 0;
-       sys_select_intr(cli->fd+1,&fds,&timeout);
+       sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
                
        /* We deliberately use receive_smb instead of
           client_receive_smb as we want to receive
@@ -2226,7 +2338,7 @@ static void process_stdin(void)
 /***************************************************** 
 return a connection to a server
 *******************************************************/
-struct cli_state *do_connect(const char *server, const char *share)
+static struct cli_state *do_connect(const char *server, const char *share)
 {
        struct cli_state *c;
        struct nmb_name called, calling;
@@ -2324,9 +2436,24 @@ struct cli_state *do_connect(const char *server, const char *share)
 
        if (!cli_send_tconX(c, sharename, "?????",
                            password, strlen(password)+1)) {
-               d_printf("tree connect failed: %s\n", cli_errstr(c));
-               cli_shutdown(c);
-               return NULL;
+               pstring full_share;
+
+               /*
+                * Some servers require \\server\share for the share
+                * while others are happy with share as we gave above
+                * Lets see if we give it the long form if it works
+                */
+               pstrcpy(full_share, "\\\\");
+               pstrcat(full_share, server);
+               pstrcat(full_share, "\\");
+               pstrcat(full_share, sharename);
+               if (!cli_send_tconX(c, full_share, "?????", password,
+                                       strlen(password) + 1)) {
+
+                       d_printf("tree connect failed: %s\n", cli_errstr(c));
+                       cli_shutdown(c);
+                       return NULL;
+               }
        }
 
        DEBUG(4,(" tconx ok\n"));
@@ -2480,9 +2607,13 @@ handle a tar operation
 static int do_tar_op(char *base_directory)
 {
        int ret;
-       cli = do_connect(desthost, service);
-       if (!cli)
-               return 1;
+
+       /* do we already have a connection? */
+       if (!cli) {
+               cli = do_connect(desthost, service);    
+               if (!cli)
+                       return 1;
+       }
 
        recurse=True;
 
@@ -2502,16 +2633,21 @@ static int do_message_op(void)
 {
        struct in_addr ip;
        struct nmb_name called, calling;
-
-        zero_ip(&ip);
+       fstring server_name;
+       char name_type_hex[10];
 
        make_nmb_name(&calling, global_myname, 0x0);
        make_nmb_name(&called , desthost, name_type);
 
+       safe_strcpy(server_name, desthost, sizeof(server_name));
+       snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
+       safe_strcat(server_name, name_type_hex, sizeof(server_name));
+
         zero_ip(&ip);
        if (have_ip) ip = dest_ip;
 
-       if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, port) != port) || !cli_connect(cli, desthost, &ip)) {
+       if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, port) != port) ||
+           !cli_connect(cli, server_name, &ip)) {
                d_printf("Connection to %s failed\n", desthost);
                return 1;
        }
@@ -2529,6 +2665,27 @@ static int do_message_op(void)
 }
 
 
+/**
+ * Process "-L hostname" option.
+ *
+ * We don't actually do anything yet -- we just stash the name in a
+ * global variable and do the query when all options have been read.
+ **/
+static void remember_query_host(const char *arg,
+                               pstring query_host)
+{
+       char *slash;
+       
+       while (*arg == '\\' || *arg == '/')
+               arg++;
+       pstrcpy(query_host, arg);
+       if ((slash = strchr(query_host, '/'))
+           || (slash = strchr(query_host, '\\'))) {
+               *slash = 0;
+       }
+}
+
+
 /****************************************************************************
   main program
 ****************************************************************************/
@@ -2598,10 +2755,6 @@ static int do_message_op(void)
        }
        DEBUGLEVEL = old_debug;
        
-#ifdef WITH_SSL
-       sslutil_init(0);
-#endif
-
        pstrcpy(workgroup,lp_workgroup());
 
        load_interfaces();
@@ -2620,7 +2773,6 @@ static int do_message_op(void)
                        got_pass = True;
                        memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
                }
-               strupper(username);
        }
 
        /* modification to support PASSWD environmental var
@@ -2637,7 +2789,6 @@ static int do_message_op(void)
 
        if (*username == 0 && getenv("LOGNAME")) {
                pstrcpy(username,getenv("LOGNAME"));
-               strupper(username);
        }
 
        if (*username == 0) {
@@ -2809,10 +2960,7 @@ static int do_message_op(void)
                        break;
 
                case 'L':
-                       p = optarg;
-                       while(*p == '\\' || *p == '/')
-                               p++;
-                       pstrcpy(query_host,p);
+                       remember_query_host(optarg, query_host);
                        break;
                case 't':
                        pstrcpy(term_code, optarg);