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
, const char *path
, mode_t mode
)
332 bool has_dacl
= False
;
335 DEBUG(10, ("[CEPH] mkdir(%p, %s)\n", handle
, path
));
337 if (lp_inherit_acls(SNUM(handle
->conn
))
338 && parent_dirname(talloc_tos(), path
, &parent
, NULL
)
339 && (has_dacl
= directory_has_default_acl(handle
->conn
, parent
)))
344 result
= ceph_mkdir(handle
->data
, path
, mode
);
347 * Note. This order is important
351 } else if (result
== 0 && !has_dacl
) {
353 * We need to do this as the default behavior of POSIX ACLs
354 * is to set the mask to be the requested group permission
355 * bits, not the group permission bits to be the requested
356 * group permission bits. This is not what we want, as it will
357 * mess up any inherited ACL bits that were set. JRA.
359 int saved_errno
= errno
; /* We may get ENOSYS */
360 if ((SMB_VFS_CHMOD_ACL(handle
->conn
, path
, mode
) == -1) && (errno
== ENOSYS
))
367 static int cephwrap_rmdir(struct vfs_handle_struct
*handle
, const char *path
)
371 DEBUG(10, ("[CEPH] rmdir(%p, %s)\n", handle
, path
));
372 result
= ceph_rmdir(handle
->data
, path
);
373 DEBUG(10, ("[CEPH] rmdir(...) = %d\n", result
));
377 static int cephwrap_closedir(struct vfs_handle_struct
*handle
, DIR *dirp
)
381 DEBUG(10, ("[CEPH] closedir(%p, %p)\n", handle
, dirp
));
382 result
= ceph_closedir(handle
->data
, (struct ceph_dir_result
*) dirp
);
383 DEBUG(10, ("[CEPH] closedir(...) = %d\n", result
));
387 /* File operations */
389 static int cephwrap_open(struct vfs_handle_struct
*handle
,
390 struct smb_filename
*smb_fname
,
391 files_struct
*fsp
, int flags
, mode_t mode
)
393 int result
= -ENOENT
;
394 DEBUG(10, ("[CEPH] open(%p, %s, %p, %d, %d)\n", handle
, smb_fname_str_dbg(smb_fname
), fsp
, flags
, mode
));
396 if (smb_fname
->stream_name
) {
400 result
= ceph_open(handle
->data
, smb_fname
->base_name
, flags
, mode
);
402 DEBUG(10, ("[CEPH] open(...) = %d\n", result
));
406 static int cephwrap_close(struct vfs_handle_struct
*handle
, files_struct
*fsp
)
410 DEBUG(10, ("[CEPH] close(%p, %p)\n", handle
, fsp
));
411 result
= ceph_close(handle
->data
, fsp
->fh
->fd
);
412 DEBUG(10, ("[CEPH] close(...) = %d\n", result
));
417 static ssize_t
cephwrap_read(struct vfs_handle_struct
*handle
, files_struct
*fsp
, void *data
, size_t n
)
421 DEBUG(10, ("[CEPH] read(%p, %p, %p, %llu)\n", handle
, fsp
, data
, llu(n
)));
423 /* Using -1 for the offset means read/write rather than pread/pwrite */
424 result
= ceph_read(handle
->data
, fsp
->fh
->fd
, data
, n
, -1);
425 DEBUG(10, ("[CEPH] read(...) = %llu\n", llu(result
)));
429 static ssize_t
cephwrap_pread(struct vfs_handle_struct
*handle
, files_struct
*fsp
, void *data
,
430 size_t n
, off_t offset
)
434 DEBUG(10, ("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle
, fsp
, data
, llu(n
), llu(offset
)));
436 result
= ceph_read(handle
->data
, fsp
->fh
->fd
, data
, n
, offset
);
437 DEBUG(10, ("[CEPH] pread(...) = %llu\n", llu(result
)));
442 static ssize_t
cephwrap_write(struct vfs_handle_struct
*handle
, files_struct
*fsp
, const void *data
, size_t n
)
446 DEBUG(10, ("[CEPH] write(%p, %p, %p, %llu)\n", handle
, fsp
, data
, llu(n
)));
448 result
= ceph_write(handle
->data
, fsp
->fh
->fd
, data
, n
, -1);
450 DEBUG(10, ("[CEPH] write(...) = %llu\n", llu(result
)));
454 fsp
->fh
->pos
+= result
;
458 static ssize_t
cephwrap_pwrite(struct vfs_handle_struct
*handle
, files_struct
*fsp
, const void *data
,
459 size_t n
, off_t offset
)
463 DEBUG(10, ("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle
, fsp
, data
, llu(n
), llu(offset
)));
464 result
= ceph_write(handle
->data
, fsp
->fh
->fd
, data
, n
, offset
);
465 DEBUG(10, ("[CEPH] pwrite(...) = %llu\n", llu(result
)));
469 static off_t
cephwrap_lseek(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t offset
, int whence
)
473 DEBUG(10, ("[CEPH] cephwrap_lseek\n"));
474 /* Cope with 'stat' file opens. */
475 if (fsp
->fh
->fd
!= -1) {
476 result
= ceph_lseek(handle
->data
, fsp
->fh
->fd
, offset
, whence
);
481 static ssize_t
cephwrap_sendfile(struct vfs_handle_struct
*handle
, int tofd
, files_struct
*fromfsp
, const DATA_BLOB
*hdr
,
482 off_t offset
, size_t n
)
485 * We cannot support sendfile because libceph is in user space.
487 DEBUG(10, ("[CEPH] cephwrap_sendfile\n"));
492 static ssize_t
cephwrap_recvfile(struct vfs_handle_struct
*handle
,
499 * We cannot support recvfile because libceph is in user space.
501 DEBUG(10, ("[CEPH] cephwrap_recvfile\n"));
506 static int cephwrap_rename(struct vfs_handle_struct
*handle
,
507 const struct smb_filename
*smb_fname_src
,
508 const struct smb_filename
*smb_fname_dst
)
511 DEBUG(10, ("[CEPH] cephwrap_rename\n"));
512 if (smb_fname_src
->stream_name
|| smb_fname_dst
->stream_name
) {
517 result
= ceph_rename(handle
->data
, smb_fname_src
->base_name
, smb_fname_dst
->base_name
);
521 static int cephwrap_fsync(struct vfs_handle_struct
*handle
, files_struct
*fsp
)
524 DEBUG(10, ("[CEPH] cephwrap_fsync\n"));
525 result
= ceph_fsync(handle
->data
, fsp
->fh
->fd
, false);
529 static int cephwrap_stat(struct vfs_handle_struct
*handle
,
530 struct smb_filename
*smb_fname
)
535 DEBUG(10, ("[CEPH] stat(%p, %s)\n", handle
, smb_fname_str_dbg(smb_fname
)));
537 if (smb_fname
->stream_name
) {
542 result
= ceph_stat(handle
->data
, smb_fname
->base_name
, (struct stat
*) &stbuf
);
543 DEBUG(10, ("[CEPH] stat(...) = %d\n", result
));
547 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
548 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
549 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
550 llu(stbuf
.st_dev
), llu(stbuf
.st_ino
), stbuf
.st_mode
, llu(stbuf
.st_nlink
),
551 stbuf
.st_uid
, stbuf
.st_gid
, llu(stbuf
.st_rdev
), llu(stbuf
.st_size
), llu(stbuf
.st_blksize
),
552 llu(stbuf
.st_blocks
), llu(stbuf
.st_atime
), llu(stbuf
.st_mtime
), llu(stbuf
.st_ctime
)));
554 init_stat_ex_from_stat(
555 &smb_fname
->st
, &stbuf
,
556 lp_fake_directory_create_times(SNUM(handle
->conn
)));
557 DEBUG(10, ("[CEPH] mode = 0x%x\n", smb_fname
->st
.st_ex_mode
));
561 static int cephwrap_fstat(struct vfs_handle_struct
*handle
, files_struct
*fsp
, SMB_STRUCT_STAT
*sbuf
)
566 DEBUG(10, ("[CEPH] fstat(%p, %d)\n", handle
, fsp
->fh
->fd
));
567 result
= ceph_fstat(handle
->data
, fsp
->fh
->fd
, (struct stat
*) &stbuf
);
568 DEBUG(10, ("[CEPH] fstat(...) = %d\n", result
));
572 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
573 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
574 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
575 llu(stbuf
.st_dev
), llu(stbuf
.st_ino
), stbuf
.st_mode
, llu(stbuf
.st_nlink
),
576 stbuf
.st_uid
, stbuf
.st_gid
, llu(stbuf
.st_rdev
), llu(stbuf
.st_size
), llu(stbuf
.st_blksize
),
577 llu(stbuf
.st_blocks
), llu(stbuf
.st_atime
), llu(stbuf
.st_mtime
), llu(stbuf
.st_ctime
)));
580 init_stat_ex_from_stat(
582 lp_fake_directory_create_times(SNUM(handle
->conn
)));
583 DEBUG(10, ("[CEPH] mode = 0x%x\n", sbuf
->st_ex_mode
));
587 static int cephwrap_lstat(struct vfs_handle_struct
*handle
,
588 struct smb_filename
*smb_fname
)
593 DEBUG(10, ("[CEPH] lstat(%p, %s)\n", handle
, smb_fname_str_dbg(smb_fname
)));
595 if (smb_fname
->stream_name
) {
600 result
= ceph_lstat(handle
->data
, smb_fname
->base_name
, &stbuf
);
601 DEBUG(10, ("[CEPH] lstat(...) = %d\n", result
));
605 init_stat_ex_from_stat(
606 &smb_fname
->st
, &stbuf
,
607 lp_fake_directory_create_times(SNUM(handle
->conn
)));
611 static int cephwrap_unlink(struct vfs_handle_struct
*handle
,
612 const struct smb_filename
*smb_fname
)
616 DEBUG(10, ("[CEPH] unlink(%p, %s)\n", handle
, smb_fname_str_dbg(smb_fname
)));
617 if (smb_fname
->stream_name
) {
621 result
= ceph_unlink(handle
->data
, smb_fname
->base_name
);
622 DEBUG(10, ("[CEPH] unlink(...) = %d\n", result
));
626 static int cephwrap_chmod(struct vfs_handle_struct
*handle
, const char *path
, mode_t mode
)
630 DEBUG(10, ("[CEPH] chmod(%p, %s, %d)\n", handle
, path
, mode
));
633 * We need to do this due to the fact that the default POSIX ACL
634 * chmod modifies the ACL *mask* for the group owner, not the
635 * group owner bits directly. JRA.
640 int saved_errno
= errno
; /* We might get ENOSYS */
641 if ((result
= SMB_VFS_CHMOD_ACL(handle
->conn
, path
, mode
)) == 0) {
644 /* Error - return the old errno. */
648 result
= ceph_chmod(handle
->data
, path
, mode
);
649 DEBUG(10, ("[CEPH] chmod(...) = %d\n", result
));
653 static int cephwrap_fchmod(struct vfs_handle_struct
*handle
, files_struct
*fsp
, mode_t mode
)
657 DEBUG(10, ("[CEPH] fchmod(%p, %p, %d)\n", handle
, fsp
, mode
));
660 * We need to do this due to the fact that the default POSIX ACL
661 * chmod modifies the ACL *mask* for the group owner, not the
662 * group owner bits directly. JRA.
666 int saved_errno
= errno
; /* We might get ENOSYS */
667 if ((result
= SMB_VFS_FCHMOD_ACL(fsp
, mode
)) == 0) {
670 /* Error - return the old errno. */
674 #if defined(HAVE_FCHMOD)
675 result
= ceph_fchmod(handle
->data
, fsp
->fh
->fd
, mode
);
676 DEBUG(10, ("[CEPH] fchmod(...) = %d\n", result
));
684 static int cephwrap_chown(struct vfs_handle_struct
*handle
, const char *path
, uid_t uid
, gid_t gid
)
687 DEBUG(10, ("[CEPH] chown(%p, %s, %d, %d)\n", handle
, path
, uid
, gid
));
688 result
= ceph_chown(handle
->data
, path
, uid
, gid
);
689 DEBUG(10, ("[CEPH] chown(...) = %d\n", result
));
693 static int cephwrap_fchown(struct vfs_handle_struct
*handle
, files_struct
*fsp
, uid_t uid
, gid_t gid
)
698 DEBUG(10, ("[CEPH] fchown(%p, %p, %d, %d)\n", handle
, fsp
, uid
, gid
));
699 result
= ceph_fchown(handle
->data
, fsp
->fh
->fd
, uid
, gid
);
700 DEBUG(10, ("[CEPH] fchown(...) = %d\n", result
));
709 static int cephwrap_lchown(struct vfs_handle_struct
*handle
, const char *path
, uid_t uid
, gid_t gid
)
713 DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", handle
, path
, uid
, gid
));
714 result
= ceph_lchown(handle
->data
, path
, uid
, gid
);
715 DEBUG(10, ("[CEPH] lchown(...) = %d\n", result
));
719 static int cephwrap_chdir(struct vfs_handle_struct
*handle
, const char *path
)
722 DEBUG(10, ("[CEPH] chdir(%p, %s)\n", handle
, path
));
724 * If the path is just / use chdir because Ceph is below / and
725 * cannot deal with changing directory above its mount point
727 if (path
&& !strcmp(path
, "/"))
730 result
= ceph_chdir(handle
->data
, path
);
731 DEBUG(10, ("[CEPH] chdir(...) = %d\n", result
));
735 static char *cephwrap_getwd(struct vfs_handle_struct
*handle
)
737 const char *cwd
= ceph_getcwd(handle
->data
);
738 DEBUG(10, ("[CEPH] getwd(%p) = %s\n", handle
, cwd
));
739 return SMB_STRDUP(cwd
);
742 static int cephwrap_ntimes(struct vfs_handle_struct
*handle
,
743 const struct smb_filename
*smb_fname
,
744 struct smb_file_time
*ft
)
749 if (null_timespec(ft
->atime
)) {
750 buf
.actime
= smb_fname
->st
.st_ex_atime
.tv_sec
;
752 buf
.actime
= ft
->atime
.tv_sec
;
754 if (null_timespec(ft
->mtime
)) {
755 buf
.modtime
= smb_fname
->st
.st_ex_mtime
.tv_sec
;
757 buf
.modtime
= ft
->mtime
.tv_sec
;
759 if (!null_timespec(ft
->create_time
)) {
760 set_create_timespec_ea(handle
->conn
, smb_fname
,
763 if (buf
.actime
== smb_fname
->st
.st_ex_atime
.tv_sec
&&
764 buf
.modtime
== smb_fname
->st
.st_ex_mtime
.tv_sec
) {
768 result
= ceph_utime(handle
->data
, smb_fname
->base_name
, &buf
);
769 DEBUG(10, ("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle
, smb_fname_str_dbg(smb_fname
),
770 ft
->mtime
.tv_sec
, ft
->atime
.tv_sec
, ft
->ctime
.tv_sec
,
771 ft
->create_time
.tv_sec
, result
));
775 static int strict_allocate_ftruncate(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t len
)
777 off_t space_to_write
;
778 uint64_t space_avail
;
779 uint64_t bsize
,dfree
,dsize
;
782 SMB_STRUCT_STAT
*pst
;
784 status
= vfs_stat_fsp(fsp
);
785 if (!NT_STATUS_IS_OK(status
)) {
788 pst
= &fsp
->fsp_name
->st
;
791 if (S_ISFIFO(pst
->st_ex_mode
))
795 if (pst
->st_ex_size
== len
)
798 /* Shrink - just ftruncate. */
799 if (pst
->st_ex_size
> len
)
800 return ftruncate(fsp
->fh
->fd
, len
);
802 space_to_write
= len
- pst
->st_ex_size
;
804 /* for allocation try fallocate first. This can fail on some
805 platforms e.g. when the filesystem doesn't support it and no
806 emulation is being done by the libc (like on AIX with JFS1). In that
807 case we do our own emulation. fallocate implementations can
808 return ENOTSUP or EINVAL in cases like that. */
809 ret
= SMB_VFS_FALLOCATE(fsp
, 0, pst
->st_ex_size
, space_to_write
);
810 if (ret
== -1 && errno
== ENOSPC
) {
816 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
817 "error %d. Falling back to slow manual allocation\n", errno
));
819 /* available disk space is enough or not? */
820 space_avail
= get_dfree_info(fsp
->conn
,
821 fsp
->fsp_name
->base_name
,
822 &bsize
, &dfree
, &dsize
);
823 /* space_avail is 1k blocks */
824 if (space_avail
== (uint64_t)-1 ||
825 ((uint64_t)space_to_write
/1024 > space_avail
) ) {
830 /* Write out the real space on disk. */
831 return vfs_slow_fallocate(fsp
, pst
->st_ex_size
, space_to_write
);
834 static int cephwrap_ftruncate(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t len
)
841 DEBUG(10, ("[CEPH] ftruncate(%p, %p, %llu\n", handle
, fsp
, llu(len
)));
843 if (lp_strict_allocate(SNUM(fsp
->conn
))) {
844 result
= strict_allocate_ftruncate(handle
, fsp
, len
);
848 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
849 sys_ftruncate if the system supports it. Then I discovered that
850 you can have some filesystems that support ftruncate
851 expansion and some that don't! On Linux fat can't do
852 ftruncate extend but ext2 can. */
854 result
= ceph_ftruncate(handle
->data
, fsp
->fh
->fd
, len
);
858 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
859 extend a file with ftruncate. Provide alternate implementation
861 currpos
= SMB_VFS_LSEEK(fsp
, 0, SEEK_CUR
);
866 /* Do an fstat to see if the file is longer than the requested
867 size in which case the ftruncate above should have
868 succeeded or shorter, in which case seek to len - 1 and
869 write 1 byte of zero */
870 if (SMB_VFS_FSTAT(fsp
, &st
) == -1) {
875 if (S_ISFIFO(st
.st_ex_mode
)) {
881 if (st
.st_ex_size
== len
) {
886 if (st
.st_ex_size
> len
) {
887 /* the sys_ftruncate should have worked */
891 if (SMB_VFS_LSEEK(fsp
, len
-1, SEEK_SET
) != len
-1)
894 if (SMB_VFS_WRITE(fsp
, &c
, 1)!=1)
897 /* Seek to where we were */
898 if (SMB_VFS_LSEEK(fsp
, currpos
, SEEK_SET
) != currpos
)
907 static bool cephwrap_lock(struct vfs_handle_struct
*handle
, files_struct
*fsp
, int op
, off_t offset
, off_t count
, int type
)
909 DEBUG(10, ("[CEPH] lock\n"));
913 static int cephwrap_kernel_flock(struct vfs_handle_struct
*handle
, files_struct
*fsp
,
914 uint32_t share_mode
, uint32_t access_mask
)
916 DEBUG(10, ("[CEPH] kernel_flock\n"));
918 * We must return zero here and pretend all is good.
919 * One day we might have this in CEPH.
924 static bool cephwrap_getlock(struct vfs_handle_struct
*handle
, files_struct
*fsp
, off_t
*poffset
, off_t
*pcount
, int *ptype
, pid_t
*ppid
)
926 DEBUG(10, ("[CEPH] getlock returning false and errno=0\n"));
933 * We cannot let this fall through to the default, because the file might only
934 * be accessible from libceph (which is a user-space client) but the fd might
935 * be for some file the kernel knows about.
937 static int cephwrap_linux_setlease(struct vfs_handle_struct
*handle
, files_struct
*fsp
,
942 DEBUG(10, ("[CEPH] linux_setlease\n"));
947 static int cephwrap_symlink(struct vfs_handle_struct
*handle
, const char *oldpath
, const char *newpath
)
950 DEBUG(10, ("[CEPH] symlink(%p, %s, %s)\n", handle
, oldpath
, newpath
));
951 result
= ceph_symlink(handle
->data
, oldpath
, newpath
);
952 DEBUG(10, ("[CEPH] symlink(...) = %d\n", result
));
956 static int cephwrap_readlink(struct vfs_handle_struct
*handle
, const char *path
, char *buf
, size_t bufsiz
)
959 DEBUG(10, ("[CEPH] readlink(%p, %s, %p, %llu)\n", handle
, path
, buf
, llu(bufsiz
)));
960 result
= ceph_readlink(handle
->data
, path
, buf
, bufsiz
);
961 DEBUG(10, ("[CEPH] readlink(...) = %d\n", result
));
965 static int cephwrap_link(struct vfs_handle_struct
*handle
, const char *oldpath
, const char *newpath
)
968 DEBUG(10, ("[CEPH] link(%p, %s, %s)\n", handle
, oldpath
, newpath
));
969 result
= ceph_link(handle
->data
, oldpath
, newpath
);
970 DEBUG(10, ("[CEPH] link(...) = %d\n", result
));
974 static int cephwrap_mknod(struct vfs_handle_struct
*handle
, const char *pathname
, mode_t mode
, SMB_DEV_T dev
)
977 DEBUG(10, ("[CEPH] mknod(%p, %s)\n", handle
, pathname
));
978 result
= ceph_mknod(handle
->data
, pathname
, mode
, dev
);
979 DEBUG(10, ("[CEPH] mknod(...) = %d\n", result
));
984 * This is a simple version of real-path ... a better version is needed to
985 * ask libceph about symbolic links.
987 static char *cephwrap_realpath(struct vfs_handle_struct
*handle
, const char *path
)
990 size_t len
= strlen(path
);
992 result
= SMB_MALLOC_ARRAY(char, PATH_MAX
+1);
993 if (len
&& (path
[0] == '/')) {
994 int r
= asprintf(&result
, "%s", path
);
995 if (r
< 0) return NULL
;
996 } else if ((len
>= 2) && (path
[0] == '.') && (path
[1] == '/')) {
998 int r
= asprintf(&result
, "%s",
999 handle
->conn
->connectpath
);
1000 if (r
< 0) return NULL
;
1002 int r
= asprintf(&result
, "%s/%s",
1003 handle
->conn
->connectpath
, &path
[2]);
1004 if (r
< 0) return NULL
;
1007 int r
= asprintf(&result
, "%s/%s",
1008 handle
->conn
->connectpath
, path
);
1009 if (r
< 0) return NULL
;
1011 DEBUG(10, ("[CEPH] realpath(%p, %s) = %s\n", handle
, path
, result
));
1015 static int cephwrap_chflags(struct vfs_handle_struct
*handle
, const char *path
,
1022 static int cephwrap_get_real_filename(struct vfs_handle_struct
*handle
,
1025 TALLOC_CTX
*mem_ctx
,
1029 * Don't fall back to get_real_filename so callers can differentiate
1030 * between a full directory scan and an actual case-insensitive stat.
1036 static const char *cephwrap_connectpath(struct vfs_handle_struct
*handle
,
1039 return handle
->conn
->connectpath
;
1042 /****************************************************************
1043 Extended attribute operations.
1044 *****************************************************************/
1046 static ssize_t
cephwrap_getxattr(struct vfs_handle_struct
*handle
,const char *path
, const char *name
, void *value
, size_t size
)
1049 DEBUG(10, ("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle
, path
, name
, value
, llu(size
)));
1050 ret
= ceph_getxattr(handle
->data
, path
, name
, value
, size
);
1051 DEBUG(10, ("[CEPH] getxattr(...) = %d\n", ret
));
1055 return (ssize_t
)ret
;
1059 static ssize_t
cephwrap_fgetxattr(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
, const char *name
, void *value
, size_t size
)
1062 DEBUG(10, ("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle
, fsp
, name
, value
, llu(size
)));
1063 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1064 ret
= ceph_fgetxattr(handle
->data
, fsp
->fh
->fd
, name
, value
, size
);
1066 ret
= ceph_getxattr(handle
->data
, fsp
->fsp_name
->base_name
, name
, value
, size
);
1068 DEBUG(10, ("[CEPH] fgetxattr(...) = %d\n", ret
));
1072 return (ssize_t
)ret
;
1076 static ssize_t
cephwrap_listxattr(struct vfs_handle_struct
*handle
, const char *path
, char *list
, size_t size
)
1079 DEBUG(10, ("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle
, path
, list
, llu(size
)));
1080 ret
= ceph_listxattr(handle
->data
, path
, list
, size
);
1081 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret
));
1085 return (ssize_t
)ret
;
1090 static ssize_t
cephwrap_llistxattr(struct vfs_handle_struct
*handle
, const char *path
, char *list
, size_t size
)
1093 DEBUG(10, ("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle
, path
, list
, llu(size
)));
1094 ret
= ceph_llistxattr(handle
->data
, path
, list
, size
);
1095 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret
));
1099 return (ssize_t
)ret
;
1104 static ssize_t
cephwrap_flistxattr(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
, char *list
, size_t size
)
1107 DEBUG(10, ("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle
, fsp
, list
, llu(size
)));
1108 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1109 ret
= ceph_flistxattr(handle
->data
, fsp
->fh
->fd
, list
, size
);
1111 ret
= ceph_listxattr(handle
->data
, fsp
->fsp_name
->base_name
, list
, size
);
1113 DEBUG(10, ("[CEPH] flistxattr(...) = %d\n", ret
));
1117 return (ssize_t
)ret
;
1121 static int cephwrap_removexattr(struct vfs_handle_struct
*handle
, const char *path
, const char *name
)
1124 DEBUG(10, ("[CEPH] removexattr(%p, %s, %s)\n", handle
, path
, name
));
1125 ret
= ceph_removexattr(handle
->data
, path
, name
);
1126 DEBUG(10, ("[CEPH] removexattr(...) = %d\n", ret
));
1130 static int cephwrap_fremovexattr(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
, const char *name
)
1133 DEBUG(10, ("[CEPH] fremovexattr(%p, %p, %s)\n", handle
, fsp
, name
));
1134 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1135 ret
= ceph_fremovexattr(handle
->data
, fsp
->fh
->fd
, name
);
1137 ret
= ceph_removexattr(handle
->data
, fsp
->fsp_name
->base_name
, name
);
1139 DEBUG(10, ("[CEPH] fremovexattr(...) = %d\n", ret
));
1143 static int cephwrap_setxattr(struct vfs_handle_struct
*handle
, const char *path
, const char *name
, const void *value
, size_t size
, int flags
)
1146 DEBUG(10, ("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle
, path
, name
, value
, llu(size
), flags
));
1147 ret
= ceph_setxattr(handle
->data
, path
, name
, value
, size
, flags
);
1148 DEBUG(10, ("[CEPH] setxattr(...) = %d\n", ret
));
1152 static int cephwrap_fsetxattr(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
, const char *name
, const void *value
, size_t size
, int flags
)
1155 DEBUG(10, ("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle
, fsp
, name
, value
, llu(size
), flags
));
1156 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1157 ret
= ceph_fsetxattr(handle
->data
, fsp
->fh
->fd
,
1158 name
, value
, size
, flags
);
1160 ret
= ceph_setxattr(handle
->data
, fsp
->fsp_name
->base_name
, name
, value
, size
, flags
);
1162 DEBUG(10, ("[CEPH] fsetxattr(...) = %d\n", ret
));
1166 static bool cephwrap_aio_force(struct vfs_handle_struct
*handle
, struct files_struct
*fsp
)
1170 * We do not support AIO yet.
1173 DEBUG(10, ("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle
, fsp
));
1178 static bool cephwrap_is_offline(struct vfs_handle_struct
*handle
,
1179 const struct smb_filename
*fname
,
1180 SMB_STRUCT_STAT
*sbuf
)
1185 static int cephwrap_set_offline(struct vfs_handle_struct
*handle
,
1186 const struct smb_filename
*fname
)
1192 static SMB_ACL_T
cephwrap_sys_acl_get_file(struct vfs_handle_struct
*handle
,
1194 SMB_ACL_TYPE_T type
,
1195 TALLOC_CTX
*mem_ctx
)
1201 static SMB_ACL_T
cephwrap_sys_acl_get_fd(struct vfs_handle_struct
*handle
,
1202 struct files_struct
*fsp
,
1203 TALLOC_CTX
*mem_ctx
)
1209 static int cephwrap_sys_acl_set_file(struct vfs_handle_struct
*handle
,
1211 SMB_ACL_TYPE_T acltype
,
1218 static int cephwrap_sys_acl_set_fd(struct vfs_handle_struct
*handle
,
1219 struct files_struct
*fsp
,
1226 static int cephwrap_sys_acl_delete_def_file(struct vfs_handle_struct
*handle
,
1233 static struct vfs_fn_pointers ceph_fns
= {
1234 /* Disk operations */
1236 .connect_fn
= cephwrap_connect
,
1237 .disconnect_fn
= cephwrap_disconnect
,
1238 .disk_free_fn
= cephwrap_disk_free
,
1239 .get_quota_fn
= cephwrap_get_quota
,
1240 .set_quota_fn
= cephwrap_set_quota
,
1241 .statvfs_fn
= cephwrap_statvfs
,
1243 /* Directory operations */
1245 .opendir_fn
= cephwrap_opendir
,
1246 .fdopendir_fn
= cephwrap_fdopendir
,
1247 .readdir_fn
= cephwrap_readdir
,
1248 .seekdir_fn
= cephwrap_seekdir
,
1249 .telldir_fn
= cephwrap_telldir
,
1250 .rewind_dir_fn
= cephwrap_rewinddir
,
1251 .mkdir_fn
= cephwrap_mkdir
,
1252 .rmdir_fn
= cephwrap_rmdir
,
1253 .closedir_fn
= cephwrap_closedir
,
1255 /* File operations */
1257 .open_fn
= cephwrap_open
,
1258 .close_fn
= cephwrap_close
,
1259 .read_fn
= cephwrap_read
,
1260 .pread_fn
= cephwrap_pread
,
1261 .write_fn
= cephwrap_write
,
1262 .pwrite_fn
= cephwrap_pwrite
,
1263 .lseek_fn
= cephwrap_lseek
,
1264 .sendfile_fn
= cephwrap_sendfile
,
1265 .recvfile_fn
= cephwrap_recvfile
,
1266 .rename_fn
= cephwrap_rename
,
1267 .fsync_fn
= cephwrap_fsync
,
1268 .stat_fn
= cephwrap_stat
,
1269 .fstat_fn
= cephwrap_fstat
,
1270 .lstat_fn
= cephwrap_lstat
,
1271 .unlink_fn
= cephwrap_unlink
,
1272 .chmod_fn
= cephwrap_chmod
,
1273 .fchmod_fn
= cephwrap_fchmod
,
1274 .chown_fn
= cephwrap_chown
,
1275 .fchown_fn
= cephwrap_fchown
,
1276 .lchown_fn
= cephwrap_lchown
,
1277 .chdir_fn
= cephwrap_chdir
,
1278 .getwd_fn
= cephwrap_getwd
,
1279 .ntimes_fn
= cephwrap_ntimes
,
1280 .ftruncate_fn
= cephwrap_ftruncate
,
1281 .lock_fn
= cephwrap_lock
,
1282 .kernel_flock_fn
= cephwrap_kernel_flock
,
1283 .linux_setlease_fn
= cephwrap_linux_setlease
,
1284 .getlock_fn
= cephwrap_getlock
,
1285 .symlink_fn
= cephwrap_symlink
,
1286 .readlink_fn
= cephwrap_readlink
,
1287 .link_fn
= cephwrap_link
,
1288 .mknod_fn
= cephwrap_mknod
,
1289 .realpath_fn
= cephwrap_realpath
,
1290 .chflags_fn
= cephwrap_chflags
,
1291 .get_real_filename_fn
= cephwrap_get_real_filename
,
1292 .connectpath_fn
= cephwrap_connectpath
,
1294 /* EA operations. */
1295 .getxattr_fn
= cephwrap_getxattr
,
1296 .fgetxattr_fn
= cephwrap_fgetxattr
,
1297 .listxattr_fn
= cephwrap_listxattr
,
1298 .flistxattr_fn
= cephwrap_flistxattr
,
1299 .removexattr_fn
= cephwrap_removexattr
,
1300 .fremovexattr_fn
= cephwrap_fremovexattr
,
1301 .setxattr_fn
= cephwrap_setxattr
,
1302 .fsetxattr_fn
= cephwrap_fsetxattr
,
1304 /* Posix ACL Operations */
1305 .sys_acl_get_file_fn
= cephwrap_sys_acl_get_file
,
1306 .sys_acl_get_fd_fn
= cephwrap_sys_acl_get_fd
,
1307 .sys_acl_set_file_fn
= cephwrap_sys_acl_set_file
,
1308 .sys_acl_set_fd_fn
= cephwrap_sys_acl_set_fd
,
1309 .sys_acl_delete_def_file_fn
= cephwrap_sys_acl_delete_def_file
,
1311 /* aio operations */
1312 .aio_force_fn
= cephwrap_aio_force
,
1314 /* offline operations */
1315 .is_offline_fn
= cephwrap_is_offline
,
1316 .set_offline_fn
= cephwrap_set_offline
1319 NTSTATUS
vfs_ceph_init(void);
1320 NTSTATUS
vfs_ceph_init(void)
1322 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,