s3: modules: vfs_ceph: Remove CHMOD_ACL in cephwrap_mkdir().
[vlendec/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
950         /*
951          * We need to do this due to the fact that the default POSIX ACL
952          * chmod modifies the ACL *mask* for the group owner, not the
953          * group owner bits directly. JRA.
954          */
955
956
957         {
958                 int saved_errno = errno; /* We might get ENOSYS */
959                 result = SMB_VFS_CHMOD_ACL(handle->conn,
960                                         smb_fname,
961                                         mode);
962                 if (result == 0) {
963                         return result;
964                 }
965                 /* Error - return the old errno. */
966                 errno = saved_errno;
967         }
968
969         result = ceph_chmod(handle->data, smb_fname->base_name, mode);
970         DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
971         WRAP_RETURN(result);
972 }
973
974 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
975 {
976         int result;
977
978         DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
979
980         /*
981          * We need to do this due to the fact that the default POSIX ACL
982          * chmod modifies the ACL *mask* for the group owner, not the
983          * group owner bits directly. JRA.
984          */
985
986         {
987                 int saved_errno = errno; /* We might get ENOSYS */
988                 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
989                         return result;
990                 }
991                 /* Error - return the old errno. */
992                 errno = saved_errno;
993         }
994
995 #if defined(HAVE_FCHMOD)
996         result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
997         DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
998         WRAP_RETURN(result);
999 #else
1000         errno = ENOSYS;
1001 #endif
1002         return -1;
1003 }
1004
1005 static int cephwrap_chown(struct vfs_handle_struct *handle,
1006                         const struct smb_filename *smb_fname,
1007                         uid_t uid,
1008                         gid_t gid)
1009 {
1010         int result;
1011         DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1012         result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
1013         DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
1014         WRAP_RETURN(result);
1015 }
1016
1017 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
1018 {
1019         int result;
1020 #ifdef HAVE_FCHOWN
1021
1022         DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
1023         result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
1024         DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
1025         WRAP_RETURN(result);
1026 #else
1027         errno = ENOSYS;
1028         result = -1;
1029 #endif
1030         return result;
1031 }
1032
1033 static int cephwrap_lchown(struct vfs_handle_struct *handle,
1034                         const struct smb_filename *smb_fname,
1035                         uid_t uid,
1036                         gid_t gid)
1037 {
1038         int result;
1039         DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1040         result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
1041         DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
1042         WRAP_RETURN(result);
1043 }
1044
1045 static int cephwrap_chdir(struct vfs_handle_struct *handle,
1046                         const struct smb_filename *smb_fname)
1047 {
1048         int result = -1;
1049         DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
1050         result = ceph_chdir(handle->data, smb_fname->base_name);
1051         DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
1052         WRAP_RETURN(result);
1053 }
1054
1055 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
1056                         TALLOC_CTX *ctx)
1057 {
1058         const char *cwd = ceph_getcwd(handle->data);
1059         DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
1060         return synthetic_smb_fname(ctx,
1061                                 cwd,
1062                                 NULL,
1063                                 NULL,
1064                                 0);
1065 }
1066
1067 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1068 {
1069         off_t space_to_write;
1070         uint64_t space_avail;
1071         uint64_t bsize,dfree,dsize;
1072         int ret;
1073         NTSTATUS status;
1074         SMB_STRUCT_STAT *pst;
1075
1076         status = vfs_stat_fsp(fsp);
1077         if (!NT_STATUS_IS_OK(status)) {
1078                 return -1;
1079         }
1080         pst = &fsp->fsp_name->st;
1081
1082 #ifdef S_ISFIFO
1083         if (S_ISFIFO(pst->st_ex_mode))
1084                 return 0;
1085 #endif
1086
1087         if (pst->st_ex_size == len)
1088                 return 0;
1089
1090         /* Shrink - just ftruncate. */
1091         if (pst->st_ex_size > len)
1092                 return ftruncate(fsp->fh->fd, len);
1093
1094         space_to_write = len - pst->st_ex_size;
1095
1096         /* for allocation try fallocate first. This can fail on some
1097            platforms e.g. when the filesystem doesn't support it and no
1098            emulation is being done by the libc (like on AIX with JFS1). In that
1099            case we do our own emulation. fallocate implementations can
1100            return ENOTSUP or EINVAL in cases like that. */
1101         ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1102         if (ret == -1 && errno == ENOSPC) {
1103                 return -1;
1104         }
1105         if (ret == 0) {
1106                 return 0;
1107         }
1108         DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1109                 "error %d. Falling back to slow manual allocation\n", errno));
1110
1111         /* available disk space is enough or not? */
1112         space_avail =
1113             get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1114         /* space_avail is 1k blocks */
1115         if (space_avail == (uint64_t)-1 ||
1116                         ((uint64_t)space_to_write/1024 > space_avail) ) {
1117                 errno = ENOSPC;
1118                 return -1;
1119         }
1120
1121         /* Write out the real space on disk. */
1122         return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1123 }
1124
1125 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1126 {
1127         int result = -1;
1128         SMB_STRUCT_STAT st;
1129         char c = 0;
1130         off_t currpos;
1131
1132         DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1133
1134         if (lp_strict_allocate(SNUM(fsp->conn))) {
1135                 result = strict_allocate_ftruncate(handle, fsp, len);
1136                 return result;
1137         }
1138
1139         /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1140            sys_ftruncate if the system supports it. Then I discovered that
1141            you can have some filesystems that support ftruncate
1142            expansion and some that don't! On Linux fat can't do
1143            ftruncate extend but ext2 can. */
1144
1145         result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1146         if (result == 0)
1147                 goto done;
1148
1149         /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1150            extend a file with ftruncate. Provide alternate implementation
1151            for this */
1152         currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1153         if (currpos == -1) {
1154                 goto done;
1155         }
1156
1157         /* Do an fstat to see if the file is longer than the requested
1158            size in which case the ftruncate above should have
1159            succeeded or shorter, in which case seek to len - 1 and
1160            write 1 byte of zero */
1161         if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1162                 goto done;
1163         }
1164
1165 #ifdef S_ISFIFO
1166         if (S_ISFIFO(st.st_ex_mode)) {
1167                 result = 0;
1168                 goto done;
1169         }
1170 #endif
1171
1172         if (st.st_ex_size == len) {
1173                 result = 0;
1174                 goto done;
1175         }
1176
1177         if (st.st_ex_size > len) {
1178                 /* the sys_ftruncate should have worked */
1179                 goto done;
1180         }
1181
1182         if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
1183                 goto done;
1184         }
1185
1186         result = 0;
1187
1188   done:
1189
1190         return result;
1191 }
1192
1193 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1194 {
1195         DBG_DEBUG("[CEPH] lock\n");
1196         return true;
1197 }
1198
1199 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1200                                 uint32_t share_mode, uint32_t access_mask)
1201 {
1202         DBG_DEBUG("[CEPH] kernel_flock\n");
1203         /*
1204          * We must return zero here and pretend all is good.
1205          * One day we might have this in CEPH.
1206          */
1207         return 0;
1208 }
1209
1210 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1211 {
1212         DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1213
1214         errno = 0;
1215         return false;
1216 }
1217
1218 /*
1219  * We cannot let this fall through to the default, because the file might only
1220  * be accessible from libceph (which is a user-space client) but the fd might
1221  * be for some file the kernel knows about.
1222  */
1223 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1224                                 int leasetype)
1225 {
1226         int result = -1;
1227
1228         DBG_DEBUG("[CEPH] linux_setlease\n");
1229         errno = ENOSYS;
1230         return result;
1231 }
1232
1233 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1234                 const char *link_target,
1235                 const struct smb_filename *new_smb_fname)
1236 {
1237         int result = -1;
1238         DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1239                         link_target,
1240                         new_smb_fname->base_name);
1241         result = ceph_symlink(handle->data,
1242                         link_target,
1243                         new_smb_fname->base_name);
1244         DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1245         WRAP_RETURN(result);
1246 }
1247
1248 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1249                 const struct smb_filename *smb_fname,
1250                 char *buf,
1251                 size_t bufsiz)
1252 {
1253         int result = -1;
1254         DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1255                         smb_fname->base_name, buf, llu(bufsiz));
1256         result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1257         DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1258         WRAP_RETURN(result);
1259 }
1260
1261 static int cephwrap_link(struct vfs_handle_struct *handle,
1262                 const struct smb_filename *old_smb_fname,
1263                 const struct smb_filename *new_smb_fname)
1264 {
1265         int result = -1;
1266         DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1267                         old_smb_fname->base_name,
1268                         new_smb_fname->base_name);
1269         result = ceph_link(handle->data,
1270                                 old_smb_fname->base_name,
1271                                 new_smb_fname->base_name);
1272         DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1273         WRAP_RETURN(result);
1274 }
1275
1276 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1277                 const struct smb_filename *smb_fname,
1278                 mode_t mode,
1279                 SMB_DEV_T dev)
1280 {
1281         int result = -1;
1282         DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1283         result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1284         DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1285         WRAP_RETURN(result);
1286 }
1287
1288 /*
1289  * This is a simple version of real-path ... a better version is needed to
1290  * ask libceph about symbolic links.
1291  */
1292 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1293                                 TALLOC_CTX *ctx,
1294                                 const struct smb_filename *smb_fname)
1295 {
1296         char *result = NULL;
1297         const char *path = smb_fname->base_name;
1298         size_t len = strlen(path);
1299         struct smb_filename *result_fname = NULL;
1300         int r = -1;
1301
1302         if (len && (path[0] == '/')) {
1303                 r = asprintf(&result, "%s", path);
1304         } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1305                 if (len == 2) {
1306                         r = asprintf(&result, "%s",
1307                                         handle->conn->connectpath);
1308                 } else {
1309                         r = asprintf(&result, "%s/%s",
1310                                         handle->conn->connectpath, &path[2]);
1311                 }
1312         } else {
1313                 r = asprintf(&result, "%s/%s",
1314                                 handle->conn->connectpath, path);
1315         }
1316
1317         if (r < 0) {
1318                 return NULL;
1319         }
1320
1321         DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1322         result_fname = synthetic_smb_fname(ctx,
1323                                 result,
1324                                 NULL,
1325                                 NULL,
1326                                 0);
1327         SAFE_FREE(result);
1328         return result_fname;
1329 }
1330
1331 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1332                         const struct smb_filename *smb_fname,
1333                         unsigned int flags)
1334 {
1335         errno = ENOSYS;
1336         return -1;
1337 }
1338
1339 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1340                                      const char *path,
1341                                      const char *name,
1342                                      TALLOC_CTX *mem_ctx,
1343                                      char **found_name)
1344 {
1345         /*
1346          * Don't fall back to get_real_filename so callers can differentiate
1347          * between a full directory scan and an actual case-insensitive stat.
1348          */
1349         errno = EOPNOTSUPP;
1350         return -1;
1351 }
1352
1353 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1354                                        const struct smb_filename *smb_fname)
1355 {
1356         return handle->conn->connectpath;
1357 }
1358
1359 /****************************************************************
1360  Extended attribute operations.
1361 *****************************************************************/
1362
1363 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1364                         const struct smb_filename *smb_fname,
1365                         const char *name,
1366                         void *value,
1367                         size_t size)
1368 {
1369         int ret;
1370         DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1371                         smb_fname->base_name, name, value, llu(size));
1372         ret = ceph_getxattr(handle->data,
1373                         smb_fname->base_name, name, value, size);
1374         DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1375         if (ret < 0) {
1376                 WRAP_RETURN(ret);
1377         } else {
1378                 return (ssize_t)ret;
1379         }
1380 }
1381
1382 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1383 {
1384         int ret;
1385         DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1386 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1387         ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1388 #else
1389         ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1390 #endif
1391         DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1392         if (ret < 0) {
1393                 WRAP_RETURN(ret);
1394         } else {
1395                 return (ssize_t)ret;
1396         }
1397 }
1398
1399 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1400                         const struct smb_filename *smb_fname,
1401                         char *list,
1402                         size_t size)
1403 {
1404         int ret;
1405         DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1406                         smb_fname->base_name, list, llu(size));
1407         ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1408         DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1409         if (ret < 0) {
1410                 WRAP_RETURN(ret);
1411         } else {
1412                 return (ssize_t)ret;
1413         }
1414 }
1415
1416 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1417 {
1418         int ret;
1419         DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1420 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1421         ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1422 #else
1423         ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1424 #endif
1425         DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1426         if (ret < 0) {
1427                 WRAP_RETURN(ret);
1428         } else {
1429                 return (ssize_t)ret;
1430         }
1431 }
1432
1433 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1434                                 const struct smb_filename *smb_fname,
1435                                 const char *name)
1436 {
1437         int ret;
1438         DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1439                         smb_fname->base_name, name);
1440         ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1441         DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1442         WRAP_RETURN(ret);
1443 }
1444
1445 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1446 {
1447         int ret;
1448         DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1449 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1450         ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1451 #else
1452         ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1453 #endif
1454         DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1455         WRAP_RETURN(ret);
1456 }
1457
1458 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1459                                 const struct smb_filename *smb_fname,
1460                                 const char *name,
1461                                 const void *value,
1462                                 size_t size,
1463                                 int flags)
1464 {
1465         int ret;
1466         DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1467                         smb_fname->base_name, name, value, llu(size), flags);
1468         ret = ceph_setxattr(handle->data, smb_fname->base_name,
1469                         name, value, size, flags);
1470         DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1471         WRAP_RETURN(ret);
1472 }
1473
1474 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1475 {
1476         int ret;
1477         DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1478 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1479         ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1480                              name, value, size, flags);
1481 #else
1482         ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1483 #endif
1484         DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1485         WRAP_RETURN(ret);
1486 }
1487
1488 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1489 {
1490
1491         /*
1492          * We do not support AIO yet.
1493          */
1494
1495         DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1496         errno = ENOTSUP;
1497         return false;
1498 }
1499
1500 static struct vfs_fn_pointers ceph_fns = {
1501         /* Disk operations */
1502
1503         .connect_fn = cephwrap_connect,
1504         .disconnect_fn = cephwrap_disconnect,
1505         .disk_free_fn = cephwrap_disk_free,
1506         .get_quota_fn = cephwrap_get_quota,
1507         .set_quota_fn = cephwrap_set_quota,
1508         .statvfs_fn = cephwrap_statvfs,
1509         .fs_capabilities_fn = cephwrap_fs_capabilities,
1510
1511         /* Directory operations */
1512
1513         .opendir_fn = cephwrap_opendir,
1514         .fdopendir_fn = cephwrap_fdopendir,
1515         .readdir_fn = cephwrap_readdir,
1516         .seekdir_fn = cephwrap_seekdir,
1517         .telldir_fn = cephwrap_telldir,
1518         .rewind_dir_fn = cephwrap_rewinddir,
1519         .mkdir_fn = cephwrap_mkdir,
1520         .rmdir_fn = cephwrap_rmdir,
1521         .closedir_fn = cephwrap_closedir,
1522
1523         /* File operations */
1524
1525         .open_fn = cephwrap_open,
1526         .close_fn = cephwrap_close,
1527         .pread_fn = cephwrap_pread,
1528         .pread_send_fn = cephwrap_pread_send,
1529         .pread_recv_fn = cephwrap_pread_recv,
1530         .pwrite_fn = cephwrap_pwrite,
1531         .pwrite_send_fn = cephwrap_pwrite_send,
1532         .pwrite_recv_fn = cephwrap_pwrite_recv,
1533         .lseek_fn = cephwrap_lseek,
1534         .sendfile_fn = cephwrap_sendfile,
1535         .recvfile_fn = cephwrap_recvfile,
1536         .rename_fn = cephwrap_rename,
1537         .fsync_send_fn = cephwrap_fsync_send,
1538         .fsync_recv_fn = cephwrap_fsync_recv,
1539         .stat_fn = cephwrap_stat,
1540         .fstat_fn = cephwrap_fstat,
1541         .lstat_fn = cephwrap_lstat,
1542         .unlink_fn = cephwrap_unlink,
1543         .chmod_fn = cephwrap_chmod,
1544         .fchmod_fn = cephwrap_fchmod,
1545         .chown_fn = cephwrap_chown,
1546         .fchown_fn = cephwrap_fchown,
1547         .lchown_fn = cephwrap_lchown,
1548         .chdir_fn = cephwrap_chdir,
1549         .getwd_fn = cephwrap_getwd,
1550         .ntimes_fn = cephwrap_ntimes,
1551         .ftruncate_fn = cephwrap_ftruncate,
1552         .lock_fn = cephwrap_lock,
1553         .kernel_flock_fn = cephwrap_kernel_flock,
1554         .linux_setlease_fn = cephwrap_linux_setlease,
1555         .getlock_fn = cephwrap_getlock,
1556         .symlink_fn = cephwrap_symlink,
1557         .readlink_fn = cephwrap_readlink,
1558         .link_fn = cephwrap_link,
1559         .mknod_fn = cephwrap_mknod,
1560         .realpath_fn = cephwrap_realpath,
1561         .chflags_fn = cephwrap_chflags,
1562         .get_real_filename_fn = cephwrap_get_real_filename,
1563         .connectpath_fn = cephwrap_connectpath,
1564
1565         /* EA operations. */
1566         .getxattr_fn = cephwrap_getxattr,
1567         .fgetxattr_fn = cephwrap_fgetxattr,
1568         .listxattr_fn = cephwrap_listxattr,
1569         .flistxattr_fn = cephwrap_flistxattr,
1570         .removexattr_fn = cephwrap_removexattr,
1571         .fremovexattr_fn = cephwrap_fremovexattr,
1572         .setxattr_fn = cephwrap_setxattr,
1573         .fsetxattr_fn = cephwrap_fsetxattr,
1574
1575         /* Posix ACL Operations */
1576         .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1577         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1578         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1579         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1580         .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1581         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1582         .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1583
1584         /* aio operations */
1585         .aio_force_fn = cephwrap_aio_force,
1586 };
1587
1588 static_decl_vfs;
1589 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1590 {
1591         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1592                                 "ceph", &ceph_fns);
1593 }