mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
s3:pylibsmb: add notify() support
The operation is a bit different from others, as results are returned in an async fashion. It returns a request handle. notify_req = conn.notify(fnum=fnum, buffer_size=0xffff, completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL, recursive=True) # ... do other operations on conn.*() ... changes = notify_req.get_changes(wait=False) # changes is likely to be None if no result arrived yet # ... do other operations on conn.*() ... changes = notify_req.get_changes(wait=True) # changes is a list of change dictionaries # each containing "name" (a string) and # "action" (an integer, e.g. libsmb.NOTIFY_ACTION_REMOVED) Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
parent
fde65c2f29
commit
3ffb817506
@ -1142,6 +1142,237 @@ static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
struct py_cli_notify_state {
|
||||
PyObject_HEAD
|
||||
struct py_cli_state *py_cli_state;
|
||||
struct tevent_req *req;
|
||||
};
|
||||
|
||||
static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
|
||||
{
|
||||
TALLOC_FREE(self->req);
|
||||
if (self->py_cli_state != NULL) {
|
||||
Py_DECREF(self->py_cli_state);
|
||||
self->py_cli_state = NULL;
|
||||
}
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static PyTypeObject py_cli_notify_state_type;
|
||||
|
||||
static PyObject *py_cli_notify(struct py_cli_state *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {
|
||||
"fnum",
|
||||
"buffer_size",
|
||||
"completion_filter",
|
||||
"recursive",
|
||||
NULL
|
||||
};
|
||||
unsigned fnum = 0;
|
||||
unsigned buffer_size = 0;
|
||||
unsigned completion_filter = 0;
|
||||
PyObject *py_recursive = Py_False;
|
||||
bool recursive = false;
|
||||
struct tevent_req *req = NULL;
|
||||
struct tevent_queue *send_queue = NULL;
|
||||
struct tevent_req *flush_req = NULL;
|
||||
bool ok;
|
||||
struct py_cli_notify_state *py_notify_state = NULL;
|
||||
struct timeval endtime;
|
||||
|
||||
ok = ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"IIIO",
|
||||
kwlist,
|
||||
&fnum,
|
||||
&buffer_size,
|
||||
&completion_filter,
|
||||
&py_recursive);
|
||||
if (!ok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
recursive = PyObject_IsTrue(py_recursive);
|
||||
|
||||
req = cli_notify_send(NULL,
|
||||
self->ev,
|
||||
self->cli,
|
||||
fnum,
|
||||
buffer_size,
|
||||
completion_filter,
|
||||
recursive);
|
||||
if (req == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just wait for the request being submitted to
|
||||
* the kernel/socket/wire.
|
||||
*/
|
||||
send_queue = smbXcli_conn_send_queue(self->cli->conn);
|
||||
flush_req = tevent_queue_wait_send(req,
|
||||
self->ev,
|
||||
send_queue);
|
||||
endtime = timeval_current_ofs_msec(self->cli->timeout);
|
||||
ok = tevent_req_set_endtime(flush_req,
|
||||
self->ev,
|
||||
endtime);
|
||||
if (!ok) {
|
||||
TALLOC_FREE(req);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
ok = py_tevent_req_wait_exc(self, flush_req);
|
||||
if (!ok) {
|
||||
TALLOC_FREE(req);
|
||||
return NULL;
|
||||
}
|
||||
TALLOC_FREE(flush_req);
|
||||
|
||||
py_notify_state = (struct py_cli_notify_state *)
|
||||
py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
|
||||
if (py_notify_state == NULL) {
|
||||
TALLOC_FREE(req);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(self);
|
||||
py_notify_state->py_cli_state = self;
|
||||
py_notify_state->req = req;
|
||||
|
||||
return (PyObject *)py_notify_state;
|
||||
}
|
||||
|
||||
static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
struct py_cli_state *py_cli_state = self->py_cli_state;
|
||||
struct tevent_req *req = self->req;
|
||||
uint32_t i;
|
||||
uint32_t num_changes = 0;
|
||||
struct notify_change *changes = NULL;
|
||||
PyObject *result = NULL;
|
||||
NTSTATUS status;
|
||||
bool ok;
|
||||
static const char *kwlist[] = {
|
||||
"wait",
|
||||
NULL
|
||||
};
|
||||
PyObject *py_wait = Py_False;
|
||||
bool wait = false;
|
||||
bool pending;
|
||||
|
||||
ok = ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O",
|
||||
kwlist,
|
||||
&py_wait);
|
||||
if (!ok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wait = PyObject_IsTrue(py_wait);
|
||||
|
||||
if (req == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"TODO req == NULL "
|
||||
"- missing change notify request?");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pending = tevent_req_is_in_progress(req);
|
||||
if (pending && !wait) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
if (pending) {
|
||||
struct timeval endtime;
|
||||
|
||||
endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
|
||||
ok = tevent_req_set_endtime(req,
|
||||
py_cli_state->ev,
|
||||
endtime);
|
||||
if (!ok) {
|
||||
TALLOC_FREE(req);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ok = py_tevent_req_wait_exc(py_cli_state, req);
|
||||
self->req = NULL;
|
||||
Py_DECREF(self->py_cli_state);
|
||||
self->py_cli_state = NULL;
|
||||
if (!ok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = cli_notify_recv(req, req, &num_changes, &changes);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(req);
|
||||
PyErr_SetNTSTATUS(status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = Py_BuildValue("[]");
|
||||
if (result == NULL) {
|
||||
TALLOC_FREE(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_changes; i++) {
|
||||
PyObject *change = NULL;
|
||||
int ret;
|
||||
|
||||
change = Py_BuildValue("{s:s,s:I}",
|
||||
"name", changes[i].name,
|
||||
"action", changes[i].action);
|
||||
if (change == NULL) {
|
||||
TALLOC_FREE(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = PyList_Append(result, change);
|
||||
if (ret == -1) {
|
||||
TALLOC_FREE(req);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TALLOC_FREE(req);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyMethodDef py_cli_notify_state_methods[] = {
|
||||
{ "get_changes",
|
||||
(PyCFunction)py_cli_notify_get_changes,
|
||||
METH_VARARGS|METH_KEYWORDS,
|
||||
"Wait for change notifications: \n"
|
||||
"N.get_changes(wait=BOOLEAN) -> "
|
||||
"change notifications as a dictionary\n"
|
||||
"\t\tList contents of a directory. The keys are, \n"
|
||||
"\t\t\tname: name of changed object\n"
|
||||
"\t\t\taction: type of the change\n"
|
||||
"None is returned if there's no response jet and wait=False is passed"
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static PyTypeObject py_cli_notify_state_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "libsmb_samba_cwrapper.Notify",
|
||||
.tp_basicsize = sizeof(struct py_cli_notify_state),
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.tp_doc = "notify request",
|
||||
.tp_dealloc = (destructor)py_cli_notify_state_dealloc,
|
||||
.tp_methods = py_cli_notify_state_methods,
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper to add directory listing entries to an overall Python list
|
||||
*/
|
||||
@ -1471,6 +1702,11 @@ static PyMethodDef py_cli_state_methods[] = {
|
||||
py_cli_delete_on_close),
|
||||
METH_VARARGS|METH_KEYWORDS,
|
||||
"Set/Reset the delete on close flag" },
|
||||
{ "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
|
||||
METH_VARARGS|METH_KEYWORDS,
|
||||
"Wait for change notifications: \n"
|
||||
"notify(fnum, buffer_size, completion_filter...) -> "
|
||||
"libsmb_samba_internal.Notify request handle\n" },
|
||||
{ "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
|
||||
METH_VARARGS|METH_KEYWORDS,
|
||||
"list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
|
||||
@ -1553,6 +1789,10 @@ MODULE_INIT_FUNC(libsmb_samba_cwrapper)
|
||||
if (PyType_Ready(&py_cli_state_type) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (PyType_Ready(&py_cli_notify_state_type) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(&py_cli_state_type);
|
||||
PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
|
||||
|
||||
@ -1579,5 +1819,31 @@ MODULE_INIT_FUNC(libsmb_samba_cwrapper)
|
||||
ADD_FLAGS(FILE_SHARE_WRITE);
|
||||
ADD_FLAGS(FILE_SHARE_DELETE);
|
||||
|
||||
/* change notify completion filter flags */
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
|
||||
ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
|
||||
|
||||
/* change notify action results */
|
||||
ADD_FLAGS(NOTIFY_ACTION_ADDED);
|
||||
ADD_FLAGS(NOTIFY_ACTION_REMOVED);
|
||||
ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
|
||||
ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
|
||||
ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
|
||||
ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
|
||||
ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
|
||||
ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user