s3: VFS: Change SMB_VFS_REALPATH to take and return struct smb_filename * instead...
[Samba.git] / source3 / modules / vfs_ceph.c
blob488ebc7795d91342182a9d57b5593c7dcb55f1aa
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>
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.
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.
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/>.
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.
27 * Add the following smb.conf parameter to each share that will be hosted on
28 * Ceph:
30 * vfs objects = ceph [any others you need go here]
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"
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_VFS
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
50 * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
52 #define llu(_var) ((long long unsigned)_var)
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
58 #define WRAP_RETURN(_res) \
59 errno = 0; \
60 if (_res < 0) { \
61 errno = -_res; \
62 return -1; \
63 } \
64 return _res \
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.
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
75 static struct ceph_mount_info * cmount = NULL;
76 static uint32_t cmount_cnt = 0;
78 /* Check for NULL pointer parameters in cephwrap_* functions */
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. */
84 static int cephwrap_connect(struct vfs_handle_struct *handle, const char *service, const char *user)
86 int ret;
87 char buf[256];
88 int snum = SNUM(handle->conn);
89 const char *conf_file;
90 const char *user_id;
92 if (cmount) {
93 handle->data = cmount; /* We have been here before */
94 cmount_cnt++;
95 return 0;
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);
102 DBG_DEBUG("[CEPH] calling: ceph_create\n");
103 ret = ceph_create(&cmount, user_id);
104 if (ret) {
105 goto err_out;
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;
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;
121 DBG_DEBUG("[CEPH] calling: ceph_mount\n");
122 ret = ceph_mount(cmount, NULL);
123 if (ret < 0) {
124 goto err_cm_release;
128 * encode mount context/state into our vfs/connection holding structure
129 * cmount is a ceph_mount_t*
131 handle->data = cmount;
132 cmount_cnt++;
134 return 0;
136 err_cm_release:
137 ceph_release(cmount);
138 cmount = NULL;
139 err_out:
141 * Handle the error correctly. Ceph returns -errno.
143 DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
144 WRAP_RETURN(ret);
147 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
149 int ret;
151 if (!cmount) {
152 DBG_ERR("[CEPH] Error, ceph not mounted\n");
153 return;
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;
162 ret = ceph_unmount(cmount);
163 if (ret < 0) {
164 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
167 ret = ceph_release(cmount);
168 if (ret < 0) {
169 DBG_ERR("[CEPH] failed to release: %s\n", strerror(-ret));
172 cmount = NULL; /* Make it safe */
175 /* Disk operations */
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)
183 struct statvfs statvfs_buf;
184 int ret;
186 if (!(ret = ceph_statfs(handle->data, smb_fname->base_name,
187 &statvfs_buf))) {
189 * Provide all the correct values.
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);
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)
209 /* libceph: Ceph does not implement this */
210 #if 0
211 /* was ifdef HAVE_SYS_QUOTAS */
212 int ret;
214 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
216 if (ret) {
217 errno = -ret;
218 ret = -1;
221 return ret;
222 #else
223 errno = ENOSYS;
224 return -1;
225 #endif
228 static int cephwrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
230 /* libceph: Ceph does not implement this */
231 #if 0
232 /* was ifdef HAVE_SYS_QUOTAS */
233 int ret;
235 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
236 if (ret) {
237 errno = -ret;
238 ret = -1;
241 return ret;
242 #else
243 WRAP_RETURN(-ENOSYS);
244 #endif
247 static int cephwrap_statvfs(struct vfs_handle_struct *handle,
248 const struct smb_filename *smb_fname,
249 vfs_statvfs_struct *statbuf)
251 struct statvfs statvfs_buf;
252 int ret;
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);
270 return ret;
273 /* Directory operations */
275 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
276 const struct smb_filename *smb_fname,
277 const char *mask, uint32_t attr)
279 int ret = 0;
280 struct ceph_dir_result *result;
281 DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
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 */
290 DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
291 return (DIR *) result;
294 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
295 struct files_struct *fsp,
296 const char *mask,
297 uint32_t attributes)
299 int ret = 0;
300 struct ceph_dir_result *result;
301 DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
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 */
309 DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
310 return (DIR *) result;
313 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
314 DIR *dirp,
315 SMB_STRUCT_STAT *sbuf)
317 struct dirent *result;
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);
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;
330 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
332 DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
333 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
336 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
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);
345 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
347 DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
348 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
351 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
352 const struct smb_filename *smb_fname,
353 mode_t mode)
355 int result;
356 bool has_dacl = False;
357 char *parent = NULL;
358 const char *path = smb_fname->base_name;
360 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
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;
367 TALLOC_FREE(parent);
369 result = ceph_mkdir(handle->data, path, mode);
372 * Note. This order is important
374 if (result) {
375 WRAP_RETURN(result);
376 } else if (result == 0 && !has_dacl) {
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.
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;
391 return result;
394 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
395 const struct smb_filename *smb_fname)
397 int result;
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);
405 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
407 int result;
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);
415 /* File operations */
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)
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);
425 if (smb_fname->stream_name) {
426 goto out;
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);
435 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
437 int result;
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);
443 WRAP_RETURN(result);
446 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
448 ssize_t result;
450 DBG_DEBUG("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
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);
458 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
459 size_t n, off_t offset)
461 ssize_t result;
463 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
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);
471 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
473 ssize_t result;
475 DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
477 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
479 DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
480 if (result < 0) {
481 WRAP_RETURN(result);
483 fsp->fh->pos += result;
484 return result;
487 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
488 size_t n, off_t offset)
490 ssize_t result;
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);
498 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
500 off_t result = 0;
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);
507 WRAP_RETURN(result);
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)
514 * We cannot support sendfile because libceph is in user space.
516 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
517 errno = ENOTSUP;
518 return -1;
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)
528 * We cannot support recvfile because libceph is in user space.
530 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
531 errno=ENOTSUP;
532 return -1;
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)
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;
546 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
547 WRAP_RETURN(result);
550 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
552 int result;
553 DBG_DEBUG("[CEPH] cephwrap_fsync\n");
554 result = ceph_fsync(handle->data, fsp->fh->fd, false);
555 WRAP_RETURN(result);
558 #ifdef HAVE_CEPH_STATX
559 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
561 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
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);
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;
584 static int cephwrap_stat(struct vfs_handle_struct *handle,
585 struct smb_filename *smb_fname)
587 int result = -1;
588 struct ceph_statx stx;
590 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
592 if (smb_fname->stream_name) {
593 errno = ENOENT;
594 return result;
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));
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;
617 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
619 int result = -1;
620 struct ceph_statx stx;
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));
638 init_stat_ex_from_ceph_statx(sbuf, &stx);
639 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
640 return result;
643 static int cephwrap_lstat(struct vfs_handle_struct *handle,
644 struct smb_filename *smb_fname)
646 int result = -1;
647 struct ceph_statx stx;
649 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
651 if (smb_fname->stream_name) {
652 errno = ENOENT;
653 return result;
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);
662 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
663 return result;
666 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
667 const struct smb_filename *smb_fname,
668 struct smb_file_time *ft)
670 struct ceph_statx stx = { 0 };
671 int result;
672 int mask = 0;
674 if (!null_timespec(ft->atime)) {
675 stx.stx_atime = ft->atime;
676 mask |= CEPH_SETATTR_ATIME;
678 if (!null_timespec(ft->mtime)) {
679 stx.stx_mtime = ft->mtime;
680 mask |= CEPH_SETATTR_MTIME;
682 if (!null_timespec(ft->create_time)) {
683 stx.stx_btime = ft->create_time;
684 mask |= CEPH_SETATTR_BTIME;
687 if (!mask) {
688 return 0;
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;
698 #else /* HAVE_CEPH_STATX */
700 static int cephwrap_stat(struct vfs_handle_struct *handle,
701 struct smb_filename *smb_fname)
703 int result = -1;
704 struct stat stbuf;
706 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
708 if (smb_fname->stream_name) {
709 errno = ENOENT;
710 return result;
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));
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;
732 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
734 int result = -1;
735 struct stat stbuf;
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));
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;
758 static int cephwrap_lstat(struct vfs_handle_struct *handle,
759 struct smb_filename *smb_fname)
761 int result = -1;
762 struct stat stbuf;
764 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
766 if (smb_fname->stream_name) {
767 errno = ENOENT;
768 return result;
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);
776 init_stat_ex_from_stat(
777 &smb_fname->st, &stbuf,
778 lp_fake_directory_create_times(SNUM(handle->conn)));
779 return result;
782 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
783 const struct smb_filename *smb_fname,
784 struct smb_file_time *ft)
786 struct utimbuf buf;
787 int result;
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;
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;
799 if (!null_timespec(ft->create_time)) {
800 set_create_timespec_ea(handle->conn, smb_fname,
801 ft->create_time);
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;
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;
814 #endif /* HAVE_CEPH_STATX */
816 static int cephwrap_unlink(struct vfs_handle_struct *handle,
817 const struct smb_filename *smb_fname)
819 int result = -1;
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;
826 result = ceph_unlink(handle->data, smb_fname->base_name);
827 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
828 WRAP_RETURN(result);
831 static int cephwrap_chmod(struct vfs_handle_struct *handle,
832 const struct smb_filename *smb_fname,
833 mode_t mode)
835 int result;
837 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
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.
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;
854 /* Error - return the old errno. */
855 errno = saved_errno;
858 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
859 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
860 WRAP_RETURN(result);
863 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
865 int result;
867 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
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.
876 int saved_errno = errno; /* We might get ENOSYS */
877 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
878 return result;
880 /* Error - return the old errno. */
881 errno = saved_errno;
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;
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)
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);
906 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
908 int result;
909 #ifdef HAVE_FCHOWN
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;
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)
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);
934 static int cephwrap_chdir(struct vfs_handle_struct *handle,
935 const struct smb_filename *smb_fname)
937 int result = -1;
938 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
940 * If the path is just / use chdir because Ceph is below / and
941 * cannot deal with changing directory above its mount point
943 if (!strcmp(smb_fname->base_name, "/")) {
944 return chdir(smb_fname->base_name);
947 result = ceph_chdir(handle->data, smb_fname->base_name);
948 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
949 WRAP_RETURN(result);
952 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
953 TALLOC_CTX *ctx)
955 const char *cwd = ceph_getcwd(handle->data);
956 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
957 return synthetic_smb_fname(ctx,
958 cwd,
959 NULL,
960 NULL,
964 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
966 off_t space_to_write;
967 uint64_t space_avail;
968 uint64_t bsize,dfree,dsize;
969 int ret;
970 NTSTATUS status;
971 SMB_STRUCT_STAT *pst;
973 status = vfs_stat_fsp(fsp);
974 if (!NT_STATUS_IS_OK(status)) {
975 return -1;
977 pst = &fsp->fsp_name->st;
979 #ifdef S_ISFIFO
980 if (S_ISFIFO(pst->st_ex_mode))
981 return 0;
982 #endif
984 if (pst->st_ex_size == len)
985 return 0;
987 /* Shrink - just ftruncate. */
988 if (pst->st_ex_size > len)
989 return ftruncate(fsp->fh->fd, len);
991 space_to_write = len - pst->st_ex_size;
993 /* for allocation try fallocate first. This can fail on some
994 platforms e.g. when the filesystem doesn't support it and no
995 emulation is being done by the libc (like on AIX with JFS1). In that
996 case we do our own emulation. fallocate implementations can
997 return ENOTSUP or EINVAL in cases like that. */
998 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
999 if (ret == -1 && errno == ENOSPC) {
1000 return -1;
1002 if (ret == 0) {
1003 return 0;
1005 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1006 "error %d. Falling back to slow manual allocation\n", errno));
1008 /* available disk space is enough or not? */
1009 space_avail =
1010 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1011 /* space_avail is 1k blocks */
1012 if (space_avail == (uint64_t)-1 ||
1013 ((uint64_t)space_to_write/1024 > space_avail) ) {
1014 errno = ENOSPC;
1015 return -1;
1018 /* Write out the real space on disk. */
1019 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1022 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1024 int result = -1;
1025 SMB_STRUCT_STAT st;
1026 char c = 0;
1027 off_t currpos;
1029 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1031 if (lp_strict_allocate(SNUM(fsp->conn))) {
1032 result = strict_allocate_ftruncate(handle, fsp, len);
1033 return result;
1036 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1037 sys_ftruncate if the system supports it. Then I discovered that
1038 you can have some filesystems that support ftruncate
1039 expansion and some that don't! On Linux fat can't do
1040 ftruncate extend but ext2 can. */
1042 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1043 if (result == 0)
1044 goto done;
1046 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1047 extend a file with ftruncate. Provide alternate implementation
1048 for this */
1049 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1050 if (currpos == -1) {
1051 goto done;
1054 /* Do an fstat to see if the file is longer than the requested
1055 size in which case the ftruncate above should have
1056 succeeded or shorter, in which case seek to len - 1 and
1057 write 1 byte of zero */
1058 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1059 goto done;
1062 #ifdef S_ISFIFO
1063 if (S_ISFIFO(st.st_ex_mode)) {
1064 result = 0;
1065 goto done;
1067 #endif
1069 if (st.st_ex_size == len) {
1070 result = 0;
1071 goto done;
1074 if (st.st_ex_size > len) {
1075 /* the sys_ftruncate should have worked */
1076 goto done;
1079 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1080 goto done;
1082 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1083 goto done;
1085 /* Seek to where we were */
1086 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1087 goto done;
1088 result = 0;
1090 done:
1092 return result;
1095 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1097 DBG_DEBUG("[CEPH] lock\n");
1098 return true;
1101 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1102 uint32_t share_mode, uint32_t access_mask)
1104 DBG_DEBUG("[CEPH] kernel_flock\n");
1106 * We must return zero here and pretend all is good.
1107 * One day we might have this in CEPH.
1109 return 0;
1112 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1114 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1116 errno = 0;
1117 return false;
1121 * We cannot let this fall through to the default, because the file might only
1122 * be accessible from libceph (which is a user-space client) but the fd might
1123 * be for some file the kernel knows about.
1125 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1126 int leasetype)
1128 int result = -1;
1130 DBG_DEBUG("[CEPH] linux_setlease\n");
1131 errno = ENOSYS;
1132 return result;
1135 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1136 const char *link_target,
1137 const struct smb_filename *new_smb_fname)
1139 int result = -1;
1140 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1141 link_target,
1142 new_smb_fname->base_name);
1143 result = ceph_symlink(handle->data,
1144 link_target,
1145 new_smb_fname->base_name);
1146 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1147 WRAP_RETURN(result);
1150 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1151 const struct smb_filename *smb_fname,
1152 char *buf,
1153 size_t bufsiz)
1155 int result = -1;
1156 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1157 smb_fname->base_name, buf, llu(bufsiz));
1158 result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1159 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1160 WRAP_RETURN(result);
1163 static int cephwrap_link(struct vfs_handle_struct *handle,
1164 const struct smb_filename *old_smb_fname,
1165 const struct smb_filename *new_smb_fname)
1167 int result = -1;
1168 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1169 old_smb_fname->base_name,
1170 new_smb_fname->base_name);
1171 result = ceph_link(handle->data,
1172 old_smb_fname->base_name,
1173 new_smb_fname->base_name);
1174 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1175 WRAP_RETURN(result);
1178 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1179 const struct smb_filename *smb_fname,
1180 mode_t mode,
1181 SMB_DEV_T dev)
1183 int result = -1;
1184 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1185 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1186 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1187 WRAP_RETURN(result);
1191 * This is a simple version of real-path ... a better version is needed to
1192 * ask libceph about symbolic links.
1194 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1195 TALLOC_CTX *ctx,
1196 const struct smb_filename *smb_fname)
1198 char *result;
1199 const char *path = smb_fname->base_name;
1200 size_t len = strlen(path);
1201 struct smb_filename *result_fname = NULL;
1203 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1204 if (len && (path[0] == '/')) {
1205 int r = asprintf(&result, "%s", path);
1206 if (r < 0) return NULL;
1207 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1208 if (len == 2) {
1209 int r = asprintf(&result, "%s",
1210 handle->conn->connectpath);
1211 if (r < 0) return NULL;
1212 } else {
1213 int r = asprintf(&result, "%s/%s",
1214 handle->conn->connectpath, &path[2]);
1215 if (r < 0) return NULL;
1217 } else {
1218 int r = asprintf(&result, "%s/%s",
1219 handle->conn->connectpath, path);
1220 if (r < 0) return NULL;
1222 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1223 result_fname = synthetic_smb_fname(ctx,
1224 result,
1225 NULL,
1226 NULL,
1228 SAFE_FREE(result);
1229 return result_fname;
1232 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1233 const struct smb_filename *smb_fname,
1234 unsigned int flags)
1236 errno = ENOSYS;
1237 return -1;
1240 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1241 const char *path,
1242 const char *name,
1243 TALLOC_CTX *mem_ctx,
1244 char **found_name)
1247 * Don't fall back to get_real_filename so callers can differentiate
1248 * between a full directory scan and an actual case-insensitive stat.
1250 errno = EOPNOTSUPP;
1251 return -1;
1254 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1255 const char *fname)
1257 return handle->conn->connectpath;
1260 /****************************************************************
1261 Extended attribute operations.
1262 *****************************************************************/
1264 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1265 const struct smb_filename *smb_fname,
1266 const char *name,
1267 void *value,
1268 size_t size)
1270 int ret;
1271 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1272 smb_fname->base_name, name, value, llu(size));
1273 ret = ceph_getxattr(handle->data,
1274 smb_fname->base_name, name, value, size);
1275 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1276 if (ret < 0) {
1277 WRAP_RETURN(ret);
1278 } else {
1279 return (ssize_t)ret;
1283 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1285 int ret;
1286 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1287 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1288 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1289 #else
1290 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1291 #endif
1292 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1293 if (ret < 0) {
1294 WRAP_RETURN(ret);
1295 } else {
1296 return (ssize_t)ret;
1300 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1301 const struct smb_filename *smb_fname,
1302 char *list,
1303 size_t size)
1305 int ret;
1306 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1307 smb_fname->base_name, list, llu(size));
1308 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1309 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1310 if (ret < 0) {
1311 WRAP_RETURN(ret);
1312 } else {
1313 return (ssize_t)ret;
1317 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1319 int ret;
1320 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1321 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1322 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1323 #else
1324 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1325 #endif
1326 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1327 if (ret < 0) {
1328 WRAP_RETURN(ret);
1329 } else {
1330 return (ssize_t)ret;
1334 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1335 const struct smb_filename *smb_fname,
1336 const char *name)
1338 int ret;
1339 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1340 smb_fname->base_name, name);
1341 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1342 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1343 WRAP_RETURN(ret);
1346 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1348 int ret;
1349 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1350 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1351 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1352 #else
1353 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1354 #endif
1355 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1356 WRAP_RETURN(ret);
1359 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1360 const struct smb_filename *smb_fname,
1361 const char *name,
1362 const void *value,
1363 size_t size,
1364 int flags)
1366 int ret;
1367 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1368 smb_fname->base_name, name, value, llu(size), flags);
1369 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1370 name, value, size, flags);
1371 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1372 WRAP_RETURN(ret);
1375 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1377 int ret;
1378 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1379 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1380 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1381 name, value, size, flags);
1382 #else
1383 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1384 #endif
1385 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1386 WRAP_RETURN(ret);
1389 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1393 * We do not support AIO yet.
1396 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1397 errno = ENOTSUP;
1398 return false;
1401 static struct vfs_fn_pointers ceph_fns = {
1402 /* Disk operations */
1404 .connect_fn = cephwrap_connect,
1405 .disconnect_fn = cephwrap_disconnect,
1406 .disk_free_fn = cephwrap_disk_free,
1407 .get_quota_fn = cephwrap_get_quota,
1408 .set_quota_fn = cephwrap_set_quota,
1409 .statvfs_fn = cephwrap_statvfs,
1411 /* Directory operations */
1413 .opendir_fn = cephwrap_opendir,
1414 .fdopendir_fn = cephwrap_fdopendir,
1415 .readdir_fn = cephwrap_readdir,
1416 .seekdir_fn = cephwrap_seekdir,
1417 .telldir_fn = cephwrap_telldir,
1418 .rewind_dir_fn = cephwrap_rewinddir,
1419 .mkdir_fn = cephwrap_mkdir,
1420 .rmdir_fn = cephwrap_rmdir,
1421 .closedir_fn = cephwrap_closedir,
1423 /* File operations */
1425 .open_fn = cephwrap_open,
1426 .close_fn = cephwrap_close,
1427 .read_fn = cephwrap_read,
1428 .pread_fn = cephwrap_pread,
1429 .write_fn = cephwrap_write,
1430 .pwrite_fn = cephwrap_pwrite,
1431 .lseek_fn = cephwrap_lseek,
1432 .sendfile_fn = cephwrap_sendfile,
1433 .recvfile_fn = cephwrap_recvfile,
1434 .rename_fn = cephwrap_rename,
1435 .fsync_fn = cephwrap_fsync,
1436 .stat_fn = cephwrap_stat,
1437 .fstat_fn = cephwrap_fstat,
1438 .lstat_fn = cephwrap_lstat,
1439 .unlink_fn = cephwrap_unlink,
1440 .chmod_fn = cephwrap_chmod,
1441 .fchmod_fn = cephwrap_fchmod,
1442 .chown_fn = cephwrap_chown,
1443 .fchown_fn = cephwrap_fchown,
1444 .lchown_fn = cephwrap_lchown,
1445 .chdir_fn = cephwrap_chdir,
1446 .getwd_fn = cephwrap_getwd,
1447 .ntimes_fn = cephwrap_ntimes,
1448 .ftruncate_fn = cephwrap_ftruncate,
1449 .lock_fn = cephwrap_lock,
1450 .kernel_flock_fn = cephwrap_kernel_flock,
1451 .linux_setlease_fn = cephwrap_linux_setlease,
1452 .getlock_fn = cephwrap_getlock,
1453 .symlink_fn = cephwrap_symlink,
1454 .readlink_fn = cephwrap_readlink,
1455 .link_fn = cephwrap_link,
1456 .mknod_fn = cephwrap_mknod,
1457 .realpath_fn = cephwrap_realpath,
1458 .chflags_fn = cephwrap_chflags,
1459 .get_real_filename_fn = cephwrap_get_real_filename,
1460 .connectpath_fn = cephwrap_connectpath,
1462 /* EA operations. */
1463 .getxattr_fn = cephwrap_getxattr,
1464 .fgetxattr_fn = cephwrap_fgetxattr,
1465 .listxattr_fn = cephwrap_listxattr,
1466 .flistxattr_fn = cephwrap_flistxattr,
1467 .removexattr_fn = cephwrap_removexattr,
1468 .fremovexattr_fn = cephwrap_fremovexattr,
1469 .setxattr_fn = cephwrap_setxattr,
1470 .fsetxattr_fn = cephwrap_fsetxattr,
1472 /* Posix ACL Operations */
1473 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1474 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1475 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1476 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1477 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1478 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1479 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1481 /* aio operations */
1482 .aio_force_fn = cephwrap_aio_force,
1485 NTSTATUS vfs_ceph_init(TALLOC_CTX *);
1486 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1488 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1489 "ceph", &ceph_fns);