summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorTim Beale <timbeale@catalyst.net.nz>2018-12-11 09:34:42 +1300
committerTim Beale <timbeale@samba.org>2019-01-07 01:23:08 +0100
commit0af78faf5c9424514ba5bc0baa18701c65c884e7 (patch)
tree595e5af46cd21acd10020c00114ff81299f7514c /source3
parente4d1d53597ac093d56ad9d528e2e580e626ab359 (diff)
downloadsamba-0af78faf5c9424514ba5bc0baa18701c65c884e7.tar.gz
s3:pylibsmb: Add .savefile() API to SMB py bindings
This provides a simple API for writing a file's contents and makes the s3 API consistent with the s4 API. All the async APIs here support SMBv2 so we don't need to use the sync APIs at all. Note that we have the choice here of using either cli_write_send() or cli_push_send(). I chose the latter, because that's what smbclient uses. It also appears to handle writing a large file better (i.e. one that exceeds the max write size of the underlying connection). BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676 Signed-off-by: Tim Beale <timbeale@catalyst.net.nz> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Diffstat (limited to 'source3')
-rw-r--r--source3/libsmb/pylibsmb.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/source3/libsmb/pylibsmb.c b/source3/libsmb/pylibsmb.c
index 156352d7b3d..2a1ae292035 100644
--- a/source3/libsmb/pylibsmb.c
+++ b/source3/libsmb/pylibsmb.c
@@ -741,6 +741,92 @@ static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
Py_RETURN_NONE;
}
+struct push_state {
+ char *data;
+ off_t nread;
+ off_t total_data;
+};
+
+/*
+ * cli_push() helper to write a chunk of data to a remote file
+ */
+static size_t push_data(uint8_t *buf, size_t n, void *priv)
+{
+ struct push_state *state = (struct push_state *)priv;
+ char *curr_ptr = NULL;
+ off_t remaining;
+ size_t copied_bytes;
+
+ if (state->nread >= state->total_data) {
+ return 0;
+ }
+
+ curr_ptr = state->data + state->nread;
+ remaining = state->total_data - state->nread;
+ copied_bytes = MIN(remaining, n);
+
+ memcpy(buf, curr_ptr, copied_bytes);
+ state->nread += copied_bytes;
+ return copied_bytes;
+}
+
+/*
+ * Writes a file with the contents specified
+ */
+static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args,
+ PyObject *kwargs)
+{
+ uint16_t fnum;
+ const char *filename = NULL;
+ char *data = NULL;
+ Py_ssize_t size = 0;
+ NTSTATUS status;
+ struct tevent_req *req = NULL;
+ struct push_state state;
+
+ if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
+ &data, &size)) {
+ return NULL;
+ }
+
+ /* create a new file handle for writing to */
+ req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
+ FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
+ SMB2_IMPERSONATION_IMPERSONATION, 0);
+ if (!py_tevent_req_wait_exc(self, req)) {
+ return NULL;
+ }
+ status = cli_ntcreate_recv(req, &fnum, NULL);
+ TALLOC_FREE(req);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ /* write the new file contents */
+ state.data = data;
+ state.nread = 0;
+ state.total_data = size;
+
+ req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
+ push_data, &state);
+ if (!py_tevent_req_wait_exc(self, req)) {
+ return NULL;
+ }
+ status = cli_push_recv(req);
+ TALLOC_FREE(req);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ /* close the file handle */
+ req = cli_close_send(NULL, self->ev, self->cli, fnum);
+ if (!py_tevent_req_wait_exc(self, req)) {
+ return NULL;
+ }
+ status = cli_close_recv(req);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ Py_RETURN_NONE;
+}
+
static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
PyObject *kwds)
{
@@ -1214,6 +1300,9 @@ static PyMethodDef py_cli_state_methods[] = {
{ "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
"chkpath(dir_path) -> True or False\n\n"
"\t\tReturn true if directory exists, false otherwise." },
+ { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
+ "savefile(path, str) -> None\n\n"
+ "\t\tWrite " PY_DESC_PY3_BYTES " str to file." },
{ NULL, NULL, 0, NULL }
};