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