libsmb: Convert cli_list_recv() to single-recv
[samba.git] / source3 / libsmb / pylibsmb.c
index 3c59ef5ba50739e35e29c0baa35f9afaa5c18a42..a1d48fe863e62b77b483332169b18f2b0e200550 100644 (file)
@@ -1146,6 +1146,29 @@ static NTSTATUS list_helper(struct file_info *finfo,
        return NT_STATUS_OK;
 }
 
+struct do_listing_state {
+       const char *mask;
+       NTSTATUS (*callback_fn)(
+               struct file_info *finfo,
+               const char *mask,
+               void *private_data);
+       void *private_data;
+       NTSTATUS status;
+};
+
+static void do_listing_cb(struct tevent_req *subreq)
+{
+       struct do_listing_state *state = tevent_req_callback_data_void(subreq);
+       struct file_info *finfo = NULL;
+
+       state->status = cli_list_recv(subreq, NULL, &finfo);
+       if (!NT_STATUS_IS_OK(state->status)) {
+               return;
+       }
+       state->callback_fn(finfo, state->mask, state->private_data);
+       TALLOC_FREE(finfo);
+}
+
 static NTSTATUS do_listing(struct py_cli_state *self,
                           const char *base_dir, const char *user_mask,
                           uint16_t attribute,
@@ -1155,9 +1178,6 @@ static NTSTATUS do_listing(struct py_cli_state *self,
 {
        char *mask = NULL;
        unsigned int info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
-       struct file_info *finfos = NULL;
-       size_t i;
-       size_t num_finfos = 0;
        NTSTATUS status;
 
        if (user_mask == NULL) {
@@ -1172,36 +1192,37 @@ static NTSTATUS do_listing(struct py_cli_state *self,
        dos_format(mask);
 
        if (self->is_smb1) {
+               struct do_listing_state state = {
+                       .mask = mask,
+                       .callback_fn = callback_fn,
+                       .private_data = priv,
+               };
                struct tevent_req *req = NULL;
 
                req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
                                    info_level);
+               if (req == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+               tevent_req_set_callback(req, do_listing_cb, &state);
+
                if (!py_tevent_req_wait_exc(self, req)) {
                        return NT_STATUS_INTERNAL_ERROR;
                }
-               status = cli_list_recv(req, NULL, &finfos, &num_finfos);
                TALLOC_FREE(req);
+
+               status = state.status;
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
+                       status = NT_STATUS_OK;
+               }
        } else {
                status = cli_list(self->cli, mask, attribute, callback_fn,
                                  priv);
        }
-       TALLOC_FREE(mask);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
 
-       /* invoke the callback for the async results (SMBv1 connections) */
-       for (i = 0; i < num_finfos; i++) {
-               status = callback_fn(&finfos[i], user_mask,
-                                    priv);
-               if (!NT_STATUS_IS_OK(status)) {
-                       TALLOC_FREE(finfos);
-                       return status;
-               }
-       }
-
-       TALLOC_FREE(finfos);
+done:
+       TALLOC_FREE(mask);
        return status;
 }
 
@@ -1336,72 +1357,40 @@ static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
        return PyBool_FromLong(dir_exists);
 }
 
-/*
- * Read ACL on a given file/directory as a security descriptor object
- */
-static PyObject *py_smb_getacl(struct py_cli_state *self, PyObject *args)
+static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
 {
-       NTSTATUS status;
-       const char *filename = NULL;
-       unsigned int sinfo = SECINFO_DEFAULT_FLAGS;
-       unsigned int access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       uint16_t fnum;
+       int fnum;
+       unsigned sinfo;
+       struct tevent_req *req = NULL;
        struct security_descriptor *sd = NULL;
+       NTSTATUS status;
 
-       /* there's no async version of cli_query_security_descriptor() */
-       if (self->thread_state != NULL) {
-               PyErr_SetString(PyExc_RuntimeError,
-                               "get_acl() is not supported on "
-                               "a multi_threaded connection");
+       if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
                return NULL;
        }
 
-       if (!PyArg_ParseTuple(args, "s|II:get_acl", &filename, &sinfo,
-                             &access_mask)) {
-               return NULL;
+       req = cli_query_security_descriptor_send(
+               NULL, self->ev, self->cli, fnum, sinfo);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return false;
        }
-
-       /* get a file handle with the desired access */
-       status = cli_ntcreate(self->cli, filename, 0, access_mask, 0,
-                             FILE_SHARE_READ|FILE_SHARE_WRITE,
-                             FILE_OPEN, 0x0, 0x0, &fnum, NULL);
+       status = cli_query_security_descriptor_recv(req, NULL, &sd);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
-       /* query the security descriptor for this file */
-       status = cli_query_security_descriptor(self->cli, fnum, sinfo,
-                                              NULL, &sd);
-       PyErr_NTSTATUS_IS_ERR_RAISE(status);
-
-       /* close the file handle and convert the SD to a python struct */
-       status = cli_close(self->cli, fnum);
-       PyErr_NTSTATUS_IS_ERR_RAISE(status);
-
-       return py_return_ndr_struct("samba.dcerpc.security", "descriptor",
-                                   sd, sd);
+       return py_return_ndr_struct(
+               "samba.dcerpc.security", "descriptor", sd, sd);
 }
 
-/*
- * Set ACL on file/directory using given security descriptor object
- */
-static PyObject *py_smb_setacl(struct py_cli_state *self, PyObject *args)
+static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
 {
-       NTSTATUS status;
-       char *filename = NULL;
        PyObject *py_sd = NULL;
+       struct tevent_req *req = NULL;
        struct security_descriptor *sd = NULL;
-       unsigned int sinfo = SECINFO_DEFAULT_FLAGS;
        uint16_t fnum;
+       unsigned int sinfo;
+       NTSTATUS status;
 
-       /* there's no async version of cli_set_security_descriptor() */
-       if (self->thread_state != NULL) {
-               PyErr_SetString(PyExc_RuntimeError,
-                               "set_acl() is not supported on "
-                               "a multi_threaded connection");
-               return NULL;
-       }
-
-       if (!PyArg_ParseTuple(args, "sO|I:set_acl", &filename, &py_sd,
-                             &sinfo)) {
+       if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
                return NULL;
        }
 
@@ -1413,16 +1402,13 @@ static PyObject *py_smb_setacl(struct py_cli_state *self, PyObject *args)
                return NULL;
        }
 
-       status = cli_ntcreate(self->cli, filename, 0,
-                             SEC_FLAG_MAXIMUM_ALLOWED, 0,
-                             FILE_SHARE_READ|FILE_SHARE_WRITE,
-                             FILE_OPEN, 0x0, 0x0, &fnum, NULL);
-       PyErr_NTSTATUS_IS_ERR_RAISE(status);
-
-       status = cli_set_security_descriptor(self->cli, fnum, sinfo, sd);
-       PyErr_NTSTATUS_IS_ERR_RAISE(status);
+       req = cli_set_security_descriptor_send(
+               NULL, self->ev, self->cli, fnum, sinfo, sd);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return false;
+       }
 
-       status = cli_close(self->cli, fnum);
+       status = cli_set_security_descriptor_recv(req);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        Py_RETURN_NONE;
@@ -1480,12 +1466,12 @@ static PyMethodDef py_cli_state_methods[] = {
        { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
          "loadfile(path) -> file contents as a " PY_DESC_PY3_BYTES
          "\n\n\t\tRead contents of a file." },
-       { "get_acl", (PyCFunction)py_smb_getacl, METH_VARARGS,
-         "get_acl(path[, security_info=0]) -> security_descriptor object\n\n"
-         "\t\tGet security descriptor for file." },
-       { "set_acl", (PyCFunction)py_smb_setacl, METH_VARARGS,
-         "set_acl(path, security_descriptor[, security_info=0]) -> None\n\n"
-         "\t\tSet security descriptor for file." },
+       { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
+         "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
+         "\t\tGet security descriptor for opened file." },
+       { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
+         "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
+         "\t\tSet security descriptor for opened file." },
        { NULL, NULL, 0, NULL }
 };
 
@@ -1550,5 +1536,9 @@ MODULE_INIT_FUNC(libsmb_samba_cwrapper)
        ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
        ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
 
+       ADD_FLAGS(FILE_SHARE_READ);
+       ADD_FLAGS(FILE_SHARE_WRITE);
+       ADD_FLAGS(FILE_SHARE_DELETE);
+
        return m;
 }