summaryrefslogtreecommitdiffstats
path: root/source3/client
diff options
context:
space:
mode:
authorAurélien Aptel <aurelien.aptel@gmail.com>2013-07-11 00:57:40 +0200
committerAndreas Schneider <asn@samba.org>2014-02-19 18:22:27 +0100
commit9032fc7eec40dcd42b853ccd95e3c69c069b0b58 (patch)
tree05c82cf52b9cb62a68ccf2058cd53de853450d4a /source3/client
parentec1583ebd48d0077aa48149bcabd47fd87c65c83 (diff)
downloadsamba-9032fc7eec40dcd42b853ccd95e3c69c069b0b58.tar.gz
samba-9032fc7eec40dcd42b853ccd95e3c69c069b0b58.tar.xz
samba-9032fc7eec40dcd42b853ccd95e3c69c069b0b58.zip
clitar.c: implement basic tar creation
Signed-off-by: Aurélien Aptel <aurelien.aptel@gmail.com> Reviewed-by: David Disseldorp <ddiss@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'source3/client')
-rw-r--r--source3/client/client.c15
-rw-r--r--source3/client/clitar.c200
2 files changed, 198 insertions, 17 deletions
diff --git a/source3/client/client.c b/source3/client/client.c
index 20a9bec4a28..49b6406d4b2 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -5319,7 +5319,7 @@ static int do_host_query(const char *query_host)
static int do_tar_op(const char *base_directory)
{
extern struct tar tar_ctx;
- int ret;
+ int ret = 0;
/* do we already have a connection? */
if (!cli) {
@@ -5330,26 +5330,27 @@ static int do_tar_op(const char *base_directory)
service, auth_info, true, smb_encrypt,
max_protocol, port, name_type, &cli);
if (!NT_STATUS_IS_OK(status)) {
- return 1;
+ ret = 1;
+ goto out;
}
cli_set_timeout(cli, io_timeout*1000);
}
- recurse=true;
+ recurse = true;
if (base_directory && *base_directory) {
ret = do_cd(base_directory);
if (ret) {
- cli_shutdown(cli);
- return ret;
+ goto out_cli;
}
}
ret = tar_process(&tar_ctx);
+ out_cli:
cli_shutdown(cli);
-
- return(ret);
+ out:
+ return ret;
}
/****************************************************************************
diff --git a/source3/client/clitar.c b/source3/client/clitar.c
index 90f619b3e45..ad3da3a5cdc 100644
--- a/source3/client/clitar.c
+++ b/source3/client/clitar.c
@@ -44,6 +44,12 @@
*/
#define TAR_DEFAULT_BLOCK_SIZE 20
+#define TAR_CLI_READ_SIZE 0xff00
+
+#define TAR_DO_LIST_ATTRIBUTE (FILE_ATTRIBUTE_DIRECTORY \
+ | FILE_ATTRIBUTE_SYSTEM \
+ | FILE_ATTRIBUTE_HIDDEN)
+
enum tar_operation {
TAR_NO_OPERATION,
TAR_CREATE, /* c flag */
@@ -512,12 +518,12 @@ static int tar_send_file(struct tar *t, struct archive_entry *entry)
}
status = cli_open(cli, full_path, flags, DENY_NONE, &remote_fd);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Error opening remote file %s: %s\n",
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Error opening remote file %s: %s\n",
full_path, nt_errstr(status)));
- err = 1;
+ err = 1;
goto out;
- }
+ }
for (;;) {
const void *buf;
@@ -549,13 +555,175 @@ static int tar_send_file(struct tar *t, struct archive_entry *entry)
close_out:
status = cli_close(cli, remote_fd);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Error losing remote file %s: %s\n",
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Error losing remote file %s: %s\n",
full_path, nt_errstr(status)));
err = 1;
- }
+ }
+
+ out:
+ return err;
+}
+
+static int tar_get_file(struct tar *t, const char *full_dos_path,
+ struct file_info *finfo)
+{
+ extern struct cli_state *cli;
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS status;
+ struct archive_entry *entry;
+ char *full_unix_path;
+ char buf[TAR_CLI_READ_SIZE];
+ size_t len;
+ uint64_t off = 0;
+ uint16_t remote_fd = (uint16_t)-1;
+ int err = 0, r;
+
+ bool isdir = finfo->mode & FILE_ATTRIBUTE_DIRECTORY;
+ struct stat st = {
+ .st_mode = (isdir ? AE_IFDIR : AE_IFREG) | 0755,
+ .st_atime = finfo->atime_ts.tv_sec,
+ .st_mtime = finfo->mtime_ts.tv_sec,
+ .st_ctime = finfo->ctime_ts.tv_sec,
+ };
+
+ full_unix_path = talloc_asprintf(ctx, ".%s", full_dos_path);
+ string_replace(full_unix_path, '\\', '/');
+
+ entry = archive_entry_new();
+ archive_entry_copy_pathname(entry, full_unix_path);
+ archive_entry_copy_stat(entry, &st);
+
+ r = archive_write_header(t->archive, entry);
+ if (r != ARCHIVE_OK) {
+ DEBUG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
+ err = 1;
+ goto out_entry;
+ }
+
+ if (isdir) {
+ goto out_entry;
+ }
+
+ status = cli_open(cli, full_dos_path, O_RDONLY, DENY_NONE, &remote_fd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("%s opening remote file %s\n",
+ nt_errstr(status), full_dos_path));
+ goto out_entry;
+ }
+
+ do {
+ status = cli_read(cli, remote_fd, buf, off, sizeof(buf), &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Error reading file %s : %s\n",
+ full_dos_path, nt_errstr(status)));
+ err = 1;
+ goto out_close;
+ }
+
+ off += len;
+
+ r = archive_write_data(t->archive, buf, len);
+ if (r != ARCHIVE_OK) {
+ DEBUG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
+ err = 1;
+ }
+
+ } while (off < finfo->size);
+
+ out_close:
+ cli_close(cli, remote_fd);
+
+ out_entry:
+ archive_entry_free(entry);
+
+ return err;
+}
+
+static NTSTATUS get_file_callback(struct cli_state *cli,
+ struct file_info *finfo,
+ const char *dir)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ NTSTATUS err = NT_STATUS_OK;
+ char *remote_name;
+
+ remote_name = talloc_asprintf(ctx, "%s%s",
+ client_get_cur_dir(), finfo->name);
+
+
+ if (strequal(finfo->name, "..") || strequal(finfo->name, ".")) {
+ err = NT_STATUS_OK;
+ goto out;
+ }
+
+ if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+ char *old_dir;
+ char *new_dir;
+ char *mask;
+
+ old_dir = talloc_strdup(ctx, client_get_cur_dir());
+ new_dir = talloc_asprintf(ctx, "%s%s\\", client_get_cur_dir(), finfo->name);
+ mask = talloc_asprintf(ctx, "%s*", new_dir);
+
+ if (tar_get_file(&tar_ctx, remote_name, finfo)) {
+ err = NT_STATUS_UNSUCCESSFUL;
+ goto out;
+ }
+
+ client_set_cur_dir(new_dir);
+ do_list(mask, TAR_DO_LIST_ATTRIBUTE, get_file_callback, false, true);
+ client_set_cur_dir(old_dir);
+ }
+
+ else {
+ if (tar_get_file(&tar_ctx, remote_name, finfo)) {
+ err = NT_STATUS_UNSUCCESSFUL;
+ goto out;
+ }
+ }
+
+ out:
+ return err;
+}
+
+static int tar_create(struct tar* t)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *mask = talloc_asprintf(ctx, "%s\\*", client_get_cur_dir());
+ int r;
+ int err = 0;
+ NTSTATUS status;
+
+ t->archive = archive_write_new();
+
+ r = archive_write_set_format_pax_restricted(t->archive);
+ if (r != ARCHIVE_OK) {
+ DEBUG(0, ("Can't open %s: %s", t->tar_path, archive_error_string(t->archive)));
+ }
+
+ if (strequal(t->tar_path, "-")) {
+ r = archive_write_open_fd(t->archive, STDOUT_FILENO);
+ } else {
+ r = archive_write_open_filename(t->archive, t->tar_path);
+ }
+
+ if (r != ARCHIVE_OK) {
+ DEBUG(0, ("Can't open %s: %s", t->tar_path, archive_error_string(t->archive)));
+ err = 1;
+ goto out;
+ }
+
+ DEBUG(5, ("tar_process do_list with mask: %s\n", mask));
+ status = do_list(mask, TAR_DO_LIST_ATTRIBUTE, get_file_callback, false, true);
+ if(!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("do_list fail %s\n", nt_errstr(status)));
+ err = 1;
+ goto out;
+ }
out:
+ archive_write_free(t->archive);
return err;
}
@@ -599,10 +767,10 @@ static int tar_extract(struct tar *t)
break;
}
if (r == ARCHIVE_WARN) {
- DEBUG(0, ("Warning: %s", archive_error_string(t->archive)));
+ DEBUG(0, ("Warning: %s\n", archive_error_string(t->archive)));
}
if (r == ARCHIVE_FATAL) {
- DEBUG(0, ("Fatal: %s", archive_error_string(t->archive)));
+ DEBUG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
err = 1;
goto out;
}
@@ -633,12 +801,14 @@ int tar_process(struct tar *t)
rc = tar_extract(t);
break;
case TAR_CREATE:
- /* tar_create(t); */
+ rc = tar_create(t);
break;
default:
DEBUG(0, ("Invalid tar state\n"));
rc = 1;
}
+
+ DEBUG(5, ("tar_process done, err = %d\n", rc));
return rc;
}
@@ -806,6 +976,16 @@ int tar_parse_args(struct tar* t, const char *flag, const char **val, int valsiz
t->tar_path = talloc_strdup(ctx, val[ival]);
ival++;
+ /*
+ * Make sure that dbf points to stderr if we are using stdout for
+ * tar output
+ */
+ if (t->mode.operation == TAR_CREATE && strequal(t->tar_path, "-")) {
+ setup_logging("smbclient", DEBUG_STDERR);
+ }
+
+
+
/* handle PATHs... */
/* flag F -> read file list */