s4-dsdb: Tests for security checks on undelete operation
[Samba.git] / source3 / modules / vfs_ceph.c
blobec72312ce79cd1cd15a136ddcd79c7f2c0f918f6
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, const char *path, bool small_query, uint64_t *bsize,
160 uint64_t *dfree, uint64_t *dsize)
162 struct statvfs statvfs_buf;
163 int ret;
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)));
174 return *dfree;
175 } else {
176 DEBUG(10, ("[CEPH] ceph_statfs returned %d\n", ret));
177 WRAP_RETURN(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 */
184 #if 0
185 /* was ifdef HAVE_SYS_QUOTAS */
186 int ret;
188 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
190 if (ret) {
191 errno = -ret;
192 ret = -1;
195 return ret;
196 #else
197 errno = ENOSYS;
198 return -1;
199 #endif
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 */
205 #if 0
206 /* was ifdef HAVE_SYS_QUOTAS */
207 int ret;
209 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
210 if (ret) {
211 errno = -ret;
212 ret = -1;
215 return ret;
216 #else
217 WRAP_RETURN(-ENOSYS);
218 #endif
221 static int cephwrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
223 struct statvfs statvfs_buf;
224 int ret;
226 ret = ceph_statfs(handle->data, path, &statvfs_buf);
227 if (ret < 0) {
228 WRAP_RETURN(ret);
229 } else {
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));
242 return ret;
245 /* Directory operations */
247 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
249 int ret = 0;
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);
255 if (ret < 0) {
256 result = NULL;
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,
266 const char *mask,
267 uint32 attributes)
269 int ret = 0;
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);
274 if (ret < 0) {
275 result = NULL;
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,
284 DIR *dirp,
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. */
295 if (sbuf)
296 SET_STAT_INVALID(*sbuf);
297 return result;
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)
308 long ret;
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));
312 WRAP_RETURN(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)
323 int result;
324 bool has_dacl = False;
325 char *parent = NULL;
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)))
332 mode = 0777;
334 TALLOC_FREE(parent);
336 result = ceph_mkdir(handle->data, path, mode);
339 * Note. This order is important
341 if (result) {
342 WRAP_RETURN(result);
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))
353 errno = saved_errno;
356 return result;
359 static int cephwrap_rmdir(struct vfs_handle_struct *handle, const char *path)
361 int result;
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));
366 WRAP_RETURN(result);
369 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
371 int result;
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));
376 WRAP_RETURN(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) {
389 goto out;
392 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
393 out:
394 DEBUG(10, ("[CEPH] open(...) = %d\n", result));
395 WRAP_RETURN(result);
398 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
400 int result;
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));
406 WRAP_RETURN(result);
409 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
411 ssize_t result;
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)));
418 WRAP_RETURN(result);
421 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
422 size_t n, off_t offset)
424 ssize_t result;
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)));
430 WRAP_RETURN(result);
434 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
436 ssize_t result;
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)));
443 if (result < 0) {
444 WRAP_RETURN(result);
446 fsp->fh->pos += result;
447 return 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)
453 ssize_t result;
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)));
458 WRAP_RETURN(result);
461 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
463 off_t result = 0;
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);
470 WRAP_RETURN(result);
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"));
480 errno = ENOTSUP;
481 return -1;
484 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
485 int fromfd,
486 files_struct *tofsp,
487 off_t offset,
488 size_t n)
491 * We cannot support recvfile because libceph is in user space.
493 DEBUG(10, ("[CEPH] cephwrap_recvfile\n"));
494 errno=ENOTSUP;
495 return -1;
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)
502 int result = -1;
503 DEBUG(10, ("[CEPH] cephwrap_rename\n"));
504 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
505 errno = ENOENT;
506 return result;
509 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
510 WRAP_RETURN(result);
513 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
515 int result;
516 DEBUG(10, ("[CEPH] cephwrap_fsync\n"));
517 result = ceph_fsync(handle->data, fsp->fh->fd, false);
518 WRAP_RETURN(result);
521 static void cephwrap_init_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
523 ZERO_STRUCT(*dst);
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)
544 int result = -1;
545 struct stat stbuf;
547 DEBUG(10, ("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
549 if (smb_fname->stream_name) {
550 errno = ENOENT;
551 return result;
554 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
555 DEBUG(10, ("[CEPH] stat(...) = %d\n", result));
556 if (result < 0) {
557 WRAP_RETURN(result);
558 } else {
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));
568 return result;
571 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
573 int result = -1;
574 struct stat stbuf;
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));
579 if (result < 0) {
580 WRAP_RETURN(result);
581 } else {
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));
592 return result;
595 static int cephwrap_lstat(struct vfs_handle_struct *handle,
596 struct smb_filename *smb_fname)
598 int result = -1;
599 struct stat stbuf;
601 DEBUG(10, ("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
603 if (smb_fname->stream_name) {
604 errno = ENOENT;
605 return result;
608 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
609 DEBUG(10, ("[CEPH] lstat(...) = %d\n", result));
610 if (result < 0) {
611 WRAP_RETURN(result);
613 cephwrap_init_stat_ex_from_stat(&(smb_fname->st), &stbuf);
614 return result;
617 static int cephwrap_unlink(struct vfs_handle_struct *handle,
618 const struct smb_filename *smb_fname)
620 int result = -1;
622 DEBUG(10, ("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
623 if (smb_fname->stream_name) {
624 errno = ENOENT;
625 return result;
627 result = ceph_unlink(handle->data, smb_fname->base_name);
628 DEBUG(10, ("[CEPH] unlink(...) = %d\n", result));
629 WRAP_RETURN(result);
632 static int cephwrap_chmod(struct vfs_handle_struct *handle, const char *path, mode_t mode)
634 int result;
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) {
648 return result;
650 /* Error - return the old errno. */
651 errno = saved_errno;
654 result = ceph_chmod(handle->data, path, mode);
655 DEBUG(10, ("[CEPH] chmod(...) = %d\n", result));
656 WRAP_RETURN(result);
659 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
661 int result;
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) {
674 return result;
676 /* Error - return the old errno. */
677 errno = saved_errno;
680 #if defined(HAVE_FCHMOD)
681 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
682 DEBUG(10, ("[CEPH] fchmod(...) = %d\n", result));
683 WRAP_RETURN(result);
684 #else
685 errno = ENOSYS;
686 #endif
687 return -1;
690 static int cephwrap_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
692 int result;
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));
696 WRAP_RETURN(result);
699 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
701 int result;
702 #ifdef HAVE_FCHOWN
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));
707 WRAP_RETURN(result);
708 #else
709 errno = ENOSYS;
710 result = -1;
711 #endif
712 return result;
715 static int cephwrap_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
717 int result;
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));
722 WRAP_RETURN(result);
725 static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path)
727 int result = -1;
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, "/"))
734 return chdir(path);
736 result = ceph_chdir(handle->data, path);
737 DEBUG(10, ("[CEPH] chdir(...) = %d\n", result));
738 WRAP_RETURN(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)
752 struct utimbuf buf;
753 int result;
754 buf.actime = ft->atime.tv_sec;
755 buf.modtime = ft->mtime.tv_sec;
756 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
757 DEBUG(10, ("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
758 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
759 ft->create_time.tv_sec, result));
760 return result;
763 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
765 off_t space_to_write;
766 uint64_t space_avail;
767 uint64_t bsize,dfree,dsize;
768 int ret;
769 NTSTATUS status;
770 SMB_STRUCT_STAT *pst;
772 status = vfs_stat_fsp(fsp);
773 if (!NT_STATUS_IS_OK(status)) {
774 return -1;
776 pst = &fsp->fsp_name->st;
778 #ifdef S_ISFIFO
779 if (S_ISFIFO(pst->st_ex_mode))
780 return 0;
781 #endif
783 if (pst->st_ex_size == len)
784 return 0;
786 /* Shrink - just ftruncate. */
787 if (pst->st_ex_size > len)
788 return ftruncate(fsp->fh->fd, len);
790 space_to_write = len - pst->st_ex_size;
792 /* for allocation try fallocate first. This can fail on some
793 platforms e.g. when the filesystem doesn't support it and no
794 emulation is being done by the libc (like on AIX with JFS1). In that
795 case we do our own emulation. fallocate implementations can
796 return ENOTSUP or EINVAL in cases like that. */
797 ret = SMB_VFS_FALLOCATE(fsp, VFS_FALLOCATE_EXTEND_SIZE,
798 pst->st_ex_size, space_to_write);
799 if (ret == -1 && errno == ENOSPC) {
800 return -1;
802 if (ret == 0) {
803 return 0;
805 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
806 "error %d. Falling back to slow manual allocation\n", errno));
808 /* available disk space is enough or not? */
809 space_avail = get_dfree_info(fsp->conn,
810 fsp->fsp_name->base_name, false,
811 &bsize,&dfree,&dsize);
812 /* space_avail is 1k blocks */
813 if (space_avail == (uint64_t)-1 ||
814 ((uint64_t)space_to_write/1024 > space_avail) ) {
815 errno = ENOSPC;
816 return -1;
819 /* Write out the real space on disk. */
820 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
823 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
825 int result = -1;
826 SMB_STRUCT_STAT st;
827 char c = 0;
828 off_t currpos;
830 DEBUG(10, ("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len)));
832 if (lp_strict_allocate(SNUM(fsp->conn))) {
833 result = strict_allocate_ftruncate(handle, fsp, len);
834 return result;
837 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
838 sys_ftruncate if the system supports it. Then I discovered that
839 you can have some filesystems that support ftruncate
840 expansion and some that don't! On Linux fat can't do
841 ftruncate extend but ext2 can. */
843 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
844 if (result == 0)
845 goto done;
847 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
848 extend a file with ftruncate. Provide alternate implementation
849 for this */
850 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
851 if (currpos == -1) {
852 goto done;
855 /* Do an fstat to see if the file is longer than the requested
856 size in which case the ftruncate above should have
857 succeeded or shorter, in which case seek to len - 1 and
858 write 1 byte of zero */
859 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
860 goto done;
863 #ifdef S_ISFIFO
864 if (S_ISFIFO(st.st_ex_mode)) {
865 result = 0;
866 goto done;
868 #endif
870 if (st.st_ex_size == len) {
871 result = 0;
872 goto done;
875 if (st.st_ex_size > len) {
876 /* the sys_ftruncate should have worked */
877 goto done;
880 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
881 goto done;
883 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
884 goto done;
886 /* Seek to where we were */
887 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
888 goto done;
889 result = 0;
891 done:
893 return result;
896 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
898 DEBUG(10, ("[CEPH] lock\n"));
899 return true;
902 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
903 uint32 share_mode, uint32 access_mask)
905 DEBUG(10, ("[CEPH] kernel_flock\n"));
907 * We must return zero here and pretend all is good.
908 * One day we might have this in CEPH.
910 return 0;
913 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
915 DEBUG(10, ("[CEPH] getlock returning false and errno=0\n"));
917 errno = 0;
918 return false;
922 * We cannot let this fall through to the default, because the file might only
923 * be accessible from libceph (which is a user-space client) but the fd might
924 * be for some file the kernel knows about.
926 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
927 int leasetype)
929 int result = -1;
931 DEBUG(10, ("[CEPH] linux_setlease\n"));
932 errno = ENOSYS;
933 return result;
936 static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
938 int result = -1;
939 DEBUG(10, ("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath));
940 result = ceph_symlink(handle->data, oldpath, newpath);
941 DEBUG(10, ("[CEPH] symlink(...) = %d\n", result));
942 WRAP_RETURN(result);
945 static int cephwrap_readlink(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
947 int result = -1;
948 DEBUG(10, ("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz)));
949 result = ceph_readlink(handle->data, path, buf, bufsiz);
950 DEBUG(10, ("[CEPH] readlink(...) = %d\n", result));
951 WRAP_RETURN(result);
954 static int cephwrap_link(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
956 int result = -1;
957 DEBUG(10, ("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath));
958 result = ceph_link(handle->data, oldpath, newpath);
959 DEBUG(10, ("[CEPH] link(...) = %d\n", result));
960 WRAP_RETURN(result);
963 static int cephwrap_mknod(struct vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
965 int result = -1;
966 DEBUG(10, ("[CEPH] mknod(%p, %s)\n", handle, pathname));
967 result = ceph_mknod(handle->data, pathname, mode, dev);
968 DEBUG(10, ("[CEPH] mknod(...) = %d\n", result));
969 WRAP_RETURN(result);
973 * This is a simple version of real-path ... a better version is needed to
974 * ask libceph about symbolic links.
976 static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *path)
978 char *result;
979 size_t len = strlen(path);
981 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
982 if (len && (path[0] == '/')) {
983 int r = asprintf(&result, "%s", path);
984 if (r < 0) return NULL;
985 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
986 if (len == 2) {
987 int r = asprintf(&result, "%s",
988 handle->conn->connectpath);
989 if (r < 0) return NULL;
990 } else {
991 int r = asprintf(&result, "%s/%s",
992 handle->conn->connectpath, &path[2]);
993 if (r < 0) return NULL;
995 } else {
996 int r = asprintf(&result, "%s/%s",
997 handle->conn->connectpath, path);
998 if (r < 0) return NULL;
1000 DEBUG(10, ("[CEPH] realpath(%p, %s) = %s\n", handle, path, result));
1001 return result;
1004 static NTSTATUS cephwrap_notify_watch(struct vfs_handle_struct *vfs_handle,
1005 struct sys_notify_context *ctx,
1006 const char *path,
1007 uint32_t *filter,
1008 uint32_t *subdir_filter,
1009 void (*callback)(struct sys_notify_context *ctx,
1010 void *private_data,
1011 struct notify_event *ev),
1012 void *private_data,
1013 void *handle_p)
1016 * We cannot call inotify on files the kernel does not know about
1018 return NT_STATUS_OK;
1021 static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
1022 unsigned int flags)
1024 errno = ENOSYS;
1025 return -1;
1028 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1029 const char *path,
1030 const char *name,
1031 TALLOC_CTX *mem_ctx,
1032 char **found_name)
1035 * Don't fall back to get_real_filename so callers can differentiate
1036 * between a full directory scan and an actual case-insensitive stat.
1038 errno = EOPNOTSUPP;
1039 return -1;
1042 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1043 const char *fname)
1045 return handle->conn->connectpath;
1048 /****************************************************************
1049 Extended attribute operations.
1050 *****************************************************************/
1052 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
1054 int ret;
1055 DEBUG(10, ("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle, path, name, value, llu(size)));
1056 ret = ceph_getxattr(handle->data, path, name, value, size);
1057 DEBUG(10, ("[CEPH] getxattr(...) = %d\n", ret));
1058 if (ret < 0) {
1059 WRAP_RETURN(ret);
1060 } else {
1061 return (ssize_t)ret;
1065 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1067 int ret;
1068 DEBUG(10, ("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size)));
1069 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1070 DEBUG(10, ("[CEPH] fgetxattr(...) = %d\n", ret));
1071 if (ret < 0) {
1072 WRAP_RETURN(ret);
1073 } else {
1074 return (ssize_t)ret;
1078 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1080 int ret;
1081 DEBUG(10, ("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1082 ret = ceph_listxattr(handle->data, path, list, size);
1083 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1084 if (ret < 0) {
1085 WRAP_RETURN(ret);
1086 } else {
1087 return (ssize_t)ret;
1091 #if 0
1092 static ssize_t cephwrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1094 int ret;
1095 DEBUG(10, ("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
1096 ret = ceph_llistxattr(handle->data, path, list, size);
1097 DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
1098 if (ret < 0) {
1099 WRAP_RETURN(ret);
1100 } else {
1101 return (ssize_t)ret;
1104 #endif
1106 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1108 int ret;
1109 DEBUG(10, ("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size)));
1110 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1111 DEBUG(10, ("[CEPH] flistxattr(...) = %d\n", ret));
1112 if (ret < 0) {
1113 WRAP_RETURN(ret);
1114 } else {
1115 return (ssize_t)ret;
1119 static int cephwrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
1121 int ret;
1122 DEBUG(10, ("[CEPH] removexattr(%p, %s, %s)\n", handle, path, name));
1123 ret = ceph_removexattr(handle->data, path, name);
1124 DEBUG(10, ("[CEPH] removexattr(...) = %d\n", ret));
1125 WRAP_RETURN(ret);
1128 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1130 int ret;
1131 DEBUG(10, ("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name));
1132 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1133 DEBUG(10, ("[CEPH] fremovexattr(...) = %d\n", ret));
1134 WRAP_RETURN(ret);
1137 static int cephwrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
1139 int ret;
1140 DEBUG(10, ("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle, path, name, value, llu(size), flags));
1141 ret = ceph_setxattr(handle->data, path, name, value, size, flags);
1142 DEBUG(10, ("[CEPH] setxattr(...) = %d\n", ret));
1143 WRAP_RETURN(ret);
1146 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1148 int ret;
1149 DEBUG(10, ("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags));
1150 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1151 DEBUG(10, ("[CEPH] fsetxattr(...) = %d\n", ret));
1152 WRAP_RETURN(ret);
1155 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1159 * We do not support AIO yet.
1162 DEBUG(10, ("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp));
1163 errno = ENOTSUP;
1164 return false;
1167 static bool cephwrap_is_offline(struct vfs_handle_struct *handle,
1168 const struct smb_filename *fname,
1169 SMB_STRUCT_STAT *sbuf)
1171 return false;
1174 static int cephwrap_set_offline(struct vfs_handle_struct *handle,
1175 const struct smb_filename *fname)
1177 errno = ENOTSUP;
1178 return -1;
1181 static struct vfs_fn_pointers ceph_fns = {
1182 /* Disk operations */
1184 .connect_fn = cephwrap_connect,
1185 .disconnect_fn = cephwrap_disconnect,
1186 .disk_free_fn = cephwrap_disk_free,
1187 .get_quota_fn = cephwrap_get_quota,
1188 .set_quota_fn = cephwrap_set_quota,
1189 .statvfs_fn = cephwrap_statvfs,
1191 /* Directory operations */
1193 .opendir_fn = cephwrap_opendir,
1194 .fdopendir_fn = cephwrap_fdopendir,
1195 .readdir_fn = cephwrap_readdir,
1196 .seekdir_fn = cephwrap_seekdir,
1197 .telldir_fn = cephwrap_telldir,
1198 .rewind_dir_fn = cephwrap_rewinddir,
1199 .mkdir_fn = cephwrap_mkdir,
1200 .rmdir_fn = cephwrap_rmdir,
1201 .closedir_fn = cephwrap_closedir,
1203 /* File operations */
1205 .open_fn = cephwrap_open,
1206 .close_fn = cephwrap_close,
1207 .read_fn = cephwrap_read,
1208 .pread_fn = cephwrap_pread,
1209 .write_fn = cephwrap_write,
1210 .pwrite_fn = cephwrap_pwrite,
1211 .lseek_fn = cephwrap_lseek,
1212 .sendfile_fn = cephwrap_sendfile,
1213 .recvfile_fn = cephwrap_recvfile,
1214 .rename_fn = cephwrap_rename,
1215 .fsync_fn = cephwrap_fsync,
1216 .stat_fn = cephwrap_stat,
1217 .fstat_fn = cephwrap_fstat,
1218 .lstat_fn = cephwrap_lstat,
1219 .unlink_fn = cephwrap_unlink,
1220 .chmod_fn = cephwrap_chmod,
1221 .fchmod_fn = cephwrap_fchmod,
1222 .chown_fn = cephwrap_chown,
1223 .fchown_fn = cephwrap_fchown,
1224 .lchown_fn = cephwrap_lchown,
1225 .chdir_fn = cephwrap_chdir,
1226 .getwd_fn = cephwrap_getwd,
1227 .ntimes_fn = cephwrap_ntimes,
1228 .ftruncate_fn = cephwrap_ftruncate,
1229 .lock_fn = cephwrap_lock,
1230 .kernel_flock_fn = cephwrap_kernel_flock,
1231 .linux_setlease_fn = cephwrap_linux_setlease,
1232 .getlock_fn = cephwrap_getlock,
1233 .symlink_fn = cephwrap_symlink,
1234 .readlink_fn = cephwrap_readlink,
1235 .link_fn = cephwrap_link,
1236 .mknod_fn = cephwrap_mknod,
1237 .realpath_fn = cephwrap_realpath,
1238 .notify_watch_fn = cephwrap_notify_watch,
1239 .chflags_fn = cephwrap_chflags,
1240 .get_real_filename_fn = cephwrap_get_real_filename,
1241 .connectpath_fn = cephwrap_connectpath,
1243 /* EA operations. */
1244 .getxattr_fn = cephwrap_getxattr,
1245 .fgetxattr_fn = cephwrap_fgetxattr,
1246 .listxattr_fn = cephwrap_listxattr,
1247 .flistxattr_fn = cephwrap_flistxattr,
1248 .removexattr_fn = cephwrap_removexattr,
1249 .fremovexattr_fn = cephwrap_fremovexattr,
1250 .setxattr_fn = cephwrap_setxattr,
1251 .fsetxattr_fn = cephwrap_fsetxattr,
1253 /* aio operations */
1254 .aio_force_fn = cephwrap_aio_force,
1256 /* offline operations */
1257 .is_offline_fn = cephwrap_is_offline,
1258 .set_offline_fn = cephwrap_set_offline
1261 NTSTATUS vfs_ceph_init(void);
1262 NTSTATUS vfs_ceph_init(void)
1264 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1265 "ceph", &ceph_fns);