Convert all uint32/16/8 to _t in source3/libsmb.
[bbaumbach/samba-autobuild/.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         static const char *kwlist[] = {
416                 "host", "share", "credentials", NULL
417         };
418
419         PyTypeObject *py_type_Credentials = get_pytype(
420                 "samba.credentials", "Credentials");
421         if (py_type_Credentials == NULL) {
422                 return -1;
423         }
424
425         ret = ParseTupleAndKeywords(
426                 args, kwds, "ss|O!", kwlist,
427                 &host, &share, py_type_Credentials, &creds);
428
429         Py_DECREF(py_type_Credentials);
430
431         if (!ret) {
432                 return -1;
433         }
434
435         if (!py_cli_state_setup_ev(self)) {
436                 return -1;
437         }
438
439         if (creds == NULL) {
440                 cli_creds = cli_credentials_init_anon(NULL);
441         } else {
442                 cli_creds = PyCredentials_AsCliCredentials(creds);
443         }
444
445         req = cli_full_connection_send(
446                 NULL, self->ev, "myname", host, NULL, 0, share, "?????",
447                 cli_credentials_get_username(cli_creds),
448                 cli_credentials_get_domain(cli_creds),
449                 cli_credentials_get_password(cli_creds),
450                 0, 0);
451         if (!py_tevent_req_wait_exc(self->ev, req)) {
452                 return -1;
453         }
454         status = cli_full_connection_recv(req, &self->cli);
455         TALLOC_FREE(req);
456
457         if (!NT_STATUS_IS_OK(status)) {
458                 PyErr_SetNTSTATUS(status);
459                 return -1;
460         }
461
462         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
463                 self->ev, self->ev, self->cli);
464         if (self->oplock_waiter == NULL) {
465                 PyErr_NoMemory();
466                 return -1;
467         }
468         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
469                                 self);
470         return 0;
471 }
472
473 static void py_cli_got_oplock_break(struct tevent_req *req)
474 {
475         struct py_cli_state *self = (struct py_cli_state *)
476                 tevent_req_callback_data_void(req);
477         struct py_cli_oplock_break b;
478         struct py_cli_oplock_break *tmp;
479         size_t num_breaks;
480         NTSTATUS status;
481
482         status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
483         TALLOC_FREE(req);
484         self->oplock_waiter = NULL;
485
486         if (!NT_STATUS_IS_OK(status)) {
487                 return;
488         }
489
490         num_breaks = talloc_array_length(self->oplock_breaks);
491         tmp = talloc_realloc(self->ev, self->oplock_breaks,
492                              struct py_cli_oplock_break, num_breaks+1);
493         if (tmp == NULL) {
494                 return;
495         }
496         self->oplock_breaks = tmp;
497         self->oplock_breaks[num_breaks] = b;
498
499         if (self->oplock_cond != NULL) {
500                 py_tevent_cond_signal(self->oplock_cond);
501         }
502
503         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
504                 self->ev, self->ev, self->cli);
505         if (self->oplock_waiter == NULL) {
506                 return;
507         }
508         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
509                                 self);
510 }
511
512 static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
513                                          PyObject *args)
514 {
515         size_t num_oplock_breaks;
516
517         if (!PyArg_ParseTuple(args, "")) {
518                 return NULL;
519         }
520
521         if (self->oplock_cond != NULL) {
522                 errno = EBUSY;
523                 PyErr_SetFromErrno(PyExc_RuntimeError);
524                 return NULL;
525         }
526
527         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
528
529         if (num_oplock_breaks == 0) {
530                 struct py_tevent_cond cond;
531                 int ret;
532
533                 self->oplock_cond = &cond;
534                 ret = py_tevent_cond_wait(&cond);
535                 self->oplock_cond = NULL;
536
537                 if (ret != 0) {
538                         errno = ret;
539                         PyErr_SetFromErrno(PyExc_RuntimeError);
540                         return NULL;
541                 }
542         }
543
544         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
545         if (num_oplock_breaks > 0) {
546                 PyObject *result;
547
548                 result = Py_BuildValue(
549                         "{s:i,s:i}",
550                         "fnum", self->oplock_breaks[0].fnum,
551                         "level", self->oplock_breaks[0].level);
552
553                 memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
554                         sizeof(self->oplock_breaks[0]) *
555                         (num_oplock_breaks - 1));
556                 self->oplock_breaks = talloc_realloc(
557                         NULL, self->oplock_breaks, struct py_cli_oplock_break,
558                         num_oplock_breaks - 1);
559
560                 return result;
561         }
562         Py_RETURN_NONE;
563 }
564
565 static void py_cli_state_dealloc(struct py_cli_state *self)
566 {
567         TALLOC_FREE(self->thread_state);
568         TALLOC_FREE(self->oplock_waiter);
569         TALLOC_FREE(self->ev);
570
571         if (self->cli != NULL) {
572                 cli_shutdown(self->cli);
573                 self->cli = NULL;
574         }
575         self->ob_type->tp_free((PyObject *)self);
576 }
577
578 static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
579                                PyObject *kwds)
580 {
581         char *fname;
582         unsigned CreateFlags = 0;
583         unsigned DesiredAccess = FILE_GENERIC_READ;
584         unsigned FileAttributes = 0;
585         unsigned ShareAccess = 0;
586         unsigned CreateDisposition = FILE_OPEN;
587         unsigned CreateOptions = 0;
588         unsigned SecurityFlags = 0;
589         uint16_t fnum;
590         struct tevent_req *req;
591         NTSTATUS status;
592
593         static const char *kwlist[] = {
594                 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
595                 "ShareAccess", "CreateDisposition", "CreateOptions",
596                 "SecurityFlags", NULL };
597
598         if (!ParseTupleAndKeywords(
599                     args, kwds, "s|IIIIIII", kwlist,
600                     &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
601                     &ShareAccess, &CreateDisposition, &CreateOptions,
602                     &SecurityFlags)) {
603                 return NULL;
604         }
605
606         req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
607                                 DesiredAccess, FileAttributes, ShareAccess,
608                                 CreateDisposition, CreateOptions,
609                                 SecurityFlags);
610         if (!py_tevent_req_wait_exc(self->ev, req)) {
611                 return NULL;
612         }
613         status = cli_ntcreate_recv(req, &fnum, NULL);
614         TALLOC_FREE(req);
615
616         if (!NT_STATUS_IS_OK(status)) {
617                 PyErr_SetNTSTATUS(status);
618                 return NULL;
619         }
620         return Py_BuildValue("I", (unsigned)fnum);
621 }
622
623 static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
624 {
625         struct tevent_req *req;
626         int fnum;
627         NTSTATUS status;
628
629         if (!PyArg_ParseTuple(args, "i", &fnum)) {
630                 return NULL;
631         }
632
633         req = cli_close_send(NULL, self->ev, self->cli, fnum);
634         if (!py_tevent_req_wait_exc(self->ev, req)) {
635                 return NULL;
636         }
637         status = cli_close_recv(req);
638         TALLOC_FREE(req);
639
640         if (!NT_STATUS_IS_OK(status)) {
641                 PyErr_SetNTSTATUS(status);
642                 return NULL;
643         }
644         Py_RETURN_NONE;
645 }
646
647 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
648                               PyObject *kwds)
649 {
650         int fnum;
651         unsigned mode = 0;
652         char *buf;
653         int buflen;
654         unsigned long long offset;
655         struct tevent_req *req;
656         NTSTATUS status;
657         size_t written;
658
659         static const char *kwlist[] = {
660                 "fnum", "buffer", "offset", "mode", NULL };
661
662         if (!ParseTupleAndKeywords(
663                     args, kwds, "Is#K|I", kwlist,
664                     &fnum, &buf, &buflen, &offset, &mode)) {
665                 return NULL;
666         }
667
668         req = cli_write_andx_send(NULL, self->ev, self->cli, fnum, mode,
669                                   (uint8_t *)buf, offset, buflen);
670         if (!py_tevent_req_wait_exc(self->ev, req)) {
671                 return NULL;
672         }
673         status = cli_write_andx_recv(req, &written);
674         TALLOC_FREE(req);
675
676         if (!NT_STATUS_IS_OK(status)) {
677                 PyErr_SetNTSTATUS(status);
678                 return NULL;
679         }
680         return Py_BuildValue("K", (unsigned long long)written);
681 }
682
683 static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
684                              PyObject *kwds)
685 {
686         int fnum;
687         unsigned long long offset;
688         unsigned size;
689         struct tevent_req *req;
690         NTSTATUS status;
691         uint8_t *buf;
692         ssize_t buflen;
693         PyObject *result;
694
695         static const char *kwlist[] = {
696                 "fnum", "offset", "size", NULL };
697
698         if (!ParseTupleAndKeywords(
699                     args, kwds, "IKI", kwlist, &fnum, &offset,
700                     &size)) {
701                 return NULL;
702         }
703
704         req = cli_read_andx_send(NULL, self->ev, self->cli, fnum,
705                                  offset, size);
706         if (!py_tevent_req_wait_exc(self->ev, req)) {
707                 return NULL;
708         }
709         status = cli_read_andx_recv(req, &buflen, &buf);
710
711         if (!NT_STATUS_IS_OK(status)) {
712                 TALLOC_FREE(req);
713                 PyErr_SetNTSTATUS(status);
714                 return NULL;
715         }
716         result = Py_BuildValue("s#", (char *)buf, (int)buflen);
717         TALLOC_FREE(req);
718         return result;
719 }
720
721 static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
722                                   PyObject *kwds)
723 {
724         int fnum;
725         unsigned long long size;
726         struct tevent_req *req;
727         NTSTATUS status;
728
729         static const char *kwlist[] = {
730                 "fnum", "size", NULL };
731
732         if (!ParseTupleAndKeywords(
733                     args, kwds, "IK", kwlist, &fnum, &size)) {
734                 return NULL;
735         }
736
737         req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
738         if (!py_tevent_req_wait_exc(self->ev, req)) {
739                 return NULL;
740         }
741         status = cli_ftruncate_recv(req);
742         TALLOC_FREE(req);
743
744         if (!NT_STATUS_IS_OK(status)) {
745                 PyErr_SetNTSTATUS(status);
746                 return NULL;
747         }
748         Py_RETURN_NONE;
749 }
750
751 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
752                                         PyObject *args,
753                                         PyObject *kwds)
754 {
755         unsigned fnum, flag;
756         struct tevent_req *req;
757         NTSTATUS status;
758
759         static const char *kwlist[] = {
760                 "fnum", "flag", NULL };
761
762         if (!ParseTupleAndKeywords(
763                     args, kwds, "II", kwlist, &fnum, &flag)) {
764                 return NULL;
765         }
766
767         req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
768                                           flag);
769         if (!py_tevent_req_wait_exc(self->ev, req)) {
770                 return NULL;
771         }
772         status = cli_nt_delete_on_close_recv(req);
773         TALLOC_FREE(req);
774
775         if (!NT_STATUS_IS_OK(status)) {
776                 PyErr_SetNTSTATUS(status);
777                 return NULL;
778         }
779         Py_RETURN_NONE;
780 }
781
782 static PyObject *py_cli_list(struct py_cli_state *self,
783                              PyObject *args,
784                              PyObject *kwds)
785 {
786         char *mask;
787         unsigned attribute =
788                 FILE_ATTRIBUTE_DIRECTORY |
789                 FILE_ATTRIBUTE_SYSTEM |
790                 FILE_ATTRIBUTE_HIDDEN;
791         unsigned info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
792         struct tevent_req *req;
793         NTSTATUS status;
794         struct file_info *finfos;
795         size_t i, num_finfos;
796         PyObject *result;
797
798         const char *kwlist[] = {
799                 "mask", "attribute", "info_level", NULL
800         };
801
802         if (!ParseTupleAndKeywords(
803                     args, kwds, "s|II", kwlist,
804                     &mask, &attribute, &info_level)) {
805                 return NULL;
806         }
807
808         req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
809                             info_level);
810         if (!py_tevent_req_wait_exc(self->ev, req)) {
811                 return NULL;
812         }
813         status = cli_list_recv(req, NULL, &finfos, &num_finfos);
814         TALLOC_FREE(req);
815
816         if (!NT_STATUS_IS_OK(status)) {
817                 PyErr_SetNTSTATUS(status);
818                 return NULL;
819         }
820
821         result = Py_BuildValue("[]");
822         if (result == NULL) {
823                 return NULL;
824         }
825
826         for (i=0; i<num_finfos; i++) {
827                 struct file_info *finfo = &finfos[i];
828                 PyObject *file;
829                 int ret;
830
831                 file = Py_BuildValue(
832                         "{s:s,s:i}",
833                         "name", finfo->name,
834                         "mode", (int)finfo->mode);
835                 if (file == NULL) {
836                         Py_XDECREF(result);
837                         return NULL;
838                 }
839
840                 ret = PyList_Append(result, file);
841                 if (ret == -1) {
842                         Py_XDECREF(result);
843                         return NULL;
844                 }
845         }
846
847         return result;
848 }
849
850 static PyMethodDef py_cli_state_methods[] = {
851         { "create", (PyCFunction)py_cli_create, METH_VARARGS|METH_KEYWORDS,
852           "Open a file" },
853         { "close", (PyCFunction)py_cli_close, METH_VARARGS,
854           "Close a file handle" },
855         { "write", (PyCFunction)py_cli_write, METH_VARARGS|METH_KEYWORDS,
856           "Write to a file handle" },
857         { "read", (PyCFunction)py_cli_read, METH_VARARGS|METH_KEYWORDS,
858           "Read from a file handle" },
859         { "truncate", (PyCFunction)py_cli_ftruncate,
860           METH_VARARGS|METH_KEYWORDS,
861           "Truncate a file" },
862         { "delete_on_close", (PyCFunction)py_cli_delete_on_close,
863           METH_VARARGS|METH_KEYWORDS,
864           "Set/Reset the delete on close flag" },
865         { "readdir", (PyCFunction)py_cli_list,
866           METH_VARARGS|METH_KEYWORDS,
867           "List a directory" },
868         { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
869           METH_VARARGS, "Wait for an oplock break" },
870         { NULL, NULL, 0, NULL }
871 };
872
873 static PyTypeObject py_cli_state_type = {
874         PyObject_HEAD_INIT(NULL)
875         .tp_name = "libsmb_samba_internal.Conn",
876         .tp_basicsize = sizeof(struct py_cli_state),
877         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
878         .tp_doc = "libsmb connection",
879         .tp_new = py_cli_state_new,
880         .tp_init = (initproc)py_cli_state_init,
881         .tp_dealloc = (destructor)py_cli_state_dealloc,
882         .tp_methods = py_cli_state_methods,
883 };
884
885 static PyMethodDef py_libsmb_methods[] = {
886         { NULL },
887 };
888
889 void initlibsmb_samba_internal(void);
890 void initlibsmb_samba_internal(void)
891 {
892         PyObject *m;
893
894         talloc_stackframe();
895
896         m = Py_InitModule3("libsmb_samba_internal", py_libsmb_methods,
897                            "libsmb wrapper");
898
899         if (PyType_Ready(&py_cli_state_type) < 0) {
900                 return;
901         }
902         Py_INCREF(&py_cli_state_type);
903         PyModule_AddObject(m, "Conn", (PyObject *)&py_cli_state_type);
904 }