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, const char *fname, const char *mask, uint32_t attr)
258 struct ceph_dir_result *result;
259 DEBUG(10, ("[CEPH] opendir(%p, %s)\n", handle, fname));
261 /* Returns NULL if it does not exist or there are problems ? */
262 ret = ceph_opendir(handle->data, fname, &result);
265 errno = -ret; /* We return result which is NULL in this case */
268 DEBUG(10, ("[CEPH] opendir(...) = %d\n", ret));
269 return (DIR *) result;
272 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
273 struct files_struct *fsp,
278 struct ceph_dir_result *result;
279 DEBUG(10, ("[CEPH] fdopendir(%p, %p)\n", handle, fsp));
281 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
284 errno = -ret; /* We return result which is NULL in this case */
287 DEBUG(10, ("[CEPH] fdopendir(...) = %d\n", ret));
288 return (DIR *) result;
291 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
293 SMB_STRUCT_STAT *sbuf)
295 struct dirent *result;
297 DEBUG(10, ("[CEPH] readdir(%p, %p)\n", handle, dirp));
298 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
299 DEBUG(10, ("[CEPH] readdir(...) = %p\n", result));
301 /* Default Posix readdir() does not give us stat info.
302 * Set to invalid to indicate we didn't return this info. */
304 SET_STAT_INVALID(*sbuf);
308 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
310 DEBUG(10, ("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset));
311 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
314 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
317 DEBUG(10, ("[CEPH] telldir(%p, %p)\n", handle, dirp));
318 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
319 DEBUG(10, ("[CEPH] telldir(...) = %ld\n", ret));
323 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
325 DEBUG(10, ("[CEPH] rewinddir(%p, %p)\n", handle, dirp));
326 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
329 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
330 const struct smb_filename *smb_fname,
334 bool has_dacl = False;
336 const char *path = smb_fname->base_name;
338 DEBUG(10, ("[CEPH] mkdir(%p, %s)\n", handle, path));
340 if (lp_inherit_acls(SNUM(handle->conn))
341 && parent_dirname(talloc_tos(), path, &parent, NULL)
342 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
347 result = ceph_mkdir(handle->data, path, mode);
350 * Note. This order is important
354 } else if (result == 0 && !has_dacl) {
356 * We need to do this as the default behavior of POSIX ACLs
357 * is to set the mask to be the requested group permission
358 * bits, not the group permission bits to be the requested
359 * group permission bits. This is not what we want, as it will
360 * mess up any inherited ACL bits that were set. JRA.
362 int saved_errno = errno; /* We may get ENOSYS */
363 if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
370 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
371 const struct smb_filename *smb_fname)
375 DEBUG(10, ("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name));
376 result = ceph_rmdir(handle->data, smb_fname->base_name);
377 DEBUG(10, ("[CEPH] rmdir(...) = %d\n", result));
381 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
385 DEBUG(10, ("[CEPH] closedir(%p, %p)\n", handle, dirp));
386 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
387 DEBUG(10, ("[CEPH] closedir(...) = %d\n", result));
391 /* File operations */
393 static int cephwrap_open(struct vfs_handle_struct *handle,
394 struct smb_filename *smb_fname,
395 files_struct *fsp, int flags, mode_t mode)
397 int result = -ENOENT;
398 DEBUG(10, ("[CEPH] open(%p, %s, %p, %d, %d)\n", handle, smb_fname_str_dbg(smb_fname), fsp, flags, mode));
400 if (smb_fname->stream_name) {
404 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
406 DEBUG(10, ("[CEPH] open(...) = %d\n", result));
410 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
414 DEBUG(10, ("[CEPH] close(%p, %p)\n", handle, fsp));
415 result = ceph_close(handle->data, fsp->fh->fd);
416 DEBUG(10, ("[CEPH] close(...) = %d\n", result));
421 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
425 DEBUG(10, ("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
427 /* Using -1 for the offset means read/write rather than pread/pwrite */
428 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
429 DEBUG(10, ("[CEPH] read(...) = %llu\n", llu(result)));
433 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
434 size_t n, off_t offset)
438 DEBUG(10, ("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
440 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
441 DEBUG(10, ("[CEPH] pread(...) = %llu\n", llu(result)));
446 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
450 DEBUG(10, ("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
452 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
454 DEBUG(10, ("[CEPH] write(...) = %llu\n", llu(result)));
458 fsp->fh->pos += result;
462 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
463 size_t n, off_t offset)
467 DEBUG(10, ("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
468 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
469 DEBUG(10, ("[CEPH] pwrite(...) = %llu\n", llu(result)));
473 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
477 DEBUG(10, ("[CEPH] cephwrap_lseek\n"));
478 /* Cope with 'stat' file opens. */
479 if (fsp->fh->fd != -1) {
480 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
485 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
486 off_t offset, size_t n)
489 * We cannot support sendfile because libceph is in user space.
491 DEBUG(10, ("[CEPH] cephwrap_sendfile\n"));
496 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
503 * We cannot support recvfile because libceph is in user space.
505 DEBUG(10, ("[CEPH] cephwrap_recvfile\n"));
510 static int cephwrap_rename(struct vfs_handle_struct *handle,
511 const struct smb_filename *smb_fname_src,
512 const struct smb_filename *smb_fname_dst)
515 DEBUG(10, ("[CEPH] cephwrap_rename\n"));
516 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
521 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
525 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
528 DEBUG(10, ("[CEPH] cephwrap_fsync\n"));
529 result = ceph_fsync(handle->data, fsp->fh->fd, false);
533 static int cephwrap_stat(struct vfs_handle_struct *handle,
534 struct smb_filename *smb_fname)
539 DEBUG(10, ("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
541 if (smb_fname->stream_name) {
546 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
547 DEBUG(10, ("[CEPH] stat(...) = %d\n", result));
551 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
552 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
553 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
554 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
555 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
556 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
558 init_stat_ex_from_stat(
559 &smb_fname->st, &stbuf,
560 lp_fake_directory_create_times(SNUM(handle->conn)));
561 DEBUG(10, ("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode));
565 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
570 DEBUG(10, ("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd));
571 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
572 DEBUG(10, ("[CEPH] fstat(...) = %d\n", result));
576 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
577 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
578 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
579 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
580 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
581 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
584 init_stat_ex_from_stat(
586 lp_fake_directory_create_times(SNUM(handle->conn)));
587 DEBUG(10, ("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode));
591 static int cephwrap_lstat(struct vfs_handle_struct *handle,
592 struct smb_filename *smb_fname)
597 DEBUG(10, ("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
599 if (smb_fname->stream_name) {
604 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
605 DEBUG(10, ("[CEPH] lstat(...) = %d\n", result));
609 init_stat_ex_from_stat(
610 &smb_fname->st, &stbuf,
611 lp_fake_directory_create_times(SNUM(handle->conn)));
615 static int cephwrap_unlink(struct vfs_handle_struct *handle,
616 const struct smb_filename *smb_fname)
620 DEBUG(10, ("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
621 if (smb_fname->stream_name) {
625 result = ceph_unlink(handle->data, smb_fname->base_name);
626 DEBUG(10, ("[CEPH] unlink(...) = %d\n", result));
630 static int cephwrap_chmod(struct vfs_handle_struct *handle, const char *path, mode_t mode)
634 DEBUG(10, ("[CEPH] chmod(%p, %s, %d)\n", handle, path, mode));
637 * We need to do this due to the fact that the default POSIX ACL
638 * chmod modifies the ACL *mask* for the group owner, not the
639 * group owner bits directly. JRA.
644 int saved_errno = errno; /* We might get ENOSYS */
645 if ((result = SMB_VFS_CHMOD_ACL(handle->conn, path, mode)) == 0) {
648 /* Error - return the old errno. */
652 result = ceph_chmod(handle->data, path, mode);
653 DEBUG(10, ("[CEPH] chmod(...) = %d\n", result));
657 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
661 DEBUG(10, ("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode));
664 * We need to do this due to the fact that the default POSIX ACL
665 * chmod modifies the ACL *mask* for the group owner, not the
666 * group owner bits directly. JRA.
670 int saved_errno = errno; /* We might get ENOSYS */
671 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
674 /* Error - return the old errno. */
678 #if defined(HAVE_FCHMOD)
679 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
680 DEBUG(10, ("[CEPH] fchmod(...) = %d\n", result));
688 static int cephwrap_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
691 DEBUG(10, ("[CEPH] chown(%p, %s, %d, %d)\n", handle, path, uid, gid));
692 result = ceph_chown(handle->data, path, uid, gid);
693 DEBUG(10, ("[CEPH] chown(...) = %d\n", result));
697 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
702 DEBUG(10, ("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid));
703 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
704 DEBUG(10, ("[CEPH] fchown(...) = %d\n", result));
713 static int cephwrap_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
717 DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", handle, path, uid, gid));
718 result = ceph_lchown(handle->data, path, uid, gid);
719 DEBUG(10, ("[CEPH] lchown(...) = %d\n", result));
723 static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path)
726 DEBUG(10, ("[CEPH] chdir(%p, %s)\n", handle, path));
728 * If the path is just / use chdir because Ceph is below / and
729 * cannot deal with changing directory above its mount point
731 if (path && !strcmp(path, "/"))
734 result = ceph_chdir(handle->data, path);
735 DEBUG(10, ("[CEPH] chdir(...) = %d\n", result));
739 static char *cephwrap_getwd(struct vfs_handle_struct *handle)
741 const char *cwd = ceph_getcwd(handle->data);
742 DEBUG(10, ("[CEPH] getwd(%p) = %s\n", handle, cwd));
743 return SMB_STRDUP(cwd);
746 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
747 const struct smb_filename *smb_fname,
748 struct smb_file_time *ft)
753 if (null_timespec(ft->atime)) {
754 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
756 buf.actime = ft->atime.tv_sec;
758 if (null_timespec(ft->mtime)) {
759 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
761 buf.modtime = ft->mtime.tv_sec;
763 if (!null_timespec(ft->create_time)) {
764 set_create_timespec_ea(handle->conn, smb_fname,
767 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
768 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
772 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
773 DEBUG(10, ("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
774 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
775 ft->create_time.tv_sec, result));
779 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
781 off_t space_to_write;
782 uint64_t space_avail;
783 uint64_t bsize,dfree,dsize;
786 SMB_STRUCT_STAT *pst;
788 status = vfs_stat_fsp(fsp);
789 if (!NT_STATUS_IS_OK(status)) {
792 pst = &fsp->fsp_name->st;
795 if (S_ISFIFO(pst->st_ex_mode))
799 if (pst->st_ex_size == len)
802 /* Shrink - just ftruncate. */
803 if (pst->st_ex_size > len)
804 return ftruncate(fsp->fh->fd, len);
806 space_to_write = len - pst->st_ex_size;
808 /* for allocation try fallocate first. This can fail on some
809 platforms e.g. when the filesystem doesn't support it and no
810 emulation is being done by the libc (like on AIX with JFS1). In that
811 case we do our own emulation. fallocate implementations can
812 return ENOTSUP or EINVAL in cases like that. */
813 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
814 if (ret == -1 && errno == ENOSPC) {
820 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
821 "error %d. Falling back to slow manual allocation\n", errno));
823 /* available disk space is enough or not? */
824 space_avail = get_dfree_info(fsp->conn,
825 fsp->fsp_name->base_name,
826 &bsize, &dfree, &dsize);
827 /* space_avail is 1k blocks */
828 if (space_avail == (uint64_t)-1 ||
829 ((uint64_t)space_to_write/1024 > space_avail) ) {
834 /* Write out the real space on disk. */
835 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
838 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
845 DEBUG(10, ("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len)));
847 if (lp_strict_allocate(SNUM(fsp->conn))) {
848 result = strict_allocate_ftruncate(handle, fsp, len);
852 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
853 sys_ftruncate if the system supports it. Then I discovered that
854 you can have some filesystems that support ftruncate
855 expansion and some that don't! On Linux fat can't do
856 ftruncate extend but ext2 can. */
858 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
862 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
863 extend a file with ftruncate. Provide alternate implementation
865 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
870 /* Do an fstat to see if the file is longer than the requested
871 size in which case the ftruncate above should have
872 succeeded or shorter, in which case seek to len - 1 and
873 write 1 byte of zero */
874 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
879 if (S_ISFIFO(st.st_ex_mode)) {
885 if (st.st_ex_size == len) {
890 if (st.st_ex_size > len) {
891 /* the sys_ftruncate should have worked */
895 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
898 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
901 /* Seek to where we were */
902 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
911 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
913 DEBUG(10, ("[CEPH] lock\n"));
917 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
918 uint32_t share_mode, uint32_t access_mask)
920 DEBUG(10, ("[CEPH] kernel_flock\n"));
922 * We must return zero here and pretend all is good.
923 * One day we might have this in CEPH.
928 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
930 DEBUG(10, ("[CEPH] getlock returning false and errno=0\n"));
937 * We cannot let this fall through to the default, because the file might only
938 * be accessible from libceph (which is a user-space client) but the fd might
939 * be for some file the kernel knows about.
941 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
946 DEBUG(10, ("[CEPH] linux_setlease\n"));
951 static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
954 DEBUG(10, ("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath));
955 result = ceph_symlink(handle->data, oldpath, newpath);
956 DEBUG(10, ("[CEPH] symlink(...) = %d\n", result));
960 static int cephwrap_readlink(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
963 DEBUG(10, ("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz)));
964 result = ceph_readlink(handle->data, path, buf, bufsiz);
965 DEBUG(10, ("[CEPH] readlink(...) = %d\n", result));
969 static int cephwrap_link(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
972 DEBUG(10, ("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath));
973 result = ceph_link(handle->data, oldpath, newpath);
974 DEBUG(10, ("[CEPH] link(...) = %d\n", result));
978 static int cephwrap_mknod(struct vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
981 DEBUG(10, ("[CEPH] mknod(%p, %s)\n", handle, pathname));
982 result = ceph_mknod(handle->data, pathname, mode, dev);
983 DEBUG(10, ("[CEPH] mknod(...) = %d\n", result));
988 * This is a simple version of real-path ... a better version is needed to
989 * ask libceph about symbolic links.
991 static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *path)
994 size_t len = strlen(path);
996 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
997 if (len && (path[0] == '/')) {
998 int r = asprintf(&result, "%s", path);
999 if (r < 0) return NULL;
1000 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1002 int r = asprintf(&result, "%s",
1003 handle->conn->connectpath);
1004 if (r < 0) return NULL;
1006 int r = asprintf(&result, "%s/%s",
1007 handle->conn->connectpath, &path[2]);
1008 if (r < 0) return NULL;
1011 int r = asprintf(&result, "%s/%s",
1012 handle->conn->connectpath, path);
1013 if (r < 0) return NULL;
1015 DEBUG(10, ("[CEPH] realpath(%p, %s) = %s\n", handle, path, result));
1019 static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
1026 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1029 TALLOC_CTX *mem_ctx,
1033 * Don't fall back to get_real_filename so callers can differentiate
1034 * between a full directory scan and an actual case-insensitive stat.
1040 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1043 return handle->conn->connectpath;
1046 /****************************************************************
1047 Extended attribute operations.
1048 *****************************************************************/
1050 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
1053 DEBUG(10, ("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle, path, name, value, llu(size)));
1054 ret = ceph_getxattr(handle->data, path, name, value, size);
1055 DEBUG(10, ("[CEPH] getxattr(...) = %d\n", ret));
1059 return (ssize_t)ret;
1063 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1066 DEBUG(10, ("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size)));
1067 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1068 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1070 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1072 DEBUG(10, ("[CEPH] fgetxattr(...) = %d\n", ret));
1076 return (ssize_t)ret;
1080 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1083 DEBUG(10, ("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1084 ret = ceph_listxattr(handle->data, path, list, size);
1085 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1089 return (ssize_t)ret;
1094 static ssize_t cephwrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1097 DEBUG(10, ("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1098 ret = ceph_llistxattr(handle->data, path, list, size);
1099 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1103 return (ssize_t)ret;
1108 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1111 DEBUG(10, ("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size)));
1112 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1113 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1115 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1117 DEBUG(10, ("[CEPH] flistxattr(...) = %d\n", ret));
1121 return (ssize_t)ret;
1125 static int cephwrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
1128 DEBUG(10, ("[CEPH] removexattr(%p, %s, %s)\n", handle, path, name));
1129 ret = ceph_removexattr(handle->data, path, name);
1130 DEBUG(10, ("[CEPH] removexattr(...) = %d\n", ret));
1134 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1137 DEBUG(10, ("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name));
1138 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1139 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1141 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1143 DEBUG(10, ("[CEPH] fremovexattr(...) = %d\n", ret));
1147 static int cephwrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
1150 DEBUG(10, ("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle, path, name, value, llu(size), flags));
1151 ret = ceph_setxattr(handle->data, path, name, value, size, flags);
1152 DEBUG(10, ("[CEPH] setxattr(...) = %d\n", ret));
1156 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1159 DEBUG(10, ("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags));
1160 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1161 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1162 name, value, size, flags);
1164 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1166 DEBUG(10, ("[CEPH] fsetxattr(...) = %d\n", ret));
1170 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1174 * We do not support AIO yet.
1177 DEBUG(10, ("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp));
1182 static bool cephwrap_is_offline(struct vfs_handle_struct *handle,
1183 const struct smb_filename *fname,
1184 SMB_STRUCT_STAT *sbuf)
1189 static int cephwrap_set_offline(struct vfs_handle_struct *handle,
1190 const struct smb_filename *fname)
1196 static SMB_ACL_T cephwrap_sys_acl_get_file(struct vfs_handle_struct *handle,
1198 SMB_ACL_TYPE_T type,
1199 TALLOC_CTX *mem_ctx)
1205 static SMB_ACL_T cephwrap_sys_acl_get_fd(struct vfs_handle_struct *handle,
1206 struct files_struct *fsp,
1207 TALLOC_CTX *mem_ctx)
1213 static int cephwrap_sys_acl_set_file(struct vfs_handle_struct *handle,
1215 SMB_ACL_TYPE_T acltype,
1222 static int cephwrap_sys_acl_set_fd(struct vfs_handle_struct *handle,
1223 struct files_struct *fsp,
1230 static int cephwrap_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
1237 static struct vfs_fn_pointers ceph_fns = {
1238 /* Disk operations */
1240 .connect_fn = cephwrap_connect,
1241 .disconnect_fn = cephwrap_disconnect,
1242 .disk_free_fn = cephwrap_disk_free,
1243 .get_quota_fn = cephwrap_get_quota,
1244 .set_quota_fn = cephwrap_set_quota,
1245 .statvfs_fn = cephwrap_statvfs,
1247 /* Directory operations */
1249 .opendir_fn = cephwrap_opendir,
1250 .fdopendir_fn = cephwrap_fdopendir,
1251 .readdir_fn = cephwrap_readdir,
1252 .seekdir_fn = cephwrap_seekdir,
1253 .telldir_fn = cephwrap_telldir,
1254 .rewind_dir_fn = cephwrap_rewinddir,
1255 .mkdir_fn = cephwrap_mkdir,
1256 .rmdir_fn = cephwrap_rmdir,
1257 .closedir_fn = cephwrap_closedir,
1259 /* File operations */
1261 .open_fn = cephwrap_open,
1262 .close_fn = cephwrap_close,
1263 .read_fn = cephwrap_read,
1264 .pread_fn = cephwrap_pread,
1265 .write_fn = cephwrap_write,
1266 .pwrite_fn = cephwrap_pwrite,
1267 .lseek_fn = cephwrap_lseek,
1268 .sendfile_fn = cephwrap_sendfile,
1269 .recvfile_fn = cephwrap_recvfile,
1270 .rename_fn = cephwrap_rename,
1271 .fsync_fn = cephwrap_fsync,
1272 .stat_fn = cephwrap_stat,
1273 .fstat_fn = cephwrap_fstat,
1274 .lstat_fn = cephwrap_lstat,
1275 .unlink_fn = cephwrap_unlink,
1276 .chmod_fn = cephwrap_chmod,
1277 .fchmod_fn = cephwrap_fchmod,
1278 .chown_fn = cephwrap_chown,
1279 .fchown_fn = cephwrap_fchown,
1280 .lchown_fn = cephwrap_lchown,
1281 .chdir_fn = cephwrap_chdir,
1282 .getwd_fn = cephwrap_getwd,
1283 .ntimes_fn = cephwrap_ntimes,
1284 .ftruncate_fn = cephwrap_ftruncate,
1285 .lock_fn = cephwrap_lock,
1286 .kernel_flock_fn = cephwrap_kernel_flock,
1287 .linux_setlease_fn = cephwrap_linux_setlease,
1288 .getlock_fn = cephwrap_getlock,
1289 .symlink_fn = cephwrap_symlink,
1290 .readlink_fn = cephwrap_readlink,
1291 .link_fn = cephwrap_link,
1292 .mknod_fn = cephwrap_mknod,
1293 .realpath_fn = cephwrap_realpath,
1294 .chflags_fn = cephwrap_chflags,
1295 .get_real_filename_fn = cephwrap_get_real_filename,
1296 .connectpath_fn = cephwrap_connectpath,
1298 /* EA operations. */
1299 .getxattr_fn = cephwrap_getxattr,
1300 .fgetxattr_fn = cephwrap_fgetxattr,
1301 .listxattr_fn = cephwrap_listxattr,
1302 .flistxattr_fn = cephwrap_flistxattr,
1303 .removexattr_fn = cephwrap_removexattr,
1304 .fremovexattr_fn = cephwrap_fremovexattr,
1305 .setxattr_fn = cephwrap_setxattr,
1306 .fsetxattr_fn = cephwrap_fsetxattr,
1308 /* Posix ACL Operations */
1309 .sys_acl_get_file_fn = cephwrap_sys_acl_get_file,
1310 .sys_acl_get_fd_fn = cephwrap_sys_acl_get_fd,
1311 .sys_acl_set_file_fn = cephwrap_sys_acl_set_file,
1312 .sys_acl_set_fd_fn = cephwrap_sys_acl_set_fd,
1313 .sys_acl_delete_def_file_fn = cephwrap_sys_acl_delete_def_file,
1315 /* aio operations */
1316 .aio_force_fn = cephwrap_aio_force,
1318 /* offline operations */
1319 .is_offline_fn = cephwrap_is_offline,
1320 .set_offline_fn = cephwrap_set_offline
1323 NTSTATUS vfs_ceph_init(void);
1324 NTSTATUS vfs_ceph_init(void)
1326 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,