s3: VFS: Change SMB_VFS_MKNOD to use const struct smb_filename * instead of const...
[Samba.git] / source3 / modules / vfs_ceph.c
blobd88ceacee334ae6461abd172a99c722ba93607f1
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 char *path, uint64_t *bsize,
179 uint64_t *dfree, uint64_t *dsize)
181 struct statvfs statvfs_buf;
182 int ret;
184 if (!(ret = ceph_statfs(handle->data, path, &statvfs_buf))) {
186 * Provide all the correct values.
188 *bsize = statvfs_buf.f_bsize;
189 *dfree = statvfs_buf.f_bavail;
190 *dsize = statvfs_buf.f_blocks;
191 DBG_DEBUG("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
192 llu(*bsize), llu(*dfree), llu(*dsize));
193 return *dfree;
194 } else {
195 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
196 WRAP_RETURN(ret);
200 static int cephwrap_get_quota(struct vfs_handle_struct *handle,
201 const char *path, enum SMB_QUOTA_TYPE qtype,
202 unid_t id, SMB_DISK_QUOTA *qt)
204 /* libceph: Ceph does not implement this */
205 #if 0
206 /* was ifdef HAVE_SYS_QUOTAS */
207 int ret;
209 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
211 if (ret) {
212 errno = -ret;
213 ret = -1;
216 return ret;
217 #else
218 errno = ENOSYS;
219 return -1;
220 #endif
223 static int cephwrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
225 /* libceph: Ceph does not implement this */
226 #if 0
227 /* was ifdef HAVE_SYS_QUOTAS */
228 int ret;
230 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
231 if (ret) {
232 errno = -ret;
233 ret = -1;
236 return ret;
237 #else
238 WRAP_RETURN(-ENOSYS);
239 #endif
242 static int cephwrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
244 struct statvfs statvfs_buf;
245 int ret;
247 ret = ceph_statfs(handle->data, path, &statvfs_buf);
248 if (ret < 0) {
249 WRAP_RETURN(ret);
250 } else {
251 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
252 statbuf->BlockSize = statvfs_buf.f_bsize;
253 statbuf->TotalBlocks = statvfs_buf.f_blocks;
254 statbuf->BlocksAvail = statvfs_buf.f_bfree;
255 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
256 statbuf->TotalFileNodes = statvfs_buf.f_files;
257 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
258 statbuf->FsIdentifier = statvfs_buf.f_fsid;
259 DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
260 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
261 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
263 return ret;
266 /* Directory operations */
268 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
269 const struct smb_filename *smb_fname,
270 const char *mask, uint32_t attr)
272 int ret = 0;
273 struct ceph_dir_result *result;
274 DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
276 /* Returns NULL if it does not exist or there are problems ? */
277 ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
278 if (ret < 0) {
279 result = NULL;
280 errno = -ret; /* We return result which is NULL in this case */
283 DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
284 return (DIR *) result;
287 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
288 struct files_struct *fsp,
289 const char *mask,
290 uint32_t attributes)
292 int ret = 0;
293 struct ceph_dir_result *result;
294 DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
296 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
297 if (ret < 0) {
298 result = NULL;
299 errno = -ret; /* We return result which is NULL in this case */
302 DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
303 return (DIR *) result;
306 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
307 DIR *dirp,
308 SMB_STRUCT_STAT *sbuf)
310 struct dirent *result;
312 DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
313 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
314 DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
316 /* Default Posix readdir() does not give us stat info.
317 * Set to invalid to indicate we didn't return this info. */
318 if (sbuf)
319 SET_STAT_INVALID(*sbuf);
320 return result;
323 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
325 DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
326 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
329 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
331 long ret;
332 DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
333 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
334 DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
335 WRAP_RETURN(ret);
338 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
340 DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
341 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
344 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
345 const struct smb_filename *smb_fname,
346 mode_t mode)
348 int result;
349 bool has_dacl = False;
350 char *parent = NULL;
351 const char *path = smb_fname->base_name;
353 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
355 if (lp_inherit_acls(SNUM(handle->conn))
356 && parent_dirname(talloc_tos(), path, &parent, NULL)
357 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
358 mode = 0777;
360 TALLOC_FREE(parent);
362 result = ceph_mkdir(handle->data, path, mode);
365 * Note. This order is important
367 if (result) {
368 WRAP_RETURN(result);
369 } else if (result == 0 && !has_dacl) {
371 * We need to do this as the default behavior of POSIX ACLs
372 * is to set the mask to be the requested group permission
373 * bits, not the group permission bits to be the requested
374 * group permission bits. This is not what we want, as it will
375 * mess up any inherited ACL bits that were set. JRA.
377 int saved_errno = errno; /* We may get ENOSYS */
378 if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
379 (errno == ENOSYS)) {
380 errno = saved_errno;
384 return result;
387 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
388 const struct smb_filename *smb_fname)
390 int result;
392 DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
393 result = ceph_rmdir(handle->data, smb_fname->base_name);
394 DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
395 WRAP_RETURN(result);
398 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
400 int result;
402 DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
403 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
404 DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
405 WRAP_RETURN(result);
408 /* File operations */
410 static int cephwrap_open(struct vfs_handle_struct *handle,
411 struct smb_filename *smb_fname,
412 files_struct *fsp, int flags, mode_t mode)
414 int result = -ENOENT;
415 DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
416 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
418 if (smb_fname->stream_name) {
419 goto out;
422 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
423 out:
424 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
425 WRAP_RETURN(result);
428 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
430 int result;
432 DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
433 result = ceph_close(handle->data, fsp->fh->fd);
434 DBG_DEBUG("[CEPH] close(...) = %d\n", result);
436 WRAP_RETURN(result);
439 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
441 ssize_t result;
443 DBG_DEBUG("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
445 /* Using -1 for the offset means read/write rather than pread/pwrite */
446 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
447 DBG_DEBUG("[CEPH] read(...) = %llu\n", llu(result));
448 WRAP_RETURN(result);
451 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
452 size_t n, off_t offset)
454 ssize_t result;
456 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
458 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
459 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
460 WRAP_RETURN(result);
464 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
466 ssize_t result;
468 DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
470 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
472 DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
473 if (result < 0) {
474 WRAP_RETURN(result);
476 fsp->fh->pos += result;
477 return result;
480 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
481 size_t n, off_t offset)
483 ssize_t result;
485 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
486 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
487 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
488 WRAP_RETURN(result);
491 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
493 off_t result = 0;
495 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
496 /* Cope with 'stat' file opens. */
497 if (fsp->fh->fd != -1) {
498 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
500 WRAP_RETURN(result);
503 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
504 off_t offset, size_t n)
507 * We cannot support sendfile because libceph is in user space.
509 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
510 errno = ENOTSUP;
511 return -1;
514 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
515 int fromfd,
516 files_struct *tofsp,
517 off_t offset,
518 size_t n)
521 * We cannot support recvfile because libceph is in user space.
523 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
524 errno=ENOTSUP;
525 return -1;
528 static int cephwrap_rename(struct vfs_handle_struct *handle,
529 const struct smb_filename *smb_fname_src,
530 const struct smb_filename *smb_fname_dst)
532 int result = -1;
533 DBG_DEBUG("[CEPH] cephwrap_rename\n");
534 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
535 errno = ENOENT;
536 return result;
539 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
540 WRAP_RETURN(result);
543 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
545 int result;
546 DBG_DEBUG("[CEPH] cephwrap_fsync\n");
547 result = ceph_fsync(handle->data, fsp->fh->fd, false);
548 WRAP_RETURN(result);
551 #ifdef HAVE_CEPH_STATX
552 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
554 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
556 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
557 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
558 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
560 dst->st_ex_dev = stx->stx_dev;
561 dst->st_ex_rdev = stx->stx_rdev;
562 dst->st_ex_ino = stx->stx_ino;
563 dst->st_ex_mode = stx->stx_mode;
564 dst->st_ex_uid = stx->stx_uid;
565 dst->st_ex_gid = stx->stx_gid;
566 dst->st_ex_size = stx->stx_size;
567 dst->st_ex_nlink = stx->stx_nlink;
568 dst->st_ex_atime = stx->stx_atime;
569 dst->st_ex_btime = stx->stx_btime;
570 dst->st_ex_ctime = stx->stx_ctime;
571 dst->st_ex_mtime = stx->stx_mtime;
572 dst->st_ex_calculated_birthtime = false;
573 dst->st_ex_blksize = stx->stx_blksize;
574 dst->st_ex_blocks = stx->stx_blocks;
577 static int cephwrap_stat(struct vfs_handle_struct *handle,
578 struct smb_filename *smb_fname)
580 int result = -1;
581 struct ceph_statx stx;
583 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
585 if (smb_fname->stream_name) {
586 errno = ENOENT;
587 return result;
590 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
591 SAMBA_STATX_ATTR_MASK, 0);
592 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
593 if (result < 0) {
594 WRAP_RETURN(result);
595 } else {
596 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
597 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
598 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
599 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
600 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
601 llu(stx.stx_size), llu(stx.stx_blksize),
602 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
603 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
605 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
606 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
607 return result;
610 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
612 int result = -1;
613 struct ceph_statx stx;
615 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
616 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
617 SAMBA_STATX_ATTR_MASK, 0);
618 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
619 if (result < 0) {
620 WRAP_RETURN(result);
621 } else {
622 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
623 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
624 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
625 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
626 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
627 llu(stx.stx_size), llu(stx.stx_blksize),
628 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
629 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
631 init_stat_ex_from_ceph_statx(sbuf, &stx);
632 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
633 return result;
636 static int cephwrap_lstat(struct vfs_handle_struct *handle,
637 struct smb_filename *smb_fname)
639 int result = -1;
640 struct ceph_statx stx;
642 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
644 if (smb_fname->stream_name) {
645 errno = ENOENT;
646 return result;
649 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
650 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
651 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
652 if (result < 0) {
653 WRAP_RETURN(result);
655 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
656 return result;
659 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
660 const struct smb_filename *smb_fname,
661 struct smb_file_time *ft)
663 struct ceph_statx stx = { 0 };
664 int result;
665 int mask = 0;
667 if (!null_timespec(ft->atime)) {
668 stx.stx_atime = ft->atime;
669 mask |= CEPH_SETATTR_ATIME;
671 if (!null_timespec(ft->mtime)) {
672 stx.stx_mtime = ft->mtime;
673 mask |= CEPH_SETATTR_MTIME;
675 if (!null_timespec(ft->create_time)) {
676 stx.stx_btime = ft->create_time;
677 mask |= CEPH_SETATTR_BTIME;
680 if (!mask) {
681 return 0;
684 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
685 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
686 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
687 ft->create_time.tv_sec, result);
688 return result;
691 #else /* HAVE_CEPH_STATX */
693 static int cephwrap_stat(struct vfs_handle_struct *handle,
694 struct smb_filename *smb_fname)
696 int result = -1;
697 struct stat stbuf;
699 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
701 if (smb_fname->stream_name) {
702 errno = ENOENT;
703 return result;
706 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
707 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
708 if (result < 0) {
709 WRAP_RETURN(result);
710 } else {
711 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
712 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
713 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
714 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
715 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
716 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
718 init_stat_ex_from_stat(
719 &smb_fname->st, &stbuf,
720 lp_fake_directory_create_times(SNUM(handle->conn)));
721 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
722 return result;
725 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
727 int result = -1;
728 struct stat stbuf;
730 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
731 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
732 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
733 if (result < 0) {
734 WRAP_RETURN(result);
735 } else {
736 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
737 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
738 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
739 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
740 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
741 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
744 init_stat_ex_from_stat(
745 sbuf, &stbuf,
746 lp_fake_directory_create_times(SNUM(handle->conn)));
747 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
748 return result;
751 static int cephwrap_lstat(struct vfs_handle_struct *handle,
752 struct smb_filename *smb_fname)
754 int result = -1;
755 struct stat stbuf;
757 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
759 if (smb_fname->stream_name) {
760 errno = ENOENT;
761 return result;
764 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
765 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
766 if (result < 0) {
767 WRAP_RETURN(result);
769 init_stat_ex_from_stat(
770 &smb_fname->st, &stbuf,
771 lp_fake_directory_create_times(SNUM(handle->conn)));
772 return result;
775 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
776 const struct smb_filename *smb_fname,
777 struct smb_file_time *ft)
779 struct utimbuf buf;
780 int result;
782 if (null_timespec(ft->atime)) {
783 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
784 } else {
785 buf.actime = ft->atime.tv_sec;
787 if (null_timespec(ft->mtime)) {
788 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
789 } else {
790 buf.modtime = ft->mtime.tv_sec;
792 if (!null_timespec(ft->create_time)) {
793 set_create_timespec_ea(handle->conn, smb_fname,
794 ft->create_time);
796 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
797 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
798 return 0;
801 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
802 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
803 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
804 ft->create_time.tv_sec, result);
805 return result;
807 #endif /* HAVE_CEPH_STATX */
809 static int cephwrap_unlink(struct vfs_handle_struct *handle,
810 const struct smb_filename *smb_fname)
812 int result = -1;
814 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
815 if (smb_fname->stream_name) {
816 errno = ENOENT;
817 return result;
819 result = ceph_unlink(handle->data, smb_fname->base_name);
820 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
821 WRAP_RETURN(result);
824 static int cephwrap_chmod(struct vfs_handle_struct *handle,
825 const struct smb_filename *smb_fname,
826 mode_t mode)
828 int result;
830 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
833 * We need to do this due to the fact that the default POSIX ACL
834 * chmod modifies the ACL *mask* for the group owner, not the
835 * group owner bits directly. JRA.
840 int saved_errno = errno; /* We might get ENOSYS */
841 result = SMB_VFS_CHMOD_ACL(handle->conn,
842 smb_fname,
843 mode);
844 if (result == 0) {
845 return result;
847 /* Error - return the old errno. */
848 errno = saved_errno;
851 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
852 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
853 WRAP_RETURN(result);
856 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
858 int result;
860 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
863 * We need to do this due to the fact that the default POSIX ACL
864 * chmod modifies the ACL *mask* for the group owner, not the
865 * group owner bits directly. JRA.
869 int saved_errno = errno; /* We might get ENOSYS */
870 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
871 return result;
873 /* Error - return the old errno. */
874 errno = saved_errno;
877 #if defined(HAVE_FCHMOD)
878 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
879 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
880 WRAP_RETURN(result);
881 #else
882 errno = ENOSYS;
883 #endif
884 return -1;
887 static int cephwrap_chown(struct vfs_handle_struct *handle,
888 const struct smb_filename *smb_fname,
889 uid_t uid,
890 gid_t gid)
892 int result;
893 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
894 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
895 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
896 WRAP_RETURN(result);
899 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
901 int result;
902 #ifdef HAVE_FCHOWN
904 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
905 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
906 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
907 WRAP_RETURN(result);
908 #else
909 errno = ENOSYS;
910 result = -1;
911 #endif
912 return result;
915 static int cephwrap_lchown(struct vfs_handle_struct *handle,
916 const struct smb_filename *smb_fname,
917 uid_t uid,
918 gid_t gid)
920 int result;
921 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
922 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
923 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
924 WRAP_RETURN(result);
927 static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path)
929 int result = -1;
930 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, path);
932 * If the path is just / use chdir because Ceph is below / and
933 * cannot deal with changing directory above its mount point
935 if (path && !strcmp(path, "/"))
936 return chdir(path);
938 result = ceph_chdir(handle->data, path);
939 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
940 WRAP_RETURN(result);
943 static char *cephwrap_getwd(struct vfs_handle_struct *handle)
945 const char *cwd = ceph_getcwd(handle->data);
946 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
947 return SMB_STRDUP(cwd);
950 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
952 off_t space_to_write;
953 uint64_t space_avail;
954 uint64_t bsize,dfree,dsize;
955 int ret;
956 NTSTATUS status;
957 SMB_STRUCT_STAT *pst;
959 status = vfs_stat_fsp(fsp);
960 if (!NT_STATUS_IS_OK(status)) {
961 return -1;
963 pst = &fsp->fsp_name->st;
965 #ifdef S_ISFIFO
966 if (S_ISFIFO(pst->st_ex_mode))
967 return 0;
968 #endif
970 if (pst->st_ex_size == len)
971 return 0;
973 /* Shrink - just ftruncate. */
974 if (pst->st_ex_size > len)
975 return ftruncate(fsp->fh->fd, len);
977 space_to_write = len - pst->st_ex_size;
979 /* for allocation try fallocate first. This can fail on some
980 platforms e.g. when the filesystem doesn't support it and no
981 emulation is being done by the libc (like on AIX with JFS1). In that
982 case we do our own emulation. fallocate implementations can
983 return ENOTSUP or EINVAL in cases like that. */
984 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
985 if (ret == -1 && errno == ENOSPC) {
986 return -1;
988 if (ret == 0) {
989 return 0;
991 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
992 "error %d. Falling back to slow manual allocation\n", errno));
994 /* available disk space is enough or not? */
995 space_avail =
996 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
997 /* space_avail is 1k blocks */
998 if (space_avail == (uint64_t)-1 ||
999 ((uint64_t)space_to_write/1024 > space_avail) ) {
1000 errno = ENOSPC;
1001 return -1;
1004 /* Write out the real space on disk. */
1005 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1008 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1010 int result = -1;
1011 SMB_STRUCT_STAT st;
1012 char c = 0;
1013 off_t currpos;
1015 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1017 if (lp_strict_allocate(SNUM(fsp->conn))) {
1018 result = strict_allocate_ftruncate(handle, fsp, len);
1019 return result;
1022 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1023 sys_ftruncate if the system supports it. Then I discovered that
1024 you can have some filesystems that support ftruncate
1025 expansion and some that don't! On Linux fat can't do
1026 ftruncate extend but ext2 can. */
1028 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1029 if (result == 0)
1030 goto done;
1032 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1033 extend a file with ftruncate. Provide alternate implementation
1034 for this */
1035 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1036 if (currpos == -1) {
1037 goto done;
1040 /* Do an fstat to see if the file is longer than the requested
1041 size in which case the ftruncate above should have
1042 succeeded or shorter, in which case seek to len - 1 and
1043 write 1 byte of zero */
1044 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1045 goto done;
1048 #ifdef S_ISFIFO
1049 if (S_ISFIFO(st.st_ex_mode)) {
1050 result = 0;
1051 goto done;
1053 #endif
1055 if (st.st_ex_size == len) {
1056 result = 0;
1057 goto done;
1060 if (st.st_ex_size > len) {
1061 /* the sys_ftruncate should have worked */
1062 goto done;
1065 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1066 goto done;
1068 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1069 goto done;
1071 /* Seek to where we were */
1072 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1073 goto done;
1074 result = 0;
1076 done:
1078 return result;
1081 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1083 DBG_DEBUG("[CEPH] lock\n");
1084 return true;
1087 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1088 uint32_t share_mode, uint32_t access_mask)
1090 DBG_DEBUG("[CEPH] kernel_flock\n");
1092 * We must return zero here and pretend all is good.
1093 * One day we might have this in CEPH.
1095 return 0;
1098 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1100 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1102 errno = 0;
1103 return false;
1107 * We cannot let this fall through to the default, because the file might only
1108 * be accessible from libceph (which is a user-space client) but the fd might
1109 * be for some file the kernel knows about.
1111 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1112 int leasetype)
1114 int result = -1;
1116 DBG_DEBUG("[CEPH] linux_setlease\n");
1117 errno = ENOSYS;
1118 return result;
1121 static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
1123 int result = -1;
1124 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath);
1125 result = ceph_symlink(handle->data, oldpath, newpath);
1126 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1127 WRAP_RETURN(result);
1130 static int cephwrap_readlink(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
1132 int result = -1;
1133 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz));
1134 result = ceph_readlink(handle->data, path, buf, bufsiz);
1135 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1136 WRAP_RETURN(result);
1139 static int cephwrap_link(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
1141 int result = -1;
1142 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath);
1143 result = ceph_link(handle->data, oldpath, newpath);
1144 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1145 WRAP_RETURN(result);
1148 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1149 const struct smb_filename *smb_fname,
1150 mode_t mode,
1151 SMB_DEV_T dev)
1153 int result = -1;
1154 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1155 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1156 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1157 WRAP_RETURN(result);
1161 * This is a simple version of real-path ... a better version is needed to
1162 * ask libceph about symbolic links.
1164 static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *path)
1166 char *result;
1167 size_t len = strlen(path);
1169 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1170 if (len && (path[0] == '/')) {
1171 int r = asprintf(&result, "%s", path);
1172 if (r < 0) return NULL;
1173 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1174 if (len == 2) {
1175 int r = asprintf(&result, "%s",
1176 handle->conn->connectpath);
1177 if (r < 0) return NULL;
1178 } else {
1179 int r = asprintf(&result, "%s/%s",
1180 handle->conn->connectpath, &path[2]);
1181 if (r < 0) return NULL;
1183 } else {
1184 int r = asprintf(&result, "%s/%s",
1185 handle->conn->connectpath, path);
1186 if (r < 0) return NULL;
1188 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1189 return result;
1192 static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
1193 unsigned int flags)
1195 errno = ENOSYS;
1196 return -1;
1199 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1200 const char *path,
1201 const char *name,
1202 TALLOC_CTX *mem_ctx,
1203 char **found_name)
1206 * Don't fall back to get_real_filename so callers can differentiate
1207 * between a full directory scan and an actual case-insensitive stat.
1209 errno = EOPNOTSUPP;
1210 return -1;
1213 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1214 const char *fname)
1216 return handle->conn->connectpath;
1219 /****************************************************************
1220 Extended attribute operations.
1221 *****************************************************************/
1223 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1224 const struct smb_filename *smb_fname,
1225 const char *name,
1226 void *value,
1227 size_t size)
1229 int ret;
1230 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1231 smb_fname->base_name, name, value, llu(size));
1232 ret = ceph_getxattr(handle->data,
1233 smb_fname->base_name, name, value, size);
1234 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1235 if (ret < 0) {
1236 WRAP_RETURN(ret);
1237 } else {
1238 return (ssize_t)ret;
1242 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1244 int ret;
1245 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1246 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1247 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1248 #else
1249 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1250 #endif
1251 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1252 if (ret < 0) {
1253 WRAP_RETURN(ret);
1254 } else {
1255 return (ssize_t)ret;
1259 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1260 const struct smb_filename *smb_fname,
1261 char *list,
1262 size_t size)
1264 int ret;
1265 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1266 smb_fname->base_name, list, llu(size));
1267 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1268 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1269 if (ret < 0) {
1270 WRAP_RETURN(ret);
1271 } else {
1272 return (ssize_t)ret;
1276 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1278 int ret;
1279 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1280 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1281 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1282 #else
1283 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1284 #endif
1285 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1286 if (ret < 0) {
1287 WRAP_RETURN(ret);
1288 } else {
1289 return (ssize_t)ret;
1293 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1294 const struct smb_filename *smb_fname,
1295 const char *name)
1297 int ret;
1298 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1299 smb_fname->base_name, name);
1300 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1301 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1302 WRAP_RETURN(ret);
1305 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1307 int ret;
1308 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1309 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1310 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1311 #else
1312 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1313 #endif
1314 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1315 WRAP_RETURN(ret);
1318 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1319 const struct smb_filename *smb_fname,
1320 const char *name,
1321 const void *value,
1322 size_t size,
1323 int flags)
1325 int ret;
1326 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1327 smb_fname->base_name, name, value, llu(size), flags);
1328 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1329 name, value, size, flags);
1330 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1331 WRAP_RETURN(ret);
1334 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1336 int ret;
1337 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1338 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1339 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1340 name, value, size, flags);
1341 #else
1342 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1343 #endif
1344 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1345 WRAP_RETURN(ret);
1348 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1352 * We do not support AIO yet.
1355 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1356 errno = ENOTSUP;
1357 return false;
1360 static struct vfs_fn_pointers ceph_fns = {
1361 /* Disk operations */
1363 .connect_fn = cephwrap_connect,
1364 .disconnect_fn = cephwrap_disconnect,
1365 .disk_free_fn = cephwrap_disk_free,
1366 .get_quota_fn = cephwrap_get_quota,
1367 .set_quota_fn = cephwrap_set_quota,
1368 .statvfs_fn = cephwrap_statvfs,
1370 /* Directory operations */
1372 .opendir_fn = cephwrap_opendir,
1373 .fdopendir_fn = cephwrap_fdopendir,
1374 .readdir_fn = cephwrap_readdir,
1375 .seekdir_fn = cephwrap_seekdir,
1376 .telldir_fn = cephwrap_telldir,
1377 .rewind_dir_fn = cephwrap_rewinddir,
1378 .mkdir_fn = cephwrap_mkdir,
1379 .rmdir_fn = cephwrap_rmdir,
1380 .closedir_fn = cephwrap_closedir,
1382 /* File operations */
1384 .open_fn = cephwrap_open,
1385 .close_fn = cephwrap_close,
1386 .read_fn = cephwrap_read,
1387 .pread_fn = cephwrap_pread,
1388 .write_fn = cephwrap_write,
1389 .pwrite_fn = cephwrap_pwrite,
1390 .lseek_fn = cephwrap_lseek,
1391 .sendfile_fn = cephwrap_sendfile,
1392 .recvfile_fn = cephwrap_recvfile,
1393 .rename_fn = cephwrap_rename,
1394 .fsync_fn = cephwrap_fsync,
1395 .stat_fn = cephwrap_stat,
1396 .fstat_fn = cephwrap_fstat,
1397 .lstat_fn = cephwrap_lstat,
1398 .unlink_fn = cephwrap_unlink,
1399 .chmod_fn = cephwrap_chmod,
1400 .fchmod_fn = cephwrap_fchmod,
1401 .chown_fn = cephwrap_chown,
1402 .fchown_fn = cephwrap_fchown,
1403 .lchown_fn = cephwrap_lchown,
1404 .chdir_fn = cephwrap_chdir,
1405 .getwd_fn = cephwrap_getwd,
1406 .ntimes_fn = cephwrap_ntimes,
1407 .ftruncate_fn = cephwrap_ftruncate,
1408 .lock_fn = cephwrap_lock,
1409 .kernel_flock_fn = cephwrap_kernel_flock,
1410 .linux_setlease_fn = cephwrap_linux_setlease,
1411 .getlock_fn = cephwrap_getlock,
1412 .symlink_fn = cephwrap_symlink,
1413 .readlink_fn = cephwrap_readlink,
1414 .link_fn = cephwrap_link,
1415 .mknod_fn = cephwrap_mknod,
1416 .realpath_fn = cephwrap_realpath,
1417 .chflags_fn = cephwrap_chflags,
1418 .get_real_filename_fn = cephwrap_get_real_filename,
1419 .connectpath_fn = cephwrap_connectpath,
1421 /* EA operations. */
1422 .getxattr_fn = cephwrap_getxattr,
1423 .fgetxattr_fn = cephwrap_fgetxattr,
1424 .listxattr_fn = cephwrap_listxattr,
1425 .flistxattr_fn = cephwrap_flistxattr,
1426 .removexattr_fn = cephwrap_removexattr,
1427 .fremovexattr_fn = cephwrap_fremovexattr,
1428 .setxattr_fn = cephwrap_setxattr,
1429 .fsetxattr_fn = cephwrap_fsetxattr,
1431 /* Posix ACL Operations */
1432 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1433 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1434 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1435 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1436 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1437 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1438 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1440 /* aio operations */
1441 .aio_force_fn = cephwrap_aio_force,
1444 NTSTATUS vfs_ceph_init(TALLOC_CTX *);
1445 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1447 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1448 "ceph", &ceph_fns);