pyldb: avoid segfault when adding an element with no name
[kamenim/samba-autobuild/.git] / source3 / modules / vfs_ceph.c
1 /*
2    Unix SMB/CIFS implementation.
3    Wrap disk only vfs functions to sidestep dodgy compilers.
4    Copyright (C) Tim Potter 1998
5    Copyright (C) Jeremy Allison 2007
6    Copyright (C) Brian Chrisman 2011 <bchrisman@gmail.com>
7    Copyright (C) Richard Sharpe 2011 <realrichardsharpe@gmail.com>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24  * This VFS only works with the libceph.so user-space client. It is not needed
25  * if you are using the kernel client or the FUSE client.
26  *
27  * Add the following smb.conf parameter to each share that will be hosted on
28  * Ceph:
29  *
30  *   vfs objects = ceph [any others you need go here]
31  */
32
33 #include "includes.h"
34 #include "smbd/smbd.h"
35 #include <dirent.h>
36 #include <sys/statvfs.h>
37 #include "cephfs/libcephfs.h"
38 #include "smbprofile.h"
39 #include "modules/posixacl_xattr.h"
40 #include "lib/util/tevent_unix.h"
41
42 #undef DBGC_CLASS
43 #define DBGC_CLASS DBGC_VFS
44
45 #ifndef LIBCEPHFS_VERSION
46 #define LIBCEPHFS_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra)
47 #define LIBCEPHFS_VERSION_CODE LIBCEPHFS_VERSION(0, 0, 0)
48 #endif
49
50 /*
51  * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
52  */
53 #define llu(_var) ((long long unsigned)_var)
54
55 /*
56  * Note, libceph's return code model is to return -errno! So we have to convert
57  * to what Samba expects, with is set errno to -return and return -1
58  */
59 #define WRAP_RETURN(_res) \
60         errno = 0; \
61         if (_res < 0) { \
62                 errno = -_res; \
63                 return -1; \
64         } \
65         return _res \
66
67 /*
68  * We mount only one file system and then all shares are assumed to be in that.
69  * FIXME: If we want to support more than one FS, then we have to deal with
70  * this differently.
71  *
72  * So, cmount tells us if we have been this way before and whether
73  * we need to mount ceph and cmount_cnt tells us how many times we have
74  * connected
75  */
76 static struct ceph_mount_info * cmount = NULL;
77 static uint32_t cmount_cnt = 0;
78
79 /* Check for NULL pointer parameters in cephwrap_* functions */
80
81 /* We don't want to have NULL function pointers lying around.  Someone
82    is sure to try and execute them.  These stubs are used to prevent
83    this possibility. */
84
85 static int cephwrap_connect(struct vfs_handle_struct *handle,  const char *service, const char *user)
86 {
87         int ret;
88         char buf[256];
89         int snum = SNUM(handle->conn);
90         const char *conf_file;
91         const char *user_id;
92
93         if (cmount) {
94                 handle->data = cmount; /* We have been here before */
95                 cmount_cnt++;
96                 return 0;
97         }
98
99         /* if config_file and/or user_id are NULL, ceph will use defaults */
100         conf_file = lp_parm_const_string(snum, "ceph", "config_file", NULL);
101         user_id = lp_parm_const_string(snum, "ceph", "user_id", NULL);
102
103         DBG_DEBUG("[CEPH] calling: ceph_create\n");
104         ret = ceph_create(&cmount, user_id);
105         if (ret) {
106                 goto err_out;
107         }
108
109         DBG_DEBUG("[CEPH] calling: ceph_conf_read_file with %s\n",
110                   (conf_file == NULL ? "default path" : conf_file));
111         ret = ceph_conf_read_file(cmount, conf_file);
112         if (ret) {
113                 goto err_cm_release;
114         }
115
116         DBG_DEBUG("[CEPH] calling: ceph_conf_get\n");
117         ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
118         if (ret < 0) {
119                 goto err_cm_release;
120         }
121
122         /* libcephfs disables POSIX ACL support by default, enable it... */
123         ret = ceph_conf_set(cmount, "client_acl_type", "posix_acl");
124         if (ret < 0) {
125                 goto err_cm_release;
126         }
127         /* tell libcephfs to perform local permission checks */
128         ret = ceph_conf_set(cmount, "fuse_default_permissions", "false");
129         if (ret < 0) {
130                 goto err_cm_release;
131         }
132
133         DBG_DEBUG("[CEPH] calling: ceph_mount\n");
134         ret = ceph_mount(cmount, NULL);
135         if (ret < 0) {
136                 goto err_cm_release;
137         }
138
139         /*
140          * encode mount context/state into our vfs/connection holding structure
141          * cmount is a ceph_mount_t*
142          */
143         handle->data = cmount;
144         cmount_cnt++;
145
146         /*
147          * Unless we have an async implementation of getxattrat turn this off.
148          */
149         lp_do_parameter(SNUM(handle->conn), "smbd:async dosmode", "false");
150
151         return 0;
152
153 err_cm_release:
154         ceph_release(cmount);
155         cmount = NULL;
156 err_out:
157         /*
158          * Handle the error correctly. Ceph returns -errno.
159          */
160         DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
161         WRAP_RETURN(ret);
162 }
163
164 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
165 {
166         int ret;
167
168         if (!cmount) {
169                 DBG_ERR("[CEPH] Error, ceph not mounted\n");
170                 return;
171         }
172
173         /* Should we unmount/shutdown? Only if the last disconnect? */
174         if (--cmount_cnt) {
175                 DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
176                 return;
177         }
178
179         ret = ceph_unmount(cmount);
180         if (ret < 0) {
181                 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
182         }
183
184         ret = ceph_release(cmount);
185         if (ret < 0) {
186                 DBG_ERR("[CEPH] failed to release: %s\n", strerror(-ret));
187         }
188
189         cmount = NULL;  /* Make it safe */
190 }
191
192 /* Disk operations */
193
194 static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
195                                 const struct smb_filename *smb_fname,
196                                 uint64_t *bsize,
197                                 uint64_t *dfree,
198                                 uint64_t *dsize)
199 {
200         struct statvfs statvfs_buf;
201         int ret;
202
203         if (!(ret = ceph_statfs(handle->data, smb_fname->base_name,
204                         &statvfs_buf))) {
205                 /*
206                  * Provide all the correct values.
207                  */
208                 *bsize = statvfs_buf.f_bsize;
209                 *dfree = statvfs_buf.f_bavail;
210                 *dsize = statvfs_buf.f_blocks;
211                 DBG_DEBUG("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
212                         llu(*bsize), llu(*dfree), llu(*dsize));
213                 return *dfree;
214         } else {
215                 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
216                 WRAP_RETURN(ret);
217         }
218 }
219
220 static int cephwrap_get_quota(struct vfs_handle_struct *handle,
221                                 const struct smb_filename *smb_fname,
222                                 enum SMB_QUOTA_TYPE qtype,
223                                 unid_t id,
224                                 SMB_DISK_QUOTA *qt)
225 {
226         /* libceph: Ceph does not implement this */
227 #if 0
228 /* was ifdef HAVE_SYS_QUOTAS */
229         int ret;
230
231         ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
232
233         if (ret) {
234                 errno = -ret;
235                 ret = -1;
236         }
237
238         return ret;
239 #else
240         errno = ENOSYS;
241         return -1;
242 #endif
243 }
244
245 static int cephwrap_set_quota(struct vfs_handle_struct *handle,  enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
246 {
247         /* libceph: Ceph does not implement this */
248 #if 0
249 /* was ifdef HAVE_SYS_QUOTAS */
250         int ret;
251
252         ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
253         if (ret) {
254                 errno = -ret;
255                 ret = -1;
256         }
257
258         return ret;
259 #else
260         WRAP_RETURN(-ENOSYS);
261 #endif
262 }
263
264 static int cephwrap_statvfs(struct vfs_handle_struct *handle,
265                                 const struct smb_filename *smb_fname,
266                                 vfs_statvfs_struct *statbuf)
267 {
268         struct statvfs statvfs_buf;
269         int ret;
270
271         ret = ceph_statfs(handle->data, smb_fname->base_name, &statvfs_buf);
272         if (ret < 0) {
273                 WRAP_RETURN(ret);
274         }
275
276         statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
277         statbuf->BlockSize = statvfs_buf.f_bsize;
278         statbuf->TotalBlocks = statvfs_buf.f_blocks;
279         statbuf->BlocksAvail = statvfs_buf.f_bfree;
280         statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
281         statbuf->TotalFileNodes = statvfs_buf.f_files;
282         statbuf->FreeFileNodes = statvfs_buf.f_ffree;
283         statbuf->FsIdentifier = statvfs_buf.f_fsid;
284         DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
285                 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
286                 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
287
288         return ret;
289 }
290
291 static uint32_t cephwrap_fs_capabilities(struct vfs_handle_struct *handle,
292                                          enum timestamp_set_resolution *p_ts_res)
293 {
294         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
295
296 #ifdef HAVE_CEPH_STATX
297         *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
298 #else
299         *p_ts_res = TIMESTAMP_SET_MSEC;
300 #endif
301
302         return caps;
303 }
304
305 /* Directory operations */
306
307 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
308                              const struct smb_filename *smb_fname,
309                              const char *mask, uint32_t attr)
310 {
311         int ret = 0;
312         struct ceph_dir_result *result;
313         DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
314
315         /* Returns NULL if it does not exist or there are problems ? */
316         ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
317         if (ret < 0) {
318                 result = NULL;
319                 errno = -ret; /* We return result which is NULL in this case */
320         }
321
322         DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
323         return (DIR *) result;
324 }
325
326 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
327                                struct files_struct *fsp,
328                                const char *mask,
329                                uint32_t attributes)
330 {
331         int ret = 0;
332         struct ceph_dir_result *result;
333         DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
334
335         ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
336         if (ret < 0) {
337                 result = NULL;
338                 errno = -ret; /* We return result which is NULL in this case */
339         }
340
341         DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
342         return (DIR *) result;
343 }
344
345 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
346                                        DIR *dirp,
347                                        SMB_STRUCT_STAT *sbuf)
348 {
349         struct dirent *result;
350
351         DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
352         result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
353         DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
354
355         /* Default Posix readdir() does not give us stat info.
356          * Set to invalid to indicate we didn't return this info. */
357         if (sbuf)
358                 SET_STAT_INVALID(*sbuf);
359         return result;
360 }
361
362 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
363 {
364         DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
365         ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
366 }
367
368 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
369 {
370         long ret;
371         DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
372         ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
373         DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
374         WRAP_RETURN(ret);
375 }
376
377 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
378 {
379         DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
380         ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
381 }
382
383 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
384                           const struct smb_filename *smb_fname,
385                           mode_t mode)
386 {
387         int result;
388         char *parent = NULL;
389         const char *path = smb_fname->base_name;
390
391         DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
392
393         if (lp_inherit_acls(SNUM(handle->conn))
394             && parent_dirname(talloc_tos(), path, &parent, NULL)
395             && directory_has_default_acl(handle->conn, parent)) {
396                 mode = 0777;
397         }
398
399         TALLOC_FREE(parent);
400
401         result = ceph_mkdir(handle->data, path, mode);
402         return WRAP_RETURN(result);
403 }
404
405 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
406                         const struct smb_filename *smb_fname)
407 {
408         int result;
409
410         DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
411         result = ceph_rmdir(handle->data, smb_fname->base_name);
412         DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
413         WRAP_RETURN(result);
414 }
415
416 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
417 {
418         int result;
419
420         DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
421         result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
422         DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
423         WRAP_RETURN(result);
424 }
425
426 /* File operations */
427
428 static int cephwrap_open(struct vfs_handle_struct *handle,
429                         struct smb_filename *smb_fname,
430                         files_struct *fsp, int flags, mode_t mode)
431 {
432         int result = -ENOENT;
433         DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
434                   smb_fname_str_dbg(smb_fname), fsp, flags, mode);
435
436         if (smb_fname->stream_name) {
437                 goto out;
438         }
439
440         result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
441 out:
442         DBG_DEBUG("[CEPH] open(...) = %d\n", result);
443         WRAP_RETURN(result);
444 }
445
446 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
447 {
448         int result;
449
450         DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
451         result = ceph_close(handle->data, fsp->fh->fd);
452         DBG_DEBUG("[CEPH] close(...) = %d\n", result);
453
454         WRAP_RETURN(result);
455 }
456
457 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
458                         size_t n, off_t offset)
459 {
460         ssize_t result;
461
462         DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
463
464         result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
465         DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
466         WRAP_RETURN(result);
467 }
468
469 struct cephwrap_pread_state {
470         ssize_t bytes_read;
471         struct vfs_aio_state vfs_aio_state;
472 };
473
474 /*
475  * Fake up an async ceph read by calling the synchronous API.
476  */
477 static struct tevent_req *cephwrap_pread_send(struct vfs_handle_struct *handle,
478                                               TALLOC_CTX *mem_ctx,
479                                               struct tevent_context *ev,
480                                               struct files_struct *fsp,
481                                               void *data,
482                                               size_t n, off_t offset)
483 {
484         struct tevent_req *req = NULL;
485         struct cephwrap_pread_state *state = NULL;
486         int ret = -1;
487
488         DBG_DEBUG("[CEPH] %s\n", __func__);
489         req = tevent_req_create(mem_ctx, &state, struct cephwrap_pread_state);
490         if (req == NULL) {
491                 return NULL;
492         }
493
494         ret = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
495         if (ret < 0) {
496                 /* ceph returns -errno on error. */
497                 tevent_req_error(req, -ret);
498                 return tevent_req_post(req, ev);
499         }
500
501         state->bytes_read = ret;
502         tevent_req_done(req);
503         /* Return and schedule the completion of the call. */
504         return tevent_req_post(req, ev);
505 }
506
507 static ssize_t cephwrap_pread_recv(struct tevent_req *req,
508                                    struct vfs_aio_state *vfs_aio_state)
509 {
510         struct cephwrap_pread_state *state =
511                 tevent_req_data(req, struct cephwrap_pread_state);
512
513         DBG_DEBUG("[CEPH] %s\n", __func__);
514         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
515                 return -1;
516         }
517         *vfs_aio_state = state->vfs_aio_state;
518         return state->bytes_read;
519 }
520
521 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
522                         size_t n, off_t offset)
523 {
524         ssize_t result;
525
526         DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
527         result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
528         DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
529         WRAP_RETURN(result);
530 }
531
532 struct cephwrap_pwrite_state {
533         ssize_t bytes_written;
534         struct vfs_aio_state vfs_aio_state;
535 };
536
537 /*
538  * Fake up an async ceph write by calling the synchronous API.
539  */
540 static struct tevent_req *cephwrap_pwrite_send(struct vfs_handle_struct *handle,
541                                                TALLOC_CTX *mem_ctx,
542                                                struct tevent_context *ev,
543                                                struct files_struct *fsp,
544                                                const void *data,
545                                                size_t n, off_t offset)
546 {
547         struct tevent_req *req = NULL;
548         struct cephwrap_pwrite_state *state = NULL;
549         int ret = -1;
550
551         DBG_DEBUG("[CEPH] %s\n", __func__);
552         req = tevent_req_create(mem_ctx, &state, struct cephwrap_pwrite_state);
553         if (req == NULL) {
554                 return NULL;
555         }
556
557         ret = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
558         if (ret < 0) {
559                 /* ceph returns -errno on error. */
560                 tevent_req_error(req, -ret);
561                 return tevent_req_post(req, ev);
562         }
563
564         state->bytes_written = ret;
565         tevent_req_done(req);
566         /* Return and schedule the completion of the call. */
567         return tevent_req_post(req, ev);
568 }
569
570 static ssize_t cephwrap_pwrite_recv(struct tevent_req *req,
571                                     struct vfs_aio_state *vfs_aio_state)
572 {
573         struct cephwrap_pwrite_state *state =
574                 tevent_req_data(req, struct cephwrap_pwrite_state);
575
576         DBG_DEBUG("[CEPH] %s\n", __func__);
577         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
578                 return -1;
579         }
580         *vfs_aio_state = state->vfs_aio_state;
581         return state->bytes_written;
582 }
583
584 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
585 {
586         off_t result = 0;
587
588         DBG_DEBUG("[CEPH] cephwrap_lseek\n");
589         result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
590         WRAP_RETURN(result);
591 }
592
593 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
594                         off_t offset, size_t n)
595 {
596         /*
597          * We cannot support sendfile because libceph is in user space.
598          */
599         DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
600         errno = ENOTSUP;
601         return -1;
602 }
603
604 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
605                         int fromfd,
606                         files_struct *tofsp,
607                         off_t offset,
608                         size_t n)
609 {
610         /*
611          * We cannot support recvfile because libceph is in user space.
612          */
613         DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
614         errno=ENOTSUP;
615         return -1;
616 }
617
618 static int cephwrap_rename(struct vfs_handle_struct *handle,
619                           const struct smb_filename *smb_fname_src,
620                           const struct smb_filename *smb_fname_dst)
621 {
622         int result = -1;
623         DBG_DEBUG("[CEPH] cephwrap_rename\n");
624         if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
625                 errno = ENOENT;
626                 return result;
627         }
628
629         result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
630         WRAP_RETURN(result);
631 }
632
633 /*
634  * Fake up an async ceph fsync by calling the synchronous API.
635  */
636
637 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
638                                         TALLOC_CTX *mem_ctx,
639                                         struct tevent_context *ev,
640                                         files_struct *fsp)
641 {
642         struct tevent_req *req = NULL;
643         struct vfs_aio_state *state = NULL;
644         int ret = -1;
645
646         DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
647
648         req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
649         if (req == NULL) {
650                 return NULL;
651         }
652
653         /* Make sync call. */
654         ret = ceph_fsync(handle->data, fsp->fh->fd, false);
655
656         if (ret != 0) {
657                 /* ceph_fsync returns -errno on error. */
658                 tevent_req_error(req, -ret);
659                 return tevent_req_post(req, ev);
660         }
661
662         /* Mark it as done. */
663         tevent_req_done(req);
664         /* Return and schedule the completion of the call. */
665         return tevent_req_post(req, ev);
666 }
667
668 static int cephwrap_fsync_recv(struct tevent_req *req,
669                                 struct vfs_aio_state *vfs_aio_state)
670 {
671         struct vfs_aio_state *state =
672                 tevent_req_data(req, struct vfs_aio_state);
673
674         DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
675
676         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
677                 return -1;
678         }
679         *vfs_aio_state = *state;
680         return 0;
681 }
682
683 #ifdef HAVE_CEPH_STATX
684 #define SAMBA_STATX_ATTR_MASK   (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
685
686 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
687 {
688         DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, "
689                   "nlink = %llu, uid = %d, gid = %d, rdev = %llx, size = %llu, "
690                   "blksize = %llu, blocks = %llu, atime = %llu, mtime = %llu, "
691                   "ctime = %llu, btime = %llu}\n",
692                   llu(stx->stx_dev), llu(stx->stx_ino), stx->stx_mode,
693                   llu(stx->stx_nlink), stx->stx_uid, stx->stx_gid,
694                   llu(stx->stx_rdev), llu(stx->stx_size), llu(stx->stx_blksize),
695                   llu(stx->stx_blocks), llu(stx->stx_atime.tv_sec),
696                   llu(stx->stx_mtime.tv_sec), llu(stx->stx_ctime.tv_sec),
697                   llu(stx->stx_btime.tv_sec));
698
699         if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK) {
700                 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
701                                 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
702         }
703
704         dst->st_ex_dev = stx->stx_dev;
705         dst->st_ex_rdev = stx->stx_rdev;
706         dst->st_ex_ino = stx->stx_ino;
707         dst->st_ex_mode = stx->stx_mode;
708         dst->st_ex_uid = stx->stx_uid;
709         dst->st_ex_gid = stx->stx_gid;
710         dst->st_ex_size = stx->stx_size;
711         dst->st_ex_nlink = stx->stx_nlink;
712         dst->st_ex_atime = stx->stx_atime;
713         dst->st_ex_btime = stx->stx_btime;
714         dst->st_ex_ctime = stx->stx_ctime;
715         dst->st_ex_mtime = stx->stx_mtime;
716         dst->st_ex_calculated_birthtime = false;
717         dst->st_ex_blksize = stx->stx_blksize;
718         dst->st_ex_blocks = stx->stx_blocks;
719 }
720
721 static int cephwrap_stat(struct vfs_handle_struct *handle,
722                         struct smb_filename *smb_fname)
723 {
724         int result = -1;
725         struct ceph_statx stx;
726
727         DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
728
729         if (smb_fname->stream_name) {
730                 errno = ENOENT;
731                 return result;
732         }
733
734         result = ceph_statx(handle->data, smb_fname->base_name, &stx,
735                                 SAMBA_STATX_ATTR_MASK, 0);
736         DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
737         if (result < 0) {
738                 WRAP_RETURN(result);
739         }
740
741         init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
742         DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
743         return result;
744 }
745
746 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
747 {
748         int result = -1;
749         struct ceph_statx stx;
750
751         DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
752         result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
753                                 SAMBA_STATX_ATTR_MASK, 0);
754         DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
755         if (result < 0) {
756                 WRAP_RETURN(result);
757         }
758
759         init_stat_ex_from_ceph_statx(sbuf, &stx);
760         DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
761         return result;
762 }
763
764 static int cephwrap_lstat(struct vfs_handle_struct *handle,
765                          struct smb_filename *smb_fname)
766 {
767         int result = -1;
768         struct ceph_statx stx;
769
770         DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
771
772         if (smb_fname->stream_name) {
773                 errno = ENOENT;
774                 return result;
775         }
776
777         result = ceph_statx(handle->data, smb_fname->base_name, &stx,
778                                 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
779         DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
780         if (result < 0) {
781                 WRAP_RETURN(result);
782         }
783
784         init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
785         return result;
786 }
787
788 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
789                          const struct smb_filename *smb_fname,
790                          struct smb_file_time *ft)
791 {
792         struct ceph_statx stx = { 0 };
793         int result;
794         int mask = 0;
795
796         if (!null_timespec(ft->atime)) {
797                 stx.stx_atime = ft->atime;
798                 mask |= CEPH_SETATTR_ATIME;
799         }
800         if (!null_timespec(ft->mtime)) {
801                 stx.stx_mtime = ft->mtime;
802                 mask |= CEPH_SETATTR_MTIME;
803         }
804         if (!null_timespec(ft->create_time)) {
805                 stx.stx_btime = ft->create_time;
806                 mask |= CEPH_SETATTR_BTIME;
807         }
808
809         if (!mask) {
810                 return 0;
811         }
812
813         result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
814         DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
815                                 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
816                                 ft->create_time.tv_sec, result);
817         return result;
818 }
819
820 #else /* HAVE_CEPH_STATX */
821
822 static int cephwrap_stat(struct vfs_handle_struct *handle,
823                         struct smb_filename *smb_fname)
824 {
825         int result = -1;
826         struct stat stbuf;
827
828         DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
829
830         if (smb_fname->stream_name) {
831                 errno = ENOENT;
832                 return result;
833         }
834
835         result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
836         DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
837         if (result < 0) {
838                 WRAP_RETURN(result);
839         }
840
841         DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
842                    "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
843                    "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
844                    llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
845                    stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
846                    llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
847
848         init_stat_ex_from_stat(
849                         &smb_fname->st, &stbuf,
850                         lp_fake_directory_create_times(SNUM(handle->conn)));
851         DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
852         return result;
853 }
854
855 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
856 {
857         int result = -1;
858         struct stat stbuf;
859
860         DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
861         result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
862         DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
863         if (result < 0) {
864                 WRAP_RETURN(result);
865         }
866
867         DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
868                    "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
869                    "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
870                    llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
871                    stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
872                    llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
873
874         init_stat_ex_from_stat(
875                         sbuf, &stbuf,
876                         lp_fake_directory_create_times(SNUM(handle->conn)));
877         DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
878         return result;
879 }
880
881 static int cephwrap_lstat(struct vfs_handle_struct *handle,
882                          struct smb_filename *smb_fname)
883 {
884         int result = -1;
885         struct stat stbuf;
886
887         DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
888
889         if (smb_fname->stream_name) {
890                 errno = ENOENT;
891                 return result;
892         }
893
894         result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
895         DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
896         if (result < 0) {
897                 WRAP_RETURN(result);
898         }
899
900         init_stat_ex_from_stat(
901                         &smb_fname->st, &stbuf,
902                         lp_fake_directory_create_times(SNUM(handle->conn)));
903         return result;
904 }
905
906 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
907                          const struct smb_filename *smb_fname,
908                          struct smb_file_time *ft)
909 {
910         struct utimbuf buf;
911         int result;
912
913         if (null_timespec(ft->atime)) {
914                 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
915         } else {
916                 buf.actime = ft->atime.tv_sec;
917         }
918         if (null_timespec(ft->mtime)) {
919                 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
920         } else {
921                 buf.modtime = ft->mtime.tv_sec;
922         }
923         if (!null_timespec(ft->create_time)) {
924                 set_create_timespec_ea(handle->conn, smb_fname,
925                                        ft->create_time);
926         }
927         if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
928             buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
929                 return 0;
930         }
931
932         result = ceph_utime(handle->data, smb_fname->base_name, &buf);
933         DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
934                                 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
935                                 ft->create_time.tv_sec, result);
936         return result;
937 }
938 #endif /* HAVE_CEPH_STATX */
939
940 static int cephwrap_unlink(struct vfs_handle_struct *handle,
941                           const struct smb_filename *smb_fname)
942 {
943         int result = -1;
944
945         DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
946         if (smb_fname->stream_name) {
947                 errno = ENOENT;
948                 return result;
949         }
950         result = ceph_unlink(handle->data, smb_fname->base_name);
951         DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
952         WRAP_RETURN(result);
953 }
954
955 static int cephwrap_chmod(struct vfs_handle_struct *handle,
956                         const struct smb_filename *smb_fname,
957                         mode_t mode)
958 {
959         int result;
960
961         DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
962         result = ceph_chmod(handle->data, smb_fname->base_name, mode);
963         DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
964         WRAP_RETURN(result);
965 }
966
967 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
968 {
969         int result;
970
971         DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
972         result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
973         DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
974         WRAP_RETURN(result);
975 }
976
977 static int cephwrap_chown(struct vfs_handle_struct *handle,
978                         const struct smb_filename *smb_fname,
979                         uid_t uid,
980                         gid_t gid)
981 {
982         int result;
983         DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
984         result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
985         DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
986         WRAP_RETURN(result);
987 }
988
989 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
990 {
991         int result;
992
993         DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
994         result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
995         DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
996         WRAP_RETURN(result);
997 }
998
999 static int cephwrap_lchown(struct vfs_handle_struct *handle,
1000                         const struct smb_filename *smb_fname,
1001                         uid_t uid,
1002                         gid_t gid)
1003 {
1004         int result;
1005         DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1006         result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
1007         DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
1008         WRAP_RETURN(result);
1009 }
1010
1011 static int cephwrap_chdir(struct vfs_handle_struct *handle,
1012                         const struct smb_filename *smb_fname)
1013 {
1014         int result = -1;
1015         DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
1016         result = ceph_chdir(handle->data, smb_fname->base_name);
1017         DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
1018         WRAP_RETURN(result);
1019 }
1020
1021 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
1022                         TALLOC_CTX *ctx)
1023 {
1024         const char *cwd = ceph_getcwd(handle->data);
1025         DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
1026         return synthetic_smb_fname(ctx,
1027                                 cwd,
1028                                 NULL,
1029                                 NULL,
1030                                 0);
1031 }
1032
1033 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1034 {
1035         off_t space_to_write;
1036         int result;
1037         NTSTATUS status;
1038         SMB_STRUCT_STAT *pst;
1039
1040         status = vfs_stat_fsp(fsp);
1041         if (!NT_STATUS_IS_OK(status)) {
1042                 return -1;
1043         }
1044         pst = &fsp->fsp_name->st;
1045
1046 #ifdef S_ISFIFO
1047         if (S_ISFIFO(pst->st_ex_mode))
1048                 return 0;
1049 #endif
1050
1051         if (pst->st_ex_size == len)
1052                 return 0;
1053
1054         /* Shrink - just ftruncate. */
1055         if (pst->st_ex_size > len) {
1056                 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1057                 WRAP_RETURN(result);
1058         }
1059
1060         space_to_write = len - pst->st_ex_size;
1061         result = ceph_fallocate(handle->data, fsp->fh->fd, 0, pst->st_ex_size,
1062                                 space_to_write);
1063         WRAP_RETURN(result);
1064 }
1065
1066 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1067 {
1068         int result = -1;
1069
1070         DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1071
1072         if (lp_strict_allocate(SNUM(fsp->conn))) {
1073                 return strict_allocate_ftruncate(handle, fsp, len);
1074         }
1075
1076         result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1077         WRAP_RETURN(result);
1078 }
1079
1080 static int cephwrap_fallocate(struct vfs_handle_struct *handle,
1081                               struct files_struct *fsp,
1082                               uint32_t mode,
1083                               off_t offset,
1084                               off_t len)
1085 {
1086         int result;
1087
1088         DBG_DEBUG("[CEPH] fallocate(%p, %p, %u, %llu, %llu\n",
1089                   handle, fsp, mode, llu(offset), llu(len));
1090         /* unsupported mode flags are rejected by libcephfs */
1091         result = ceph_fallocate(handle->data, fsp->fh->fd, mode, offset, len);
1092         DBG_DEBUG("[CEPH] fallocate(...) = %d\n", result);
1093         WRAP_RETURN(result);
1094 }
1095
1096 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1097 {
1098         DBG_DEBUG("[CEPH] lock\n");
1099         return true;
1100 }
1101
1102 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1103                                 uint32_t share_mode, uint32_t access_mask)
1104 {
1105         DBG_ERR("[CEPH] flock unsupported! Consider setting "
1106                 "\"kernel share modes = no\"\n");
1107
1108         errno = ENOSYS;
1109         return -1;
1110 }
1111
1112 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1113 {
1114         DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1115
1116         errno = 0;
1117         return false;
1118 }
1119
1120 /*
1121  * We cannot let this fall through to the default, because the file might only
1122  * be accessible from libceph (which is a user-space client) but the fd might
1123  * be for some file the kernel knows about.
1124  */
1125 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1126                                 int leasetype)
1127 {
1128         int result = -1;
1129
1130         DBG_DEBUG("[CEPH] linux_setlease\n");
1131         errno = ENOSYS;
1132         return result;
1133 }
1134
1135 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1136                 const char *link_target,
1137                 const struct smb_filename *new_smb_fname)
1138 {
1139         int result = -1;
1140         DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1141                         link_target,
1142                         new_smb_fname->base_name);
1143         result = ceph_symlink(handle->data,
1144                         link_target,
1145                         new_smb_fname->base_name);
1146         DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1147         WRAP_RETURN(result);
1148 }
1149
1150 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1151                 const struct smb_filename *smb_fname,
1152                 char *buf,
1153                 size_t bufsiz)
1154 {
1155         int result = -1;
1156         DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1157                         smb_fname->base_name, buf, llu(bufsiz));
1158         result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1159         DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1160         WRAP_RETURN(result);
1161 }
1162
1163 static int cephwrap_link(struct vfs_handle_struct *handle,
1164                 const struct smb_filename *old_smb_fname,
1165                 const struct smb_filename *new_smb_fname)
1166 {
1167         int result = -1;
1168         DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1169                         old_smb_fname->base_name,
1170                         new_smb_fname->base_name);
1171         result = ceph_link(handle->data,
1172                                 old_smb_fname->base_name,
1173                                 new_smb_fname->base_name);
1174         DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1175         WRAP_RETURN(result);
1176 }
1177
1178 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1179                 const struct smb_filename *smb_fname,
1180                 mode_t mode,
1181                 SMB_DEV_T dev)
1182 {
1183         int result = -1;
1184         DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1185         result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1186         DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1187         WRAP_RETURN(result);
1188 }
1189
1190 /*
1191  * This is a simple version of real-path ... a better version is needed to
1192  * ask libceph about symbolic links.
1193  */
1194 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1195                                 TALLOC_CTX *ctx,
1196                                 const struct smb_filename *smb_fname)
1197 {
1198         char *result = NULL;
1199         const char *path = smb_fname->base_name;
1200         size_t len = strlen(path);
1201         struct smb_filename *result_fname = NULL;
1202         int r = -1;
1203
1204         if (len && (path[0] == '/')) {
1205                 r = asprintf(&result, "%s", path);
1206         } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1207                 if (len == 2) {
1208                         r = asprintf(&result, "%s",
1209                                         handle->conn->connectpath);
1210                 } else {
1211                         r = asprintf(&result, "%s/%s",
1212                                         handle->conn->connectpath, &path[2]);
1213                 }
1214         } else {
1215                 r = asprintf(&result, "%s/%s",
1216                                 handle->conn->connectpath, path);
1217         }
1218
1219         if (r < 0) {
1220                 return NULL;
1221         }
1222
1223         DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1224         result_fname = synthetic_smb_fname(ctx,
1225                                 result,
1226                                 NULL,
1227                                 NULL,
1228                                 0);
1229         SAFE_FREE(result);
1230         return result_fname;
1231 }
1232
1233 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1234                         const struct smb_filename *smb_fname,
1235                         unsigned int flags)
1236 {
1237         errno = ENOSYS;
1238         return -1;
1239 }
1240
1241 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1242                                      const char *path,
1243                                      const char *name,
1244                                      TALLOC_CTX *mem_ctx,
1245                                      char **found_name)
1246 {
1247         /*
1248          * Don't fall back to get_real_filename so callers can differentiate
1249          * between a full directory scan and an actual case-insensitive stat.
1250          */
1251         errno = EOPNOTSUPP;
1252         return -1;
1253 }
1254
1255 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1256                                        const struct smb_filename *smb_fname)
1257 {
1258         return handle->conn->connectpath;
1259 }
1260
1261 /****************************************************************
1262  Extended attribute operations.
1263 *****************************************************************/
1264
1265 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1266                         const struct smb_filename *smb_fname,
1267                         const char *name,
1268                         void *value,
1269                         size_t size)
1270 {
1271         int ret;
1272         DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1273                         smb_fname->base_name, name, value, llu(size));
1274         ret = ceph_getxattr(handle->data,
1275                         smb_fname->base_name, name, value, size);
1276         DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1277         if (ret < 0) {
1278                 WRAP_RETURN(ret);
1279         }
1280         return (ssize_t)ret;
1281 }
1282
1283 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1284 {
1285         int ret;
1286         DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1287 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1288         ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1289 #else
1290         ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1291 #endif
1292         DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1293         if (ret < 0) {
1294                 WRAP_RETURN(ret);
1295         }
1296         return (ssize_t)ret;
1297 }
1298
1299 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1300                         const struct smb_filename *smb_fname,
1301                         char *list,
1302                         size_t size)
1303 {
1304         int ret;
1305         DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1306                         smb_fname->base_name, list, llu(size));
1307         ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1308         DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1309         if (ret < 0) {
1310                 WRAP_RETURN(ret);
1311         }
1312         return (ssize_t)ret;
1313 }
1314
1315 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1316 {
1317         int ret;
1318         DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1319 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1320         ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1321 #else
1322         ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1323 #endif
1324         DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1325         if (ret < 0) {
1326                 WRAP_RETURN(ret);
1327         }
1328         return (ssize_t)ret;
1329 }
1330
1331 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1332                                 const struct smb_filename *smb_fname,
1333                                 const char *name)
1334 {
1335         int ret;
1336         DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1337                         smb_fname->base_name, name);
1338         ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1339         DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1340         WRAP_RETURN(ret);
1341 }
1342
1343 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1344 {
1345         int ret;
1346         DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1347 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1348         ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1349 #else
1350         ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1351 #endif
1352         DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1353         WRAP_RETURN(ret);
1354 }
1355
1356 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1357                                 const struct smb_filename *smb_fname,
1358                                 const char *name,
1359                                 const void *value,
1360                                 size_t size,
1361                                 int flags)
1362 {
1363         int ret;
1364         DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1365                         smb_fname->base_name, name, value, llu(size), flags);
1366         ret = ceph_setxattr(handle->data, smb_fname->base_name,
1367                         name, value, size, flags);
1368         DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1369         WRAP_RETURN(ret);
1370 }
1371
1372 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1373 {
1374         int ret;
1375         DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1376 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1377         ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1378                              name, value, size, flags);
1379 #else
1380         ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1381 #endif
1382         DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1383         WRAP_RETURN(ret);
1384 }
1385
1386 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1387 {
1388
1389         /*
1390          * We do not support AIO yet.
1391          */
1392
1393         DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1394         errno = ENOTSUP;
1395         return false;
1396 }
1397
1398 static struct vfs_fn_pointers ceph_fns = {
1399         /* Disk operations */
1400
1401         .connect_fn = cephwrap_connect,
1402         .disconnect_fn = cephwrap_disconnect,
1403         .disk_free_fn = cephwrap_disk_free,
1404         .get_quota_fn = cephwrap_get_quota,
1405         .set_quota_fn = cephwrap_set_quota,
1406         .statvfs_fn = cephwrap_statvfs,
1407         .fs_capabilities_fn = cephwrap_fs_capabilities,
1408
1409         /* Directory operations */
1410
1411         .opendir_fn = cephwrap_opendir,
1412         .fdopendir_fn = cephwrap_fdopendir,
1413         .readdir_fn = cephwrap_readdir,
1414         .seekdir_fn = cephwrap_seekdir,
1415         .telldir_fn = cephwrap_telldir,
1416         .rewind_dir_fn = cephwrap_rewinddir,
1417         .mkdir_fn = cephwrap_mkdir,
1418         .rmdir_fn = cephwrap_rmdir,
1419         .closedir_fn = cephwrap_closedir,
1420
1421         /* File operations */
1422
1423         .open_fn = cephwrap_open,
1424         .close_fn = cephwrap_close,
1425         .pread_fn = cephwrap_pread,
1426         .pread_send_fn = cephwrap_pread_send,
1427         .pread_recv_fn = cephwrap_pread_recv,
1428         .pwrite_fn = cephwrap_pwrite,
1429         .pwrite_send_fn = cephwrap_pwrite_send,
1430         .pwrite_recv_fn = cephwrap_pwrite_recv,
1431         .lseek_fn = cephwrap_lseek,
1432         .sendfile_fn = cephwrap_sendfile,
1433         .recvfile_fn = cephwrap_recvfile,
1434         .rename_fn = cephwrap_rename,
1435         .fsync_send_fn = cephwrap_fsync_send,
1436         .fsync_recv_fn = cephwrap_fsync_recv,
1437         .stat_fn = cephwrap_stat,
1438         .fstat_fn = cephwrap_fstat,
1439         .lstat_fn = cephwrap_lstat,
1440         .unlink_fn = cephwrap_unlink,
1441         .chmod_fn = cephwrap_chmod,
1442         .fchmod_fn = cephwrap_fchmod,
1443         .chown_fn = cephwrap_chown,
1444         .fchown_fn = cephwrap_fchown,
1445         .lchown_fn = cephwrap_lchown,
1446         .chdir_fn = cephwrap_chdir,
1447         .getwd_fn = cephwrap_getwd,
1448         .ntimes_fn = cephwrap_ntimes,
1449         .ftruncate_fn = cephwrap_ftruncate,
1450         .fallocate_fn = cephwrap_fallocate,
1451         .lock_fn = cephwrap_lock,
1452         .kernel_flock_fn = cephwrap_kernel_flock,
1453         .linux_setlease_fn = cephwrap_linux_setlease,
1454         .getlock_fn = cephwrap_getlock,
1455         .symlink_fn = cephwrap_symlink,
1456         .readlink_fn = cephwrap_readlink,
1457         .link_fn = cephwrap_link,
1458         .mknod_fn = cephwrap_mknod,
1459         .realpath_fn = cephwrap_realpath,
1460         .chflags_fn = cephwrap_chflags,
1461         .get_real_filename_fn = cephwrap_get_real_filename,
1462         .connectpath_fn = cephwrap_connectpath,
1463
1464         /* EA operations. */
1465         .getxattr_fn = cephwrap_getxattr,
1466         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1467         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1468         .fgetxattr_fn = cephwrap_fgetxattr,
1469         .listxattr_fn = cephwrap_listxattr,
1470         .flistxattr_fn = cephwrap_flistxattr,
1471         .removexattr_fn = cephwrap_removexattr,
1472         .fremovexattr_fn = cephwrap_fremovexattr,
1473         .setxattr_fn = cephwrap_setxattr,
1474         .fsetxattr_fn = cephwrap_fsetxattr,
1475
1476         /* Posix ACL Operations */
1477         .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1478         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1479         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1480         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1481         .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1482         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1483         .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1484
1485         /* aio operations */
1486         .aio_force_fn = cephwrap_aio_force,
1487 };
1488
1489 static_decl_vfs;
1490 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1491 {
1492         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1493                                 "ceph", &ceph_fns);
1494 }