vfs_btrfs: add snapshot create/delete calls
[Samba.git] / source3 / modules / vfs_ceph.c
blobb3e334effcbdac199c8f694d1c60d5e70e5f966d
1 /*
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
28 * Ceph:
30 * vfs objects = ceph [any others you need go here]
33 #include "includes.h"
34 #include "smbd/smbd.h"
35 #include <dirent.h>
36 #include <sys/statvfs.h>
37 #include "cephfs/libcephfs.h"
38 #include "smbprofile.h"
40 #undef DBGC_CLASS
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) \
53 errno = 0; \
54 if (_res < 0) { \
55 errno = -_res; \
56 return -1; \
57 } \
58 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
63 * this differently.
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
67 * connected
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
76 this possibility. */
78 static int cephwrap_connect(struct vfs_handle_struct *handle, const char *service, const char *user)
80 int ret;
81 char buf[256];
83 const char * conf_file;
85 if (cmount) {
86 handle->data = cmount; /* We have been here before */
87 cmount_cnt++;
88 return 0;
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);
95 if (ret)
96 goto err_out;
98 if (conf_file) {
99 /* Override the config file */
100 DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file\n" ));
101 ret = ceph_conf_read_file(cmount, conf_file);
102 } else {
104 DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file with %s\n", conf_file));
105 ret = ceph_conf_read_file(cmount, NULL);
108 if (ret)
109 goto err_out;
111 DEBUG(2, ( "[CEPH] calling: ceph_conf_get\n" ));
112 ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
113 if (ret < 0)
114 goto err_out;
116 DEBUG(2, ("[CEPH] calling: ceph_mount\n"));
117 ret = ceph_mount(cmount, NULL);
118 if (ret < 0)
119 goto err_out;
123 * encode mount context/state into our vfs/connection holding structure
124 * cmount is a ceph_mount_t*
126 handle->data = cmount;
127 cmount_cnt++;
129 return 0;
131 err_out:
133 * Handle the error correctly. Ceph returns -errno.
135 DEBUG(2, ("[CEPH] Error return: %s\n", strerror(-ret)));
136 WRAP_RETURN(ret);
139 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
141 if (!cmount) {
142 DEBUG(0, ("[CEPH] Error, ceph not mounted\n"));
143 return;
146 /* Should we unmount/shutdown? Only if the last disconnect? */
147 if (--cmount_cnt) {
148 DEBUG(10, ("[CEPH] Not shuting down CEPH because still more connections\n"));
149 return;
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,
160 const char *path, uint64_t *bsize,
161 uint64_t *dfree, uint64_t *dsize)
163 struct statvfs statvfs_buf;
164 int ret;
166 if (!(ret = ceph_statfs(handle->data, path, &statvfs_buf))) {
168 * Provide all the correct values.
170 *bsize = statvfs_buf.f_bsize;
171 *dfree = statvfs_buf.f_bavail;
172 *dsize = statvfs_buf.f_blocks;
173 disk_norm(bsize, dfree, dsize);
174 DEBUG(10, ("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
175 llu(*bsize), llu(*dfree), llu(*dsize)));
176 return *dfree;
177 } else {
178 DEBUG(10, ("[CEPH] ceph_statfs returned %d\n", ret));
179 WRAP_RETURN(ret);
183 static int cephwrap_get_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
185 /* libceph: Ceph does not implement this */
186 #if 0
187 /* was ifdef HAVE_SYS_QUOTAS */
188 int ret;
190 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
192 if (ret) {
193 errno = -ret;
194 ret = -1;
197 return ret;
198 #else
199 errno = ENOSYS;
200 return -1;
201 #endif
204 static int cephwrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
206 /* libceph: Ceph does not implement this */
207 #if 0
208 /* was ifdef HAVE_SYS_QUOTAS */
209 int ret;
211 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
212 if (ret) {
213 errno = -ret;
214 ret = -1;
217 return ret;
218 #else
219 WRAP_RETURN(-ENOSYS);
220 #endif
223 static int cephwrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
225 struct statvfs statvfs_buf;
226 int ret;
228 ret = ceph_statfs(handle->data, path, &statvfs_buf);
229 if (ret < 0) {
230 WRAP_RETURN(ret);
231 } else {
232 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
233 statbuf->BlockSize = statvfs_buf.f_bsize;
234 statbuf->TotalBlocks = statvfs_buf.f_blocks;
235 statbuf->BlocksAvail = statvfs_buf.f_bfree;
236 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
237 statbuf->TotalFileNodes = statvfs_buf.f_files;
238 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
239 statbuf->FsIdentifier = statvfs_buf.f_fsid;
240 DEBUG(10, ("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
241 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
242 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail));
244 return ret;
247 /* Directory operations */
249 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
251 int ret = 0;
252 struct ceph_dir_result *result;
253 DEBUG(10, ("[CEPH] opendir(%p, %s)\n", handle, fname));
255 /* Returns NULL if it does not exist or there are problems ? */
256 ret = ceph_opendir(handle->data, fname, &result);
257 if (ret < 0) {
258 result = NULL;
259 errno = -ret; /* We return result which is NULL in this case */
262 DEBUG(10, ("[CEPH] opendir(...) = %d\n", ret));
263 return (DIR *) result;
266 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
267 struct files_struct *fsp,
268 const char *mask,
269 uint32 attributes)
271 int ret = 0;
272 struct ceph_dir_result *result;
273 DEBUG(10, ("[CEPH] fdopendir(%p, %p)\n", handle, fsp));
275 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
276 if (ret < 0) {
277 result = NULL;
278 errno = -ret; /* We return result which is NULL in this case */
281 DEBUG(10, ("[CEPH] fdopendir(...) = %d\n", ret));
282 return (DIR *) result;
285 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
286 DIR *dirp,
287 SMB_STRUCT_STAT *sbuf)
289 struct dirent *result;
291 DEBUG(10, ("[CEPH] readdir(%p, %p)\n", handle, dirp));
292 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
293 DEBUG(10, ("[CEPH] readdir(...) = %p\n", result));
295 /* Default Posix readdir() does not give us stat info.
296 * Set to invalid to indicate we didn't return this info. */
297 if (sbuf)
298 SET_STAT_INVALID(*sbuf);
299 return result;
302 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
304 DEBUG(10, ("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset));
305 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
308 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
310 long ret;
311 DEBUG(10, ("[CEPH] telldir(%p, %p)\n", handle, dirp));
312 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
313 DEBUG(10, ("[CEPH] telldir(...) = %ld\n", ret));
314 WRAP_RETURN(ret);
317 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
319 DEBUG(10, ("[CEPH] rewinddir(%p, %p)\n", handle, dirp));
320 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
323 static int cephwrap_mkdir(struct vfs_handle_struct *handle, const char *path, mode_t mode)
325 int result;
326 bool has_dacl = False;
327 char *parent = NULL;
329 DEBUG(10, ("[CEPH] mkdir(%p, %s)\n", handle, path));
331 if (lp_inherit_acls(SNUM(handle->conn))
332 && parent_dirname(talloc_tos(), path, &parent, NULL)
333 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
334 mode = 0777;
336 TALLOC_FREE(parent);
338 result = ceph_mkdir(handle->data, path, mode);
341 * Note. This order is important
343 if (result) {
344 WRAP_RETURN(result);
345 } else if (result == 0 && !has_dacl) {
347 * We need to do this as the default behavior of POSIX ACLs
348 * is to set the mask to be the requested group permission
349 * bits, not the group permission bits to be the requested
350 * group permission bits. This is not what we want, as it will
351 * mess up any inherited ACL bits that were set. JRA.
353 int saved_errno = errno; /* We may get ENOSYS */
354 if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
355 errno = saved_errno;
358 return result;
361 static int cephwrap_rmdir(struct vfs_handle_struct *handle, const char *path)
363 int result;
365 DEBUG(10, ("[CEPH] rmdir(%p, %s)\n", handle, path));
366 result = ceph_rmdir(handle->data, path);
367 DEBUG(10, ("[CEPH] rmdir(...) = %d\n", result));
368 WRAP_RETURN(result);
371 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
373 int result;
375 DEBUG(10, ("[CEPH] closedir(%p, %p)\n", handle, dirp));
376 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
377 DEBUG(10, ("[CEPH] closedir(...) = %d\n", result));
378 WRAP_RETURN(result);
381 /* File operations */
383 static int cephwrap_open(struct vfs_handle_struct *handle,
384 struct smb_filename *smb_fname,
385 files_struct *fsp, int flags, mode_t mode)
387 int result = -ENOENT;
388 DEBUG(10, ("[CEPH] open(%p, %s, %p, %d, %d)\n", handle, smb_fname_str_dbg(smb_fname), fsp, flags, mode));
390 if (smb_fname->stream_name) {
391 goto out;
394 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
395 out:
396 DEBUG(10, ("[CEPH] open(...) = %d\n", result));
397 WRAP_RETURN(result);
400 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
402 int result;
404 DEBUG(10, ("[CEPH] close(%p, %p)\n", handle, fsp));
405 result = ceph_close(handle->data, fsp->fh->fd);
406 DEBUG(10, ("[CEPH] close(...) = %d\n", result));
408 WRAP_RETURN(result);
411 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
413 ssize_t result;
415 DEBUG(10, ("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
417 /* Using -1 for the offset means read/write rather than pread/pwrite */
418 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
419 DEBUG(10, ("[CEPH] read(...) = %llu\n", llu(result)));
420 WRAP_RETURN(result);
423 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
424 size_t n, off_t offset)
426 ssize_t result;
428 DEBUG(10, ("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
430 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
431 DEBUG(10, ("[CEPH] pread(...) = %llu\n", llu(result)));
432 WRAP_RETURN(result);
436 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
438 ssize_t result;
440 DEBUG(10, ("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
442 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
444 DEBUG(10, ("[CEPH] write(...) = %llu\n", llu(result)));
445 if (result < 0) {
446 WRAP_RETURN(result);
448 fsp->fh->pos += result;
449 return result;
452 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
453 size_t n, off_t offset)
455 ssize_t result;
457 DEBUG(10, ("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
458 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
459 DEBUG(10, ("[CEPH] pwrite(...) = %llu\n", llu(result)));
460 WRAP_RETURN(result);
463 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
465 off_t result = 0;
467 DEBUG(10, ("[CEPH] cephwrap_lseek\n"));
468 /* Cope with 'stat' file opens. */
469 if (fsp->fh->fd != -1) {
470 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
472 WRAP_RETURN(result);
475 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
476 off_t offset, size_t n)
479 * We cannot support sendfile because libceph is in user space.
481 DEBUG(10, ("[CEPH] cephwrap_sendfile\n"));
482 errno = ENOTSUP;
483 return -1;
486 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
487 int fromfd,
488 files_struct *tofsp,
489 off_t offset,
490 size_t n)
493 * We cannot support recvfile because libceph is in user space.
495 DEBUG(10, ("[CEPH] cephwrap_recvfile\n"));
496 errno=ENOTSUP;
497 return -1;
500 static int cephwrap_rename(struct vfs_handle_struct *handle,
501 const struct smb_filename *smb_fname_src,
502 const struct smb_filename *smb_fname_dst)
504 int result = -1;
505 DEBUG(10, ("[CEPH] cephwrap_rename\n"));
506 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
507 errno = ENOENT;
508 return result;
511 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
512 WRAP_RETURN(result);
515 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
517 int result;
518 DEBUG(10, ("[CEPH] cephwrap_fsync\n"));
519 result = ceph_fsync(handle->data, fsp->fh->fd, false);
520 WRAP_RETURN(result);
523 static int cephwrap_stat(struct vfs_handle_struct *handle,
524 struct smb_filename *smb_fname)
526 int result = -1;
527 struct stat stbuf;
529 DEBUG(10, ("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
531 if (smb_fname->stream_name) {
532 errno = ENOENT;
533 return result;
536 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
537 DEBUG(10, ("[CEPH] stat(...) = %d\n", result));
538 if (result < 0) {
539 WRAP_RETURN(result);
540 } else {
541 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
542 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
543 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
544 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
545 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
546 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
548 init_stat_ex_from_stat(
549 &smb_fname->st, &stbuf,
550 lp_fake_directory_create_times(SNUM(handle->conn)));
551 DEBUG(10, ("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode));
552 return result;
555 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
557 int result = -1;
558 struct stat stbuf;
560 DEBUG(10, ("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd));
561 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
562 DEBUG(10, ("[CEPH] fstat(...) = %d\n", result));
563 if (result < 0) {
564 WRAP_RETURN(result);
565 } else {
566 DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
567 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
568 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
569 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
570 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
571 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
574 init_stat_ex_from_stat(
575 sbuf, &stbuf,
576 lp_fake_directory_create_times(SNUM(handle->conn)));
577 DEBUG(10, ("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode));
578 return result;
581 static int cephwrap_lstat(struct vfs_handle_struct *handle,
582 struct smb_filename *smb_fname)
584 int result = -1;
585 struct stat stbuf;
587 DEBUG(10, ("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
589 if (smb_fname->stream_name) {
590 errno = ENOENT;
591 return result;
594 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
595 DEBUG(10, ("[CEPH] lstat(...) = %d\n", result));
596 if (result < 0) {
597 WRAP_RETURN(result);
599 init_stat_ex_from_stat(
600 &smb_fname->st, &stbuf,
601 lp_fake_directory_create_times(SNUM(handle->conn)));
602 return result;
605 static int cephwrap_unlink(struct vfs_handle_struct *handle,
606 const struct smb_filename *smb_fname)
608 int result = -1;
610 DEBUG(10, ("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
611 if (smb_fname->stream_name) {
612 errno = ENOENT;
613 return result;
615 result = ceph_unlink(handle->data, smb_fname->base_name);
616 DEBUG(10, ("[CEPH] unlink(...) = %d\n", result));
617 WRAP_RETURN(result);
620 static int cephwrap_chmod(struct vfs_handle_struct *handle, const char *path, mode_t mode)
622 int result;
624 DEBUG(10, ("[CEPH] chmod(%p, %s, %d)\n", handle, path, mode));
627 * We need to do this due to the fact that the default POSIX ACL
628 * chmod modifies the ACL *mask* for the group owner, not the
629 * group owner bits directly. JRA.
634 int saved_errno = errno; /* We might get ENOSYS */
635 if ((result = SMB_VFS_CHMOD_ACL(handle->conn, path, mode)) == 0) {
636 return result;
638 /* Error - return the old errno. */
639 errno = saved_errno;
642 result = ceph_chmod(handle->data, path, mode);
643 DEBUG(10, ("[CEPH] chmod(...) = %d\n", result));
644 WRAP_RETURN(result);
647 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
649 int result;
651 DEBUG(10, ("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode));
654 * We need to do this due to the fact that the default POSIX ACL
655 * chmod modifies the ACL *mask* for the group owner, not the
656 * group owner bits directly. JRA.
660 int saved_errno = errno; /* We might get ENOSYS */
661 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
662 return result;
664 /* Error - return the old errno. */
665 errno = saved_errno;
668 #if defined(HAVE_FCHMOD)
669 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
670 DEBUG(10, ("[CEPH] fchmod(...) = %d\n", result));
671 WRAP_RETURN(result);
672 #else
673 errno = ENOSYS;
674 #endif
675 return -1;
678 static int cephwrap_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
680 int result;
681 DEBUG(10, ("[CEPH] chown(%p, %s, %d, %d)\n", handle, path, uid, gid));
682 result = ceph_chown(handle->data, path, uid, gid);
683 DEBUG(10, ("[CEPH] chown(...) = %d\n", result));
684 WRAP_RETURN(result);
687 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
689 int result;
690 #ifdef HAVE_FCHOWN
692 DEBUG(10, ("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid));
693 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
694 DEBUG(10, ("[CEPH] fchown(...) = %d\n", result));
695 WRAP_RETURN(result);
696 #else
697 errno = ENOSYS;
698 result = -1;
699 #endif
700 return result;
703 static int cephwrap_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
705 int result;
707 DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", handle, path, uid, gid));
708 result = ceph_lchown(handle->data, path, uid, gid);
709 DEBUG(10, ("[CEPH] lchown(...) = %d\n", result));
710 WRAP_RETURN(result);
713 static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path)
715 int result = -1;
716 DEBUG(10, ("[CEPH] chdir(%p, %s)\n", handle, path));
718 * If the path is just / use chdir because Ceph is below / and
719 * cannot deal with changing directory above its mount point
721 if (path && !strcmp(path, "/"))
722 return chdir(path);
724 result = ceph_chdir(handle->data, path);
725 DEBUG(10, ("[CEPH] chdir(...) = %d\n", result));
726 WRAP_RETURN(result);
729 static char *cephwrap_getwd(struct vfs_handle_struct *handle)
731 const char *cwd = ceph_getcwd(handle->data);
732 DEBUG(10, ("[CEPH] getwd(%p) = %s\n", handle, cwd));
733 return SMB_STRDUP(cwd);
736 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
737 const struct smb_filename *smb_fname,
738 struct smb_file_time *ft)
740 struct utimbuf buf;
741 int result;
743 if (null_timespec(ft->atime)) {
744 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
745 } else {
746 buf.actime = ft->atime.tv_sec;
748 if (null_timespec(ft->mtime)) {
749 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
750 } else {
751 buf.modtime = ft->mtime.tv_sec;
753 if (!null_timespec(ft->create_time)) {
754 set_create_timespec_ea(handle->conn, smb_fname,
755 ft->create_time);
757 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
758 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
759 return 0;
762 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
763 DEBUG(10, ("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
764 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
765 ft->create_time.tv_sec, result));
766 return result;
769 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
771 off_t space_to_write;
772 uint64_t space_avail;
773 uint64_t bsize,dfree,dsize;
774 int ret;
775 NTSTATUS status;
776 SMB_STRUCT_STAT *pst;
778 status = vfs_stat_fsp(fsp);
779 if (!NT_STATUS_IS_OK(status)) {
780 return -1;
782 pst = &fsp->fsp_name->st;
784 #ifdef S_ISFIFO
785 if (S_ISFIFO(pst->st_ex_mode))
786 return 0;
787 #endif
789 if (pst->st_ex_size == len)
790 return 0;
792 /* Shrink - just ftruncate. */
793 if (pst->st_ex_size > len)
794 return ftruncate(fsp->fh->fd, len);
796 space_to_write = len - pst->st_ex_size;
798 /* for allocation try fallocate first. This can fail on some
799 platforms e.g. when the filesystem doesn't support it and no
800 emulation is being done by the libc (like on AIX with JFS1). In that
801 case we do our own emulation. fallocate implementations can
802 return ENOTSUP or EINVAL in cases like that. */
803 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
804 if (ret == -1 && errno == ENOSPC) {
805 return -1;
807 if (ret == 0) {
808 return 0;
810 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
811 "error %d. Falling back to slow manual allocation\n", errno));
813 /* available disk space is enough or not? */
814 space_avail = get_dfree_info(fsp->conn,
815 fsp->fsp_name->base_name,
816 &bsize, &dfree, &dsize);
817 /* space_avail is 1k blocks */
818 if (space_avail == (uint64_t)-1 ||
819 ((uint64_t)space_to_write/1024 > space_avail) ) {
820 errno = ENOSPC;
821 return -1;
824 /* Write out the real space on disk. */
825 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
828 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
830 int result = -1;
831 SMB_STRUCT_STAT st;
832 char c = 0;
833 off_t currpos;
835 DEBUG(10, ("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len)));
837 if (lp_strict_allocate(SNUM(fsp->conn))) {
838 result = strict_allocate_ftruncate(handle, fsp, len);
839 return result;
842 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
843 sys_ftruncate if the system supports it. Then I discovered that
844 you can have some filesystems that support ftruncate
845 expansion and some that don't! On Linux fat can't do
846 ftruncate extend but ext2 can. */
848 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
849 if (result == 0)
850 goto done;
852 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
853 extend a file with ftruncate. Provide alternate implementation
854 for this */
855 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
856 if (currpos == -1) {
857 goto done;
860 /* Do an fstat to see if the file is longer than the requested
861 size in which case the ftruncate above should have
862 succeeded or shorter, in which case seek to len - 1 and
863 write 1 byte of zero */
864 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
865 goto done;
868 #ifdef S_ISFIFO
869 if (S_ISFIFO(st.st_ex_mode)) {
870 result = 0;
871 goto done;
873 #endif
875 if (st.st_ex_size == len) {
876 result = 0;
877 goto done;
880 if (st.st_ex_size > len) {
881 /* the sys_ftruncate should have worked */
882 goto done;
885 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
886 goto done;
888 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
889 goto done;
891 /* Seek to where we were */
892 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
893 goto done;
894 result = 0;
896 done:
898 return result;
901 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
903 DEBUG(10, ("[CEPH] lock\n"));
904 return true;
907 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
908 uint32 share_mode, uint32 access_mask)
910 DEBUG(10, ("[CEPH] kernel_flock\n"));
912 * We must return zero here and pretend all is good.
913 * One day we might have this in CEPH.
915 return 0;
918 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
920 DEBUG(10, ("[CEPH] getlock returning false and errno=0\n"));
922 errno = 0;
923 return false;
927 * We cannot let this fall through to the default, because the file might only
928 * be accessible from libceph (which is a user-space client) but the fd might
929 * be for some file the kernel knows about.
931 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
932 int leasetype)
934 int result = -1;
936 DEBUG(10, ("[CEPH] linux_setlease\n"));
937 errno = ENOSYS;
938 return result;
941 static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
943 int result = -1;
944 DEBUG(10, ("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath));
945 result = ceph_symlink(handle->data, oldpath, newpath);
946 DEBUG(10, ("[CEPH] symlink(...) = %d\n", result));
947 WRAP_RETURN(result);
950 static int cephwrap_readlink(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
952 int result = -1;
953 DEBUG(10, ("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz)));
954 result = ceph_readlink(handle->data, path, buf, bufsiz);
955 DEBUG(10, ("[CEPH] readlink(...) = %d\n", result));
956 WRAP_RETURN(result);
959 static int cephwrap_link(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
961 int result = -1;
962 DEBUG(10, ("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath));
963 result = ceph_link(handle->data, oldpath, newpath);
964 DEBUG(10, ("[CEPH] link(...) = %d\n", result));
965 WRAP_RETURN(result);
968 static int cephwrap_mknod(struct vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
970 int result = -1;
971 DEBUG(10, ("[CEPH] mknod(%p, %s)\n", handle, pathname));
972 result = ceph_mknod(handle->data, pathname, mode, dev);
973 DEBUG(10, ("[CEPH] mknod(...) = %d\n", result));
974 WRAP_RETURN(result);
978 * This is a simple version of real-path ... a better version is needed to
979 * ask libceph about symbolic links.
981 static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *path)
983 char *result;
984 size_t len = strlen(path);
986 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
987 if (len && (path[0] == '/')) {
988 int r = asprintf(&result, "%s", path);
989 if (r < 0) return NULL;
990 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
991 if (len == 2) {
992 int r = asprintf(&result, "%s",
993 handle->conn->connectpath);
994 if (r < 0) return NULL;
995 } else {
996 int r = asprintf(&result, "%s/%s",
997 handle->conn->connectpath, &path[2]);
998 if (r < 0) return NULL;
1000 } else {
1001 int r = asprintf(&result, "%s/%s",
1002 handle->conn->connectpath, path);
1003 if (r < 0) return NULL;
1005 DEBUG(10, ("[CEPH] realpath(%p, %s) = %s\n", handle, path, result));
1006 return result;
1009 static NTSTATUS cephwrap_notify_watch(struct vfs_handle_struct *vfs_handle,
1010 struct sys_notify_context *ctx,
1011 const char *path,
1012 uint32_t *filter,
1013 uint32_t *subdir_filter,
1014 void (*callback)(struct sys_notify_context *ctx,
1015 void *private_data,
1016 struct notify_event *ev),
1017 void *private_data,
1018 void *handle_p)
1021 * We cannot call inotify on files the kernel does not know about
1023 return NT_STATUS_OK;
1026 static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
1027 unsigned int flags)
1029 errno = ENOSYS;
1030 return -1;
1033 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1034 const char *path,
1035 const char *name,
1036 TALLOC_CTX *mem_ctx,
1037 char **found_name)
1040 * Don't fall back to get_real_filename so callers can differentiate
1041 * between a full directory scan and an actual case-insensitive stat.
1043 errno = EOPNOTSUPP;
1044 return -1;
1047 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1048 const char *fname)
1050 return handle->conn->connectpath;
1053 /****************************************************************
1054 Extended attribute operations.
1055 *****************************************************************/
1057 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
1059 int ret;
1060 DEBUG(10, ("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle, path, name, value, llu(size)));
1061 ret = ceph_getxattr(handle->data, path, name, value, size);
1062 DEBUG(10, ("[CEPH] getxattr(...) = %d\n", ret));
1063 if (ret < 0) {
1064 WRAP_RETURN(ret);
1065 } else {
1066 return (ssize_t)ret;
1070 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1072 int ret;
1073 DEBUG(10, ("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size)));
1074 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1075 DEBUG(10, ("[CEPH] fgetxattr(...) = %d\n", ret));
1076 if (ret < 0) {
1077 WRAP_RETURN(ret);
1078 } else {
1079 return (ssize_t)ret;
1083 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1085 int ret;
1086 DEBUG(10, ("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1087 ret = ceph_listxattr(handle->data, path, list, size);
1088 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1089 if (ret < 0) {
1090 WRAP_RETURN(ret);
1091 } else {
1092 return (ssize_t)ret;
1096 #if 0
1097 static ssize_t cephwrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1099 int ret;
1100 DEBUG(10, ("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1101 ret = ceph_llistxattr(handle->data, path, list, size);
1102 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1103 if (ret < 0) {
1104 WRAP_RETURN(ret);
1105 } else {
1106 return (ssize_t)ret;
1109 #endif
1111 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1113 int ret;
1114 DEBUG(10, ("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size)));
1115 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1116 DEBUG(10, ("[CEPH] flistxattr(...) = %d\n", ret));
1117 if (ret < 0) {
1118 WRAP_RETURN(ret);
1119 } else {
1120 return (ssize_t)ret;
1124 static int cephwrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
1126 int ret;
1127 DEBUG(10, ("[CEPH] removexattr(%p, %s, %s)\n", handle, path, name));
1128 ret = ceph_removexattr(handle->data, path, name);
1129 DEBUG(10, ("[CEPH] removexattr(...) = %d\n", ret));
1130 WRAP_RETURN(ret);
1133 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1135 int ret;
1136 DEBUG(10, ("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name));
1137 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1138 DEBUG(10, ("[CEPH] fremovexattr(...) = %d\n", ret));
1139 WRAP_RETURN(ret);
1142 static int cephwrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
1144 int ret;
1145 DEBUG(10, ("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle, path, name, value, llu(size), flags));
1146 ret = ceph_setxattr(handle->data, path, name, value, size, flags);
1147 DEBUG(10, ("[CEPH] setxattr(...) = %d\n", ret));
1148 WRAP_RETURN(ret);
1151 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1153 int ret;
1154 DEBUG(10, ("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags));
1155 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1156 DEBUG(10, ("[CEPH] fsetxattr(...) = %d\n", ret));
1157 WRAP_RETURN(ret);
1160 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1164 * We do not support AIO yet.
1167 DEBUG(10, ("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp));
1168 errno = ENOTSUP;
1169 return false;
1172 static bool cephwrap_is_offline(struct vfs_handle_struct *handle,
1173 const struct smb_filename *fname,
1174 SMB_STRUCT_STAT *sbuf)
1176 return false;
1179 static int cephwrap_set_offline(struct vfs_handle_struct *handle,
1180 const struct smb_filename *fname)
1182 errno = ENOTSUP;
1183 return -1;
1186 static struct vfs_fn_pointers ceph_fns = {
1187 /* Disk operations */
1189 .connect_fn = cephwrap_connect,
1190 .disconnect_fn = cephwrap_disconnect,
1191 .disk_free_fn = cephwrap_disk_free,
1192 .get_quota_fn = cephwrap_get_quota,
1193 .set_quota_fn = cephwrap_set_quota,
1194 .statvfs_fn = cephwrap_statvfs,
1196 /* Directory operations */
1198 .opendir_fn = cephwrap_opendir,
1199 .fdopendir_fn = cephwrap_fdopendir,
1200 .readdir_fn = cephwrap_readdir,
1201 .seekdir_fn = cephwrap_seekdir,
1202 .telldir_fn = cephwrap_telldir,
1203 .rewind_dir_fn = cephwrap_rewinddir,
1204 .mkdir_fn = cephwrap_mkdir,
1205 .rmdir_fn = cephwrap_rmdir,
1206 .closedir_fn = cephwrap_closedir,
1208 /* File operations */
1210 .open_fn = cephwrap_open,
1211 .close_fn = cephwrap_close,
1212 .read_fn = cephwrap_read,
1213 .pread_fn = cephwrap_pread,
1214 .write_fn = cephwrap_write,
1215 .pwrite_fn = cephwrap_pwrite,
1216 .lseek_fn = cephwrap_lseek,
1217 .sendfile_fn = cephwrap_sendfile,
1218 .recvfile_fn = cephwrap_recvfile,
1219 .rename_fn = cephwrap_rename,
1220 .fsync_fn = cephwrap_fsync,
1221 .stat_fn = cephwrap_stat,
1222 .fstat_fn = cephwrap_fstat,
1223 .lstat_fn = cephwrap_lstat,
1224 .unlink_fn = cephwrap_unlink,
1225 .chmod_fn = cephwrap_chmod,
1226 .fchmod_fn = cephwrap_fchmod,
1227 .chown_fn = cephwrap_chown,
1228 .fchown_fn = cephwrap_fchown,
1229 .lchown_fn = cephwrap_lchown,
1230 .chdir_fn = cephwrap_chdir,
1231 .getwd_fn = cephwrap_getwd,
1232 .ntimes_fn = cephwrap_ntimes,
1233 .ftruncate_fn = cephwrap_ftruncate,
1234 .lock_fn = cephwrap_lock,
1235 .kernel_flock_fn = cephwrap_kernel_flock,
1236 .linux_setlease_fn = cephwrap_linux_setlease,
1237 .getlock_fn = cephwrap_getlock,
1238 .symlink_fn = cephwrap_symlink,
1239 .readlink_fn = cephwrap_readlink,
1240 .link_fn = cephwrap_link,
1241 .mknod_fn = cephwrap_mknod,
1242 .realpath_fn = cephwrap_realpath,
1243 .notify_watch_fn = cephwrap_notify_watch,
1244 .chflags_fn = cephwrap_chflags,
1245 .get_real_filename_fn = cephwrap_get_real_filename,
1246 .connectpath_fn = cephwrap_connectpath,
1248 /* EA operations. */
1249 .getxattr_fn = cephwrap_getxattr,
1250 .fgetxattr_fn = cephwrap_fgetxattr,
1251 .listxattr_fn = cephwrap_listxattr,
1252 .flistxattr_fn = cephwrap_flistxattr,
1253 .removexattr_fn = cephwrap_removexattr,
1254 .fremovexattr_fn = cephwrap_fremovexattr,
1255 .setxattr_fn = cephwrap_setxattr,
1256 .fsetxattr_fn = cephwrap_fsetxattr,
1258 /* aio operations */
1259 .aio_force_fn = cephwrap_aio_force,
1261 /* offline operations */
1262 .is_offline_fn = cephwrap_is_offline,
1263 .set_offline_fn = cephwrap_set_offline
1266 NTSTATUS vfs_ceph_init(void);
1267 NTSTATUS vfs_ceph_init(void)
1269 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1270 "ceph", &ceph_fns);