Replace cli_rpc_pipe_close by a talloc destructor on rpc_pipe_struct
[kai/samba.git] / source / client / client.c
index 1c85a6dafc273e3cefc0ad4713d38faac8f4cadd..b4e1985a837b3a14eb1fed04106ff8469c4102d0 100644 (file)
@@ -33,7 +33,6 @@ extern int do_smb_browse(void); /* mDNS browsing */
 extern bool AllowDebugChange;
 extern bool override_logfile;
 extern char tar_type;
-extern bool in_client;
 
 static int port = 0;
 static char *service;
@@ -43,7 +42,7 @@ static bool grepable = false;
 static char *cmdstr = NULL;
 static const char *cmd_ptr = NULL;
 
-static int io_bufsize = 64512;
+static int io_bufsize = 524288;
 
 static int name_type = 0x20;
 extern int max_protocol;
@@ -308,6 +307,17 @@ static int cmd_pwd(void)
        return 0;
 }
 
+/****************************************************************************
+ Ensure name has correct directory separators.
+****************************************************************************/
+
+static void normalize_name(char *newdir)
+{
+       if (!(cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
+               string_replace(newdir,'/','\\');
+       }
+}
+
 /****************************************************************************
  Change directory - inner section.
 ****************************************************************************/
@@ -329,7 +339,8 @@ static int do_cd(const char *new_dir)
                TALLOC_FREE(ctx);
                return 1;
        }
-       string_replace(newdir,'/','\\');
+
+       normalize_name(newdir);
 
        /* Save the current directory in case the new directory is invalid */
 
@@ -349,17 +360,16 @@ static int do_cd(const char *new_dir)
                if (!new_cd) {
                        goto out;
                }
-               if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
-                       new_cd = talloc_asprintf_append(new_cd, CLI_DIRSEP_STR);
-                       if (!new_cd) {
-                               goto out;
-                       }
-               }
-               client_set_cur_dir(new_cd);
        }
-       if (!new_cd) {
-               goto out;
+
+       /* Ensure cur_dir ends in a DIRSEP */
+       if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
+               new_cd = talloc_asprintf_append(new_cd, CLI_DIRSEP_STR);
+               if (!new_cd) {
+                       goto out;
+               }
        }
+       client_set_cur_dir(new_cd);
 
        new_cd = clean_name(ctx, new_cd);
        client_set_cur_dir(new_cd);
@@ -851,26 +861,15 @@ static int cmd_dir(void)
        int rc = 1;
 
        dir_total = 0;
-       if (strcmp(client_get_cur_dir(), CLI_DIRSEP_STR) != 0) {
-               mask = talloc_strdup(ctx, client_get_cur_dir());
-               if (!mask) {
-                       return 1;
-               }
-               if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
-                       mask = talloc_asprintf_append(mask, CLI_DIRSEP_STR);
-               }
-       } else {
-               mask = talloc_strdup(ctx, CLI_DIRSEP_STR);
-       }
-
+       mask = talloc_strdup(ctx, client_get_cur_dir());
        if (!mask) {
                return 1;
        }
 
        if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
-               string_replace(buf,'/','\\');
+               normalize_name(buf);
                if (*buf == CLI_DIRSEP_CHAR) {
-                       mask = talloc_strdup(ctx, buf + 1);
+                       mask = talloc_strdup(ctx, buf);
                } else {
                        mask = talloc_asprintf_append(mask, buf);
                }
@@ -920,7 +919,7 @@ static int cmd_du(void)
        }
 
        if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
-               string_replace(buf,'/','\\');
+               normalize_name(buf);
                if (*buf == CLI_DIRSEP_CHAR) {
                        mask = talloc_strdup(ctx, buf);
                } else {
@@ -964,22 +963,30 @@ static int cmd_echo(void)
  Get a file from rname to lname
 ****************************************************************************/
 
+static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
+{
+       int *pfd = (int *)priv;
+       if (writefile(*pfd, buf, n) == -1) {
+               return map_nt_error_from_unix(errno);
+       }
+       return NT_STATUS_OK;
+}
+
 static int do_get(const char *rname, const char *lname_in, bool reget)
 {
        TALLOC_CTX *ctx = talloc_tos();
        int handle = 0, fnum;
        bool newhandle = false;
-       char *data = NULL;
        struct timeval tp_start;
-       int read_size = io_bufsize;
        uint16 attr;
        SMB_OFF_T size;
        off_t start = 0;
-       off_t nread = 0;
+       SMB_OFF_T nread = 0;
        int rc = 0;
        struct cli_state *targetcli = NULL;
        char *targetname = NULL;
        char *lname = NULL;
+       NTSTATUS status;
 
        lname = talloc_strdup(ctx, lname_in);
        if (!lname) {
@@ -1038,36 +1045,15 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
        DEBUG(1,("getting file %s of size %.0f as %s ",
                 rname, (double)size, lname));
 
-       if(!(data = (char *)SMB_MALLOC(read_size))) {
-               d_printf("malloc fail for size %d\n", read_size);
+       status = cli_pull(targetcli, fnum, start, size, io_bufsize,
+                         writefile_sink, (void *)&handle, &nread);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "parallel_read returned %s\n",
+                         nt_errstr(status));
                cli_close(targetcli, fnum);
                return 1;
        }
 
-       while (1) {
-               int n = cli_read(targetcli, fnum, data, nread + start, read_size);
-
-               if (n <= 0)
-                       break;
-
-               if (writefile(handle,data, n) != n) {
-                       d_printf("Error writing local file\n");
-                       rc = 1;
-                       break;
-               }
-
-               nread += n;
-       }
-
-       if (nread + start < size) {
-               DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
-                           rname, (long)nread));
-
-               rc = 1;
-       }
-
-       SAFE_FREE(data);
-
        if (!cli_close(targetcli, fnum)) {
                d_printf("Error %s closing remote file\n",cli_errstr(cli));
                rc = 1;
@@ -1112,10 +1098,7 @@ static int cmd_get(void)
        char *rname = NULL;
        char *fname = NULL;
 
-       rname = talloc_asprintf(ctx,
-                       "%s%s",
-                       client_get_cur_dir(),
-                       CLI_DIRSEP_STR);
+       rname = talloc_strdup(ctx, client_get_cur_dir());
        if (!rname) {
                return 1;
        }
@@ -1262,10 +1245,7 @@ static int cmd_more(void)
        int fd;
        int rc = 0;
 
-       rname = talloc_asprintf(ctx,
-                       "%s%s",
-                       client_get_cur_dir(),
-                       CLI_DIRSEP_STR);
+       rname = talloc_strdup(ctx, client_get_cur_dir());
        if (!rname) {
                return 1;
        }
@@ -1334,15 +1314,6 @@ static int cmd_mget(void)
                if (!mget_mask) {
                        return 1;
                }
-               if ((mget_mask[0] != '\0') &&
-                               (mget_mask[strlen(mget_mask)-1]!=CLI_DIRSEP_CHAR)) {
-                       mget_mask = talloc_asprintf_append(mget_mask,
-                                                       CLI_DIRSEP_STR);
-                       if (!mget_mask) {
-                               return 1;
-                       }
-               }
-
                if (*buf == CLI_DIRSEP_CHAR) {
                        mget_mask = talloc_strdup(ctx, buf);
                } else {
@@ -1356,18 +1327,9 @@ static int cmd_mget(void)
        }
 
        if (!*mget_mask) {
-               mget_mask = talloc_strdup(ctx, client_get_cur_dir());
-               if (!mget_mask) {
-                       return 1;
-               }
-               if(mget_mask[strlen(mget_mask)-1]!=CLI_DIRSEP_CHAR) {
-                       mget_mask = talloc_asprintf_append(mget_mask,
-                                                       CLI_DIRSEP_STR);
-                       if (!mget_mask) {
-                               return 1;
-                       }
-               }
-               mget_mask = talloc_asprintf_append(mget_mask, "*");
+               mget_mask = talloc_asprintf(ctx,
+                                       "%s*",
+                                       client_get_cur_dir());
                if (!mget_mask) {
                        return 1;
                }
@@ -1760,10 +1722,7 @@ static int cmd_put(void)
        char *rname;
        char *buf;
 
-       rname = talloc_asprintf(ctx,
-                       "%s%s",
-                       client_get_cur_dir(),
-                       CLI_DIRSEP_STR);
+       rname = talloc_strdup(ctx, client_get_cur_dir());
        if (!rname) {
                return 1;
        }
@@ -1980,10 +1939,10 @@ static int cmd_mput(void)
                                                break;
                                } else { /* Yes */
                                        SAFE_FREE(rname);
-                                       if(asprintf(&rname, "%s%s", cur_dir, lname) < 0) {
+                                       if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
                                                break;
                                        }
-                                       string_replace(rname,'/','\\');
+                                       normalize_name(rname);
                                        if (!cli_chkpath(cli, rname) &&
                                            !do_mkdir(rname)) {
                                                DEBUG (0, ("Unable to make dir, skipping..."));
@@ -2007,12 +1966,12 @@ static int cmd_mput(void)
 
                                /* Yes */
                                SAFE_FREE(rname);
-                               if (asprintf(&rname, "%s%s", cur_dir, lname) < 0) {
+                               if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
                                        break;
                                }
                        }
 
-                       string_replace(rname,'/','\\');
+                       normalize_name(rname);
 
                        do_put(rname, lname, false);
                }
@@ -3556,10 +3515,7 @@ static int cmd_reget(void)
        char *fname = NULL;
        char *p = NULL;
 
-       remote_name = talloc_asprintf(ctx,
-                               "%s%s",
-                               client_get_cur_dir(),
-                               CLI_DIRSEP_STR);
+       remote_name = talloc_strdup(ctx, client_get_cur_dir());
        if (!remote_name) {
                return 1;
        }
@@ -3598,10 +3554,7 @@ static int cmd_reput(void)
        char *buf;
        SMB_STRUCT_STAT st;
 
-       remote_name = talloc_asprintf(ctx,
-                               "%s%s",
-                               client_get_cur_dir(),
-                               CLI_DIRSEP_STR);
+       remote_name = talloc_strdup(ctx, client_get_cur_dir());
        if (!remote_name) {
                return 1;
        }
@@ -3674,13 +3627,13 @@ static bool browse_host_rpc(bool sort)
        NTSTATUS status;
        struct rpc_pipe_client *pipe_hnd;
        TALLOC_CTX *frame = talloc_stackframe();
-       ENUM_HND enum_hnd;
        WERROR werr;
-       SRV_SHARE_INFO_CTR ctr;
+       struct srvsvc_NetShareInfoCtr info_ctr;
+       struct srvsvc_NetShareCtr1 ctr1;
+       uint32_t resume_handle = 0;
+       uint32_t total_entries = 0;
        int i;
 
-       init_enum_hnd(&enum_hnd, 0);
-
        pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &status);
 
        if (pipe_hnd == NULL) {
@@ -3690,26 +3643,32 @@ static bool browse_host_rpc(bool sort)
                return false;
        }
 
-       werr = rpccli_srvsvc_net_share_enum(pipe_hnd, frame, 1, &ctr,
-                                           0xffffffff, &enum_hnd);
+       ZERO_STRUCT(info_ctr);
+       ZERO_STRUCT(ctr1);
 
-       if (!W_ERROR_IS_OK(werr)) {
-               cli_rpc_pipe_close(pipe_hnd);
+       info_ctr.level = 1;
+       info_ctr.ctr.ctr1 = &ctr1;
+
+       status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, frame,
+                                             pipe_hnd->desthost,
+                                             &info_ctr,
+                                             0xffffffff,
+                                             &total_entries,
+                                             &resume_handle,
+                                             &werr);
+
+       if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
+               TALLOC_FREE(pipe_hnd);
                TALLOC_FREE(frame);
                return false;
        }
 
-       for (i=0; i<ctr.num_entries; i++) {
-               SRV_SHARE_INFO_1 *info = &ctr.share.info1[i];
-               char *name, *comment;
-               name = rpcstr_pull_unistr2_talloc(
-                       frame, &info->info_1_str.uni_netname);
-               comment = rpcstr_pull_unistr2_talloc(
-                       frame, &info->info_1_str.uni_remark);
-               browse_fn(name, info->info_1.type, comment, NULL);
+       for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
+               struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
+               browse_fn(info.name, info.type, info.comment, NULL);
        }
 
-       cli_rpc_pipe_close(pipe_hnd);
+       TALLOC_FREE(pipe_hnd);
        TALLOC_FREE(frame);
        return true;
 }
@@ -4143,11 +4102,7 @@ static void completion_remote_filter(const char *mnt,
                        TALLOC_CTX *ctx = talloc_stackframe();
                        char *tmp;
 
-                       if (info->dirmask && info->dirmask[0] != 0) {
-                               tmp = talloc_strdup(ctx,info->dirmask);
-                       } else {
-                               tmp = talloc_strdup(ctx,"");
-                       }
+                       tmp = talloc_strdup(ctx,info->dirmask);
                        if (!tmp) {
                                TALLOC_FREE(ctx);
                                return;
@@ -4158,7 +4113,7 @@ static void completion_remote_filter(const char *mnt,
                                return;
                        }
                        if (f->mode & aDIR) {
-                               tmp = talloc_asprintf_append(tmp, "/");
+                               tmp = talloc_asprintf_append(tmp, CLI_DIRSEP_STR);
                        }
                        if (!tmp) {
                                TALLOC_FREE(ctx);
@@ -4559,6 +4514,8 @@ static int process(const char *base_directory)
 
 static int do_host_query(const char *query_host)
 {
+       struct sockaddr_storage ss;
+
        cli = cli_cm_open(talloc_tos(), NULL,
                        query_host, "IPC$", true, smb_encrypt);
        if (!cli)
@@ -4566,6 +4523,12 @@ static int do_host_query(const char *query_host)
 
        browse_host(true);
 
+       if (interpret_string_addr(&ss, query_host, 0) && (ss.ss_family != AF_INET)) {
+               d_printf("%s is an IPv6 address -- no workgroup available\n",
+                       query_host);
+               return 1;
+       }
+
        if (port != 139) {
 
                /* Workgroups simply don't make sense over anything
@@ -4747,7 +4710,7 @@ static int do_message_op(void)
        pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
        poptSetOtherOptionHelp(pc, "service <password>");
 
-       in_client = true;   /* Make sure that we tell lp_load we are */
+        lp_set_in_client(true); /* Make sure that we tell lp_load we are */
 
        while ((opt = poptGetNextOpt(pc)) != -1) {
 
@@ -4944,7 +4907,10 @@ static int do_message_op(void)
        }
 
        smb_encrypt = get_cmdline_auth_info_smb_encrypt();
-       init_names();
+       if (!init_names()) {
+               fprintf(stderr, "init_names() failed\n");
+               exit(1);
+       }
 
        if(new_name_resolve_order)
                lp_set_name_resolve_order(new_name_resolve_order);