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