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