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