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