d2167e917d6b0147185d6f91727589688e684c98
[metze/samba/wip.git] / source3 / libsmb / pylibsmb.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Samba-internal work in progress Python binding for libsmbclient
4  *
5  * Copyright (C) Volker Lendecke 2012
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <Python.h>
22 #include "includes.h"
23 #include "libsmb/libsmb.h"
24 #include "libcli/security/security.h"
25 #include "system/select.h"
26 #include "source4/libcli/util/pyerrors.h"
27 #include "auth/credentials/pycredentials.h"
28 #include "trans2.h"
29
30 static PyTypeObject *get_pytype(const char *module, const char *type)
31 {
32         PyObject *mod;
33         PyTypeObject *result;
34
35         mod = PyImport_ImportModule(module);
36         if (mod == NULL) {
37                 PyErr_Format(PyExc_RuntimeError,
38                              "Unable to import %s to check type %s",
39                              module, type);
40                 return NULL;
41         }
42         result = (PyTypeObject *)PyObject_GetAttrString(mod, type);
43         Py_DECREF(mod);
44         if (result == NULL) {
45                 PyErr_Format(PyExc_RuntimeError,
46                              "Unable to find type %s in module %s",
47                              module, type);
48                 return NULL;
49         }
50         return result;
51 }
52
53 /*
54  * We're using "const char * const *" for keywords,
55  * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
56  * inevitable warnings to just one place.
57  */
58 static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
59                                  const char *format, const char * const *keywords,
60                                  ...)
61 {
62         char **_keywords = discard_const_p(char *, keywords);
63         va_list a;
64         int ret;
65         va_start(a, keywords);
66         ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
67                                             _keywords, a);
68         va_end(a);
69         return ret;
70 }
71
72 struct py_cli_thread;
73
74 struct py_cli_oplock_break {
75         uint16_t fnum;
76         uint8_t level;
77 };
78
79 struct py_cli_state {
80         PyObject_HEAD
81         struct cli_state *cli;
82         struct tevent_context *ev;
83         struct py_cli_thread *thread_state;
84
85         struct tevent_req *oplock_waiter;
86         struct py_cli_oplock_break *oplock_breaks;
87         struct py_tevent_cond *oplock_cond;
88 };
89
90 #if HAVE_PTHREAD
91
92 #include <pthread.h>
93
94 struct py_cli_thread {
95
96         /*
97          * Pipe to make the poll thread wake up in our destructor, so
98          * that we can exit and join the thread.
99          */
100         int shutdown_pipe[2];
101         struct tevent_fd *shutdown_fde;
102         bool do_shutdown;
103         pthread_t id;
104
105         /*
106          * Thread state to release the GIL during the poll(2) syscall
107          */
108         PyThreadState *py_threadstate;
109 };
110
111 static void *py_cli_state_poll_thread(void *private_data)
112 {
113         struct py_cli_state *self = (struct py_cli_state *)private_data;
114         struct py_cli_thread *t = self->thread_state;
115         PyGILState_STATE gstate;
116
117         gstate = PyGILState_Ensure();
118
119         while (!t->do_shutdown) {
120                 int ret;
121                 ret = tevent_loop_once(self->ev);
122                 assert(ret == 0);
123         }
124         PyGILState_Release(gstate);
125         return NULL;
126 }
127
128 static void py_cli_state_trace_callback(enum tevent_trace_point point,
129                                         void *private_data)
130 {
131         struct py_cli_state *self = (struct py_cli_state *)private_data;
132         struct py_cli_thread *t = self->thread_state;
133
134         switch(point) {
135         case TEVENT_TRACE_BEFORE_WAIT:
136                 assert(t->py_threadstate == NULL);
137                 t->py_threadstate = PyEval_SaveThread();
138                 break;
139         case TEVENT_TRACE_AFTER_WAIT:
140                 assert(t->py_threadstate != NULL);
141                 PyEval_RestoreThread(t->py_threadstate);
142                 t->py_threadstate = NULL;
143                 break;
144         default:
145                 break;
146         }
147 }
148
149 static void py_cli_state_shutdown_handler(struct tevent_context *ev,
150                                           struct tevent_fd *fde,
151                                           uint16_t flags,
152                                           void *private_data)
153 {
154         struct py_cli_state *self = (struct py_cli_state *)private_data;
155         struct py_cli_thread *t = self->thread_state;
156
157         if ((flags & TEVENT_FD_READ) == 0) {
158                 return;
159         }
160         TALLOC_FREE(t->shutdown_fde);
161         t->do_shutdown = true;
162 }
163
164 static int py_cli_thread_destructor(struct py_cli_thread *t)
165 {
166         char c = 0;
167         ssize_t written;
168         int ret;
169
170         do {
171                 /*
172                  * This will wake the poll thread from the poll(2)
173                  */
174                 written = write(t->shutdown_pipe[1], &c, 1);
175         } while ((written == -1) && (errno == EINTR));
176
177         /*
178          * Allow the poll thread to do its own cleanup under the GIL
179          */
180         Py_BEGIN_ALLOW_THREADS
181         ret = pthread_join(t->id, NULL);
182         Py_END_ALLOW_THREADS
183         assert(ret == 0);
184
185         if (t->shutdown_pipe[0] != -1) {
186                 close(t->shutdown_pipe[0]);
187                 t->shutdown_pipe[0] = -1;
188         }
189         if (t->shutdown_pipe[1] != -1) {
190                 close(t->shutdown_pipe[1]);
191                 t->shutdown_pipe[1] = -1;
192         }
193         return 0;
194 }
195
196 static bool py_cli_state_setup_ev(struct py_cli_state *self)
197 {
198         struct py_cli_thread *t = NULL;
199         int ret;
200
201         self->ev = tevent_context_init_byname(NULL, "poll_mt");
202         if (self->ev == NULL) {
203                 goto fail;
204         }
205         samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt");
206         tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self);
207
208         self->thread_state = talloc_zero(NULL, struct py_cli_thread);
209         if (self->thread_state == NULL) {
210                 goto fail;
211         }
212         t = self->thread_state;
213
214         ret = pipe(t->shutdown_pipe);
215         if (ret == -1) {
216                 goto fail;
217         }
218         t->shutdown_fde = tevent_add_fd(
219                 self->ev, self->ev, t->shutdown_pipe[0], TEVENT_FD_READ,
220                 py_cli_state_shutdown_handler, self);
221         if (t->shutdown_fde == NULL) {
222                 goto fail;
223         }
224
225         PyEval_InitThreads();
226
227         ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self);
228         if (ret != 0) {
229                 goto fail;
230         }
231         talloc_set_destructor(self->thread_state, py_cli_thread_destructor);
232         return true;
233
234 fail:
235         if (t != NULL) {
236                 TALLOC_FREE(t->shutdown_fde);
237
238                 if (t->shutdown_pipe[0] != -1) {
239                         close(t->shutdown_pipe[0]);
240                         t->shutdown_pipe[0] = -1;
241                 }
242                 if (t->shutdown_pipe[1] != -1) {
243                         close(t->shutdown_pipe[1]);
244                         t->shutdown_pipe[1] = -1;
245                 }
246         }
247
248         TALLOC_FREE(self->thread_state);
249         TALLOC_FREE(self->ev);
250         return false;
251 }
252
253 struct py_tevent_cond {
254         pthread_mutex_t mutex;
255         pthread_cond_t cond;
256         bool is_done;
257 };
258
259 static void py_tevent_signalme(struct tevent_req *req);
260
261 static int py_tevent_cond_wait(struct py_tevent_cond *cond)
262 {
263         int ret, result;
264
265         result = pthread_mutex_init(&cond->mutex, NULL);
266         if (result != 0) {
267                 goto fail;
268         }
269         result = pthread_cond_init(&cond->cond, NULL);
270         if (result != 0) {
271                 goto fail_mutex;
272         }
273
274         result = pthread_mutex_lock(&cond->mutex);
275         if (result != 0) {
276                 goto fail_cond;
277         }
278
279         cond->is_done = false;
280
281         while (!cond->is_done) {
282
283                 Py_BEGIN_ALLOW_THREADS
284                 result = pthread_cond_wait(&cond->cond, &cond->mutex);
285                 Py_END_ALLOW_THREADS
286
287                 if (result != 0) {
288                         goto fail_unlock;
289                 }
290         }
291
292 fail_unlock:
293         ret = pthread_mutex_unlock(&cond->mutex);
294         assert(ret == 0);
295 fail_cond:
296         ret = pthread_cond_destroy(&cond->cond);
297         assert(ret == 0);
298 fail_mutex:
299         ret = pthread_mutex_destroy(&cond->mutex);
300         assert(ret == 0);
301 fail:
302         return result;
303 }
304
305 static int py_tevent_req_wait(struct tevent_context *ev,
306                               struct tevent_req *req)
307 {
308         struct py_tevent_cond cond;
309         tevent_req_set_callback(req, py_tevent_signalme, &cond);
310         return py_tevent_cond_wait(&cond);
311 }
312
313 static void py_tevent_cond_signal(struct py_tevent_cond *cond)
314 {
315         int ret;
316
317         ret = pthread_mutex_lock(&cond->mutex);
318         assert(ret == 0);
319
320         cond->is_done = true;
321
322         ret = pthread_cond_signal(&cond->cond);
323         assert(ret == 0);
324         ret = pthread_mutex_unlock(&cond->mutex);
325         assert(ret == 0);
326 }
327
328 static void py_tevent_signalme(struct tevent_req *req)
329 {
330         struct py_tevent_cond *cond = (struct py_tevent_cond *)
331                 tevent_req_callback_data_void(req);
332
333         py_tevent_cond_signal(cond);
334 }
335
336 #else
337
338 static bool py_cli_state_setup_ev(struct py_cli_state *self)
339 {
340         self->ev = tevent_context_init(NULL);
341         if (self->ev == NULL) {
342                 return false;
343         }
344
345         samba_tevent_set_debug(self->ev, "pylibsmb_tevent");
346
347         return true;
348 }
349
350 static int py_tevent_req_wait(struct tevent_context *ev,
351                               struct tevent_req *req)
352 {
353         while (tevent_req_is_in_progress(req)) {
354                 int ret;
355
356                 ret = tevent_loop_once(ev);
357                 if (ret != 0) {
358                         return ret;
359                 }
360         }
361         return 0;
362 }
363
364 #endif
365
366 static bool py_tevent_req_wait_exc(struct tevent_context *ev,
367                                    struct tevent_req *req)
368 {
369         int ret;
370
371         if (req == NULL) {
372                 PyErr_NoMemory();
373                 return false;
374         }
375         ret = py_tevent_req_wait(ev, req);
376         if (ret != 0) {
377                 TALLOC_FREE(req);
378                 errno = ret;
379                 PyErr_SetFromErrno(PyExc_RuntimeError);
380                 return false;
381         }
382         return true;
383 }
384
385 static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
386                                   PyObject *kwds)
387 {
388         struct py_cli_state *self;
389
390         self = (struct py_cli_state *)type->tp_alloc(type, 0);
391         if (self == NULL) {
392                 return NULL;
393         }
394         self->cli = NULL;
395         self->ev = NULL;
396         self->thread_state = NULL;
397         self->oplock_waiter = NULL;
398         self->oplock_cond = NULL;
399         self->oplock_breaks = NULL;
400         return (PyObject *)self;
401 }
402
403 static void py_cli_got_oplock_break(struct tevent_req *req);
404
405 static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
406                              PyObject *kwds)
407 {
408         NTSTATUS status;
409         char *host, *share;
410         PyObject *creds = NULL;
411         struct cli_credentials *cli_creds;
412         struct tevent_req *req;
413         bool ret;
414         /*
415          * For now we only support SMB1,
416          * as most of the cli_*_send() function
417          * don't support SMB2, it's only plugged
418          * into the sync wrapper functions currently.
419          */
420         int flags = CLI_FULL_CONNECTION_FORCE_SMB1;
421
422         static const char *kwlist[] = {
423                 "host", "share", "credentials", NULL
424         };
425
426         PyTypeObject *py_type_Credentials = get_pytype(
427                 "samba.credentials", "Credentials");
428         if (py_type_Credentials == NULL) {
429                 return -1;
430         }
431
432         ret = ParseTupleAndKeywords(
433                 args, kwds, "ss|O!", kwlist,
434                 &host, &share, py_type_Credentials, &creds);
435
436         Py_DECREF(py_type_Credentials);
437
438         if (!ret) {
439                 return -1;
440         }
441
442         if (!py_cli_state_setup_ev(self)) {
443                 return -1;
444         }
445
446         if (creds == NULL) {
447                 cli_creds = cli_credentials_init_anon(NULL);
448         } else {
449                 cli_creds = PyCredentials_AsCliCredentials(creds);
450         }
451
452         req = cli_full_connection_creds_send(
453                 NULL, self->ev, "myname", host, NULL, 0, share, "?????",
454                 cli_creds, flags, SMB_SIGNING_DEFAULT);
455         if (!py_tevent_req_wait_exc(self->ev, req)) {
456                 return -1;
457         }
458         status = cli_full_connection_creds_recv(req, &self->cli);
459         TALLOC_FREE(req);
460
461         if (!NT_STATUS_IS_OK(status)) {
462                 PyErr_SetNTSTATUS(status);
463                 return -1;
464         }
465
466         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
467                 self->ev, self->ev, self->cli);
468         if (self->oplock_waiter == NULL) {
469                 PyErr_NoMemory();
470                 return -1;
471         }
472         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
473                                 self);
474         return 0;
475 }
476
477 static void py_cli_got_oplock_break(struct tevent_req *req)
478 {
479         struct py_cli_state *self = (struct py_cli_state *)
480                 tevent_req_callback_data_void(req);
481         struct py_cli_oplock_break b;
482         struct py_cli_oplock_break *tmp;
483         size_t num_breaks;
484         NTSTATUS status;
485
486         status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
487         TALLOC_FREE(req);
488         self->oplock_waiter = NULL;
489
490         if (!NT_STATUS_IS_OK(status)) {
491                 return;
492         }
493
494         num_breaks = talloc_array_length(self->oplock_breaks);
495         tmp = talloc_realloc(self->ev, self->oplock_breaks,
496                              struct py_cli_oplock_break, num_breaks+1);
497         if (tmp == NULL) {
498                 return;
499         }
500         self->oplock_breaks = tmp;
501         self->oplock_breaks[num_breaks] = b;
502
503         if (self->oplock_cond != NULL) {
504                 py_tevent_cond_signal(self->oplock_cond);
505         }
506
507         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
508                 self->ev, self->ev, self->cli);
509         if (self->oplock_waiter == NULL) {
510                 return;
511         }
512         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
513                                 self);
514 }
515
516 static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
517                                          PyObject *args)
518 {
519         size_t num_oplock_breaks;
520
521         if (!PyArg_ParseTuple(args, "")) {
522                 return NULL;
523         }
524
525         if (self->oplock_cond != NULL) {
526                 errno = EBUSY;
527                 PyErr_SetFromErrno(PyExc_RuntimeError);
528                 return NULL;
529         }
530
531         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
532
533         if (num_oplock_breaks == 0) {
534                 struct py_tevent_cond cond;
535                 int ret;
536
537                 self->oplock_cond = &cond;
538                 ret = py_tevent_cond_wait(&cond);
539                 self->oplock_cond = NULL;
540
541                 if (ret != 0) {
542                         errno = ret;
543                         PyErr_SetFromErrno(PyExc_RuntimeError);
544                         return NULL;
545                 }
546         }
547
548         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
549         if (num_oplock_breaks > 0) {
550                 PyObject *result;
551
552                 result = Py_BuildValue(
553                         "{s:i,s:i}",
554                         "fnum", self->oplock_breaks[0].fnum,
555                         "level", self->oplock_breaks[0].level);
556
557                 memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
558                         sizeof(self->oplock_breaks[0]) *
559                         (num_oplock_breaks - 1));
560                 self->oplock_breaks = talloc_realloc(
561                         NULL, self->oplock_breaks, struct py_cli_oplock_break,
562                         num_oplock_breaks - 1);
563
564                 return result;
565         }
566         Py_RETURN_NONE;
567 }
568
569 static void py_cli_state_dealloc(struct py_cli_state *self)
570 {
571         TALLOC_FREE(self->thread_state);
572         TALLOC_FREE(self->oplock_waiter);
573         TALLOC_FREE(self->ev);
574
575         if (self->cli != NULL) {
576                 cli_shutdown(self->cli);
577                 self->cli = NULL;
578         }
579         self->ob_type->tp_free((PyObject *)self);
580 }
581
582 static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
583                                PyObject *kwds)
584 {
585         char *fname;
586         unsigned CreateFlags = 0;
587         unsigned DesiredAccess = FILE_GENERIC_READ;
588         unsigned FileAttributes = 0;
589         unsigned ShareAccess = 0;
590         unsigned CreateDisposition = FILE_OPEN;
591         unsigned CreateOptions = 0;
592         unsigned SecurityFlags = 0;
593         uint16_t fnum;
594         struct tevent_req *req;
595         NTSTATUS status;
596
597         static const char *kwlist[] = {
598                 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
599                 "ShareAccess", "CreateDisposition", "CreateOptions",
600                 "SecurityFlags", NULL };
601
602         if (!ParseTupleAndKeywords(
603                     args, kwds, "s|IIIIIII", kwlist,
604                     &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
605                     &ShareAccess, &CreateDisposition, &CreateOptions,
606                     &SecurityFlags)) {
607                 return NULL;
608         }
609
610         req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
611                                 DesiredAccess, FileAttributes, ShareAccess,
612                                 CreateDisposition, CreateOptions,
613                                 SecurityFlags);
614         if (!py_tevent_req_wait_exc(self->ev, req)) {
615                 return NULL;
616         }
617         status = cli_ntcreate_recv(req, &fnum, NULL);
618         TALLOC_FREE(req);
619
620         if (!NT_STATUS_IS_OK(status)) {
621                 PyErr_SetNTSTATUS(status);
622                 return NULL;
623         }
624         return Py_BuildValue("I", (unsigned)fnum);
625 }
626
627 static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
628 {
629         struct tevent_req *req;
630         int fnum;
631         NTSTATUS status;
632
633         if (!PyArg_ParseTuple(args, "i", &fnum)) {
634                 return NULL;
635         }
636
637         req = cli_close_send(NULL, self->ev, self->cli, fnum);
638         if (!py_tevent_req_wait_exc(self->ev, req)) {
639                 return NULL;
640         }
641         status = cli_close_recv(req);
642         TALLOC_FREE(req);
643
644         if (!NT_STATUS_IS_OK(status)) {
645                 PyErr_SetNTSTATUS(status);
646                 return NULL;
647         }
648         Py_RETURN_NONE;
649 }
650
651 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
652                               PyObject *kwds)
653 {
654         int fnum;
655         unsigned mode = 0;
656         char *buf;
657         Py_ssize_t buflen;
658         unsigned long long offset;
659         struct tevent_req *req;
660         NTSTATUS status;
661         size_t written;
662
663         static const char *kwlist[] = {
664                 "fnum", "buffer", "offset", "mode", NULL };
665
666         if (!ParseTupleAndKeywords(
667                     args, kwds, "Is#K|I", kwlist,
668                     &fnum, &buf, &buflen, &offset, &mode)) {
669                 return NULL;
670         }
671
672         req = cli_write_andx_send(NULL, self->ev, self->cli, fnum, mode,
673                                   (uint8_t *)buf, offset, buflen);
674         if (!py_tevent_req_wait_exc(self->ev, req)) {
675                 return NULL;
676         }
677         status = cli_write_andx_recv(req, &written);
678         TALLOC_FREE(req);
679
680         if (!NT_STATUS_IS_OK(status)) {
681                 PyErr_SetNTSTATUS(status);
682                 return NULL;
683         }
684         return Py_BuildValue("K", (unsigned long long)written);
685 }
686
687 static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
688                              PyObject *kwds)
689 {
690         int fnum;
691         unsigned long long offset;
692         unsigned size;
693         struct tevent_req *req;
694         NTSTATUS status;
695         uint8_t *buf;
696         ssize_t buflen;
697         PyObject *result;
698
699         static const char *kwlist[] = {
700                 "fnum", "offset", "size", NULL };
701
702         if (!ParseTupleAndKeywords(
703                     args, kwds, "IKI", kwlist, &fnum, &offset,
704                     &size)) {
705                 return NULL;
706         }
707
708         req = cli_read_andx_send(NULL, self->ev, self->cli, fnum,
709                                  offset, size);
710         if (!py_tevent_req_wait_exc(self->ev, req)) {
711                 return NULL;
712         }
713         status = cli_read_andx_recv(req, &buflen, &buf);
714
715         if (!NT_STATUS_IS_OK(status)) {
716                 TALLOC_FREE(req);
717                 PyErr_SetNTSTATUS(status);
718                 return NULL;
719         }
720         result = Py_BuildValue("s#", (char *)buf, (int)buflen);
721         TALLOC_FREE(req);
722         return result;
723 }
724
725 static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
726                                   PyObject *kwds)
727 {
728         int fnum;
729         unsigned long long size;
730         struct tevent_req *req;
731         NTSTATUS status;
732
733         static const char *kwlist[] = {
734                 "fnum", "size", NULL };
735
736         if (!ParseTupleAndKeywords(
737                     args, kwds, "IK", kwlist, &fnum, &size)) {
738                 return NULL;
739         }
740
741         req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
742         if (!py_tevent_req_wait_exc(self->ev, req)) {
743                 return NULL;
744         }
745         status = cli_ftruncate_recv(req);
746         TALLOC_FREE(req);
747
748         if (!NT_STATUS_IS_OK(status)) {
749                 PyErr_SetNTSTATUS(status);
750                 return NULL;
751         }
752         Py_RETURN_NONE;
753 }
754
755 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
756                                         PyObject *args,
757                                         PyObject *kwds)
758 {
759         unsigned fnum, flag;
760         struct tevent_req *req;
761         NTSTATUS status;
762
763         static const char *kwlist[] = {
764                 "fnum", "flag", NULL };
765
766         if (!ParseTupleAndKeywords(
767                     args, kwds, "II", kwlist, &fnum, &flag)) {
768                 return NULL;
769         }
770
771         req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
772                                           flag);
773         if (!py_tevent_req_wait_exc(self->ev, req)) {
774                 return NULL;
775         }
776         status = cli_nt_delete_on_close_recv(req);
777         TALLOC_FREE(req);
778
779         if (!NT_STATUS_IS_OK(status)) {
780                 PyErr_SetNTSTATUS(status);
781                 return NULL;
782         }
783         Py_RETURN_NONE;
784 }
785
786 static PyObject *py_cli_list(struct py_cli_state *self,
787                              PyObject *args,
788                              PyObject *kwds)
789 {
790         char *mask;
791         unsigned attribute =
792                 FILE_ATTRIBUTE_DIRECTORY |
793                 FILE_ATTRIBUTE_SYSTEM |
794                 FILE_ATTRIBUTE_HIDDEN;
795         unsigned info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
796         struct tevent_req *req;
797         NTSTATUS status;
798         struct file_info *finfos;
799         size_t i, num_finfos;
800         PyObject *result;
801
802         const char *kwlist[] = {
803                 "mask", "attribute", "info_level", NULL
804         };
805
806         if (!ParseTupleAndKeywords(
807                     args, kwds, "s|II", kwlist,
808                     &mask, &attribute, &info_level)) {
809                 return NULL;
810         }
811
812         req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
813                             info_level);
814         if (!py_tevent_req_wait_exc(self->ev, req)) {
815                 return NULL;
816         }
817         status = cli_list_recv(req, NULL, &finfos, &num_finfos);
818         TALLOC_FREE(req);
819
820         if (!NT_STATUS_IS_OK(status)) {
821                 PyErr_SetNTSTATUS(status);
822                 return NULL;
823         }
824
825         result = Py_BuildValue("[]");
826         if (result == NULL) {
827                 return NULL;
828         }
829
830         for (i=0; i<num_finfos; i++) {
831                 struct file_info *finfo = &finfos[i];
832                 PyObject *file;
833                 int ret;
834
835                 file = Py_BuildValue(
836                         "{s:s,s:i}",
837                         "name", finfo->name,
838                         "mode", (int)finfo->mode);
839                 if (file == NULL) {
840                         Py_XDECREF(result);
841                         return NULL;
842                 }
843
844                 ret = PyList_Append(result, file);
845                 if (ret == -1) {
846                         Py_XDECREF(result);
847                         return NULL;
848                 }
849         }
850
851         return result;
852 }
853
854 static PyMethodDef py_cli_state_methods[] = {
855         { "create", (PyCFunction)py_cli_create, METH_VARARGS|METH_KEYWORDS,
856           "Open a file" },
857         { "close", (PyCFunction)py_cli_close, METH_VARARGS,
858           "Close a file handle" },
859         { "write", (PyCFunction)py_cli_write, METH_VARARGS|METH_KEYWORDS,
860           "Write to a file handle" },
861         { "read", (PyCFunction)py_cli_read, METH_VARARGS|METH_KEYWORDS,
862           "Read from a file handle" },
863         { "truncate", (PyCFunction)py_cli_ftruncate,
864           METH_VARARGS|METH_KEYWORDS,
865           "Truncate a file" },
866         { "delete_on_close", (PyCFunction)py_cli_delete_on_close,
867           METH_VARARGS|METH_KEYWORDS,
868           "Set/Reset the delete on close flag" },
869         { "readdir", (PyCFunction)py_cli_list,
870           METH_VARARGS|METH_KEYWORDS,
871           "List a directory" },
872         { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
873           METH_VARARGS, "Wait for an oplock break" },
874         { NULL, NULL, 0, NULL }
875 };
876
877 static PyTypeObject py_cli_state_type = {
878         PyObject_HEAD_INIT(NULL)
879         .tp_name = "libsmb_samba_internal.Conn",
880         .tp_basicsize = sizeof(struct py_cli_state),
881         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
882         .tp_doc = "libsmb connection",
883         .tp_new = py_cli_state_new,
884         .tp_init = (initproc)py_cli_state_init,
885         .tp_dealloc = (destructor)py_cli_state_dealloc,
886         .tp_methods = py_cli_state_methods,
887 };
888
889 static PyMethodDef py_libsmb_methods[] = {
890         { NULL },
891 };
892
893 void initlibsmb_samba_internal(void);
894 void initlibsmb_samba_internal(void)
895 {
896         PyObject *m;
897
898         talloc_stackframe();
899
900         m = Py_InitModule3("libsmb_samba_internal", py_libsmb_methods,
901                            "libsmb wrapper");
902
903         if (PyType_Ready(&py_cli_state_type) < 0) {
904                 return;
905         }
906         Py_INCREF(&py_cli_state_type);
907         PyModule_AddObject(m, "Conn", (PyObject *)&py_cli_state_type);
908 }