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
44 * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
46 #define llu(_var) ((long long unsigned)_var)
49 * Note, libceph's return code model is to return -errno! So we have to convert
50 * to what Samba expects, with is set errno to -return and return -1
52 #define WRAP_RETURN(_res) \
61 * We mount only one file system and then all shares are assumed to be in that.
62 * FIXME: If we want to support more than one FS, then we have to deal with
65 * So, cmount tells us if we have been this way before and whether
66 * we need to mount ceph and cmount_cnt tells us how many times we have
69 static struct ceph_mount_info
* cmount
= NULL
;
70 static uint32_t cmount_cnt
= 0;
72 /* Check for NULL pointer parameters in cephwrap_* functions */
74 /* We don't want to have NULL function pointers lying around. Someone
75 is sure to try and execute them. These stubs are used to prevent
78 static int cephwrap_connect(struct vfs_handle_struct
*handle
, const char *service
, const char *user
)
83 const char * conf_file
;
86 handle
->data
= cmount
; /* We have been here before */
91 conf_file
= lp_parm_const_string(SNUM(handle
->conn
), "ceph", "config_file", NULL
);
93 DEBUG(2, ( "[CEPH] calling: ceph_create\n" ));
94 ret
= ceph_create(&cmount
, NULL
);
99 /* Override the config file */
100 DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file\n" ));
101 ret
= ceph_conf_read_file(cmount
, conf_file
);
104 DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file with %s\n", conf_file
));
105 ret
= ceph_conf_read_file(cmount
, NULL
);
111 DEBUG(2, ( "[CEPH] calling: ceph_conf_get\n" ));
112 ret
= ceph_conf_get(cmount
, "log file", buf
, sizeof(buf
));
116 DEBUG(2, ("[CEPH] calling: ceph_mount\n"));
117 ret
= ceph_mount(cmount
, NULL
);
123 * encode mount context/state into our vfs/connection holding structure
124 * cmount is a ceph_mount_t*
126 handle
->data
= cmount
;
133 * Handle the error correctly. Ceph returns -errno.
135 DEBUG(2, ("[CEPH] Error return: %s\n", strerror(-ret
)));
139 static void cephwrap_disconnect(struct vfs_handle_struct
*handle
)
142 DEBUG(0, ("[CEPH] Error, ceph not mounted\n"));
146 /* Should we unmount/shutdown? Only if the last disconnect? */
148 DEBUG(10, ("[CEPH] Not shuting down CEPH because still more connections\n"));
152 ceph_shutdown(cmount
);
154 cmount
= NULL
; /* Make it safe */
157 /* Disk operations */
159 static uint64_t cephwrap_disk_free(struct vfs_handle_struct
*handle
, const char *path
, bool small_query
, uint64_t *bsize
,
160 uint64_t *dfree
, uint64_t *dsize
)
162 struct statvfs statvfs_buf
;
165 if (!(ret
= ceph_statfs(handle
->data
, path
, &statvfs_buf
))) {
167 * Provide all the correct values.
169 *bsize
= statvfs_buf
.f_bsize
;
170 *dfree
= statvfs_buf
.f_bsize
* statvfs_buf
.f_bavail
;
171 *dsize
= statvfs_buf
.f_bsize
* statvfs_buf
.f_blocks
;
172 DEBUG(10, ("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
173 llu(*bsize
), llu(*dfree
), llu(*dsize
)));
176 DEBUG(10, ("[CEPH] ceph_statfs returned %d\n", ret
));
181 static int cephwrap_get_quota(struct vfs_handle_struct
*handle
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*qt
)
183 /* libceph: Ceph does not implement this */
185 /* was ifdef HAVE_SYS_QUOTAS */
188 ret
= ceph_get_quota(handle
->conn
->connectpath
, qtype
, id
, qt
);
202 static int cephwrap_set_quota(struct vfs_handle_struct
*handle
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*qt
)
204 /* libceph: Ceph does not implement this */
206 /* was ifdef HAVE_SYS_QUOTAS */
209 ret
= ceph_set_quota(handle
->conn
->connectpath
, qtype
, id
, qt
);
217 WRAP_RETURN(-ENOSYS
);
221 static int cephwrap_statvfs(struct vfs_handle_struct
*handle
, const char *path
, vfs_statvfs_struct
*statbuf
)
223 struct statvfs statvfs_buf
;
226 ret
= ceph_statfs(handle
->data
, path
, &statvfs_buf
);
230 statbuf
->OptimalTransferSize
= statvfs_buf
.f_frsize
;
231 statbuf
->BlockSize
= statvfs_buf
.f_bsize
;
232 statbuf
->TotalBlocks
= statvfs_buf
.f_blocks
;
233 statbuf
->BlocksAvail
= statvfs_buf
.f_bfree
;
234 statbuf
->UserBlocksAvail
= statvfs_buf
.f_bavail
;
235 statbuf
->TotalFileNodes
= statvfs_buf
.f_files
;
236 statbuf
->FreeFileNodes
= statvfs_buf
.f_ffree
;
237 statbuf
->FsIdentifier
= statvfs_buf
.f_fsid
;
238 DEBUG(10, ("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
239 (long int)statvfs_buf
.f_bsize
, (long int)statvfs_buf
.f_blocks
,
240 (long int)statvfs_buf
.f_bfree
, (long int)statvfs_buf
.f_bavail
));
245 /* Directory operations */
247 static DIR *cephwrap_opendir(struct vfs_handle_struct
*handle
, const char *fname
, const char *mask
, uint32 attr
)
250 struct ceph_dir_result
*result
;
251 DEBUG(10, ("[CEPH] opendir(%p, %s)\n", handle
, fname
));
253 /* Returns NULL if it does not exist or there are problems ? */
254 ret
= ceph_opendir(handle
->data
, fname
, &result
);
257 errno
= -ret
; /* We return result which is NULL in this case */
260 DEBUG(10, ("[CEPH] opendir(...) = %d\n", ret
));
261 return (DIR *) result
;
264 static DIR *cephwrap_fdopendir(struct vfs_handle_struct
*handle
,
265 struct files_struct
*fsp
,
270 struct ceph_dir_result
*result
;
271 DEBUG(10, ("[CEPH] fdopendir(%p, %p)\n", handle
, fsp
));
273 ret
= ceph_opendir(handle
->data
, fsp
->fsp_name
->base_name
, &result
);
276 errno
= -ret
; /* We return result which is NULL in this case */
279 DEBUG(10, ("[CEPH] fdopendir(...) = %d\n", ret
));
280 return (DIR *) result
;
283 static struct dirent
*cephwrap_readdir(struct vfs_handle_struct
*handle
,
285 SMB_STRUCT_STAT
*sbuf
)
287 struct dirent
*result
;
289 DEBUG(10, ("[CEPH] readdir(%p, %p)\n", handle
, dirp
));
290 result
= ceph_readdir(handle
->data
, (struct ceph_dir_result
*) dirp
);
291 DEBUG(10, ("[CEPH] readdir(...) = %p\n", result
));
293 /* Default Posix readdir() does not give us stat info.
294 * Set to invalid to indicate we didn't return this info. */
296 SET_STAT_INVALID(*sbuf
);
300 static void cephwrap_seekdir(struct vfs_handle_struct
*handle
, DIR *dirp
, long offset
)
302 DEBUG(10, ("[CEPH] seekdir(%p, %p, %ld)\n", handle
, dirp
, offset
));
303 ceph_seekdir(handle
->data
, (struct ceph_dir_result
*) dirp
, offset
);
306 static long cephwrap_telldir(struct vfs_handle_struct
*handle
, DIR *dirp
)
309 DEBUG(10, ("[CEPH] telldir(%p, %p)\n", handle
, dirp
));
310 ret
= ceph_telldir(handle
->data
, (struct ceph_dir_result
*) dirp
);
311 DEBUG(10, ("[CEPH] telldir(...) = %ld\n", ret
));
315 static void cephwrap_rewinddir(struct vfs_handle_struct
*handle
, DIR *dirp
)
317 DEBUG(10, ("[CEPH] rewinddir(%p, %p)\n", handle
, dirp
));
318 ceph_rewinddir(handle
->data
, (struct ceph_dir_result
*) dirp
);
321 static int cephwrap_mkdir(struct vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
324 bool has_dacl
= False
;
327 DEBUG(10, ("[CEPH] mkdir(%p, %s)\n", handle
, path
));
329 if (lp_inherit_acls(SNUM(handle
->conn
))
330 && parent_dirname(talloc_tos(), path
, &parent
, NULL
)
331 && (has_dacl
= directory_has_default_acl(handle
->conn
, parent
)))
336 result
= ceph_mkdir(handle
->data
, path
, mode
);
339 * Note. This order is important
343 } else if (result
== 0 && !has_dacl
) {
345 * We need to do this as the default behavior of POSIX ACLs
346 * is to set the mask to be the requested group permission
347 * bits, not the group permission bits to be the requested
348 * group permission bits. This is not what we want, as it will
349 * mess up any inherited ACL bits that were set. JRA.
351 int saved_errno
= errno
; /* We may get ENOSYS */
352 if ((SMB_VFS_CHMOD_ACL(handle
->conn
, path
, mode
) == -1) && (errno
== ENOSYS
))
359 static int cephwrap_rmdir(struct vfs_handle_struct
*handle
, const char *path
)
363 DEBUG(10, ("[CEPH] rmdir(%p, %s)\n", handle
, path
));
364 result
= ceph_rmdir(handle
->data
, path
);
365 DEBUG(10, ("[CEPH] rmdir(...) = %d\n", result
));
369 static int cephwrap_closedir(struct vfs_handle_struct
*handle
, DIR *dirp
)
373 DEBUG(10, ("[CEPH] closedir(%p, %p)\n", handle
, dirp
));
374 result
= ceph_closedir(handle
->data
, (struct ceph_dir_result
*) dirp
);
375 DEBUG(10, ("[CEPH] closedir(...) = %d\n", result
));
379 /* File operations */
381 static int cephwrap_open(struct vfs_handle_struct
*handle
,
382 struct smb_filename
*smb_fname
,
383 files_struct
*fsp
, int flags
, mode_t mode
)
385 int result
= -ENOENT
;
386 DEBUG(10, ("[CEPH] open(%p, %s, %p, %d, %d)\n", handle
, smb_fname_str_dbg(smb_fname
), fsp
, flags
, mode
));
388 if (smb_fname
->stream_name
) {
392 result
= ceph_open(handle
->data
, smb_fname
->base_name
, flags
, mode
);
394 DEBUG(10, ("[CEPH] open(...) = %d\n", result
));
398 static int cephwrap_close(struct vfs_handle_struct
*handle
, files_struct
*fsp
)
402 DEBUG(10, ("[CEPH] close(%p, %p)\n", handle
, fsp
));
403 result
= ceph_close(handle
->data
, fsp
->fh
->fd
);
404 DEBUG(10, ("[CEPH] close(...) = %d\n", result
));
409 static ssize_t
cephwrap_read(struct vfs_handle_struct
*handle
, files_struct
*fsp
, void *data
, size_t n
)
413 DEBUG(10, ("[CEPH] read(%p, %p, %p, %llu)\n", handle
, fsp
, data
, llu(n
)));
415 /* Using -1 for the offset means read/write rather than pread/pwrite */
416 result
= ceph_read(handle
->data
, fsp
->fh
->fd
, data
, n
, -1);
417 DEBUG(10, ("[CEPH] read(...) = %llu\n", llu(result
)));
421 static ssize_t
cephwrap_pread(struct vfs_handle_struct
*handle
, files_struct
*fsp
, void *data
,
422 size_t n
, off_t offset
)
426 DEBUG(10, ("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle
, fsp
, data
, llu(n
), llu(offset
)));
428 result
= ceph_read(handle
->data
, fsp
->fh
->fd
, data
, n
, offset
);
429 DEBUG(10, ("[CEPH] pread(...) = %llu\n", llu(result
)));
434 static ssize_t
cephwrap_write(struct vfs_handle_struct
*handle
, files_struct
*fsp
, const void *data
, size_t n
)
438 DEBUG(10, ("[CEPH] write(%p, %p, %p, %llu)\n", handle
, fsp
, data
, llu(n
)));
440 result
= ceph_write(handle
->data
, fsp
->fh
->fd
, data
, n
, -1);
442 DEBUG(10, ("[CEPH] write(...) = %llu\n", llu(result
)));
446 fsp
->fh
->pos
+= result
;
450 static ssize_t
cephwrap_pwrite(struct vfs_handle_struct
*handle
, files_struct
*fsp
, const void *data
,
451 size_t n
, off_t offset
)
455 DEBUG(10, ("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle
, fsp
, data
, llu(n
), llu(offset
)));
456 result
= ceph_write(handle
->data
, fsp
->fh
->fd
, data
, n
, offset
);
457 DEBUG(10, ("[CEPH] pwrite(...) = %llu\n", llu(result
)));
461 static off_t
cephwrap_lseek(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t offset
, int whence
)
465 DEBUG(10, ("[CEPH] cephwrap_lseek\n"));
466 /* Cope with 'stat' file opens. */
467 if (fsp
->fh
->fd
!= -1) {
468 result
= ceph_lseek(handle
->data
, fsp
->fh
->fd
, offset
, whence
);
473 static ssize_t
cephwrap_sendfile(struct vfs_handle_struct
*handle
, int tofd
, files_struct
*fromfsp
, const DATA_BLOB
*hdr
,
474 off_t offset
, size_t n
)
477 * We cannot support sendfile because libceph is in user space.
479 DEBUG(10, ("[CEPH] cephwrap_sendfile\n"));
484 static ssize_t
cephwrap_recvfile(struct vfs_handle_struct
*handle
,
491 * We cannot support recvfile because libceph is in user space.
493 DEBUG(10, ("[CEPH] cephwrap_recvfile\n"));
498 static int cephwrap_rename(struct vfs_handle_struct
*handle
,
499 const struct smb_filename
*smb_fname_src
,
500 const struct smb_filename
*smb_fname_dst
)
503 DEBUG(10, ("[CEPH] cephwrap_rename\n"));
504 if (smb_fname_src
->stream_name
|| smb_fname_dst
->stream_name
) {
509 result
= ceph_rename(handle
->data
, smb_fname_src
->base_name
, smb_fname_dst
->base_name
);
513 static int cephwrap_fsync(struct vfs_handle_struct
*handle
, files_struct
*fsp
)
516 DEBUG(10, ("[CEPH] cephwrap_fsync\n"));
517 result
= ceph_fsync(handle
->data
, fsp
->fh
->fd
, false);
521 static void cephwrap_init_stat_ex_from_stat(struct stat_ex
*dst
, const struct stat
*src
)
525 dst
->st_ex_dev
= src
->st_dev
;
526 dst
->st_ex_ino
= src
->st_ino
;
527 dst
->st_ex_mode
= src
->st_mode
;
528 dst
->st_ex_nlink
= src
->st_nlink
;
529 dst
->st_ex_uid
= src
->st_uid
;
530 dst
->st_ex_gid
= src
->st_gid
;
531 dst
->st_ex_rdev
= src
->st_rdev
;
532 dst
->st_ex_size
= src
->st_size
;
533 dst
->st_ex_atime
.tv_sec
= src
->st_atime
;
534 dst
->st_ex_mtime
.tv_sec
= src
->st_mtime
;
535 dst
->st_ex_ctime
.tv_sec
= src
->st_ctime
;
536 dst
->st_ex_btime
.tv_sec
= src
->st_mtime
;
537 dst
->st_ex_blksize
= src
->st_blksize
;
538 dst
->st_ex_blocks
= src
->st_blocks
;
541 static int cephwrap_stat(struct vfs_handle_struct
*handle
,
542 struct smb_filename
*smb_fname
)
547 DEBUG(10, ("[CEPH] stat(%p, %s)\n", handle
, smb_fname_str_dbg(smb_fname
)));
549 if (smb_fname
->stream_name
) {
554 result
= ceph_stat(handle
->data
, smb_fname
->base_name
, (struct stat
*) &stbuf
);
555 DEBUG(10, ("[CEPH] stat(...) = %d\n", result
));
559 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
560 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
561 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
562 llu(stbuf
.st_dev
), llu(stbuf
.st_ino
), stbuf
.st_mode
, llu(stbuf
.st_nlink
),
563 stbuf
.st_uid
, stbuf
.st_gid
, llu(stbuf
.st_rdev
), llu(stbuf
.st_size
), llu(stbuf
.st_blksize
),
564 llu(stbuf
.st_blocks
), llu(stbuf
.st_atime
), llu(stbuf
.st_mtime
), llu(stbuf
.st_ctime
)));
566 cephwrap_init_stat_ex_from_stat(&(smb_fname
->st
), &stbuf
);
567 DEBUG(10, ("[CEPH] mode = 0x%x\n", smb_fname
->st
.st_ex_mode
));
571 static int cephwrap_fstat(struct vfs_handle_struct
*handle
, files_struct
*fsp
, SMB_STRUCT_STAT
*sbuf
)
576 DEBUG(10, ("[CEPH] fstat(%p, %d)\n", handle
, fsp
->fh
->fd
));
577 result
= ceph_fstat(handle
->data
, fsp
->fh
->fd
, (struct stat
*) &stbuf
);
578 DEBUG(10, ("[CEPH] fstat(...) = %d\n", result
));
582 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
583 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
584 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
585 llu(stbuf
.st_dev
), llu(stbuf
.st_ino
), stbuf
.st_mode
, llu(stbuf
.st_nlink
),
586 stbuf
.st_uid
, stbuf
.st_gid
, llu(stbuf
.st_rdev
), llu(stbuf
.st_size
), llu(stbuf
.st_blksize
),
587 llu(stbuf
.st_blocks
), llu(stbuf
.st_atime
), llu(stbuf
.st_mtime
), llu(stbuf
.st_ctime
)));
590 cephwrap_init_stat_ex_from_stat(sbuf
, &stbuf
);
591 DEBUG(10, ("[CEPH] mode = 0x%x\n", sbuf
->st_ex_mode
));
595 static int cephwrap_lstat(struct vfs_handle_struct
*handle
,
596 struct smb_filename
*smb_fname
)
601 DEBUG(10, ("[CEPH] lstat(%p, %s)\n", handle
, smb_fname_str_dbg(smb_fname
)));
603 if (smb_fname
->stream_name
) {
608 result
= ceph_lstat(handle
->data
, smb_fname
->base_name
, &stbuf
);
609 DEBUG(10, ("[CEPH] lstat(...) = %d\n", result
));
613 cephwrap_init_stat_ex_from_stat(&(smb_fname
->st
), &stbuf
);
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
, const char *path
, mode_t mode
)
636 DEBUG(10, ("[CEPH] chmod(%p, %s, %d)\n", handle
, path
, mode
));
639 * We need to do this due to the fact that the default POSIX ACL
640 * chmod modifies the ACL *mask* for the group owner, not the
641 * group owner bits directly. JRA.
646 int saved_errno
= errno
; /* We might get ENOSYS */
647 if ((result
= SMB_VFS_CHMOD_ACL(handle
->conn
, path
, mode
)) == 0) {
650 /* Error - return the old errno. */
654 result
= ceph_chmod(handle
->data
, path
, mode
);
655 DEBUG(10, ("[CEPH] chmod(...) = %d\n", result
));
659 static int cephwrap_fchmod(struct vfs_handle_struct
*handle
, files_struct
*fsp
, mode_t mode
)
663 DEBUG(10, ("[CEPH] fchmod(%p, %p, %d)\n", handle
, fsp
, mode
));
666 * We need to do this due to the fact that the default POSIX ACL
667 * chmod modifies the ACL *mask* for the group owner, not the
668 * group owner bits directly. JRA.
672 int saved_errno
= errno
; /* We might get ENOSYS */
673 if ((result
= SMB_VFS_FCHMOD_ACL(fsp
, mode
)) == 0) {
676 /* Error - return the old errno. */
680 #if defined(HAVE_FCHMOD)
681 result
= ceph_fchmod(handle
->data
, fsp
->fh
->fd
, mode
);
682 DEBUG(10, ("[CEPH] fchmod(...) = %d\n", result
));
690 static int cephwrap_chown(struct vfs_handle_struct
*handle
, const char *path
, uid_t uid
, gid_t gid
)
693 DEBUG(10, ("[CEPH] chown(%p, %s, %d, %d)\n", handle
, path
, uid
, gid
));
694 result
= ceph_chown(handle
->data
, path
, uid
, gid
);
695 DEBUG(10, ("[CEPH] chown(...) = %d\n", result
));
699 static int cephwrap_fchown(struct vfs_handle_struct
*handle
, files_struct
*fsp
, uid_t uid
, gid_t gid
)
704 DEBUG(10, ("[CEPH] fchown(%p, %p, %d, %d)\n", handle
, fsp
, uid
, gid
));
705 result
= ceph_fchown(handle
->data
, fsp
->fh
->fd
, uid
, gid
);
706 DEBUG(10, ("[CEPH] fchown(...) = %d\n", result
));
715 static int cephwrap_lchown(struct vfs_handle_struct
*handle
, const char *path
, uid_t uid
, gid_t gid
)
719 DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", handle
, path
, uid
, gid
));
720 result
= ceph_lchown(handle
->data
, path
, uid
, gid
);
721 DEBUG(10, ("[CEPH] lchown(...) = %d\n", result
));
725 static int cephwrap_chdir(struct vfs_handle_struct
*handle
, const char *path
)
728 DEBUG(10, ("[CEPH] chdir(%p, %s)\n", handle
, path
));
730 * If the path is just / use chdir because Ceph is below / and
731 * cannot deal with changing directory above its mount point
733 if (path
&& !strcmp(path
, "/"))
736 result
= ceph_chdir(handle
->data
, path
);
737 DEBUG(10, ("[CEPH] chdir(...) = %d\n", result
));
741 static char *cephwrap_getwd(struct vfs_handle_struct
*handle
)
743 const char *cwd
= ceph_getcwd(handle
->data
);
744 DEBUG(10, ("[CEPH] getwd(%p) = %s\n", handle
, cwd
));
745 return SMB_STRDUP(cwd
);
748 static int cephwrap_ntimes(struct vfs_handle_struct
*handle
,
749 const struct smb_filename
*smb_fname
,
750 struct smb_file_time
*ft
)
753 buf
.actime
= ft
->atime
.tv_sec
;
754 buf
.modtime
= ft
->mtime
.tv_sec
;
755 int result
= ceph_utime(handle
->data
, smb_fname
->base_name
, &buf
);
756 DEBUG(10, ("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle
, smb_fname_str_dbg(smb_fname
),
757 ft
->mtime
.tv_sec
, ft
->atime
.tv_sec
, ft
->ctime
.tv_sec
,
758 ft
->create_time
.tv_sec
, result
));
762 static int strict_allocate_ftruncate(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t len
)
764 off_t space_to_write
;
765 uint64_t space_avail
;
766 uint64_t bsize
,dfree
,dsize
;
769 SMB_STRUCT_STAT
*pst
;
771 status
= vfs_stat_fsp(fsp
);
772 if (!NT_STATUS_IS_OK(status
)) {
775 pst
= &fsp
->fsp_name
->st
;
778 if (S_ISFIFO(pst
->st_ex_mode
))
782 if (pst
->st_ex_size
== len
)
785 /* Shrink - just ftruncate. */
786 if (pst
->st_ex_size
> len
)
787 return ftruncate(fsp
->fh
->fd
, len
);
789 space_to_write
= len
- pst
->st_ex_size
;
791 /* for allocation try fallocate first. This can fail on some
792 platforms e.g. when the filesystem doesn't support it and no
793 emulation is being done by the libc (like on AIX with JFS1). In that
794 case we do our own emulation. fallocate implementations can
795 return ENOTSUP or EINVAL in cases like that. */
796 ret
= SMB_VFS_FALLOCATE(fsp
, VFS_FALLOCATE_EXTEND_SIZE
,
797 pst
->st_ex_size
, space_to_write
);
798 if (ret
== -1 && errno
== ENOSPC
) {
804 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
805 "error %d. Falling back to slow manual allocation\n", errno
));
807 /* available disk space is enough or not? */
808 space_avail
= get_dfree_info(fsp
->conn
,
809 fsp
->fsp_name
->base_name
, false,
810 &bsize
,&dfree
,&dsize
);
811 /* space_avail is 1k blocks */
812 if (space_avail
== (uint64_t)-1 ||
813 ((uint64_t)space_to_write
/1024 > space_avail
) ) {
818 /* Write out the real space on disk. */
819 return vfs_slow_fallocate(fsp
, pst
->st_ex_size
, space_to_write
);
822 static int cephwrap_ftruncate(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t len
)
829 DEBUG(10, ("[CEPH] ftruncate(%p, %p, %llu\n", handle
, fsp
, llu(len
)));
831 if (lp_strict_allocate(SNUM(fsp
->conn
))) {
832 result
= strict_allocate_ftruncate(handle
, fsp
, len
);
836 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
837 sys_ftruncate if the system supports it. Then I discovered that
838 you can have some filesystems that support ftruncate
839 expansion and some that don't! On Linux fat can't do
840 ftruncate extend but ext2 can. */
842 result
= ceph_ftruncate(handle
->data
, fsp
->fh
->fd
, len
);
846 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
847 extend a file with ftruncate. Provide alternate implementation
849 currpos
= SMB_VFS_LSEEK(fsp
, 0, SEEK_CUR
);
854 /* Do an fstat to see if the file is longer than the requested
855 size in which case the ftruncate above should have
856 succeeded or shorter, in which case seek to len - 1 and
857 write 1 byte of zero */
858 if (SMB_VFS_FSTAT(fsp
, &st
) == -1) {
863 if (S_ISFIFO(st
.st_ex_mode
)) {
869 if (st
.st_ex_size
== len
) {
874 if (st
.st_ex_size
> len
) {
875 /* the sys_ftruncate should have worked */
879 if (SMB_VFS_LSEEK(fsp
, len
-1, SEEK_SET
) != len
-1)
882 if (SMB_VFS_WRITE(fsp
, &c
, 1)!=1)
885 /* Seek to where we were */
886 if (SMB_VFS_LSEEK(fsp
, currpos
, SEEK_SET
) != currpos
)
895 static bool cephwrap_lock(struct vfs_handle_struct
*handle
, files_struct
*fsp
, int op
, off_t offset
, off_t count
, int type
)
897 DEBUG(10, ("[CEPH] lock\n"));
901 static int cephwrap_kernel_flock(struct vfs_handle_struct
*handle
, files_struct
*fsp
,
902 uint32 share_mode
, uint32 access_mask
)
904 DEBUG(10, ("[CEPH] kernel_flock\n"));
906 * We must return zero here and pretend all is good.
907 * One day we might have this in CEPH.
912 static bool cephwrap_getlock(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t
*poffset
, off_t
*pcount
, int *ptype
, pid_t
*ppid
)
914 DEBUG(10, ("[CEPH] getlock returning false and errno=0\n"));
921 * We cannot let this fall through to the default, because the file might only
922 * be accessible from libceph (which is a user-space client) but the fd might
923 * be for some file the kernel knows about.
925 static int cephwrap_linux_setlease(struct vfs_handle_struct
*handle
, files_struct
*fsp
,
930 DEBUG(10, ("[CEPH] linux_setlease\n"));
935 static int cephwrap_symlink(struct vfs_handle_struct
*handle
, const char *oldpath
, const char *newpath
)
938 DEBUG(10, ("[CEPH] symlink(%p, %s, %s)\n", handle
, oldpath
, newpath
));
939 result
= ceph_symlink(handle
->data
, oldpath
, newpath
);
940 DEBUG(10, ("[CEPH] symlink(...) = %d\n", result
));
944 static int cephwrap_readlink(struct vfs_handle_struct
*handle
, const char *path
, char *buf
, size_t bufsiz
)
947 DEBUG(10, ("[CEPH] readlink(%p, %s, %p, %llu)\n", handle
, path
, buf
, llu(bufsiz
)));
948 result
= ceph_readlink(handle
->data
, path
, buf
, bufsiz
);
949 DEBUG(10, ("[CEPH] readlink(...) = %d\n", result
));
953 static int cephwrap_link(struct vfs_handle_struct
*handle
, const char *oldpath
, const char *newpath
)
956 DEBUG(10, ("[CEPH] link(%p, %s, %s)\n", handle
, oldpath
, newpath
));
957 result
= ceph_link(handle
->data
, oldpath
, newpath
);
958 DEBUG(10, ("[CEPH] link(...) = %d\n", result
));
962 static int cephwrap_mknod(struct vfs_handle_struct
*handle
, const char *pathname
, mode_t mode
, SMB_DEV_T dev
)
965 DEBUG(10, ("[CEPH] mknod(%p, %s)\n", handle
, pathname
));
966 result
= ceph_mknod(handle
->data
, pathname
, mode
, dev
);
967 DEBUG(10, ("[CEPH] mknod(...) = %d\n", result
));
972 * This is a simple version of real-path ... a better version is needed to
973 * ask libceph about symbolic links.
975 static char *cephwrap_realpath(struct vfs_handle_struct
*handle
, const char *path
)
978 size_t len
= strlen(path
);
980 result
= SMB_MALLOC_ARRAY(char, PATH_MAX
+1);
981 if (len
&& (path
[0] == '/')) {
982 int r
= asprintf(&result
, "%s", path
);
983 if (r
< 0) return NULL
;
984 } else if ((len
>= 2) && (path
[0] == '.') && (path
[1] == '/')) {
986 int r
= asprintf(&result
, "%s",
987 handle
->conn
->connectpath
);
988 if (r
< 0) return NULL
;
990 int r
= asprintf(&result
, "%s/%s",
991 handle
->conn
->connectpath
, &path
[2]);
992 if (r
< 0) return NULL
;
995 int r
= asprintf(&result
, "%s/%s",
996 handle
->conn
->connectpath
, path
);
997 if (r
< 0) return NULL
;
999 DEBUG(10, ("[CEPH] realpath(%p, %s) = %s\n", handle
, path
, result
));
1003 static NTSTATUS
cephwrap_notify_watch(struct vfs_handle_struct
*vfs_handle
,
1004 struct sys_notify_context
*ctx
,
1007 uint32_t *subdir_filter
,
1008 void (*callback
)(struct sys_notify_context
*ctx
,
1010 struct notify_event
*ev
),
1015 * We cannot call inotify on files the kernel does not know about
1017 return NT_STATUS_OK
;
1020 static int cephwrap_chflags(struct vfs_handle_struct
*handle
, const char *path
,
1027 static int cephwrap_get_real_filename(struct vfs_handle_struct
*handle
,
1030 TALLOC_CTX
*mem_ctx
,
1034 * Don't fall back to get_real_filename so callers can differentiate
1035 * between a full directory scan and an actual case-insensitive stat.
1041 static const char *cephwrap_connectpath(struct vfs_handle_struct
*handle
,
1044 return handle
->conn
->connectpath
;
1047 /****************************************************************
1048 Extended attribute operations.
1049 *****************************************************************/
1051 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 int 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
)
1065 DEBUG(10, ("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle
, fsp
, name
, value
, llu(size
)));
1066 int ret
= ceph_getxattr(handle
->data
, fsp
->fsp_name
->base_name
, name
, value
, size
);
1067 DEBUG(10, ("[CEPH] fgetxattr(...) = %d\n", ret
));
1071 return (ssize_t
)ret
;
1075 static ssize_t
cephwrap_listxattr(struct vfs_handle_struct
*handle
, const char *path
, char *list
, size_t size
)
1077 DEBUG(10, ("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle
, path
, list
, llu(size
)));
1078 int ret
= ceph_listxattr(handle
->data
, path
, list
, size
);
1079 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret
));
1083 return (ssize_t
)ret
;
1088 static ssize_t
cephwrap_llistxattr(struct vfs_handle_struct
*handle
, const char *path
, char *list
, size_t size
)
1090 DEBUG(10, ("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle
, path
, list
, llu(size
)));
1091 int ret
= ceph_llistxattr(handle
->data
, path
, list
, size
);
1092 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret
));
1096 return (ssize_t
)ret
;
1101 static ssize_t
cephwrap_flistxattr(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
, char *list
, size_t size
)
1103 DEBUG(10, ("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle
, fsp
, list
, llu(size
)));
1104 int ret
= ceph_listxattr(handle
->data
, fsp
->fsp_name
->base_name
, list
, size
);
1105 DEBUG(10, ("[CEPH] flistxattr(...) = %d\n", ret
));
1109 return (ssize_t
)ret
;
1113 static int cephwrap_removexattr(struct vfs_handle_struct
*handle
, const char *path
, const char *name
)
1115 DEBUG(10, ("[CEPH] removexattr(%p, %s, %s)\n", handle
, path
, name
));
1116 int ret
= ceph_removexattr(handle
->data
, path
, name
);
1117 DEBUG(10, ("[CEPH] removexattr(...) = %d\n", ret
));
1121 static int cephwrap_fremovexattr(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
, const char *name
)
1123 DEBUG(10, ("[CEPH] fremovexattr(%p, %p, %s)\n", handle
, fsp
, name
));
1124 int ret
= ceph_removexattr(handle
->data
, fsp
->fsp_name
->base_name
, name
);
1125 DEBUG(10, ("[CEPH] fremovexattr(...) = %d\n", ret
));
1129 static int cephwrap_setxattr(struct vfs_handle_struct
*handle
, const char *path
, const char *name
, const void *value
, size_t size
, int flags
)
1131 DEBUG(10, ("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle
, path
, name
, value
, llu(size
), flags
));
1132 int ret
= ceph_setxattr(handle
->data
, path
, name
, value
, size
, flags
);
1133 DEBUG(10, ("[CEPH] setxattr(...) = %d\n", ret
));
1137 static int cephwrap_fsetxattr(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
, const char *name
, const void *value
, size_t size
, int flags
)
1139 DEBUG(10, ("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle
, fsp
, name
, value
, llu(size
), flags
));
1140 int ret
= ceph_setxattr(handle
->data
, fsp
->fsp_name
->base_name
, name
, value
, size
, flags
);
1141 DEBUG(10, ("[CEPH] fsetxattr(...) = %d\n", ret
));
1145 static bool cephwrap_aio_force(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
)
1149 * We do not support AIO yet.
1152 DEBUG(10, ("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle
, fsp
));
1157 static bool cephwrap_is_offline(struct vfs_handle_struct
*handle
,
1158 const struct smb_filename
*fname
,
1159 SMB_STRUCT_STAT
*sbuf
)
1164 static int cephwrap_set_offline(struct vfs_handle_struct
*handle
,
1165 const struct smb_filename
*fname
)
1171 static struct vfs_fn_pointers ceph_fns
= {
1172 /* Disk operations */
1174 .connect_fn
= cephwrap_connect
,
1175 .disconnect_fn
= cephwrap_disconnect
,
1176 .disk_free_fn
= cephwrap_disk_free
,
1177 .get_quota_fn
= cephwrap_get_quota
,
1178 .set_quota_fn
= cephwrap_set_quota
,
1179 .statvfs_fn
= cephwrap_statvfs
,
1181 /* Directory operations */
1183 .opendir_fn
= cephwrap_opendir
,
1184 .fdopendir_fn
= cephwrap_fdopendir
,
1185 .readdir_fn
= cephwrap_readdir
,
1186 .seekdir_fn
= cephwrap_seekdir
,
1187 .telldir_fn
= cephwrap_telldir
,
1188 .rewind_dir_fn
= cephwrap_rewinddir
,
1189 .mkdir_fn
= cephwrap_mkdir
,
1190 .rmdir_fn
= cephwrap_rmdir
,
1191 .closedir_fn
= cephwrap_closedir
,
1193 /* File operations */
1195 .open_fn
= cephwrap_open
,
1196 .close_fn
= cephwrap_close
,
1197 .read_fn
= cephwrap_read
,
1198 .pread_fn
= cephwrap_pread
,
1199 .write_fn
= cephwrap_write
,
1200 .pwrite_fn
= cephwrap_pwrite
,
1201 .lseek_fn
= cephwrap_lseek
,
1202 .sendfile_fn
= cephwrap_sendfile
,
1203 .recvfile_fn
= cephwrap_recvfile
,
1204 .rename_fn
= cephwrap_rename
,
1205 .fsync_fn
= cephwrap_fsync
,
1206 .stat_fn
= cephwrap_stat
,
1207 .fstat_fn
= cephwrap_fstat
,
1208 .lstat_fn
= cephwrap_lstat
,
1209 .unlink_fn
= cephwrap_unlink
,
1210 .chmod_fn
= cephwrap_chmod
,
1211 .fchmod_fn
= cephwrap_fchmod
,
1212 .chown_fn
= cephwrap_chown
,
1213 .fchown_fn
= cephwrap_fchown
,
1214 .lchown_fn
= cephwrap_lchown
,
1215 .chdir_fn
= cephwrap_chdir
,
1216 .getwd_fn
= cephwrap_getwd
,
1217 .ntimes_fn
= cephwrap_ntimes
,
1218 .ftruncate_fn
= cephwrap_ftruncate
,
1219 .lock_fn
= cephwrap_lock
,
1220 .kernel_flock_fn
= cephwrap_kernel_flock
,
1221 .linux_setlease_fn
= cephwrap_linux_setlease
,
1222 .getlock_fn
= cephwrap_getlock
,
1223 .symlink_fn
= cephwrap_symlink
,
1224 .readlink_fn
= cephwrap_readlink
,
1225 .link_fn
= cephwrap_link
,
1226 .mknod_fn
= cephwrap_mknod
,
1227 .realpath_fn
= cephwrap_realpath
,
1228 .notify_watch_fn
= cephwrap_notify_watch
,
1229 .chflags_fn
= cephwrap_chflags
,
1230 .get_real_filename_fn
= cephwrap_get_real_filename
,
1231 .connectpath_fn
= cephwrap_connectpath
,
1233 /* EA operations. */
1234 .getxattr_fn
= cephwrap_getxattr
,
1235 .fgetxattr_fn
= cephwrap_fgetxattr
,
1236 .listxattr_fn
= cephwrap_listxattr
,
1237 .flistxattr_fn
= cephwrap_flistxattr
,
1238 .removexattr_fn
= cephwrap_removexattr
,
1239 .fremovexattr_fn
= cephwrap_fremovexattr
,
1240 .setxattr_fn
= cephwrap_setxattr
,
1241 .fsetxattr_fn
= cephwrap_fsetxattr
,
1243 /* aio operations */
1244 .aio_force_fn
= cephwrap_aio_force
,
1246 /* offline operations */
1247 .is_offline_fn
= cephwrap_is_offline
,
1248 .set_offline_fn
= cephwrap_set_offline
1251 NTSTATUS
vfs_ceph_init(void);
1252 NTSTATUS
vfs_ceph_init(void)
1254 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,