s3:auth: only call secrets_fetch_domain_sid() once in finalize_local_nt_token()
[Samba.git] / source3 / modules / vfs_ceph.c
blobd61213110e01402aca3671cdcf1c0475eb7ff89d
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 static uint32_t cephwrap_fs_capabilities(struct vfs_handle_struct *handle,
274 enum timestamp_set_resolution *p_ts_res)
276 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
278 #ifdef HAVE_CEPH_STATX
279 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
280 #else
281 *p_ts_res = TIMESTAMP_SET_MSEC;
282 #endif
284 return caps;
287 /* Directory operations */
289 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
290 const struct smb_filename *smb_fname,
291 const char *mask, uint32_t attr)
293 int ret = 0;
294 struct ceph_dir_result *result;
295 DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
297 /* Returns NULL if it does not exist or there are problems ? */
298 ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
299 if (ret < 0) {
300 result = NULL;
301 errno = -ret; /* We return result which is NULL in this case */
304 DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
305 return (DIR *) result;
308 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
309 struct files_struct *fsp,
310 const char *mask,
311 uint32_t attributes)
313 int ret = 0;
314 struct ceph_dir_result *result;
315 DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
317 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
318 if (ret < 0) {
319 result = NULL;
320 errno = -ret; /* We return result which is NULL in this case */
323 DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
324 return (DIR *) result;
327 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
328 DIR *dirp,
329 SMB_STRUCT_STAT *sbuf)
331 struct dirent *result;
333 DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
334 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
335 DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
337 /* Default Posix readdir() does not give us stat info.
338 * Set to invalid to indicate we didn't return this info. */
339 if (sbuf)
340 SET_STAT_INVALID(*sbuf);
341 return result;
344 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
346 DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
347 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
350 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
352 long ret;
353 DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
354 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
355 DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
356 WRAP_RETURN(ret);
359 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
361 DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
362 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
365 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
366 const struct smb_filename *smb_fname,
367 mode_t mode)
369 int result;
370 bool has_dacl = False;
371 char *parent = NULL;
372 const char *path = smb_fname->base_name;
374 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
376 if (lp_inherit_acls(SNUM(handle->conn))
377 && parent_dirname(talloc_tos(), path, &parent, NULL)
378 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
379 mode = 0777;
381 TALLOC_FREE(parent);
383 result = ceph_mkdir(handle->data, path, mode);
386 * Note. This order is important
388 if (result) {
389 WRAP_RETURN(result);
390 } else if (result == 0 && !has_dacl) {
392 * We need to do this as the default behavior of POSIX ACLs
393 * is to set the mask to be the requested group permission
394 * bits, not the group permission bits to be the requested
395 * group permission bits. This is not what we want, as it will
396 * mess up any inherited ACL bits that were set. JRA.
398 int saved_errno = errno; /* We may get ENOSYS */
399 if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
400 (errno == ENOSYS)) {
401 errno = saved_errno;
405 return result;
408 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
409 const struct smb_filename *smb_fname)
411 int result;
413 DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
414 result = ceph_rmdir(handle->data, smb_fname->base_name);
415 DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
416 WRAP_RETURN(result);
419 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
421 int result;
423 DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
424 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
425 DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
426 WRAP_RETURN(result);
429 /* File operations */
431 static int cephwrap_open(struct vfs_handle_struct *handle,
432 struct smb_filename *smb_fname,
433 files_struct *fsp, int flags, mode_t mode)
435 int result = -ENOENT;
436 DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
437 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
439 if (smb_fname->stream_name) {
440 goto out;
443 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
444 out:
445 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
446 WRAP_RETURN(result);
449 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
451 int result;
453 DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
454 result = ceph_close(handle->data, fsp->fh->fd);
455 DBG_DEBUG("[CEPH] close(...) = %d\n", result);
457 WRAP_RETURN(result);
460 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
462 ssize_t result;
464 DBG_DEBUG("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
466 /* Using -1 for the offset means read/write rather than pread/pwrite */
467 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
468 DBG_DEBUG("[CEPH] read(...) = %llu\n", llu(result));
469 WRAP_RETURN(result);
472 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
473 size_t n, off_t offset)
475 ssize_t result;
477 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
479 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
480 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
481 WRAP_RETURN(result);
485 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
487 ssize_t result;
489 DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
491 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
493 DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
494 if (result < 0) {
495 WRAP_RETURN(result);
497 fsp->fh->pos += result;
498 return result;
501 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
502 size_t n, off_t offset)
504 ssize_t result;
506 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
507 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
508 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
509 WRAP_RETURN(result);
512 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
514 off_t result = 0;
516 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
517 /* Cope with 'stat' file opens. */
518 if (fsp->fh->fd != -1) {
519 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
521 WRAP_RETURN(result);
524 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
525 off_t offset, size_t n)
528 * We cannot support sendfile because libceph is in user space.
530 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
531 errno = ENOTSUP;
532 return -1;
535 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
536 int fromfd,
537 files_struct *tofsp,
538 off_t offset,
539 size_t n)
542 * We cannot support recvfile because libceph is in user space.
544 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
545 errno=ENOTSUP;
546 return -1;
549 static int cephwrap_rename(struct vfs_handle_struct *handle,
550 const struct smb_filename *smb_fname_src,
551 const struct smb_filename *smb_fname_dst)
553 int result = -1;
554 DBG_DEBUG("[CEPH] cephwrap_rename\n");
555 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
556 errno = ENOENT;
557 return result;
560 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
561 WRAP_RETURN(result);
564 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
566 int result;
567 DBG_DEBUG("[CEPH] cephwrap_fsync\n");
568 result = ceph_fsync(handle->data, fsp->fh->fd, false);
569 WRAP_RETURN(result);
572 #ifdef HAVE_CEPH_STATX
573 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
575 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
577 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
578 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
579 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
581 dst->st_ex_dev = stx->stx_dev;
582 dst->st_ex_rdev = stx->stx_rdev;
583 dst->st_ex_ino = stx->stx_ino;
584 dst->st_ex_mode = stx->stx_mode;
585 dst->st_ex_uid = stx->stx_uid;
586 dst->st_ex_gid = stx->stx_gid;
587 dst->st_ex_size = stx->stx_size;
588 dst->st_ex_nlink = stx->stx_nlink;
589 dst->st_ex_atime = stx->stx_atime;
590 dst->st_ex_btime = stx->stx_btime;
591 dst->st_ex_ctime = stx->stx_ctime;
592 dst->st_ex_mtime = stx->stx_mtime;
593 dst->st_ex_calculated_birthtime = false;
594 dst->st_ex_blksize = stx->stx_blksize;
595 dst->st_ex_blocks = stx->stx_blocks;
598 static int cephwrap_stat(struct vfs_handle_struct *handle,
599 struct smb_filename *smb_fname)
601 int result = -1;
602 struct ceph_statx stx;
604 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
606 if (smb_fname->stream_name) {
607 errno = ENOENT;
608 return result;
611 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
612 SAMBA_STATX_ATTR_MASK, 0);
613 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
614 if (result < 0) {
615 WRAP_RETURN(result);
616 } else {
617 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
618 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
619 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
620 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
621 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
622 llu(stx.stx_size), llu(stx.stx_blksize),
623 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
624 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
626 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
627 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
628 return result;
631 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
633 int result = -1;
634 struct ceph_statx stx;
636 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
637 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
638 SAMBA_STATX_ATTR_MASK, 0);
639 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
640 if (result < 0) {
641 WRAP_RETURN(result);
642 } else {
643 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
644 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
645 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
646 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
647 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
648 llu(stx.stx_size), llu(stx.stx_blksize),
649 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
650 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
652 init_stat_ex_from_ceph_statx(sbuf, &stx);
653 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
654 return result;
657 static int cephwrap_lstat(struct vfs_handle_struct *handle,
658 struct smb_filename *smb_fname)
660 int result = -1;
661 struct ceph_statx stx;
663 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
665 if (smb_fname->stream_name) {
666 errno = ENOENT;
667 return result;
670 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
671 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
672 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
673 if (result < 0) {
674 WRAP_RETURN(result);
676 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
677 return result;
680 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
681 const struct smb_filename *smb_fname,
682 struct smb_file_time *ft)
684 struct ceph_statx stx = { 0 };
685 int result;
686 int mask = 0;
688 if (!null_timespec(ft->atime)) {
689 stx.stx_atime = ft->atime;
690 mask |= CEPH_SETATTR_ATIME;
692 if (!null_timespec(ft->mtime)) {
693 stx.stx_mtime = ft->mtime;
694 mask |= CEPH_SETATTR_MTIME;
696 if (!null_timespec(ft->create_time)) {
697 stx.stx_btime = ft->create_time;
698 mask |= CEPH_SETATTR_BTIME;
701 if (!mask) {
702 return 0;
705 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
706 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
707 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
708 ft->create_time.tv_sec, result);
709 return result;
712 #else /* HAVE_CEPH_STATX */
714 static int cephwrap_stat(struct vfs_handle_struct *handle,
715 struct smb_filename *smb_fname)
717 int result = -1;
718 struct stat stbuf;
720 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
722 if (smb_fname->stream_name) {
723 errno = ENOENT;
724 return result;
727 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
728 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
729 if (result < 0) {
730 WRAP_RETURN(result);
731 } else {
732 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
733 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
734 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
735 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
736 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
737 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
739 init_stat_ex_from_stat(
740 &smb_fname->st, &stbuf,
741 lp_fake_directory_create_times(SNUM(handle->conn)));
742 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
743 return result;
746 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
748 int result = -1;
749 struct stat stbuf;
751 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
752 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
753 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
754 if (result < 0) {
755 WRAP_RETURN(result);
756 } else {
757 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
758 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
759 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
760 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
761 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
762 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
765 init_stat_ex_from_stat(
766 sbuf, &stbuf,
767 lp_fake_directory_create_times(SNUM(handle->conn)));
768 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
769 return result;
772 static int cephwrap_lstat(struct vfs_handle_struct *handle,
773 struct smb_filename *smb_fname)
775 int result = -1;
776 struct stat stbuf;
778 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
780 if (smb_fname->stream_name) {
781 errno = ENOENT;
782 return result;
785 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
786 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
787 if (result < 0) {
788 WRAP_RETURN(result);
790 init_stat_ex_from_stat(
791 &smb_fname->st, &stbuf,
792 lp_fake_directory_create_times(SNUM(handle->conn)));
793 return result;
796 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
797 const struct smb_filename *smb_fname,
798 struct smb_file_time *ft)
800 struct utimbuf buf;
801 int result;
803 if (null_timespec(ft->atime)) {
804 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
805 } else {
806 buf.actime = ft->atime.tv_sec;
808 if (null_timespec(ft->mtime)) {
809 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
810 } else {
811 buf.modtime = ft->mtime.tv_sec;
813 if (!null_timespec(ft->create_time)) {
814 set_create_timespec_ea(handle->conn, smb_fname,
815 ft->create_time);
817 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
818 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
819 return 0;
822 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
823 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
824 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
825 ft->create_time.tv_sec, result);
826 return result;
828 #endif /* HAVE_CEPH_STATX */
830 static int cephwrap_unlink(struct vfs_handle_struct *handle,
831 const struct smb_filename *smb_fname)
833 int result = -1;
835 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
836 if (smb_fname->stream_name) {
837 errno = ENOENT;
838 return result;
840 result = ceph_unlink(handle->data, smb_fname->base_name);
841 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
842 WRAP_RETURN(result);
845 static int cephwrap_chmod(struct vfs_handle_struct *handle,
846 const struct smb_filename *smb_fname,
847 mode_t mode)
849 int result;
851 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
854 * We need to do this due to the fact that the default POSIX ACL
855 * chmod modifies the ACL *mask* for the group owner, not the
856 * group owner bits directly. JRA.
861 int saved_errno = errno; /* We might get ENOSYS */
862 result = SMB_VFS_CHMOD_ACL(handle->conn,
863 smb_fname,
864 mode);
865 if (result == 0) {
866 return result;
868 /* Error - return the old errno. */
869 errno = saved_errno;
872 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
873 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
874 WRAP_RETURN(result);
877 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
879 int result;
881 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
884 * We need to do this due to the fact that the default POSIX ACL
885 * chmod modifies the ACL *mask* for the group owner, not the
886 * group owner bits directly. JRA.
890 int saved_errno = errno; /* We might get ENOSYS */
891 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
892 return result;
894 /* Error - return the old errno. */
895 errno = saved_errno;
898 #if defined(HAVE_FCHMOD)
899 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
900 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
901 WRAP_RETURN(result);
902 #else
903 errno = ENOSYS;
904 #endif
905 return -1;
908 static int cephwrap_chown(struct vfs_handle_struct *handle,
909 const struct smb_filename *smb_fname,
910 uid_t uid,
911 gid_t gid)
913 int result;
914 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
915 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
916 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
917 WRAP_RETURN(result);
920 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
922 int result;
923 #ifdef HAVE_FCHOWN
925 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
926 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
927 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
928 WRAP_RETURN(result);
929 #else
930 errno = ENOSYS;
931 result = -1;
932 #endif
933 return result;
936 static int cephwrap_lchown(struct vfs_handle_struct *handle,
937 const struct smb_filename *smb_fname,
938 uid_t uid,
939 gid_t gid)
941 int result;
942 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
943 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
944 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
945 WRAP_RETURN(result);
948 static int cephwrap_chdir(struct vfs_handle_struct *handle,
949 const struct smb_filename *smb_fname)
951 int result = -1;
952 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
953 result = ceph_chdir(handle->data, smb_fname->base_name);
954 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
955 WRAP_RETURN(result);
958 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
959 TALLOC_CTX *ctx)
961 const char *cwd = ceph_getcwd(handle->data);
962 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
963 return synthetic_smb_fname(ctx,
964 cwd,
965 NULL,
966 NULL,
970 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
972 off_t space_to_write;
973 uint64_t space_avail;
974 uint64_t bsize,dfree,dsize;
975 int ret;
976 NTSTATUS status;
977 SMB_STRUCT_STAT *pst;
979 status = vfs_stat_fsp(fsp);
980 if (!NT_STATUS_IS_OK(status)) {
981 return -1;
983 pst = &fsp->fsp_name->st;
985 #ifdef S_ISFIFO
986 if (S_ISFIFO(pst->st_ex_mode))
987 return 0;
988 #endif
990 if (pst->st_ex_size == len)
991 return 0;
993 /* Shrink - just ftruncate. */
994 if (pst->st_ex_size > len)
995 return ftruncate(fsp->fh->fd, len);
997 space_to_write = len - pst->st_ex_size;
999 /* for allocation try fallocate first. This can fail on some
1000 platforms e.g. when the filesystem doesn't support it and no
1001 emulation is being done by the libc (like on AIX with JFS1). In that
1002 case we do our own emulation. fallocate implementations can
1003 return ENOTSUP or EINVAL in cases like that. */
1004 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1005 if (ret == -1 && errno == ENOSPC) {
1006 return -1;
1008 if (ret == 0) {
1009 return 0;
1011 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1012 "error %d. Falling back to slow manual allocation\n", errno));
1014 /* available disk space is enough or not? */
1015 space_avail =
1016 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1017 /* space_avail is 1k blocks */
1018 if (space_avail == (uint64_t)-1 ||
1019 ((uint64_t)space_to_write/1024 > space_avail) ) {
1020 errno = ENOSPC;
1021 return -1;
1024 /* Write out the real space on disk. */
1025 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1028 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1030 int result = -1;
1031 SMB_STRUCT_STAT st;
1032 char c = 0;
1033 off_t currpos;
1035 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1037 if (lp_strict_allocate(SNUM(fsp->conn))) {
1038 result = strict_allocate_ftruncate(handle, fsp, len);
1039 return result;
1042 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1043 sys_ftruncate if the system supports it. Then I discovered that
1044 you can have some filesystems that support ftruncate
1045 expansion and some that don't! On Linux fat can't do
1046 ftruncate extend but ext2 can. */
1048 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1049 if (result == 0)
1050 goto done;
1052 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1053 extend a file with ftruncate. Provide alternate implementation
1054 for this */
1055 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1056 if (currpos == -1) {
1057 goto done;
1060 /* Do an fstat to see if the file is longer than the requested
1061 size in which case the ftruncate above should have
1062 succeeded or shorter, in which case seek to len - 1 and
1063 write 1 byte of zero */
1064 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1065 goto done;
1068 #ifdef S_ISFIFO
1069 if (S_ISFIFO(st.st_ex_mode)) {
1070 result = 0;
1071 goto done;
1073 #endif
1075 if (st.st_ex_size == len) {
1076 result = 0;
1077 goto done;
1080 if (st.st_ex_size > len) {
1081 /* the sys_ftruncate should have worked */
1082 goto done;
1085 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1086 goto done;
1088 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1089 goto done;
1091 /* Seek to where we were */
1092 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1093 goto done;
1094 result = 0;
1096 done:
1098 return result;
1101 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1103 DBG_DEBUG("[CEPH] lock\n");
1104 return true;
1107 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1108 uint32_t share_mode, uint32_t access_mask)
1110 DBG_DEBUG("[CEPH] kernel_flock\n");
1112 * We must return zero here and pretend all is good.
1113 * One day we might have this in CEPH.
1115 return 0;
1118 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1120 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1122 errno = 0;
1123 return false;
1127 * We cannot let this fall through to the default, because the file might only
1128 * be accessible from libceph (which is a user-space client) but the fd might
1129 * be for some file the kernel knows about.
1131 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1132 int leasetype)
1134 int result = -1;
1136 DBG_DEBUG("[CEPH] linux_setlease\n");
1137 errno = ENOSYS;
1138 return result;
1141 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1142 const char *link_target,
1143 const struct smb_filename *new_smb_fname)
1145 int result = -1;
1146 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1147 link_target,
1148 new_smb_fname->base_name);
1149 result = ceph_symlink(handle->data,
1150 link_target,
1151 new_smb_fname->base_name);
1152 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1153 WRAP_RETURN(result);
1156 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1157 const struct smb_filename *smb_fname,
1158 char *buf,
1159 size_t bufsiz)
1161 int result = -1;
1162 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1163 smb_fname->base_name, buf, llu(bufsiz));
1164 result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1165 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1166 WRAP_RETURN(result);
1169 static int cephwrap_link(struct vfs_handle_struct *handle,
1170 const struct smb_filename *old_smb_fname,
1171 const struct smb_filename *new_smb_fname)
1173 int result = -1;
1174 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1175 old_smb_fname->base_name,
1176 new_smb_fname->base_name);
1177 result = ceph_link(handle->data,
1178 old_smb_fname->base_name,
1179 new_smb_fname->base_name);
1180 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1181 WRAP_RETURN(result);
1184 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1185 const struct smb_filename *smb_fname,
1186 mode_t mode,
1187 SMB_DEV_T dev)
1189 int result = -1;
1190 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1191 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1192 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1193 WRAP_RETURN(result);
1197 * This is a simple version of real-path ... a better version is needed to
1198 * ask libceph about symbolic links.
1200 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1201 TALLOC_CTX *ctx,
1202 const struct smb_filename *smb_fname)
1204 char *result;
1205 const char *path = smb_fname->base_name;
1206 size_t len = strlen(path);
1207 struct smb_filename *result_fname = NULL;
1209 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1210 if (len && (path[0] == '/')) {
1211 int r = asprintf(&result, "%s", path);
1212 if (r < 0) return NULL;
1213 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1214 if (len == 2) {
1215 int r = asprintf(&result, "%s",
1216 handle->conn->connectpath);
1217 if (r < 0) return NULL;
1218 } else {
1219 int r = asprintf(&result, "%s/%s",
1220 handle->conn->connectpath, &path[2]);
1221 if (r < 0) return NULL;
1223 } else {
1224 int r = asprintf(&result, "%s/%s",
1225 handle->conn->connectpath, path);
1226 if (r < 0) return NULL;
1228 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1229 result_fname = synthetic_smb_fname(ctx,
1230 result,
1231 NULL,
1232 NULL,
1234 SAFE_FREE(result);
1235 return result_fname;
1238 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1239 const struct smb_filename *smb_fname,
1240 unsigned int flags)
1242 errno = ENOSYS;
1243 return -1;
1246 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1247 const char *path,
1248 const char *name,
1249 TALLOC_CTX *mem_ctx,
1250 char **found_name)
1253 * Don't fall back to get_real_filename so callers can differentiate
1254 * between a full directory scan and an actual case-insensitive stat.
1256 errno = EOPNOTSUPP;
1257 return -1;
1260 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1261 const struct smb_filename *smb_fname)
1263 return handle->conn->connectpath;
1266 /****************************************************************
1267 Extended attribute operations.
1268 *****************************************************************/
1270 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1271 const struct smb_filename *smb_fname,
1272 const char *name,
1273 void *value,
1274 size_t size)
1276 int ret;
1277 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1278 smb_fname->base_name, name, value, llu(size));
1279 ret = ceph_getxattr(handle->data,
1280 smb_fname->base_name, name, value, size);
1281 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1282 if (ret < 0) {
1283 WRAP_RETURN(ret);
1284 } else {
1285 return (ssize_t)ret;
1289 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1291 int ret;
1292 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1293 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1294 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1295 #else
1296 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1297 #endif
1298 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1299 if (ret < 0) {
1300 WRAP_RETURN(ret);
1301 } else {
1302 return (ssize_t)ret;
1306 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1307 const struct smb_filename *smb_fname,
1308 char *list,
1309 size_t size)
1311 int ret;
1312 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1313 smb_fname->base_name, list, llu(size));
1314 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1315 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1316 if (ret < 0) {
1317 WRAP_RETURN(ret);
1318 } else {
1319 return (ssize_t)ret;
1323 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1325 int ret;
1326 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1327 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1328 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1329 #else
1330 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1331 #endif
1332 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1333 if (ret < 0) {
1334 WRAP_RETURN(ret);
1335 } else {
1336 return (ssize_t)ret;
1340 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1341 const struct smb_filename *smb_fname,
1342 const char *name)
1344 int ret;
1345 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1346 smb_fname->base_name, name);
1347 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1348 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1349 WRAP_RETURN(ret);
1352 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1354 int ret;
1355 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1356 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1357 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1358 #else
1359 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1360 #endif
1361 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1362 WRAP_RETURN(ret);
1365 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1366 const struct smb_filename *smb_fname,
1367 const char *name,
1368 const void *value,
1369 size_t size,
1370 int flags)
1372 int ret;
1373 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1374 smb_fname->base_name, name, value, llu(size), flags);
1375 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1376 name, value, size, flags);
1377 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1378 WRAP_RETURN(ret);
1381 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1383 int ret;
1384 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1385 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1386 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1387 name, value, size, flags);
1388 #else
1389 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1390 #endif
1391 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1392 WRAP_RETURN(ret);
1395 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1399 * We do not support AIO yet.
1402 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1403 errno = ENOTSUP;
1404 return false;
1407 static struct vfs_fn_pointers ceph_fns = {
1408 /* Disk operations */
1410 .connect_fn = cephwrap_connect,
1411 .disconnect_fn = cephwrap_disconnect,
1412 .disk_free_fn = cephwrap_disk_free,
1413 .get_quota_fn = cephwrap_get_quota,
1414 .set_quota_fn = cephwrap_set_quota,
1415 .statvfs_fn = cephwrap_statvfs,
1416 .fs_capabilities_fn = cephwrap_fs_capabilities,
1418 /* Directory operations */
1420 .opendir_fn = cephwrap_opendir,
1421 .fdopendir_fn = cephwrap_fdopendir,
1422 .readdir_fn = cephwrap_readdir,
1423 .seekdir_fn = cephwrap_seekdir,
1424 .telldir_fn = cephwrap_telldir,
1425 .rewind_dir_fn = cephwrap_rewinddir,
1426 .mkdir_fn = cephwrap_mkdir,
1427 .rmdir_fn = cephwrap_rmdir,
1428 .closedir_fn = cephwrap_closedir,
1430 /* File operations */
1432 .open_fn = cephwrap_open,
1433 .close_fn = cephwrap_close,
1434 .read_fn = cephwrap_read,
1435 .pread_fn = cephwrap_pread,
1436 .write_fn = cephwrap_write,
1437 .pwrite_fn = cephwrap_pwrite,
1438 .lseek_fn = cephwrap_lseek,
1439 .sendfile_fn = cephwrap_sendfile,
1440 .recvfile_fn = cephwrap_recvfile,
1441 .rename_fn = cephwrap_rename,
1442 .fsync_fn = cephwrap_fsync,
1443 .stat_fn = cephwrap_stat,
1444 .fstat_fn = cephwrap_fstat,
1445 .lstat_fn = cephwrap_lstat,
1446 .unlink_fn = cephwrap_unlink,
1447 .chmod_fn = cephwrap_chmod,
1448 .fchmod_fn = cephwrap_fchmod,
1449 .chown_fn = cephwrap_chown,
1450 .fchown_fn = cephwrap_fchown,
1451 .lchown_fn = cephwrap_lchown,
1452 .chdir_fn = cephwrap_chdir,
1453 .getwd_fn = cephwrap_getwd,
1454 .ntimes_fn = cephwrap_ntimes,
1455 .ftruncate_fn = cephwrap_ftruncate,
1456 .lock_fn = cephwrap_lock,
1457 .kernel_flock_fn = cephwrap_kernel_flock,
1458 .linux_setlease_fn = cephwrap_linux_setlease,
1459 .getlock_fn = cephwrap_getlock,
1460 .symlink_fn = cephwrap_symlink,
1461 .readlink_fn = cephwrap_readlink,
1462 .link_fn = cephwrap_link,
1463 .mknod_fn = cephwrap_mknod,
1464 .realpath_fn = cephwrap_realpath,
1465 .chflags_fn = cephwrap_chflags,
1466 .get_real_filename_fn = cephwrap_get_real_filename,
1467 .connectpath_fn = cephwrap_connectpath,
1469 /* EA operations. */
1470 .getxattr_fn = cephwrap_getxattr,
1471 .fgetxattr_fn = cephwrap_fgetxattr,
1472 .listxattr_fn = cephwrap_listxattr,
1473 .flistxattr_fn = cephwrap_flistxattr,
1474 .removexattr_fn = cephwrap_removexattr,
1475 .fremovexattr_fn = cephwrap_fremovexattr,
1476 .setxattr_fn = cephwrap_setxattr,
1477 .fsetxattr_fn = cephwrap_fsetxattr,
1479 /* Posix ACL Operations */
1480 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1481 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1482 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1483 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1484 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1485 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1486 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1488 /* aio operations */
1489 .aio_force_fn = cephwrap_aio_force,
1492 static_decl_vfs;
1493 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1495 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1496 "ceph", &ceph_fns);