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
30 * vfs objects = ceph [any others you need go here]
34 #include "smbd/smbd.h"
36 #include <sys/statvfs.h>
37 #include "cephfs/libcephfs.h"
38 #include "smbprofile.h"
39 #include "modules/posixacl_xattr.h"
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)
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) \
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
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
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
84 static int cephwrap_connect(struct vfs_handle_struct *handle, const char *service, const char *user)
88 int snum = SNUM(handle->conn);
89 const char *conf_file;
93 handle->data = cmount; /* We have been here before */
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);
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);
115 DBG_DEBUG("[CEPH] calling: ceph_conf_get\n");
116 ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
121 DBG_DEBUG("[CEPH] calling: ceph_mount\n");
122 ret = ceph_mount(cmount, NULL);
128 * encode mount context/state into our vfs/connection holding structure
129 * cmount is a ceph_mount_t*
131 handle->data = cmount;
137 ceph_release(cmount);
141 * Handle the error correctly. Ceph returns -errno.
143 DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
147 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
152 DBG_ERR("[CEPH] Error, ceph not mounted\n");
156 /* Should we unmount/shutdown? Only if the last disconnect? */
158 DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
162 ret = ceph_unmount(cmount);
164 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
167 ret = ceph_release(cmount);
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,
183 struct statvfs statvfs_buf;
186 if (!(ret = ceph_statfs(handle->data, smb_fname->base_name,
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));
198 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", 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,
209 /* libceph: Ceph does not implement this */
211 /* was ifdef HAVE_SYS_QUOTAS */
214 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
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 */
232 /* was ifdef HAVE_SYS_QUOTAS */
235 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
243 WRAP_RETURN(-ENOSYS);
247 static int cephwrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
249 struct statvfs statvfs_buf;
252 ret = ceph_statfs(handle->data, path, &statvfs_buf);
256 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
257 statbuf->BlockSize = statvfs_buf.f_bsize;
258 statbuf->TotalBlocks = statvfs_buf.f_blocks;
259 statbuf->BlocksAvail = statvfs_buf.f_bfree;
260 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
261 statbuf->TotalFileNodes = statvfs_buf.f_files;
262 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
263 statbuf->FsIdentifier = statvfs_buf.f_fsid;
264 DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
265 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
266 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
271 /* Directory operations */
273 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
274 const struct smb_filename *smb_fname,
275 const char *mask, uint32_t attr)
278 struct ceph_dir_result *result;
279 DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
281 /* Returns NULL if it does not exist or there are problems ? */
282 ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
285 errno = -ret; /* We return result which is NULL in this case */
288 DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
289 return (DIR *) result;
292 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
293 struct files_struct *fsp,
298 struct ceph_dir_result *result;
299 DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
301 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
304 errno = -ret; /* We return result which is NULL in this case */
307 DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
308 return (DIR *) result;
311 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
313 SMB_STRUCT_STAT *sbuf)
315 struct dirent *result;
317 DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
318 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
319 DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
321 /* Default Posix readdir() does not give us stat info.
322 * Set to invalid to indicate we didn't return this info. */
324 SET_STAT_INVALID(*sbuf);
328 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
330 DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
331 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
334 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
337 DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
338 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
339 DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
343 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
345 DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
346 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
349 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
350 const struct smb_filename *smb_fname,
354 bool has_dacl = False;
356 const char *path = smb_fname->base_name;
358 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
360 if (lp_inherit_acls(SNUM(handle->conn))
361 && parent_dirname(talloc_tos(), path, &parent, NULL)
362 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
367 result = ceph_mkdir(handle->data, path, mode);
370 * Note. This order is important
374 } else if (result == 0 && !has_dacl) {
376 * We need to do this as the default behavior of POSIX ACLs
377 * is to set the mask to be the requested group permission
378 * bits, not the group permission bits to be the requested
379 * group permission bits. This is not what we want, as it will
380 * mess up any inherited ACL bits that were set. JRA.
382 int saved_errno = errno; /* We may get ENOSYS */
383 if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
392 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
393 const struct smb_filename *smb_fname)
397 DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
398 result = ceph_rmdir(handle->data, smb_fname->base_name);
399 DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
403 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
407 DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
408 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
409 DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
413 /* File operations */
415 static int cephwrap_open(struct vfs_handle_struct *handle,
416 struct smb_filename *smb_fname,
417 files_struct *fsp, int flags, mode_t mode)
419 int result = -ENOENT;
420 DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
421 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
423 if (smb_fname->stream_name) {
427 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
429 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
433 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
437 DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
438 result = ceph_close(handle->data, fsp->fh->fd);
439 DBG_DEBUG("[CEPH] close(...) = %d\n", result);
444 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
448 DBG_DEBUG("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
450 /* Using -1 for the offset means read/write rather than pread/pwrite */
451 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
452 DBG_DEBUG("[CEPH] read(...) = %llu\n", llu(result));
456 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
457 size_t n, off_t offset)
461 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
463 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
464 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
469 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
473 DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
475 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
477 DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
481 fsp->fh->pos += result;
485 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
486 size_t n, off_t offset)
490 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
491 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
492 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
496 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
500 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
501 /* Cope with 'stat' file opens. */
502 if (fsp->fh->fd != -1) {
503 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
508 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
509 off_t offset, size_t n)
512 * We cannot support sendfile because libceph is in user space.
514 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
519 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
526 * We cannot support recvfile because libceph is in user space.
528 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
533 static int cephwrap_rename(struct vfs_handle_struct *handle,
534 const struct smb_filename *smb_fname_src,
535 const struct smb_filename *smb_fname_dst)
538 DBG_DEBUG("[CEPH] cephwrap_rename\n");
539 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
544 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
548 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
551 DBG_DEBUG("[CEPH] cephwrap_fsync\n");
552 result = ceph_fsync(handle->data, fsp->fh->fd, false);
556 #ifdef HAVE_CEPH_STATX
557 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
559 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
561 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
562 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
563 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
565 dst->st_ex_dev = stx->stx_dev;
566 dst->st_ex_rdev = stx->stx_rdev;
567 dst->st_ex_ino = stx->stx_ino;
568 dst->st_ex_mode = stx->stx_mode;
569 dst->st_ex_uid = stx->stx_uid;
570 dst->st_ex_gid = stx->stx_gid;
571 dst->st_ex_size = stx->stx_size;
572 dst->st_ex_nlink = stx->stx_nlink;
573 dst->st_ex_atime = stx->stx_atime;
574 dst->st_ex_btime = stx->stx_btime;
575 dst->st_ex_ctime = stx->stx_ctime;
576 dst->st_ex_mtime = stx->stx_mtime;
577 dst->st_ex_calculated_birthtime = false;
578 dst->st_ex_blksize = stx->stx_blksize;
579 dst->st_ex_blocks = stx->stx_blocks;
582 static int cephwrap_stat(struct vfs_handle_struct *handle,
583 struct smb_filename *smb_fname)
586 struct ceph_statx stx;
588 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
590 if (smb_fname->stream_name) {
595 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
596 SAMBA_STATX_ATTR_MASK, 0);
597 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
601 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
602 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
603 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
604 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
605 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
606 llu(stx.stx_size), llu(stx.stx_blksize),
607 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
608 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
610 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
611 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
615 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
618 struct ceph_statx stx;
620 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
621 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
622 SAMBA_STATX_ATTR_MASK, 0);
623 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
627 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
628 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
629 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
630 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
631 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
632 llu(stx.stx_size), llu(stx.stx_blksize),
633 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
634 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
636 init_stat_ex_from_ceph_statx(sbuf, &stx);
637 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
641 static int cephwrap_lstat(struct vfs_handle_struct *handle,
642 struct smb_filename *smb_fname)
645 struct ceph_statx stx;
647 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
649 if (smb_fname->stream_name) {
654 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
655 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
656 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
660 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
664 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
665 const struct smb_filename *smb_fname,
666 struct smb_file_time *ft)
668 struct ceph_statx stx = { 0 };
672 if (!null_timespec(ft->atime)) {
673 stx.stx_atime = ft->atime;
674 mask |= CEPH_SETATTR_ATIME;
676 if (!null_timespec(ft->mtime)) {
677 stx.stx_mtime = ft->mtime;
678 mask |= CEPH_SETATTR_MTIME;
680 if (!null_timespec(ft->create_time)) {
681 stx.stx_btime = ft->create_time;
682 mask |= CEPH_SETATTR_BTIME;
689 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
690 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
691 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
692 ft->create_time.tv_sec, result);
696 #else /* HAVE_CEPH_STATX */
698 static int cephwrap_stat(struct vfs_handle_struct *handle,
699 struct smb_filename *smb_fname)
704 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
706 if (smb_fname->stream_name) {
711 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
712 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
716 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
717 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
718 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
719 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
720 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
721 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
723 init_stat_ex_from_stat(
724 &smb_fname->st, &stbuf,
725 lp_fake_directory_create_times(SNUM(handle->conn)));
726 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
730 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
735 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
736 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
737 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
741 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
742 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
743 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
744 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
745 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
746 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
749 init_stat_ex_from_stat(
751 lp_fake_directory_create_times(SNUM(handle->conn)));
752 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
756 static int cephwrap_lstat(struct vfs_handle_struct *handle,
757 struct smb_filename *smb_fname)
762 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
764 if (smb_fname->stream_name) {
769 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
770 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
774 init_stat_ex_from_stat(
775 &smb_fname->st, &stbuf,
776 lp_fake_directory_create_times(SNUM(handle->conn)));
780 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
781 const struct smb_filename *smb_fname,
782 struct smb_file_time *ft)
787 if (null_timespec(ft->atime)) {
788 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
790 buf.actime = ft->atime.tv_sec;
792 if (null_timespec(ft->mtime)) {
793 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
795 buf.modtime = ft->mtime.tv_sec;
797 if (!null_timespec(ft->create_time)) {
798 set_create_timespec_ea(handle->conn, smb_fname,
801 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
802 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
806 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
807 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
808 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
809 ft->create_time.tv_sec, result);
812 #endif /* HAVE_CEPH_STATX */
814 static int cephwrap_unlink(struct vfs_handle_struct *handle,
815 const struct smb_filename *smb_fname)
819 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
820 if (smb_fname->stream_name) {
824 result = ceph_unlink(handle->data, smb_fname->base_name);
825 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
829 static int cephwrap_chmod(struct vfs_handle_struct *handle,
830 const struct smb_filename *smb_fname,
835 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
838 * We need to do this due to the fact that the default POSIX ACL
839 * chmod modifies the ACL *mask* for the group owner, not the
840 * group owner bits directly. JRA.
845 int saved_errno = errno; /* We might get ENOSYS */
846 result = SMB_VFS_CHMOD_ACL(handle->conn,
852 /* Error - return the old errno. */
856 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
857 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
861 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
865 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
868 * We need to do this due to the fact that the default POSIX ACL
869 * chmod modifies the ACL *mask* for the group owner, not the
870 * group owner bits directly. JRA.
874 int saved_errno = errno; /* We might get ENOSYS */
875 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
878 /* Error - return the old errno. */
882 #if defined(HAVE_FCHMOD)
883 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
884 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
892 static int cephwrap_chown(struct vfs_handle_struct *handle,
893 const struct smb_filename *smb_fname,
898 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
899 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
900 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
904 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
909 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
910 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
911 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
920 static int cephwrap_lchown(struct vfs_handle_struct *handle,
921 const struct smb_filename *smb_fname,
926 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
927 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
928 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
932 static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path)
935 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, path);
937 * If the path is just / use chdir because Ceph is below / and
938 * cannot deal with changing directory above its mount point
940 if (path && !strcmp(path, "/"))
943 result = ceph_chdir(handle->data, path);
944 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
948 static char *cephwrap_getwd(struct vfs_handle_struct *handle)
950 const char *cwd = ceph_getcwd(handle->data);
951 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
952 return SMB_STRDUP(cwd);
955 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
957 off_t space_to_write;
958 uint64_t space_avail;
959 uint64_t bsize,dfree,dsize;
962 SMB_STRUCT_STAT *pst;
964 status = vfs_stat_fsp(fsp);
965 if (!NT_STATUS_IS_OK(status)) {
968 pst = &fsp->fsp_name->st;
971 if (S_ISFIFO(pst->st_ex_mode))
975 if (pst->st_ex_size == len)
978 /* Shrink - just ftruncate. */
979 if (pst->st_ex_size > len)
980 return ftruncate(fsp->fh->fd, len);
982 space_to_write = len - pst->st_ex_size;
984 /* for allocation try fallocate first. This can fail on some
985 platforms e.g. when the filesystem doesn't support it and no
986 emulation is being done by the libc (like on AIX with JFS1). In that
987 case we do our own emulation. fallocate implementations can
988 return ENOTSUP or EINVAL in cases like that. */
989 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
990 if (ret == -1 && errno == ENOSPC) {
996 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
997 "error %d. Falling back to slow manual allocation\n", errno));
999 /* available disk space is enough or not? */
1001 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1002 /* space_avail is 1k blocks */
1003 if (space_avail == (uint64_t)-1 ||
1004 ((uint64_t)space_to_write/1024 > space_avail) ) {
1009 /* Write out the real space on disk. */
1010 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1013 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1020 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1022 if (lp_strict_allocate(SNUM(fsp->conn))) {
1023 result = strict_allocate_ftruncate(handle, fsp, len);
1027 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1028 sys_ftruncate if the system supports it. Then I discovered that
1029 you can have some filesystems that support ftruncate
1030 expansion and some that don't! On Linux fat can't do
1031 ftruncate extend but ext2 can. */
1033 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1037 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1038 extend a file with ftruncate. Provide alternate implementation
1040 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1041 if (currpos == -1) {
1045 /* Do an fstat to see if the file is longer than the requested
1046 size in which case the ftruncate above should have
1047 succeeded or shorter, in which case seek to len - 1 and
1048 write 1 byte of zero */
1049 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1054 if (S_ISFIFO(st.st_ex_mode)) {
1060 if (st.st_ex_size == len) {
1065 if (st.st_ex_size > len) {
1066 /* the sys_ftruncate should have worked */
1070 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1073 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1076 /* Seek to where we were */
1077 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1086 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1088 DBG_DEBUG("[CEPH] lock\n");
1092 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1093 uint32_t share_mode, uint32_t access_mask)
1095 DBG_DEBUG("[CEPH] kernel_flock\n");
1097 * We must return zero here and pretend all is good.
1098 * One day we might have this in CEPH.
1103 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1105 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1112 * We cannot let this fall through to the default, because the file might only
1113 * be accessible from libceph (which is a user-space client) but the fd might
1114 * be for some file the kernel knows about.
1116 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1121 DBG_DEBUG("[CEPH] linux_setlease\n");
1126 static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
1129 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath);
1130 result = ceph_symlink(handle->data, oldpath, newpath);
1131 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1132 WRAP_RETURN(result);
1135 static int cephwrap_readlink(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
1138 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz));
1139 result = ceph_readlink(handle->data, path, buf, bufsiz);
1140 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1141 WRAP_RETURN(result);
1144 static int cephwrap_link(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
1147 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath);
1148 result = ceph_link(handle->data, oldpath, newpath);
1149 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1150 WRAP_RETURN(result);
1153 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1154 const struct smb_filename *smb_fname,
1159 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1160 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1161 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1162 WRAP_RETURN(result);
1166 * This is a simple version of real-path ... a better version is needed to
1167 * ask libceph about symbolic links.
1169 static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *path)
1172 size_t len = strlen(path);
1174 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1175 if (len && (path[0] == '/')) {
1176 int r = asprintf(&result, "%s", path);
1177 if (r < 0) return NULL;
1178 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1180 int r = asprintf(&result, "%s",
1181 handle->conn->connectpath);
1182 if (r < 0) return NULL;
1184 int r = asprintf(&result, "%s/%s",
1185 handle->conn->connectpath, &path[2]);
1186 if (r < 0) return NULL;
1189 int r = asprintf(&result, "%s/%s",
1190 handle->conn->connectpath, path);
1191 if (r < 0) return NULL;
1193 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1197 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1198 const struct smb_filename *smb_fname,
1205 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1208 TALLOC_CTX *mem_ctx,
1212 * Don't fall back to get_real_filename so callers can differentiate
1213 * between a full directory scan and an actual case-insensitive stat.
1219 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1222 return handle->conn->connectpath;
1225 /****************************************************************
1226 Extended attribute operations.
1227 *****************************************************************/
1229 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1230 const struct smb_filename *smb_fname,
1236 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1237 smb_fname->base_name, name, value, llu(size));
1238 ret = ceph_getxattr(handle->data,
1239 smb_fname->base_name, name, value, size);
1240 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1244 return (ssize_t)ret;
1248 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1251 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1252 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1253 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1255 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1257 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1261 return (ssize_t)ret;
1265 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1266 const struct smb_filename *smb_fname,
1271 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1272 smb_fname->base_name, list, llu(size));
1273 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1274 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1278 return (ssize_t)ret;
1282 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1285 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1286 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1287 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1289 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1291 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1295 return (ssize_t)ret;
1299 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1300 const struct smb_filename *smb_fname,
1304 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1305 smb_fname->base_name, name);
1306 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1307 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1311 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1314 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1315 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1316 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1318 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1320 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1324 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1325 const struct smb_filename *smb_fname,
1332 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1333 smb_fname->base_name, name, value, llu(size), flags);
1334 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1335 name, value, size, flags);
1336 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1340 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1343 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1344 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1345 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1346 name, value, size, flags);
1348 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1350 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1354 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1358 * We do not support AIO yet.
1361 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1366 static struct vfs_fn_pointers ceph_fns = {
1367 /* Disk operations */
1369 .connect_fn = cephwrap_connect,
1370 .disconnect_fn = cephwrap_disconnect,
1371 .disk_free_fn = cephwrap_disk_free,
1372 .get_quota_fn = cephwrap_get_quota,
1373 .set_quota_fn = cephwrap_set_quota,
1374 .statvfs_fn = cephwrap_statvfs,
1376 /* Directory operations */
1378 .opendir_fn = cephwrap_opendir,
1379 .fdopendir_fn = cephwrap_fdopendir,
1380 .readdir_fn = cephwrap_readdir,
1381 .seekdir_fn = cephwrap_seekdir,
1382 .telldir_fn = cephwrap_telldir,
1383 .rewind_dir_fn = cephwrap_rewinddir,
1384 .mkdir_fn = cephwrap_mkdir,
1385 .rmdir_fn = cephwrap_rmdir,
1386 .closedir_fn = cephwrap_closedir,
1388 /* File operations */
1390 .open_fn = cephwrap_open,
1391 .close_fn = cephwrap_close,
1392 .read_fn = cephwrap_read,
1393 .pread_fn = cephwrap_pread,
1394 .write_fn = cephwrap_write,
1395 .pwrite_fn = cephwrap_pwrite,
1396 .lseek_fn = cephwrap_lseek,
1397 .sendfile_fn = cephwrap_sendfile,
1398 .recvfile_fn = cephwrap_recvfile,
1399 .rename_fn = cephwrap_rename,
1400 .fsync_fn = cephwrap_fsync,
1401 .stat_fn = cephwrap_stat,
1402 .fstat_fn = cephwrap_fstat,
1403 .lstat_fn = cephwrap_lstat,
1404 .unlink_fn = cephwrap_unlink,
1405 .chmod_fn = cephwrap_chmod,
1406 .fchmod_fn = cephwrap_fchmod,
1407 .chown_fn = cephwrap_chown,
1408 .fchown_fn = cephwrap_fchown,
1409 .lchown_fn = cephwrap_lchown,
1410 .chdir_fn = cephwrap_chdir,
1411 .getwd_fn = cephwrap_getwd,
1412 .ntimes_fn = cephwrap_ntimes,
1413 .ftruncate_fn = cephwrap_ftruncate,
1414 .lock_fn = cephwrap_lock,
1415 .kernel_flock_fn = cephwrap_kernel_flock,
1416 .linux_setlease_fn = cephwrap_linux_setlease,
1417 .getlock_fn = cephwrap_getlock,
1418 .symlink_fn = cephwrap_symlink,
1419 .readlink_fn = cephwrap_readlink,
1420 .link_fn = cephwrap_link,
1421 .mknod_fn = cephwrap_mknod,
1422 .realpath_fn = cephwrap_realpath,
1423 .chflags_fn = cephwrap_chflags,
1424 .get_real_filename_fn = cephwrap_get_real_filename,
1425 .connectpath_fn = cephwrap_connectpath,
1427 /* EA operations. */
1428 .getxattr_fn = cephwrap_getxattr,
1429 .fgetxattr_fn = cephwrap_fgetxattr,
1430 .listxattr_fn = cephwrap_listxattr,
1431 .flistxattr_fn = cephwrap_flistxattr,
1432 .removexattr_fn = cephwrap_removexattr,
1433 .fremovexattr_fn = cephwrap_fremovexattr,
1434 .setxattr_fn = cephwrap_setxattr,
1435 .fsetxattr_fn = cephwrap_fsetxattr,
1437 /* Posix ACL Operations */
1438 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1439 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1440 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1441 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1442 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1443 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1444 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1446 /* aio operations */
1447 .aio_force_fn = cephwrap_aio_force,
1450 NTSTATUS vfs_ceph_init(TALLOC_CTX *);
1451 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1453 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,