s3: add st_ex_file_id to struct stat_ex
[samba.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         /* OpenDir_fsp() falls back to regular open */
332         errno = ENOSYS;
333         return NULL;
334 }
335
336 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
337                                        DIR *dirp,
338                                        SMB_STRUCT_STAT *sbuf)
339 {
340         struct dirent *result;
341
342         DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
343         result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
344         DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
345
346         /* Default Posix readdir() does not give us stat info.
347          * Set to invalid to indicate we didn't return this info. */
348         if (sbuf)
349                 SET_STAT_INVALID(*sbuf);
350         return result;
351 }
352
353 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
354 {
355         DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
356         ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
357 }
358
359 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
360 {
361         long ret;
362         DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
363         ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
364         DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
365         WRAP_RETURN(ret);
366 }
367
368 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
369 {
370         DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
371         ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
372 }
373
374 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
375                           const struct smb_filename *smb_fname,
376                           mode_t mode)
377 {
378         int result;
379         char *parent = NULL;
380         const char *path = smb_fname->base_name;
381
382         DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
383
384         if (lp_inherit_acls(SNUM(handle->conn))
385             && parent_dirname(talloc_tos(), path, &parent, NULL)
386             && directory_has_default_acl(handle->conn, parent)) {
387                 mode = 0777;
388         }
389
390         TALLOC_FREE(parent);
391
392         result = ceph_mkdir(handle->data, path, mode);
393         return WRAP_RETURN(result);
394 }
395
396 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
397                         const struct smb_filename *smb_fname)
398 {
399         int result;
400
401         DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
402         result = ceph_rmdir(handle->data, smb_fname->base_name);
403         DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
404         WRAP_RETURN(result);
405 }
406
407 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
408 {
409         int result;
410
411         DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
412         result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
413         DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
414         WRAP_RETURN(result);
415 }
416
417 /* File operations */
418
419 static int cephwrap_open(struct vfs_handle_struct *handle,
420                         struct smb_filename *smb_fname,
421                         files_struct *fsp, int flags, mode_t mode)
422 {
423         int result = -ENOENT;
424         DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
425                   smb_fname_str_dbg(smb_fname), fsp, flags, mode);
426
427         if (smb_fname->stream_name) {
428                 goto out;
429         }
430
431         result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
432 out:
433         DBG_DEBUG("[CEPH] open(...) = %d\n", result);
434         WRAP_RETURN(result);
435 }
436
437 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
438 {
439         int result;
440
441         DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
442         result = ceph_close(handle->data, fsp->fh->fd);
443         DBG_DEBUG("[CEPH] close(...) = %d\n", result);
444
445         WRAP_RETURN(result);
446 }
447
448 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
449                         size_t n, off_t offset)
450 {
451         ssize_t result;
452
453         DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
454
455         result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
456         DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
457         WRAP_RETURN(result);
458 }
459
460 struct cephwrap_pread_state {
461         ssize_t bytes_read;
462         struct vfs_aio_state vfs_aio_state;
463 };
464
465 /*
466  * Fake up an async ceph read by calling the synchronous API.
467  */
468 static struct tevent_req *cephwrap_pread_send(struct vfs_handle_struct *handle,
469                                               TALLOC_CTX *mem_ctx,
470                                               struct tevent_context *ev,
471                                               struct files_struct *fsp,
472                                               void *data,
473                                               size_t n, off_t offset)
474 {
475         struct tevent_req *req = NULL;
476         struct cephwrap_pread_state *state = NULL;
477         int ret = -1;
478
479         DBG_DEBUG("[CEPH] %s\n", __func__);
480         req = tevent_req_create(mem_ctx, &state, struct cephwrap_pread_state);
481         if (req == NULL) {
482                 return NULL;
483         }
484
485         ret = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
486         if (ret < 0) {
487                 /* ceph returns -errno on error. */
488                 tevent_req_error(req, -ret);
489                 return tevent_req_post(req, ev);
490         }
491
492         state->bytes_read = ret;
493         tevent_req_done(req);
494         /* Return and schedule the completion of the call. */
495         return tevent_req_post(req, ev);
496 }
497
498 static ssize_t cephwrap_pread_recv(struct tevent_req *req,
499                                    struct vfs_aio_state *vfs_aio_state)
500 {
501         struct cephwrap_pread_state *state =
502                 tevent_req_data(req, struct cephwrap_pread_state);
503
504         DBG_DEBUG("[CEPH] %s\n", __func__);
505         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
506                 return -1;
507         }
508         *vfs_aio_state = state->vfs_aio_state;
509         return state->bytes_read;
510 }
511
512 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
513                         size_t n, off_t offset)
514 {
515         ssize_t result;
516
517         DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
518         result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
519         DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
520         WRAP_RETURN(result);
521 }
522
523 struct cephwrap_pwrite_state {
524         ssize_t bytes_written;
525         struct vfs_aio_state vfs_aio_state;
526 };
527
528 /*
529  * Fake up an async ceph write by calling the synchronous API.
530  */
531 static struct tevent_req *cephwrap_pwrite_send(struct vfs_handle_struct *handle,
532                                                TALLOC_CTX *mem_ctx,
533                                                struct tevent_context *ev,
534                                                struct files_struct *fsp,
535                                                const void *data,
536                                                size_t n, off_t offset)
537 {
538         struct tevent_req *req = NULL;
539         struct cephwrap_pwrite_state *state = NULL;
540         int ret = -1;
541
542         DBG_DEBUG("[CEPH] %s\n", __func__);
543         req = tevent_req_create(mem_ctx, &state, struct cephwrap_pwrite_state);
544         if (req == NULL) {
545                 return NULL;
546         }
547
548         ret = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
549         if (ret < 0) {
550                 /* ceph returns -errno on error. */
551                 tevent_req_error(req, -ret);
552                 return tevent_req_post(req, ev);
553         }
554
555         state->bytes_written = ret;
556         tevent_req_done(req);
557         /* Return and schedule the completion of the call. */
558         return tevent_req_post(req, ev);
559 }
560
561 static ssize_t cephwrap_pwrite_recv(struct tevent_req *req,
562                                     struct vfs_aio_state *vfs_aio_state)
563 {
564         struct cephwrap_pwrite_state *state =
565                 tevent_req_data(req, struct cephwrap_pwrite_state);
566
567         DBG_DEBUG("[CEPH] %s\n", __func__);
568         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
569                 return -1;
570         }
571         *vfs_aio_state = state->vfs_aio_state;
572         return state->bytes_written;
573 }
574
575 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
576 {
577         off_t result = 0;
578
579         DBG_DEBUG("[CEPH] cephwrap_lseek\n");
580         result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
581         WRAP_RETURN(result);
582 }
583
584 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
585                         off_t offset, size_t n)
586 {
587         /*
588          * We cannot support sendfile because libceph is in user space.
589          */
590         DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
591         errno = ENOTSUP;
592         return -1;
593 }
594
595 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
596                         int fromfd,
597                         files_struct *tofsp,
598                         off_t offset,
599                         size_t n)
600 {
601         /*
602          * We cannot support recvfile because libceph is in user space.
603          */
604         DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
605         errno=ENOTSUP;
606         return -1;
607 }
608
609 static int cephwrap_rename(struct vfs_handle_struct *handle,
610                           const struct smb_filename *smb_fname_src,
611                           const struct smb_filename *smb_fname_dst)
612 {
613         int result = -1;
614         DBG_DEBUG("[CEPH] cephwrap_rename\n");
615         if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
616                 errno = ENOENT;
617                 return result;
618         }
619
620         result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
621         WRAP_RETURN(result);
622 }
623
624 /*
625  * Fake up an async ceph fsync by calling the synchronous API.
626  */
627
628 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
629                                         TALLOC_CTX *mem_ctx,
630                                         struct tevent_context *ev,
631                                         files_struct *fsp)
632 {
633         struct tevent_req *req = NULL;
634         struct vfs_aio_state *state = NULL;
635         int ret = -1;
636
637         DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
638
639         req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
640         if (req == NULL) {
641                 return NULL;
642         }
643
644         /* Make sync call. */
645         ret = ceph_fsync(handle->data, fsp->fh->fd, false);
646
647         if (ret != 0) {
648                 /* ceph_fsync returns -errno on error. */
649                 tevent_req_error(req, -ret);
650                 return tevent_req_post(req, ev);
651         }
652
653         /* Mark it as done. */
654         tevent_req_done(req);
655         /* Return and schedule the completion of the call. */
656         return tevent_req_post(req, ev);
657 }
658
659 static int cephwrap_fsync_recv(struct tevent_req *req,
660                                 struct vfs_aio_state *vfs_aio_state)
661 {
662         struct vfs_aio_state *state =
663                 tevent_req_data(req, struct vfs_aio_state);
664
665         DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
666
667         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
668                 return -1;
669         }
670         *vfs_aio_state = *state;
671         return 0;
672 }
673
674 #ifdef HAVE_CEPH_STATX
675 #define SAMBA_STATX_ATTR_MASK   (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
676
677 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
678 {
679         DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, "
680                   "nlink = %llu, uid = %d, gid = %d, rdev = %llx, size = %llu, "
681                   "blksize = %llu, blocks = %llu, atime = %llu, mtime = %llu, "
682                   "ctime = %llu, btime = %llu}\n",
683                   llu(stx->stx_dev), llu(stx->stx_ino), stx->stx_mode,
684                   llu(stx->stx_nlink), stx->stx_uid, stx->stx_gid,
685                   llu(stx->stx_rdev), llu(stx->stx_size), llu(stx->stx_blksize),
686                   llu(stx->stx_blocks), llu(stx->stx_atime.tv_sec),
687                   llu(stx->stx_mtime.tv_sec), llu(stx->stx_ctime.tv_sec),
688                   llu(stx->stx_btime.tv_sec));
689
690         if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK) {
691                 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
692                                 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
693         }
694
695         dst->st_ex_dev = stx->stx_dev;
696         dst->st_ex_rdev = stx->stx_rdev;
697         dst->st_ex_ino = stx->stx_ino;
698         dst->st_ex_mode = stx->stx_mode;
699         dst->st_ex_uid = stx->stx_uid;
700         dst->st_ex_gid = stx->stx_gid;
701         dst->st_ex_size = stx->stx_size;
702         dst->st_ex_nlink = stx->stx_nlink;
703         dst->st_ex_atime = stx->stx_atime;
704         dst->st_ex_btime = stx->stx_btime;
705         dst->st_ex_ctime = stx->stx_ctime;
706         dst->st_ex_mtime = stx->stx_mtime;
707         dst->st_ex_itime = dst->st_ex_btime;
708         dst->st_ex_iflags = ST_EX_IFLAG_CALCULATED_ITIME;
709         dst->st_ex_blksize = stx->stx_blksize;
710         dst->st_ex_blocks = stx->stx_blocks;
711         dst->st_ex_file_id = dst->st_ex_ino;
712         dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
713 }
714
715 static int cephwrap_stat(struct vfs_handle_struct *handle,
716                         struct smb_filename *smb_fname)
717 {
718         int result = -1;
719         struct ceph_statx stx;
720
721         DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
722
723         if (smb_fname->stream_name) {
724                 errno = ENOENT;
725                 return result;
726         }
727
728         result = ceph_statx(handle->data, smb_fname->base_name, &stx,
729                                 SAMBA_STATX_ATTR_MASK, 0);
730         DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
731         if (result < 0) {
732                 WRAP_RETURN(result);
733         }
734
735         init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
736         DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
737         return result;
738 }
739
740 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
741 {
742         int result = -1;
743         struct ceph_statx stx;
744
745         DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
746         result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
747                                 SAMBA_STATX_ATTR_MASK, 0);
748         DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
749         if (result < 0) {
750                 WRAP_RETURN(result);
751         }
752
753         init_stat_ex_from_ceph_statx(sbuf, &stx);
754         DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
755         return result;
756 }
757
758 static int cephwrap_lstat(struct vfs_handle_struct *handle,
759                          struct smb_filename *smb_fname)
760 {
761         int result = -1;
762         struct ceph_statx stx;
763
764         DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
765
766         if (smb_fname->stream_name) {
767                 errno = ENOENT;
768                 return result;
769         }
770
771         result = ceph_statx(handle->data, smb_fname->base_name, &stx,
772                                 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
773         DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
774         if (result < 0) {
775                 WRAP_RETURN(result);
776         }
777
778         init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
779         return result;
780 }
781
782 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
783                          const struct smb_filename *smb_fname,
784                          struct smb_file_time *ft)
785 {
786         struct ceph_statx stx = { 0 };
787         int result;
788         int mask = 0;
789
790         if (!null_timespec(ft->atime)) {
791                 stx.stx_atime = ft->atime;
792                 mask |= CEPH_SETATTR_ATIME;
793         }
794         if (!null_timespec(ft->mtime)) {
795                 stx.stx_mtime = ft->mtime;
796                 mask |= CEPH_SETATTR_MTIME;
797         }
798         if (!null_timespec(ft->create_time)) {
799                 stx.stx_btime = ft->create_time;
800                 mask |= CEPH_SETATTR_BTIME;
801         }
802
803         if (!mask) {
804                 return 0;
805         }
806
807         result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
808         DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
809                                 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
810                                 ft->create_time.tv_sec, result);
811         return result;
812 }
813
814 #else /* HAVE_CEPH_STATX */
815
816 static int cephwrap_stat(struct vfs_handle_struct *handle,
817                         struct smb_filename *smb_fname)
818 {
819         int result = -1;
820         struct stat stbuf;
821
822         DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
823
824         if (smb_fname->stream_name) {
825                 errno = ENOENT;
826                 return result;
827         }
828
829         result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
830         DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
831         if (result < 0) {
832                 WRAP_RETURN(result);
833         }
834
835         DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
836                    "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
837                    "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
838                    llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
839                    stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
840                    llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
841
842         init_stat_ex_from_stat(
843                         &smb_fname->st, &stbuf,
844                         lp_fake_directory_create_times(SNUM(handle->conn)));
845         DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
846         return result;
847 }
848
849 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
850 {
851         int result = -1;
852         struct stat stbuf;
853
854         DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
855         result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
856         DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
857         if (result < 0) {
858                 WRAP_RETURN(result);
859         }
860
861         DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
862                    "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
863                    "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
864                    llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
865                    stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
866                    llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
867
868         init_stat_ex_from_stat(
869                         sbuf, &stbuf,
870                         lp_fake_directory_create_times(SNUM(handle->conn)));
871         DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
872         return result;
873 }
874
875 static int cephwrap_lstat(struct vfs_handle_struct *handle,
876                          struct smb_filename *smb_fname)
877 {
878         int result = -1;
879         struct stat stbuf;
880
881         DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
882
883         if (smb_fname->stream_name) {
884                 errno = ENOENT;
885                 return result;
886         }
887
888         result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
889         DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
890         if (result < 0) {
891                 WRAP_RETURN(result);
892         }
893
894         init_stat_ex_from_stat(
895                         &smb_fname->st, &stbuf,
896                         lp_fake_directory_create_times(SNUM(handle->conn)));
897         return result;
898 }
899
900 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
901                          const struct smb_filename *smb_fname,
902                          struct smb_file_time *ft)
903 {
904         struct utimbuf buf;
905         int result;
906
907         if (null_timespec(ft->atime)) {
908                 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
909         } else {
910                 buf.actime = ft->atime.tv_sec;
911         }
912         if (null_timespec(ft->mtime)) {
913                 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
914         } else {
915                 buf.modtime = ft->mtime.tv_sec;
916         }
917         if (!null_timespec(ft->create_time)) {
918                 set_create_timespec_ea(handle->conn, smb_fname,
919                                        ft->create_time);
920         }
921         if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
922             buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
923                 return 0;
924         }
925
926         result = ceph_utime(handle->data, smb_fname->base_name, &buf);
927         DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
928                                 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
929                                 ft->create_time.tv_sec, result);
930         return result;
931 }
932 #endif /* HAVE_CEPH_STATX */
933
934 static int cephwrap_unlink(struct vfs_handle_struct *handle,
935                           const struct smb_filename *smb_fname)
936 {
937         int result = -1;
938
939         DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
940         if (smb_fname->stream_name) {
941                 errno = ENOENT;
942                 return result;
943         }
944         result = ceph_unlink(handle->data, smb_fname->base_name);
945         DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
946         WRAP_RETURN(result);
947 }
948
949 static int cephwrap_chmod(struct vfs_handle_struct *handle,
950                         const struct smb_filename *smb_fname,
951                         mode_t mode)
952 {
953         int result;
954
955         DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
956         result = ceph_chmod(handle->data, smb_fname->base_name, mode);
957         DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
958         WRAP_RETURN(result);
959 }
960
961 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
962 {
963         int result;
964
965         DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
966         result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
967         DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
968         WRAP_RETURN(result);
969 }
970
971 static int cephwrap_chown(struct vfs_handle_struct *handle,
972                         const struct smb_filename *smb_fname,
973                         uid_t uid,
974                         gid_t gid)
975 {
976         int result;
977         DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
978         result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
979         DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
980         WRAP_RETURN(result);
981 }
982
983 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
984 {
985         int result;
986
987         DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
988         result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
989         DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
990         WRAP_RETURN(result);
991 }
992
993 static int cephwrap_lchown(struct vfs_handle_struct *handle,
994                         const struct smb_filename *smb_fname,
995                         uid_t uid,
996                         gid_t gid)
997 {
998         int result;
999         DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1000         result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
1001         DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
1002         WRAP_RETURN(result);
1003 }
1004
1005 static int cephwrap_chdir(struct vfs_handle_struct *handle,
1006                         const struct smb_filename *smb_fname)
1007 {
1008         int result = -1;
1009         DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
1010         result = ceph_chdir(handle->data, smb_fname->base_name);
1011         DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
1012         WRAP_RETURN(result);
1013 }
1014
1015 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
1016                         TALLOC_CTX *ctx)
1017 {
1018         const char *cwd = ceph_getcwd(handle->data);
1019         DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
1020         return synthetic_smb_fname(ctx,
1021                                 cwd,
1022                                 NULL,
1023                                 NULL,
1024                                 0);
1025 }
1026
1027 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1028 {
1029         off_t space_to_write;
1030         int result;
1031         NTSTATUS status;
1032         SMB_STRUCT_STAT *pst;
1033
1034         status = vfs_stat_fsp(fsp);
1035         if (!NT_STATUS_IS_OK(status)) {
1036                 return -1;
1037         }
1038         pst = &fsp->fsp_name->st;
1039
1040 #ifdef S_ISFIFO
1041         if (S_ISFIFO(pst->st_ex_mode))
1042                 return 0;
1043 #endif
1044
1045         if (pst->st_ex_size == len)
1046                 return 0;
1047
1048         /* Shrink - just ftruncate. */
1049         if (pst->st_ex_size > len) {
1050                 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1051                 WRAP_RETURN(result);
1052         }
1053
1054         space_to_write = len - pst->st_ex_size;
1055         result = ceph_fallocate(handle->data, fsp->fh->fd, 0, pst->st_ex_size,
1056                                 space_to_write);
1057         WRAP_RETURN(result);
1058 }
1059
1060 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1061 {
1062         int result = -1;
1063
1064         DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1065
1066         if (lp_strict_allocate(SNUM(fsp->conn))) {
1067                 return strict_allocate_ftruncate(handle, fsp, len);
1068         }
1069
1070         result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1071         WRAP_RETURN(result);
1072 }
1073
1074 static int cephwrap_fallocate(struct vfs_handle_struct *handle,
1075                               struct files_struct *fsp,
1076                               uint32_t mode,
1077                               off_t offset,
1078                               off_t len)
1079 {
1080         int result;
1081
1082         DBG_DEBUG("[CEPH] fallocate(%p, %p, %u, %llu, %llu\n",
1083                   handle, fsp, mode, llu(offset), llu(len));
1084         /* unsupported mode flags are rejected by libcephfs */
1085         result = ceph_fallocate(handle->data, fsp->fh->fd, mode, offset, len);
1086         DBG_DEBUG("[CEPH] fallocate(...) = %d\n", result);
1087         WRAP_RETURN(result);
1088 }
1089
1090 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1091 {
1092         DBG_DEBUG("[CEPH] lock\n");
1093         return true;
1094 }
1095
1096 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1097                                 uint32_t share_mode, uint32_t access_mask)
1098 {
1099         DBG_ERR("[CEPH] flock unsupported! Consider setting "
1100                 "\"kernel share modes = no\"\n");
1101
1102         errno = ENOSYS;
1103         return -1;
1104 }
1105
1106 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1107 {
1108         DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1109
1110         errno = 0;
1111         return false;
1112 }
1113
1114 /*
1115  * We cannot let this fall through to the default, because the file might only
1116  * be accessible from libceph (which is a user-space client) but the fd might
1117  * be for some file the kernel knows about.
1118  */
1119 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1120                                 int leasetype)
1121 {
1122         int result = -1;
1123
1124         DBG_DEBUG("[CEPH] linux_setlease\n");
1125         errno = ENOSYS;
1126         return result;
1127 }
1128
1129 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1130                 const char *link_target,
1131                 const struct smb_filename *new_smb_fname)
1132 {
1133         int result = -1;
1134         DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1135                         link_target,
1136                         new_smb_fname->base_name);
1137         result = ceph_symlink(handle->data,
1138                         link_target,
1139                         new_smb_fname->base_name);
1140         DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1141         WRAP_RETURN(result);
1142 }
1143
1144 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1145                 const struct smb_filename *smb_fname,
1146                 char *buf,
1147                 size_t bufsiz)
1148 {
1149         int result = -1;
1150         DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1151                         smb_fname->base_name, buf, llu(bufsiz));
1152         result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1153         DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1154         WRAP_RETURN(result);
1155 }
1156
1157 static int cephwrap_link(struct vfs_handle_struct *handle,
1158                 const struct smb_filename *old_smb_fname,
1159                 const struct smb_filename *new_smb_fname)
1160 {
1161         int result = -1;
1162         DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1163                         old_smb_fname->base_name,
1164                         new_smb_fname->base_name);
1165         result = ceph_link(handle->data,
1166                                 old_smb_fname->base_name,
1167                                 new_smb_fname->base_name);
1168         DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1169         WRAP_RETURN(result);
1170 }
1171
1172 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1173                 const struct smb_filename *smb_fname,
1174                 mode_t mode,
1175                 SMB_DEV_T dev)
1176 {
1177         int result = -1;
1178         DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1179         result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1180         DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1181         WRAP_RETURN(result);
1182 }
1183
1184 /*
1185  * This is a simple version of real-path ... a better version is needed to
1186  * ask libceph about symbolic links.
1187  */
1188 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1189                                 TALLOC_CTX *ctx,
1190                                 const struct smb_filename *smb_fname)
1191 {
1192         char *result = NULL;
1193         const char *path = smb_fname->base_name;
1194         size_t len = strlen(path);
1195         struct smb_filename *result_fname = NULL;
1196         int r = -1;
1197
1198         if (len && (path[0] == '/')) {
1199                 r = asprintf(&result, "%s", path);
1200         } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1201                 if (len == 2) {
1202                         r = asprintf(&result, "%s",
1203                                         handle->conn->cwd_fname->base_name);
1204                 } else {
1205                         r = asprintf(&result, "%s/%s",
1206                                         handle->conn->cwd_fname->base_name, &path[2]);
1207                 }
1208         } else {
1209                 r = asprintf(&result, "%s/%s",
1210                                 handle->conn->cwd_fname->base_name, path);
1211         }
1212
1213         if (r < 0) {
1214                 return NULL;
1215         }
1216
1217         DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1218         result_fname = synthetic_smb_fname(ctx,
1219                                 result,
1220                                 NULL,
1221                                 NULL,
1222                                 0);
1223         SAFE_FREE(result);
1224         return result_fname;
1225 }
1226
1227 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1228                         const struct smb_filename *smb_fname,
1229                         unsigned int flags)
1230 {
1231         errno = ENOSYS;
1232         return -1;
1233 }
1234
1235 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1236                                      const char *path,
1237                                      const char *name,
1238                                      TALLOC_CTX *mem_ctx,
1239                                      char **found_name)
1240 {
1241         /*
1242          * Don't fall back to get_real_filename so callers can differentiate
1243          * between a full directory scan and an actual case-insensitive stat.
1244          */
1245         errno = EOPNOTSUPP;
1246         return -1;
1247 }
1248
1249 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1250                                        const struct smb_filename *smb_fname)
1251 {
1252         return handle->conn->connectpath;
1253 }
1254
1255 /****************************************************************
1256  Extended attribute operations.
1257 *****************************************************************/
1258
1259 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1260                         const struct smb_filename *smb_fname,
1261                         const char *name,
1262                         void *value,
1263                         size_t size)
1264 {
1265         int ret;
1266         DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1267                         smb_fname->base_name, name, value, llu(size));
1268         ret = ceph_getxattr(handle->data,
1269                         smb_fname->base_name, name, value, size);
1270         DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1271         if (ret < 0) {
1272                 WRAP_RETURN(ret);
1273         }
1274         return (ssize_t)ret;
1275 }
1276
1277 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1278 {
1279         int ret;
1280         DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1281 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1282         ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1283 #else
1284         ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1285 #endif
1286         DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1287         if (ret < 0) {
1288                 WRAP_RETURN(ret);
1289         }
1290         return (ssize_t)ret;
1291 }
1292
1293 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1294                         const struct smb_filename *smb_fname,
1295                         char *list,
1296                         size_t size)
1297 {
1298         int ret;
1299         DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1300                         smb_fname->base_name, list, llu(size));
1301         ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1302         DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1303         if (ret < 0) {
1304                 WRAP_RETURN(ret);
1305         }
1306         return (ssize_t)ret;
1307 }
1308
1309 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1310 {
1311         int ret;
1312         DBG_DEBUG("[CEPH] flistxattr(%p, %p, %p, %llu)\n",
1313                   handle, fsp, list, llu(size));
1314 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1315         ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1316 #else
1317         ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1318 #endif
1319         DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1320         if (ret < 0) {
1321                 WRAP_RETURN(ret);
1322         }
1323         return (ssize_t)ret;
1324 }
1325
1326 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1327                                 const struct smb_filename *smb_fname,
1328                                 const char *name)
1329 {
1330         int ret;
1331         DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1332                         smb_fname->base_name, name);
1333         ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1334         DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1335         WRAP_RETURN(ret);
1336 }
1337
1338 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1339 {
1340         int ret;
1341         DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1342 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1343         ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1344 #else
1345         ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1346 #endif
1347         DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1348         WRAP_RETURN(ret);
1349 }
1350
1351 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1352                                 const struct smb_filename *smb_fname,
1353                                 const char *name,
1354                                 const void *value,
1355                                 size_t size,
1356                                 int flags)
1357 {
1358         int ret;
1359         DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1360                         smb_fname->base_name, name, value, llu(size), flags);
1361         ret = ceph_setxattr(handle->data, smb_fname->base_name,
1362                         name, value, size, flags);
1363         DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1364         WRAP_RETURN(ret);
1365 }
1366
1367 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1368 {
1369         int ret;
1370         DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1371 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1372         ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1373                              name, value, size, flags);
1374 #else
1375         ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1376 #endif
1377         DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1378         WRAP_RETURN(ret);
1379 }
1380
1381 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1382 {
1383
1384         /*
1385          * We do not support AIO yet.
1386          */
1387
1388         DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1389         errno = ENOTSUP;
1390         return false;
1391 }
1392
1393 static struct vfs_fn_pointers ceph_fns = {
1394         /* Disk operations */
1395
1396         .connect_fn = cephwrap_connect,
1397         .disconnect_fn = cephwrap_disconnect,
1398         .disk_free_fn = cephwrap_disk_free,
1399         .get_quota_fn = cephwrap_get_quota,
1400         .set_quota_fn = cephwrap_set_quota,
1401         .statvfs_fn = cephwrap_statvfs,
1402         .fs_capabilities_fn = cephwrap_fs_capabilities,
1403
1404         /* Directory operations */
1405
1406         .opendir_fn = cephwrap_opendir,
1407         .fdopendir_fn = cephwrap_fdopendir,
1408         .readdir_fn = cephwrap_readdir,
1409         .seekdir_fn = cephwrap_seekdir,
1410         .telldir_fn = cephwrap_telldir,
1411         .rewind_dir_fn = cephwrap_rewinddir,
1412         .mkdir_fn = cephwrap_mkdir,
1413         .rmdir_fn = cephwrap_rmdir,
1414         .closedir_fn = cephwrap_closedir,
1415
1416         /* File operations */
1417
1418         .open_fn = cephwrap_open,
1419         .close_fn = cephwrap_close,
1420         .pread_fn = cephwrap_pread,
1421         .pread_send_fn = cephwrap_pread_send,
1422         .pread_recv_fn = cephwrap_pread_recv,
1423         .pwrite_fn = cephwrap_pwrite,
1424         .pwrite_send_fn = cephwrap_pwrite_send,
1425         .pwrite_recv_fn = cephwrap_pwrite_recv,
1426         .lseek_fn = cephwrap_lseek,
1427         .sendfile_fn = cephwrap_sendfile,
1428         .recvfile_fn = cephwrap_recvfile,
1429         .rename_fn = cephwrap_rename,
1430         .fsync_send_fn = cephwrap_fsync_send,
1431         .fsync_recv_fn = cephwrap_fsync_recv,
1432         .stat_fn = cephwrap_stat,
1433         .fstat_fn = cephwrap_fstat,
1434         .lstat_fn = cephwrap_lstat,
1435         .unlink_fn = cephwrap_unlink,
1436         .chmod_fn = cephwrap_chmod,
1437         .fchmod_fn = cephwrap_fchmod,
1438         .chown_fn = cephwrap_chown,
1439         .fchown_fn = cephwrap_fchown,
1440         .lchown_fn = cephwrap_lchown,
1441         .chdir_fn = cephwrap_chdir,
1442         .getwd_fn = cephwrap_getwd,
1443         .ntimes_fn = cephwrap_ntimes,
1444         .ftruncate_fn = cephwrap_ftruncate,
1445         .fallocate_fn = cephwrap_fallocate,
1446         .lock_fn = cephwrap_lock,
1447         .kernel_flock_fn = cephwrap_kernel_flock,
1448         .linux_setlease_fn = cephwrap_linux_setlease,
1449         .getlock_fn = cephwrap_getlock,
1450         .symlink_fn = cephwrap_symlink,
1451         .readlink_fn = cephwrap_readlink,
1452         .link_fn = cephwrap_link,
1453         .mknod_fn = cephwrap_mknod,
1454         .realpath_fn = cephwrap_realpath,
1455         .chflags_fn = cephwrap_chflags,
1456         .get_real_filename_fn = cephwrap_get_real_filename,
1457         .connectpath_fn = cephwrap_connectpath,
1458
1459         /* EA operations. */
1460         .getxattr_fn = cephwrap_getxattr,
1461         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1462         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1463         .fgetxattr_fn = cephwrap_fgetxattr,
1464         .listxattr_fn = cephwrap_listxattr,
1465         .flistxattr_fn = cephwrap_flistxattr,
1466         .removexattr_fn = cephwrap_removexattr,
1467         .fremovexattr_fn = cephwrap_fremovexattr,
1468         .setxattr_fn = cephwrap_setxattr,
1469         .fsetxattr_fn = cephwrap_fsetxattr,
1470
1471         /* Posix ACL Operations */
1472         .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1473         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1474         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1475         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1476         .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1477         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1478         .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1479
1480         /* aio operations */
1481         .aio_force_fn = cephwrap_aio_force,
1482 };
1483
1484 static_decl_vfs;
1485 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1486 {
1487         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1488                                 "ceph", &ceph_fns);
1489 }