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"
41 #define DBGC_CLASS DBGC_VFS
43 #ifndef LIBCEPHFS_VERSION
44 #define LIBCEPHFS_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra)
45 #define LIBCEPHFS_VERSION_CODE LIBCEPHFS_VERSION(0, 0, 0)
49 * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
51 #define llu(_var) ((long long unsigned)_var)
54 * Note, libceph's return code model is to return -errno! So we have to convert
55 * to what Samba expects, with is set errno to -return and return -1
57 #define WRAP_RETURN(_res) \
66 * We mount only one file system and then all shares are assumed to be in that.
67 * FIXME: If we want to support more than one FS, then we have to deal with
70 * So, cmount tells us if we have been this way before and whether
71 * we need to mount ceph and cmount_cnt tells us how many times we have
74 static struct ceph_mount_info * cmount = NULL;
75 static uint32_t cmount_cnt = 0;
77 /* Check for NULL pointer parameters in cephwrap_* functions */
79 /* We don't want to have NULL function pointers lying around. Someone
80 is sure to try and execute them. These stubs are used to prevent
83 static int cephwrap_connect(struct vfs_handle_struct *handle, const char *service, const char *user)
88 const char * conf_file;
91 handle->data = cmount; /* We have been here before */
96 conf_file = lp_parm_const_string(SNUM(handle->conn), "ceph", "config_file", NULL);
98 DEBUG(2, ( "[CEPH] calling: ceph_create\n" ));
99 ret = ceph_create(&cmount, NULL);
104 /* Override the config file */
105 DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file\n" ));
106 ret = ceph_conf_read_file(cmount, conf_file);
109 DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file with %s\n", conf_file));
110 ret = ceph_conf_read_file(cmount, NULL);
116 DEBUG(2, ( "[CEPH] calling: ceph_conf_get\n" ));
117 ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
121 DEBUG(2, ("[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;
138 * Handle the error correctly. Ceph returns -errno.
140 DEBUG(2, ("[CEPH] Error return: %s\n", strerror(-ret)));
144 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
147 DEBUG(0, ("[CEPH] Error, ceph not mounted\n"));
151 /* Should we unmount/shutdown? Only if the last disconnect? */
153 DEBUG(10, ("[CEPH] Not shuting down CEPH because still more connections\n"));
157 ceph_shutdown(cmount);
159 cmount = NULL; /* Make it safe */
162 /* Disk operations */
164 static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
165 const char *path, uint64_t *bsize,
166 uint64_t *dfree, uint64_t *dsize)
168 struct statvfs statvfs_buf;
171 if (!(ret = ceph_statfs(handle->data, path, &statvfs_buf))) {
173 * Provide all the correct values.
175 *bsize = statvfs_buf.f_bsize;
176 *dfree = statvfs_buf.f_bavail;
177 *dsize = statvfs_buf.f_blocks;
178 DEBUG(10, ("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
179 llu(*bsize), llu(*dfree), llu(*dsize)));
182 DEBUG(10, ("[CEPH] ceph_statfs returned %d\n", ret));
187 static int cephwrap_get_quota(struct vfs_handle_struct *handle,
188 const char *path, enum SMB_QUOTA_TYPE qtype,
189 unid_t id, SMB_DISK_QUOTA *qt)
191 /* libceph: Ceph does not implement this */
193 /* was ifdef HAVE_SYS_QUOTAS */
196 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
210 static int cephwrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
212 /* libceph: Ceph does not implement this */
214 /* was ifdef HAVE_SYS_QUOTAS */
217 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
225 WRAP_RETURN(-ENOSYS);
229 static int cephwrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
231 struct statvfs statvfs_buf;
234 ret = ceph_statfs(handle->data, path, &statvfs_buf);
238 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
239 statbuf->BlockSize = statvfs_buf.f_bsize;
240 statbuf->TotalBlocks = statvfs_buf.f_blocks;
241 statbuf->BlocksAvail = statvfs_buf.f_bfree;
242 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
243 statbuf->TotalFileNodes = statvfs_buf.f_files;
244 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
245 statbuf->FsIdentifier = statvfs_buf.f_fsid;
246 DEBUG(10, ("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
247 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
248 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail));
253 /* Directory operations */
255 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
256 const struct smb_filename *smb_fname,
257 const char *mask, uint32_t attr)
260 struct ceph_dir_result *result;
261 DEBUG(10, ("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name));
263 /* Returns NULL if it does not exist or there are problems ? */
264 ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
267 errno = -ret; /* We return result which is NULL in this case */
270 DEBUG(10, ("[CEPH] opendir(...) = %d\n", ret));
271 return (DIR *) result;
274 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
275 struct files_struct *fsp,
280 struct ceph_dir_result *result;
281 DEBUG(10, ("[CEPH] fdopendir(%p, %p)\n", handle, fsp));
283 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
286 errno = -ret; /* We return result which is NULL in this case */
289 DEBUG(10, ("[CEPH] fdopendir(...) = %d\n", ret));
290 return (DIR *) result;
293 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
295 SMB_STRUCT_STAT *sbuf)
297 struct dirent *result;
299 DEBUG(10, ("[CEPH] readdir(%p, %p)\n", handle, dirp));
300 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
301 DEBUG(10, ("[CEPH] readdir(...) = %p\n", result));
303 /* Default Posix readdir() does not give us stat info.
304 * Set to invalid to indicate we didn't return this info. */
306 SET_STAT_INVALID(*sbuf);
310 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
312 DEBUG(10, ("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset));
313 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
316 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
319 DEBUG(10, ("[CEPH] telldir(%p, %p)\n", handle, dirp));
320 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
321 DEBUG(10, ("[CEPH] telldir(...) = %ld\n", ret));
325 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
327 DEBUG(10, ("[CEPH] rewinddir(%p, %p)\n", handle, dirp));
328 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
331 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
332 const struct smb_filename *smb_fname,
336 bool has_dacl = False;
338 const char *path = smb_fname->base_name;
340 DEBUG(10, ("[CEPH] mkdir(%p, %s)\n", handle, path));
342 if (lp_inherit_acls(SNUM(handle->conn))
343 && parent_dirname(talloc_tos(), path, &parent, NULL)
344 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
349 result = ceph_mkdir(handle->data, path, mode);
352 * Note. This order is important
356 } else if (result == 0 && !has_dacl) {
358 * We need to do this as the default behavior of POSIX ACLs
359 * is to set the mask to be the requested group permission
360 * bits, not the group permission bits to be the requested
361 * group permission bits. This is not what we want, as it will
362 * mess up any inherited ACL bits that were set. JRA.
364 int saved_errno = errno; /* We may get ENOSYS */
365 if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
372 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
373 const struct smb_filename *smb_fname)
377 DEBUG(10, ("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name));
378 result = ceph_rmdir(handle->data, smb_fname->base_name);
379 DEBUG(10, ("[CEPH] rmdir(...) = %d\n", result));
383 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
387 DEBUG(10, ("[CEPH] closedir(%p, %p)\n", handle, dirp));
388 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
389 DEBUG(10, ("[CEPH] closedir(...) = %d\n", result));
393 /* File operations */
395 static int cephwrap_open(struct vfs_handle_struct *handle,
396 struct smb_filename *smb_fname,
397 files_struct *fsp, int flags, mode_t mode)
399 int result = -ENOENT;
400 DEBUG(10, ("[CEPH] open(%p, %s, %p, %d, %d)\n", handle, smb_fname_str_dbg(smb_fname), fsp, flags, mode));
402 if (smb_fname->stream_name) {
406 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
408 DEBUG(10, ("[CEPH] open(...) = %d\n", result));
412 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
416 DEBUG(10, ("[CEPH] close(%p, %p)\n", handle, fsp));
417 result = ceph_close(handle->data, fsp->fh->fd);
418 DEBUG(10, ("[CEPH] close(...) = %d\n", result));
423 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
427 DEBUG(10, ("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
429 /* Using -1 for the offset means read/write rather than pread/pwrite */
430 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
431 DEBUG(10, ("[CEPH] read(...) = %llu\n", llu(result)));
435 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
436 size_t n, off_t offset)
440 DEBUG(10, ("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
442 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
443 DEBUG(10, ("[CEPH] pread(...) = %llu\n", llu(result)));
448 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
452 DEBUG(10, ("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
454 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
456 DEBUG(10, ("[CEPH] write(...) = %llu\n", llu(result)));
460 fsp->fh->pos += result;
464 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
465 size_t n, off_t offset)
469 DEBUG(10, ("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
470 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
471 DEBUG(10, ("[CEPH] pwrite(...) = %llu\n", llu(result)));
475 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
479 DEBUG(10, ("[CEPH] cephwrap_lseek\n"));
480 /* Cope with 'stat' file opens. */
481 if (fsp->fh->fd != -1) {
482 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
487 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
488 off_t offset, size_t n)
491 * We cannot support sendfile because libceph is in user space.
493 DEBUG(10, ("[CEPH] cephwrap_sendfile\n"));
498 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
505 * We cannot support recvfile because libceph is in user space.
507 DEBUG(10, ("[CEPH] cephwrap_recvfile\n"));
512 static int cephwrap_rename(struct vfs_handle_struct *handle,
513 const struct smb_filename *smb_fname_src,
514 const struct smb_filename *smb_fname_dst)
517 DEBUG(10, ("[CEPH] cephwrap_rename\n"));
518 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
523 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
527 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
530 DEBUG(10, ("[CEPH] cephwrap_fsync\n"));
531 result = ceph_fsync(handle->data, fsp->fh->fd, false);
535 static int cephwrap_stat(struct vfs_handle_struct *handle,
536 struct smb_filename *smb_fname)
541 DEBUG(10, ("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
543 if (smb_fname->stream_name) {
548 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
549 DEBUG(10, ("[CEPH] stat(...) = %d\n", result));
553 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
554 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
555 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
556 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
557 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
558 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
560 init_stat_ex_from_stat(
561 &smb_fname->st, &stbuf,
562 lp_fake_directory_create_times(SNUM(handle->conn)));
563 DEBUG(10, ("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode));
567 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
572 DEBUG(10, ("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd));
573 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
574 DEBUG(10, ("[CEPH] fstat(...) = %d\n", result));
578 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
579 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
580 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
581 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
582 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
583 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
586 init_stat_ex_from_stat(
588 lp_fake_directory_create_times(SNUM(handle->conn)));
589 DEBUG(10, ("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode));
593 static int cephwrap_lstat(struct vfs_handle_struct *handle,
594 struct smb_filename *smb_fname)
599 DEBUG(10, ("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
601 if (smb_fname->stream_name) {
606 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
607 DEBUG(10, ("[CEPH] lstat(...) = %d\n", result));
611 init_stat_ex_from_stat(
612 &smb_fname->st, &stbuf,
613 lp_fake_directory_create_times(SNUM(handle->conn)));
617 static int cephwrap_unlink(struct vfs_handle_struct *handle,
618 const struct smb_filename *smb_fname)
622 DEBUG(10, ("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
623 if (smb_fname->stream_name) {
627 result = ceph_unlink(handle->data, smb_fname->base_name);
628 DEBUG(10, ("[CEPH] unlink(...) = %d\n", result));
632 static int cephwrap_chmod(struct vfs_handle_struct *handle,
633 const struct smb_filename *smb_fname,
638 DEBUG(10, ("[CEPH] chmod(%p, %s, %d)\n",
640 smb_fname->base_name,
644 * We need to do this due to the fact that the default POSIX ACL
645 * chmod modifies the ACL *mask* for the group owner, not the
646 * group owner bits directly. JRA.
651 int saved_errno = errno; /* We might get ENOSYS */
652 result = SMB_VFS_CHMOD_ACL(handle->conn,
653 smb_fname->base_name,
658 /* Error - return the old errno. */
662 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
663 DEBUG(10, ("[CEPH] chmod(...) = %d\n", result));
667 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
671 DEBUG(10, ("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode));
674 * We need to do this due to the fact that the default POSIX ACL
675 * chmod modifies the ACL *mask* for the group owner, not the
676 * group owner bits directly. JRA.
680 int saved_errno = errno; /* We might get ENOSYS */
681 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
684 /* Error - return the old errno. */
688 #if defined(HAVE_FCHMOD)
689 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
690 DEBUG(10, ("[CEPH] fchmod(...) = %d\n", result));
698 static int cephwrap_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
701 DEBUG(10, ("[CEPH] chown(%p, %s, %d, %d)\n", handle, path, uid, gid));
702 result = ceph_chown(handle->data, path, uid, gid);
703 DEBUG(10, ("[CEPH] chown(...) = %d\n", result));
707 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
712 DEBUG(10, ("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid));
713 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
714 DEBUG(10, ("[CEPH] fchown(...) = %d\n", result));
723 static int cephwrap_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
727 DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", handle, path, uid, gid));
728 result = ceph_lchown(handle->data, path, uid, gid);
729 DEBUG(10, ("[CEPH] lchown(...) = %d\n", result));
733 static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path)
736 DEBUG(10, ("[CEPH] chdir(%p, %s)\n", handle, path));
738 * If the path is just / use chdir because Ceph is below / and
739 * cannot deal with changing directory above its mount point
741 if (path && !strcmp(path, "/"))
744 result = ceph_chdir(handle->data, path);
745 DEBUG(10, ("[CEPH] chdir(...) = %d\n", result));
749 static char *cephwrap_getwd(struct vfs_handle_struct *handle)
751 const char *cwd = ceph_getcwd(handle->data);
752 DEBUG(10, ("[CEPH] getwd(%p) = %s\n", handle, cwd));
753 return SMB_STRDUP(cwd);
756 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
757 const struct smb_filename *smb_fname,
758 struct smb_file_time *ft)
763 if (null_timespec(ft->atime)) {
764 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
766 buf.actime = ft->atime.tv_sec;
768 if (null_timespec(ft->mtime)) {
769 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
771 buf.modtime = ft->mtime.tv_sec;
773 if (!null_timespec(ft->create_time)) {
774 set_create_timespec_ea(handle->conn, smb_fname,
777 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
778 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
782 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
783 DEBUG(10, ("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
784 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
785 ft->create_time.tv_sec, result));
789 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
791 off_t space_to_write;
792 uint64_t space_avail;
793 uint64_t bsize,dfree,dsize;
796 SMB_STRUCT_STAT *pst;
798 status = vfs_stat_fsp(fsp);
799 if (!NT_STATUS_IS_OK(status)) {
802 pst = &fsp->fsp_name->st;
805 if (S_ISFIFO(pst->st_ex_mode))
809 if (pst->st_ex_size == len)
812 /* Shrink - just ftruncate. */
813 if (pst->st_ex_size > len)
814 return ftruncate(fsp->fh->fd, len);
816 space_to_write = len - pst->st_ex_size;
818 /* for allocation try fallocate first. This can fail on some
819 platforms e.g. when the filesystem doesn't support it and no
820 emulation is being done by the libc (like on AIX with JFS1). In that
821 case we do our own emulation. fallocate implementations can
822 return ENOTSUP or EINVAL in cases like that. */
823 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
824 if (ret == -1 && errno == ENOSPC) {
830 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
831 "error %d. Falling back to slow manual allocation\n", errno));
833 /* available disk space is enough or not? */
834 space_avail = get_dfree_info(fsp->conn,
835 fsp->fsp_name->base_name,
836 &bsize, &dfree, &dsize);
837 /* space_avail is 1k blocks */
838 if (space_avail == (uint64_t)-1 ||
839 ((uint64_t)space_to_write/1024 > space_avail) ) {
844 /* Write out the real space on disk. */
845 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
848 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
855 DEBUG(10, ("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len)));
857 if (lp_strict_allocate(SNUM(fsp->conn))) {
858 result = strict_allocate_ftruncate(handle, fsp, len);
862 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
863 sys_ftruncate if the system supports it. Then I discovered that
864 you can have some filesystems that support ftruncate
865 expansion and some that don't! On Linux fat can't do
866 ftruncate extend but ext2 can. */
868 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
872 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
873 extend a file with ftruncate. Provide alternate implementation
875 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
880 /* Do an fstat to see if the file is longer than the requested
881 size in which case the ftruncate above should have
882 succeeded or shorter, in which case seek to len - 1 and
883 write 1 byte of zero */
884 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
889 if (S_ISFIFO(st.st_ex_mode)) {
895 if (st.st_ex_size == len) {
900 if (st.st_ex_size > len) {
901 /* the sys_ftruncate should have worked */
905 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
908 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
911 /* Seek to where we were */
912 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
921 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
923 DEBUG(10, ("[CEPH] lock\n"));
927 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
928 uint32_t share_mode, uint32_t access_mask)
930 DEBUG(10, ("[CEPH] kernel_flock\n"));
932 * We must return zero here and pretend all is good.
933 * One day we might have this in CEPH.
938 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
940 DEBUG(10, ("[CEPH] getlock returning false and errno=0\n"));
947 * We cannot let this fall through to the default, because the file might only
948 * be accessible from libceph (which is a user-space client) but the fd might
949 * be for some file the kernel knows about.
951 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
956 DEBUG(10, ("[CEPH] linux_setlease\n"));
961 static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
964 DEBUG(10, ("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath));
965 result = ceph_symlink(handle->data, oldpath, newpath);
966 DEBUG(10, ("[CEPH] symlink(...) = %d\n", result));
970 static int cephwrap_readlink(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
973 DEBUG(10, ("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz)));
974 result = ceph_readlink(handle->data, path, buf, bufsiz);
975 DEBUG(10, ("[CEPH] readlink(...) = %d\n", result));
979 static int cephwrap_link(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
982 DEBUG(10, ("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath));
983 result = ceph_link(handle->data, oldpath, newpath);
984 DEBUG(10, ("[CEPH] link(...) = %d\n", result));
988 static int cephwrap_mknod(struct vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
991 DEBUG(10, ("[CEPH] mknod(%p, %s)\n", handle, pathname));
992 result = ceph_mknod(handle->data, pathname, mode, dev);
993 DEBUG(10, ("[CEPH] mknod(...) = %d\n", result));
998 * This is a simple version of real-path ... a better version is needed to
999 * ask libceph about symbolic links.
1001 static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *path)
1004 size_t len = strlen(path);
1006 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1007 if (len && (path[0] == '/')) {
1008 int r = asprintf(&result, "%s", path);
1009 if (r < 0) return NULL;
1010 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1012 int r = asprintf(&result, "%s",
1013 handle->conn->connectpath);
1014 if (r < 0) return NULL;
1016 int r = asprintf(&result, "%s/%s",
1017 handle->conn->connectpath, &path[2]);
1018 if (r < 0) return NULL;
1021 int r = asprintf(&result, "%s/%s",
1022 handle->conn->connectpath, path);
1023 if (r < 0) return NULL;
1025 DEBUG(10, ("[CEPH] realpath(%p, %s) = %s\n", handle, path, result));
1029 static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
1036 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1039 TALLOC_CTX *mem_ctx,
1043 * Don't fall back to get_real_filename so callers can differentiate
1044 * between a full directory scan and an actual case-insensitive stat.
1050 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1053 return handle->conn->connectpath;
1056 /****************************************************************
1057 Extended attribute operations.
1058 *****************************************************************/
1060 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
1063 DEBUG(10, ("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle, path, name, value, llu(size)));
1064 ret = ceph_getxattr(handle->data, path, name, value, size);
1065 DEBUG(10, ("[CEPH] getxattr(...) = %d\n", ret));
1069 return (ssize_t)ret;
1073 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1076 DEBUG(10, ("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size)));
1077 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1078 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1080 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1082 DEBUG(10, ("[CEPH] fgetxattr(...) = %d\n", ret));
1086 return (ssize_t)ret;
1090 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1093 DEBUG(10, ("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1094 ret = ceph_listxattr(handle->data, path, list, size);
1095 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1099 return (ssize_t)ret;
1104 static ssize_t cephwrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1107 DEBUG(10, ("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1108 ret = ceph_llistxattr(handle->data, path, list, size);
1109 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1113 return (ssize_t)ret;
1118 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1121 DEBUG(10, ("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size)));
1122 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1123 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1125 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1127 DEBUG(10, ("[CEPH] flistxattr(...) = %d\n", ret));
1131 return (ssize_t)ret;
1135 static int cephwrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
1138 DEBUG(10, ("[CEPH] removexattr(%p, %s, %s)\n", handle, path, name));
1139 ret = ceph_removexattr(handle->data, path, name);
1140 DEBUG(10, ("[CEPH] removexattr(...) = %d\n", ret));
1144 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1147 DEBUG(10, ("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name));
1148 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1149 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1151 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1153 DEBUG(10, ("[CEPH] fremovexattr(...) = %d\n", ret));
1157 static int cephwrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
1160 DEBUG(10, ("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle, path, name, value, llu(size), flags));
1161 ret = ceph_setxattr(handle->data, path, name, value, size, flags);
1162 DEBUG(10, ("[CEPH] setxattr(...) = %d\n", ret));
1166 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1169 DEBUG(10, ("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags));
1170 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1171 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1172 name, value, size, flags);
1174 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1176 DEBUG(10, ("[CEPH] fsetxattr(...) = %d\n", ret));
1180 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1184 * We do not support AIO yet.
1187 DEBUG(10, ("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp));
1192 static bool cephwrap_is_offline(struct vfs_handle_struct *handle,
1193 const struct smb_filename *fname,
1194 SMB_STRUCT_STAT *sbuf)
1199 static int cephwrap_set_offline(struct vfs_handle_struct *handle,
1200 const struct smb_filename *fname)
1206 static SMB_ACL_T cephwrap_sys_acl_get_file(struct vfs_handle_struct *handle,
1208 SMB_ACL_TYPE_T type,
1209 TALLOC_CTX *mem_ctx)
1215 static SMB_ACL_T cephwrap_sys_acl_get_fd(struct vfs_handle_struct *handle,
1216 struct files_struct *fsp,
1217 TALLOC_CTX *mem_ctx)
1223 static int cephwrap_sys_acl_set_file(struct vfs_handle_struct *handle,
1225 SMB_ACL_TYPE_T acltype,
1232 static int cephwrap_sys_acl_set_fd(struct vfs_handle_struct *handle,
1233 struct files_struct *fsp,
1240 static int cephwrap_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
1247 static struct vfs_fn_pointers ceph_fns = {
1248 /* Disk operations */
1250 .connect_fn = cephwrap_connect,
1251 .disconnect_fn = cephwrap_disconnect,
1252 .disk_free_fn = cephwrap_disk_free,
1253 .get_quota_fn = cephwrap_get_quota,
1254 .set_quota_fn = cephwrap_set_quota,
1255 .statvfs_fn = cephwrap_statvfs,
1257 /* Directory operations */
1259 .opendir_fn = cephwrap_opendir,
1260 .fdopendir_fn = cephwrap_fdopendir,
1261 .readdir_fn = cephwrap_readdir,
1262 .seekdir_fn = cephwrap_seekdir,
1263 .telldir_fn = cephwrap_telldir,
1264 .rewind_dir_fn = cephwrap_rewinddir,
1265 .mkdir_fn = cephwrap_mkdir,
1266 .rmdir_fn = cephwrap_rmdir,
1267 .closedir_fn = cephwrap_closedir,
1269 /* File operations */
1271 .open_fn = cephwrap_open,
1272 .close_fn = cephwrap_close,
1273 .read_fn = cephwrap_read,
1274 .pread_fn = cephwrap_pread,
1275 .write_fn = cephwrap_write,
1276 .pwrite_fn = cephwrap_pwrite,
1277 .lseek_fn = cephwrap_lseek,
1278 .sendfile_fn = cephwrap_sendfile,
1279 .recvfile_fn = cephwrap_recvfile,
1280 .rename_fn = cephwrap_rename,
1281 .fsync_fn = cephwrap_fsync,
1282 .stat_fn = cephwrap_stat,
1283 .fstat_fn = cephwrap_fstat,
1284 .lstat_fn = cephwrap_lstat,
1285 .unlink_fn = cephwrap_unlink,
1286 .chmod_fn = cephwrap_chmod,
1287 .fchmod_fn = cephwrap_fchmod,
1288 .chown_fn = cephwrap_chown,
1289 .fchown_fn = cephwrap_fchown,
1290 .lchown_fn = cephwrap_lchown,
1291 .chdir_fn = cephwrap_chdir,
1292 .getwd_fn = cephwrap_getwd,
1293 .ntimes_fn = cephwrap_ntimes,
1294 .ftruncate_fn = cephwrap_ftruncate,
1295 .lock_fn = cephwrap_lock,
1296 .kernel_flock_fn = cephwrap_kernel_flock,
1297 .linux_setlease_fn = cephwrap_linux_setlease,
1298 .getlock_fn = cephwrap_getlock,
1299 .symlink_fn = cephwrap_symlink,
1300 .readlink_fn = cephwrap_readlink,
1301 .link_fn = cephwrap_link,
1302 .mknod_fn = cephwrap_mknod,
1303 .realpath_fn = cephwrap_realpath,
1304 .chflags_fn = cephwrap_chflags,
1305 .get_real_filename_fn = cephwrap_get_real_filename,
1306 .connectpath_fn = cephwrap_connectpath,
1308 /* EA operations. */
1309 .getxattr_fn = cephwrap_getxattr,
1310 .fgetxattr_fn = cephwrap_fgetxattr,
1311 .listxattr_fn = cephwrap_listxattr,
1312 .flistxattr_fn = cephwrap_flistxattr,
1313 .removexattr_fn = cephwrap_removexattr,
1314 .fremovexattr_fn = cephwrap_fremovexattr,
1315 .setxattr_fn = cephwrap_setxattr,
1316 .fsetxattr_fn = cephwrap_fsetxattr,
1318 /* Posix ACL Operations */
1319 .sys_acl_get_file_fn = cephwrap_sys_acl_get_file,
1320 .sys_acl_get_fd_fn = cephwrap_sys_acl_get_fd,
1321 .sys_acl_set_file_fn = cephwrap_sys_acl_set_file,
1322 .sys_acl_set_fd_fn = cephwrap_sys_acl_set_fd,
1323 .sys_acl_delete_def_file_fn = cephwrap_sys_acl_delete_def_file,
1325 /* aio operations */
1326 .aio_force_fn = cephwrap_aio_force,
1328 /* offline operations */
1329 .is_offline_fn = cephwrap_is_offline,
1330 .set_offline_fn = cephwrap_set_offline
1333 NTSTATUS vfs_ceph_init(void);
1334 NTSTATUS vfs_ceph_init(void)
1336 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,