s3: VFS: Remove SMB_VFS_READ() function and all implementations.
[metze/samba/wip.git] / source3 / modules / vfs_ceph.c
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>
8
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.
13
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.
18
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/>.
21 */
22
23 /*
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.
26  *
27  * Add the following smb.conf parameter to each share that will be hosted on
28  * Ceph:
29  *
30  *   vfs objects = ceph [any others you need go here]
31  */
32
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"
39 #include "modules/posixacl_xattr.h"
40 #include "lib/util/tevent_unix.h"
41
42 #undef DBGC_CLASS
43 #define DBGC_CLASS DBGC_VFS
44
45 #ifndef LIBCEPHFS_VERSION
46 #define LIBCEPHFS_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra)
47 #define LIBCEPHFS_VERSION_CODE LIBCEPHFS_VERSION(0, 0, 0)
48 #endif
49
50 /*
51  * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
52  */
53 #define llu(_var) ((long long unsigned)_var)
54
55 /*
56  * Note, libceph's return code model is to return -errno! So we have to convert
57  * to what Samba expects, with is set errno to -return and return -1
58  */
59 #define WRAP_RETURN(_res) \
60         errno = 0; \
61         if (_res < 0) { \
62                 errno = -_res; \
63                 return -1; \
64         } \
65         return _res \
66
67 /*
68  * We mount only one file system and then all shares are assumed to be in that.
69  * FIXME: If we want to support more than one FS, then we have to deal with
70  * this differently.
71  *
72  * So, cmount tells us if we have been this way before and whether
73  * we need to mount ceph and cmount_cnt tells us how many times we have
74  * connected
75  */
76 static struct ceph_mount_info * cmount = NULL;
77 static uint32_t cmount_cnt = 0;
78
79 /* Check for NULL pointer parameters in cephwrap_* functions */
80
81 /* We don't want to have NULL function pointers lying around.  Someone
82    is sure to try and execute them.  These stubs are used to prevent
83    this possibility. */
84
85 static int cephwrap_connect(struct vfs_handle_struct *handle,  const char *service, const char *user)
86 {
87         int ret;
88         char buf[256];
89         int snum = SNUM(handle->conn);
90         const char *conf_file;
91         const char *user_id;
92
93         if (cmount) {
94                 handle->data = cmount; /* We have been here before */
95                 cmount_cnt++;
96                 return 0;
97         }
98
99         /* if config_file and/or user_id are NULL, ceph will use defaults */
100         conf_file = lp_parm_const_string(snum, "ceph", "config_file", NULL);
101         user_id = lp_parm_const_string(snum, "ceph", "user_id", NULL);
102
103         DBG_DEBUG("[CEPH] calling: ceph_create\n");
104         ret = ceph_create(&cmount, user_id);
105         if (ret) {
106                 goto err_out;
107         }
108
109         DBG_DEBUG("[CEPH] calling: ceph_conf_read_file with %s\n",
110                   (conf_file == NULL ? "default path" : conf_file));
111         ret = ceph_conf_read_file(cmount, conf_file);
112         if (ret) {
113                 goto err_cm_release;
114         }
115
116         DBG_DEBUG("[CEPH] calling: ceph_conf_get\n");
117         ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
118         if (ret < 0) {
119                 goto err_cm_release;
120         }
121
122         DBG_DEBUG("[CEPH] calling: ceph_mount\n");
123         ret = ceph_mount(cmount, NULL);
124         if (ret < 0) {
125                 goto err_cm_release;
126         }
127
128         /*
129          * encode mount context/state into our vfs/connection holding structure
130          * cmount is a ceph_mount_t*
131          */
132         handle->data = cmount;
133         cmount_cnt++;
134
135         return 0;
136
137 err_cm_release:
138         ceph_release(cmount);
139         cmount = NULL;
140 err_out:
141         /*
142          * Handle the error correctly. Ceph returns -errno.
143          */
144         DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
145         WRAP_RETURN(ret);
146 }
147
148 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
149 {
150         int ret;
151
152         if (!cmount) {
153                 DBG_ERR("[CEPH] Error, ceph not mounted\n");
154                 return;
155         }
156
157         /* Should we unmount/shutdown? Only if the last disconnect? */
158         if (--cmount_cnt) {
159                 DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
160                 return;
161         }
162
163         ret = ceph_unmount(cmount);
164         if (ret < 0) {
165                 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
166         }
167
168         ret = ceph_release(cmount);
169         if (ret < 0) {
170                 DBG_ERR("[CEPH] failed to release: %s\n", strerror(-ret));
171         }
172
173         cmount = NULL;  /* Make it safe */
174 }
175
176 /* Disk operations */
177
178 static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
179                                 const struct smb_filename *smb_fname,
180                                 uint64_t *bsize,
181                                 uint64_t *dfree,
182                                 uint64_t *dsize)
183 {
184         struct statvfs statvfs_buf;
185         int ret;
186
187         if (!(ret = ceph_statfs(handle->data, smb_fname->base_name,
188                         &statvfs_buf))) {
189                 /*
190                  * Provide all the correct values.
191                  */
192                 *bsize = statvfs_buf.f_bsize;
193                 *dfree = statvfs_buf.f_bavail;
194                 *dsize = statvfs_buf.f_blocks;
195                 DBG_DEBUG("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
196                         llu(*bsize), llu(*dfree), llu(*dsize));
197                 return *dfree;
198         } else {
199                 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
200                 WRAP_RETURN(ret);
201         }
202 }
203
204 static int cephwrap_get_quota(struct vfs_handle_struct *handle,
205                                 const struct smb_filename *smb_fname,
206                                 enum SMB_QUOTA_TYPE qtype,
207                                 unid_t id,
208                                 SMB_DISK_QUOTA *qt)
209 {
210         /* libceph: Ceph does not implement this */
211 #if 0
212 /* was ifdef HAVE_SYS_QUOTAS */
213         int ret;
214
215         ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
216
217         if (ret) {
218                 errno = -ret;
219                 ret = -1;
220         }
221
222         return ret;
223 #else
224         errno = ENOSYS;
225         return -1;
226 #endif
227 }
228
229 static int cephwrap_set_quota(struct vfs_handle_struct *handle,  enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
230 {
231         /* libceph: Ceph does not implement this */
232 #if 0
233 /* was ifdef HAVE_SYS_QUOTAS */
234         int ret;
235
236         ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
237         if (ret) {
238                 errno = -ret;
239                 ret = -1;
240         }
241
242         return ret;
243 #else
244         WRAP_RETURN(-ENOSYS);
245 #endif
246 }
247
248 static int cephwrap_statvfs(struct vfs_handle_struct *handle,
249                                 const struct smb_filename *smb_fname,
250                                 vfs_statvfs_struct *statbuf)
251 {
252         struct statvfs statvfs_buf;
253         int ret;
254
255         ret = ceph_statfs(handle->data, smb_fname->base_name, &statvfs_buf);
256         if (ret < 0) {
257                 WRAP_RETURN(ret);
258         } else {
259                 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
260                 statbuf->BlockSize = statvfs_buf.f_bsize;
261                 statbuf->TotalBlocks = statvfs_buf.f_blocks;
262                 statbuf->BlocksAvail = statvfs_buf.f_bfree;
263                 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
264                 statbuf->TotalFileNodes = statvfs_buf.f_files;
265                 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
266                 statbuf->FsIdentifier = statvfs_buf.f_fsid;
267                 DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
268                         (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
269                         (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
270         }
271         return ret;
272 }
273
274 static uint32_t cephwrap_fs_capabilities(struct vfs_handle_struct *handle,
275                                          enum timestamp_set_resolution *p_ts_res)
276 {
277         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
278
279 #ifdef HAVE_CEPH_STATX
280         *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
281 #else
282         *p_ts_res = TIMESTAMP_SET_MSEC;
283 #endif
284
285         return caps;
286 }
287
288 /* Directory operations */
289
290 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
291                              const struct smb_filename *smb_fname,
292                              const char *mask, uint32_t attr)
293 {
294         int ret = 0;
295         struct ceph_dir_result *result;
296         DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
297
298         /* Returns NULL if it does not exist or there are problems ? */
299         ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
300         if (ret < 0) {
301                 result = NULL;
302                 errno = -ret; /* We return result which is NULL in this case */
303         }
304
305         DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
306         return (DIR *) result;
307 }
308
309 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
310                                struct files_struct *fsp,
311                                const char *mask,
312                                uint32_t attributes)
313 {
314         int ret = 0;
315         struct ceph_dir_result *result;
316         DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
317
318         ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
319         if (ret < 0) {
320                 result = NULL;
321                 errno = -ret; /* We return result which is NULL in this case */
322         }
323
324         DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
325         return (DIR *) result;
326 }
327
328 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
329                                        DIR *dirp,
330                                        SMB_STRUCT_STAT *sbuf)
331 {
332         struct dirent *result;
333
334         DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
335         result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
336         DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
337
338         /* Default Posix readdir() does not give us stat info.
339          * Set to invalid to indicate we didn't return this info. */
340         if (sbuf)
341                 SET_STAT_INVALID(*sbuf);
342         return result;
343 }
344
345 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
346 {
347         DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
348         ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
349 }
350
351 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
352 {
353         long ret;
354         DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
355         ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
356         DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
357         WRAP_RETURN(ret);
358 }
359
360 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
361 {
362         DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
363         ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
364 }
365
366 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
367                           const struct smb_filename *smb_fname,
368                           mode_t mode)
369 {
370         int result;
371         bool has_dacl = False;
372         char *parent = NULL;
373         const char *path = smb_fname->base_name;
374
375         DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
376
377         if (lp_inherit_acls(SNUM(handle->conn))
378             && parent_dirname(talloc_tos(), path, &parent, NULL)
379             && (has_dacl = directory_has_default_acl(handle->conn, parent)))
380                 mode = 0777;
381
382         TALLOC_FREE(parent);
383
384         result = ceph_mkdir(handle->data, path, mode);
385
386         /*
387          * Note. This order is important
388          */
389         if (result) {
390                 WRAP_RETURN(result);
391         } else if (result == 0 && !has_dacl) {
392                 /*
393                  * We need to do this as the default behavior of POSIX ACLs
394                  * is to set the mask to be the requested group permission
395                  * bits, not the group permission bits to be the requested
396                  * group permission bits. This is not what we want, as it will
397                  * mess up any inherited ACL bits that were set. JRA.
398                  */
399                 int saved_errno = errno; /* We may get ENOSYS */
400                 if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
401                                 (errno == ENOSYS)) {
402                         errno = saved_errno;
403                 }
404         }
405
406         return result;
407 }
408
409 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
410                         const struct smb_filename *smb_fname)
411 {
412         int result;
413
414         DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
415         result = ceph_rmdir(handle->data, smb_fname->base_name);
416         DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
417         WRAP_RETURN(result);
418 }
419
420 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
421 {
422         int result;
423
424         DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
425         result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
426         DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
427         WRAP_RETURN(result);
428 }
429
430 /* File operations */
431
432 static int cephwrap_open(struct vfs_handle_struct *handle,
433                         struct smb_filename *smb_fname,
434                         files_struct *fsp, int flags, mode_t mode)
435 {
436         int result = -ENOENT;
437         DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
438                   smb_fname_str_dbg(smb_fname), fsp, flags, mode);
439
440         if (smb_fname->stream_name) {
441                 goto out;
442         }
443
444         result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
445 out:
446         DBG_DEBUG("[CEPH] open(...) = %d\n", result);
447         WRAP_RETURN(result);
448 }
449
450 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
451 {
452         int result;
453
454         DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
455         result = ceph_close(handle->data, fsp->fh->fd);
456         DBG_DEBUG("[CEPH] close(...) = %d\n", result);
457
458         WRAP_RETURN(result);
459 }
460
461 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
462                         size_t n, off_t offset)
463 {
464         ssize_t result;
465
466         DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
467
468         result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
469         DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
470         WRAP_RETURN(result);
471 }
472
473
474 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
475 {
476         ssize_t result;
477
478         DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
479
480         result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
481
482         DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
483         if (result < 0) {
484                 WRAP_RETURN(result);
485         }
486         fsp->fh->pos += result;
487         return result;
488 }
489
490 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
491                         size_t n, off_t offset)
492 {
493         ssize_t result;
494
495         DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
496         result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
497         DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
498         WRAP_RETURN(result);
499 }
500
501 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
502 {
503         off_t result = 0;
504
505         DBG_DEBUG("[CEPH] cephwrap_lseek\n");
506         /* Cope with 'stat' file opens. */
507         if (fsp->fh->fd != -1) {
508                 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
509         }
510         WRAP_RETURN(result);
511 }
512
513 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
514                         off_t offset, size_t n)
515 {
516         /*
517          * We cannot support sendfile because libceph is in user space.
518          */
519         DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
520         errno = ENOTSUP;
521         return -1;
522 }
523
524 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
525                         int fromfd,
526                         files_struct *tofsp,
527                         off_t offset,
528                         size_t n)
529 {
530         /*
531          * We cannot support recvfile because libceph is in user space.
532          */
533         DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
534         errno=ENOTSUP;
535         return -1;
536 }
537
538 static int cephwrap_rename(struct vfs_handle_struct *handle,
539                           const struct smb_filename *smb_fname_src,
540                           const struct smb_filename *smb_fname_dst)
541 {
542         int result = -1;
543         DBG_DEBUG("[CEPH] cephwrap_rename\n");
544         if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
545                 errno = ENOENT;
546                 return result;
547         }
548
549         result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
550         WRAP_RETURN(result);
551 }
552
553 /*
554  * Fake up an async ceph fsync by calling the sychronous API.
555  */
556
557 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
558                                         TALLOC_CTX *mem_ctx,
559                                         struct tevent_context *ev,
560                                         files_struct *fsp)
561 {
562         struct tevent_req *req = NULL;
563         struct vfs_aio_state *state = NULL;
564         int ret = -1;
565
566         DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
567
568         req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
569         if (req == NULL) {
570                 return NULL;
571         }
572
573         /* Make sync call. */
574         ret = ceph_fsync(handle->data, fsp->fh->fd, false);
575
576         if (ret != 0) {
577                 /* ceph_fsync returns -errno on error. */
578                 tevent_req_error(req, -ret);
579                 return tevent_req_post(req, ev);
580         }
581
582         /* Mark it as done. */
583         tevent_req_done(req);
584         /* Return and schedule the completion of the call. */
585         return tevent_req_post(req, ev);
586 }
587
588 static int cephwrap_fsync_recv(struct tevent_req *req,
589                                 struct vfs_aio_state *vfs_aio_state)
590 {
591         struct vfs_aio_state *state =
592                 tevent_req_data(req, struct vfs_aio_state);
593
594         DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
595
596         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
597                 return -1;
598         }
599         *vfs_aio_state = *state;
600         return 0;
601 }
602
603 #ifdef HAVE_CEPH_STATX
604 #define SAMBA_STATX_ATTR_MASK   (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
605
606 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
607 {
608         if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
609                 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
610                                 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
611
612         dst->st_ex_dev = stx->stx_dev;
613         dst->st_ex_rdev = stx->stx_rdev;
614         dst->st_ex_ino = stx->stx_ino;
615         dst->st_ex_mode = stx->stx_mode;
616         dst->st_ex_uid = stx->stx_uid;
617         dst->st_ex_gid = stx->stx_gid;
618         dst->st_ex_size = stx->stx_size;
619         dst->st_ex_nlink = stx->stx_nlink;
620         dst->st_ex_atime = stx->stx_atime;
621         dst->st_ex_btime = stx->stx_btime;
622         dst->st_ex_ctime = stx->stx_ctime;
623         dst->st_ex_mtime = stx->stx_mtime;
624         dst->st_ex_calculated_birthtime = false;
625         dst->st_ex_blksize = stx->stx_blksize;
626         dst->st_ex_blocks = stx->stx_blocks;
627 }
628
629 static int cephwrap_stat(struct vfs_handle_struct *handle,
630                         struct smb_filename *smb_fname)
631 {
632         int result = -1;
633         struct ceph_statx stx;
634
635         DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
636
637         if (smb_fname->stream_name) {
638                 errno = ENOENT;
639                 return result;
640         }
641
642         result = ceph_statx(handle->data, smb_fname->base_name, &stx,
643                                 SAMBA_STATX_ATTR_MASK, 0);
644         DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
645         if (result < 0) {
646                 WRAP_RETURN(result);
647         } else {
648                 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
649                            "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
650                            "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
651                            llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
652                            llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
653                            llu(stx.stx_size), llu(stx.stx_blksize),
654                            llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
655                            llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
656         }
657         init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
658         DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
659         return result;
660 }
661
662 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
663 {
664         int result = -1;
665         struct ceph_statx stx;
666
667         DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
668         result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
669                                 SAMBA_STATX_ATTR_MASK, 0);
670         DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
671         if (result < 0) {
672                 WRAP_RETURN(result);
673         } else {
674                 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
675                            "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
676                            "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
677                            llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
678                            llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
679                            llu(stx.stx_size), llu(stx.stx_blksize),
680                            llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
681                            llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
682         }
683         init_stat_ex_from_ceph_statx(sbuf, &stx);
684         DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
685         return result;
686 }
687
688 static int cephwrap_lstat(struct vfs_handle_struct *handle,
689                          struct smb_filename *smb_fname)
690 {
691         int result = -1;
692         struct ceph_statx stx;
693
694         DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
695
696         if (smb_fname->stream_name) {
697                 errno = ENOENT;
698                 return result;
699         }
700
701         result = ceph_statx(handle->data, smb_fname->base_name, &stx,
702                                 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
703         DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
704         if (result < 0) {
705                 WRAP_RETURN(result);
706         }
707         init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
708         return result;
709 }
710
711 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
712                          const struct smb_filename *smb_fname,
713                          struct smb_file_time *ft)
714 {
715         struct ceph_statx stx = { 0 };
716         int result;
717         int mask = 0;
718
719         if (!null_timespec(ft->atime)) {
720                 stx.stx_atime = ft->atime;
721                 mask |= CEPH_SETATTR_ATIME;
722         }
723         if (!null_timespec(ft->mtime)) {
724                 stx.stx_mtime = ft->mtime;
725                 mask |= CEPH_SETATTR_MTIME;
726         }
727         if (!null_timespec(ft->create_time)) {
728                 stx.stx_btime = ft->create_time;
729                 mask |= CEPH_SETATTR_BTIME;
730         }
731
732         if (!mask) {
733                 return 0;
734         }
735
736         result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
737         DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
738                                 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
739                                 ft->create_time.tv_sec, result);
740         return result;
741 }
742
743 #else /* HAVE_CEPH_STATX */
744
745 static int cephwrap_stat(struct vfs_handle_struct *handle,
746                         struct smb_filename *smb_fname)
747 {
748         int result = -1;
749         struct stat stbuf;
750
751         DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
752
753         if (smb_fname->stream_name) {
754                 errno = ENOENT;
755                 return result;
756         }
757
758         result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
759         DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
760         if (result < 0) {
761                 WRAP_RETURN(result);
762         } else {
763                 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
764                            "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
765                            "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
766                            llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
767                            stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
768                            llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
769         }
770         init_stat_ex_from_stat(
771                         &smb_fname->st, &stbuf,
772                         lp_fake_directory_create_times(SNUM(handle->conn)));
773         DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
774         return result;
775 }
776
777 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
778 {
779         int result = -1;
780         struct stat stbuf;
781
782         DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
783         result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
784         DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
785         if (result < 0) {
786                 WRAP_RETURN(result);
787         } else {
788                 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
789                            "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
790                            "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
791                            llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
792                            stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
793                            llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
794         }
795
796         init_stat_ex_from_stat(
797                         sbuf, &stbuf,
798                         lp_fake_directory_create_times(SNUM(handle->conn)));
799         DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
800         return result;
801 }
802
803 static int cephwrap_lstat(struct vfs_handle_struct *handle,
804                          struct smb_filename *smb_fname)
805 {
806         int result = -1;
807         struct stat stbuf;
808
809         DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
810
811         if (smb_fname->stream_name) {
812                 errno = ENOENT;
813                 return result;
814         }
815
816         result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
817         DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
818         if (result < 0) {
819                 WRAP_RETURN(result);
820         }
821         init_stat_ex_from_stat(
822                         &smb_fname->st, &stbuf,
823                         lp_fake_directory_create_times(SNUM(handle->conn)));
824         return result;
825 }
826
827 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
828                          const struct smb_filename *smb_fname,
829                          struct smb_file_time *ft)
830 {
831         struct utimbuf buf;
832         int result;
833
834         if (null_timespec(ft->atime)) {
835                 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
836         } else {
837                 buf.actime = ft->atime.tv_sec;
838         }
839         if (null_timespec(ft->mtime)) {
840                 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
841         } else {
842                 buf.modtime = ft->mtime.tv_sec;
843         }
844         if (!null_timespec(ft->create_time)) {
845                 set_create_timespec_ea(handle->conn, smb_fname,
846                                        ft->create_time);
847         }
848         if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
849             buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
850                 return 0;
851         }
852
853         result = ceph_utime(handle->data, smb_fname->base_name, &buf);
854         DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
855                                 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
856                                 ft->create_time.tv_sec, result);
857         return result;
858 }
859 #endif /* HAVE_CEPH_STATX */
860
861 static int cephwrap_unlink(struct vfs_handle_struct *handle,
862                           const struct smb_filename *smb_fname)
863 {
864         int result = -1;
865
866         DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
867         if (smb_fname->stream_name) {
868                 errno = ENOENT;
869                 return result;
870         }
871         result = ceph_unlink(handle->data, smb_fname->base_name);
872         DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
873         WRAP_RETURN(result);
874 }
875
876 static int cephwrap_chmod(struct vfs_handle_struct *handle,
877                         const struct smb_filename *smb_fname,
878                         mode_t mode)
879 {
880         int result;
881
882         DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
883
884         /*
885          * We need to do this due to the fact that the default POSIX ACL
886          * chmod modifies the ACL *mask* for the group owner, not the
887          * group owner bits directly. JRA.
888          */
889
890
891         {
892                 int saved_errno = errno; /* We might get ENOSYS */
893                 result = SMB_VFS_CHMOD_ACL(handle->conn,
894                                         smb_fname,
895                                         mode);
896                 if (result == 0) {
897                         return result;
898                 }
899                 /* Error - return the old errno. */
900                 errno = saved_errno;
901         }
902
903         result = ceph_chmod(handle->data, smb_fname->base_name, mode);
904         DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
905         WRAP_RETURN(result);
906 }
907
908 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
909 {
910         int result;
911
912         DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
913
914         /*
915          * We need to do this due to the fact that the default POSIX ACL
916          * chmod modifies the ACL *mask* for the group owner, not the
917          * group owner bits directly. JRA.
918          */
919
920         {
921                 int saved_errno = errno; /* We might get ENOSYS */
922                 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
923                         return result;
924                 }
925                 /* Error - return the old errno. */
926                 errno = saved_errno;
927         }
928
929 #if defined(HAVE_FCHMOD)
930         result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
931         DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
932         WRAP_RETURN(result);
933 #else
934         errno = ENOSYS;
935 #endif
936         return -1;
937 }
938
939 static int cephwrap_chown(struct vfs_handle_struct *handle,
940                         const struct smb_filename *smb_fname,
941                         uid_t uid,
942                         gid_t gid)
943 {
944         int result;
945         DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
946         result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
947         DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
948         WRAP_RETURN(result);
949 }
950
951 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
952 {
953         int result;
954 #ifdef HAVE_FCHOWN
955
956         DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
957         result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
958         DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
959         WRAP_RETURN(result);
960 #else
961         errno = ENOSYS;
962         result = -1;
963 #endif
964         return result;
965 }
966
967 static int cephwrap_lchown(struct vfs_handle_struct *handle,
968                         const struct smb_filename *smb_fname,
969                         uid_t uid,
970                         gid_t gid)
971 {
972         int result;
973         DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
974         result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
975         DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
976         WRAP_RETURN(result);
977 }
978
979 static int cephwrap_chdir(struct vfs_handle_struct *handle,
980                         const struct smb_filename *smb_fname)
981 {
982         int result = -1;
983         DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
984         result = ceph_chdir(handle->data, smb_fname->base_name);
985         DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
986         WRAP_RETURN(result);
987 }
988
989 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
990                         TALLOC_CTX *ctx)
991 {
992         const char *cwd = ceph_getcwd(handle->data);
993         DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
994         return synthetic_smb_fname(ctx,
995                                 cwd,
996                                 NULL,
997                                 NULL,
998                                 0);
999 }
1000
1001 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1002 {
1003         off_t space_to_write;
1004         uint64_t space_avail;
1005         uint64_t bsize,dfree,dsize;
1006         int ret;
1007         NTSTATUS status;
1008         SMB_STRUCT_STAT *pst;
1009
1010         status = vfs_stat_fsp(fsp);
1011         if (!NT_STATUS_IS_OK(status)) {
1012                 return -1;
1013         }
1014         pst = &fsp->fsp_name->st;
1015
1016 #ifdef S_ISFIFO
1017         if (S_ISFIFO(pst->st_ex_mode))
1018                 return 0;
1019 #endif
1020
1021         if (pst->st_ex_size == len)
1022                 return 0;
1023
1024         /* Shrink - just ftruncate. */
1025         if (pst->st_ex_size > len)
1026                 return ftruncate(fsp->fh->fd, len);
1027
1028         space_to_write = len - pst->st_ex_size;
1029
1030         /* for allocation try fallocate first. This can fail on some
1031            platforms e.g. when the filesystem doesn't support it and no
1032            emulation is being done by the libc (like on AIX with JFS1). In that
1033            case we do our own emulation. fallocate implementations can
1034            return ENOTSUP or EINVAL in cases like that. */
1035         ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1036         if (ret == -1 && errno == ENOSPC) {
1037                 return -1;
1038         }
1039         if (ret == 0) {
1040                 return 0;
1041         }
1042         DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1043                 "error %d. Falling back to slow manual allocation\n", errno));
1044
1045         /* available disk space is enough or not? */
1046         space_avail =
1047             get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1048         /* space_avail is 1k blocks */
1049         if (space_avail == (uint64_t)-1 ||
1050                         ((uint64_t)space_to_write/1024 > space_avail) ) {
1051                 errno = ENOSPC;
1052                 return -1;
1053         }
1054
1055         /* Write out the real space on disk. */
1056         return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1057 }
1058
1059 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1060 {
1061         int result = -1;
1062         SMB_STRUCT_STAT st;
1063         char c = 0;
1064         off_t currpos;
1065
1066         DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1067
1068         if (lp_strict_allocate(SNUM(fsp->conn))) {
1069                 result = strict_allocate_ftruncate(handle, fsp, len);
1070                 return result;
1071         }
1072
1073         /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1074            sys_ftruncate if the system supports it. Then I discovered that
1075            you can have some filesystems that support ftruncate
1076            expansion and some that don't! On Linux fat can't do
1077            ftruncate extend but ext2 can. */
1078
1079         result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1080         if (result == 0)
1081                 goto done;
1082
1083         /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1084            extend a file with ftruncate. Provide alternate implementation
1085            for this */
1086         currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1087         if (currpos == -1) {
1088                 goto done;
1089         }
1090
1091         /* Do an fstat to see if the file is longer than the requested
1092            size in which case the ftruncate above should have
1093            succeeded or shorter, in which case seek to len - 1 and
1094            write 1 byte of zero */
1095         if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1096                 goto done;
1097         }
1098
1099 #ifdef S_ISFIFO
1100         if (S_ISFIFO(st.st_ex_mode)) {
1101                 result = 0;
1102                 goto done;
1103         }
1104 #endif
1105
1106         if (st.st_ex_size == len) {
1107                 result = 0;
1108                 goto done;
1109         }
1110
1111         if (st.st_ex_size > len) {
1112                 /* the sys_ftruncate should have worked */
1113                 goto done;
1114         }
1115
1116         if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1117                 goto done;
1118
1119         if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1120                 goto done;
1121
1122         /* Seek to where we were */
1123         if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1124                 goto done;
1125         result = 0;
1126
1127   done:
1128
1129         return result;
1130 }
1131
1132 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1133 {
1134         DBG_DEBUG("[CEPH] lock\n");
1135         return true;
1136 }
1137
1138 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1139                                 uint32_t share_mode, uint32_t access_mask)
1140 {
1141         DBG_DEBUG("[CEPH] kernel_flock\n");
1142         /*
1143          * We must return zero here and pretend all is good.
1144          * One day we might have this in CEPH.
1145          */
1146         return 0;
1147 }
1148
1149 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1150 {
1151         DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1152
1153         errno = 0;
1154         return false;
1155 }
1156
1157 /*
1158  * We cannot let this fall through to the default, because the file might only
1159  * be accessible from libceph (which is a user-space client) but the fd might
1160  * be for some file the kernel knows about.
1161  */
1162 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1163                                 int leasetype)
1164 {
1165         int result = -1;
1166
1167         DBG_DEBUG("[CEPH] linux_setlease\n");
1168         errno = ENOSYS;
1169         return result;
1170 }
1171
1172 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1173                 const char *link_target,
1174                 const struct smb_filename *new_smb_fname)
1175 {
1176         int result = -1;
1177         DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1178                         link_target,
1179                         new_smb_fname->base_name);
1180         result = ceph_symlink(handle->data,
1181                         link_target,
1182                         new_smb_fname->base_name);
1183         DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1184         WRAP_RETURN(result);
1185 }
1186
1187 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1188                 const struct smb_filename *smb_fname,
1189                 char *buf,
1190                 size_t bufsiz)
1191 {
1192         int result = -1;
1193         DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1194                         smb_fname->base_name, buf, llu(bufsiz));
1195         result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1196         DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1197         WRAP_RETURN(result);
1198 }
1199
1200 static int cephwrap_link(struct vfs_handle_struct *handle,
1201                 const struct smb_filename *old_smb_fname,
1202                 const struct smb_filename *new_smb_fname)
1203 {
1204         int result = -1;
1205         DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1206                         old_smb_fname->base_name,
1207                         new_smb_fname->base_name);
1208         result = ceph_link(handle->data,
1209                                 old_smb_fname->base_name,
1210                                 new_smb_fname->base_name);
1211         DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1212         WRAP_RETURN(result);
1213 }
1214
1215 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1216                 const struct smb_filename *smb_fname,
1217                 mode_t mode,
1218                 SMB_DEV_T dev)
1219 {
1220         int result = -1;
1221         DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1222         result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1223         DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1224         WRAP_RETURN(result);
1225 }
1226
1227 /*
1228  * This is a simple version of real-path ... a better version is needed to
1229  * ask libceph about symbolic links.
1230  */
1231 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1232                                 TALLOC_CTX *ctx,
1233                                 const struct smb_filename *smb_fname)
1234 {
1235         char *result;
1236         const char *path = smb_fname->base_name;
1237         size_t len = strlen(path);
1238         struct smb_filename *result_fname = NULL;
1239
1240         result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1241         if (len && (path[0] == '/')) {
1242                 int r = asprintf(&result, "%s", path);
1243                 if (r < 0) return NULL;
1244         } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1245                 if (len == 2) {
1246                         int r = asprintf(&result, "%s",
1247                                         handle->conn->connectpath);
1248                         if (r < 0) return NULL;
1249                 } else {
1250                         int r = asprintf(&result, "%s/%s",
1251                                         handle->conn->connectpath, &path[2]);
1252                         if (r < 0) return NULL;
1253                 }
1254         } else {
1255                 int r = asprintf(&result, "%s/%s",
1256                                 handle->conn->connectpath, path);
1257                 if (r < 0) return NULL;
1258         }
1259         DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1260         result_fname = synthetic_smb_fname(ctx,
1261                                 result,
1262                                 NULL,
1263                                 NULL,
1264                                 0);
1265         SAFE_FREE(result);
1266         return result_fname;
1267 }
1268
1269 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1270                         const struct smb_filename *smb_fname,
1271                         unsigned int flags)
1272 {
1273         errno = ENOSYS;
1274         return -1;
1275 }
1276
1277 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1278                                      const char *path,
1279                                      const char *name,
1280                                      TALLOC_CTX *mem_ctx,
1281                                      char **found_name)
1282 {
1283         /*
1284          * Don't fall back to get_real_filename so callers can differentiate
1285          * between a full directory scan and an actual case-insensitive stat.
1286          */
1287         errno = EOPNOTSUPP;
1288         return -1;
1289 }
1290
1291 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1292                                        const struct smb_filename *smb_fname)
1293 {
1294         return handle->conn->connectpath;
1295 }
1296
1297 /****************************************************************
1298  Extended attribute operations.
1299 *****************************************************************/
1300
1301 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1302                         const struct smb_filename *smb_fname,
1303                         const char *name,
1304                         void *value,
1305                         size_t size)
1306 {
1307         int ret;
1308         DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1309                         smb_fname->base_name, name, value, llu(size));
1310         ret = ceph_getxattr(handle->data,
1311                         smb_fname->base_name, name, value, size);
1312         DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1313         if (ret < 0) {
1314                 WRAP_RETURN(ret);
1315         } else {
1316                 return (ssize_t)ret;
1317         }
1318 }
1319
1320 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1321 {
1322         int ret;
1323         DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1324 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1325         ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1326 #else
1327         ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1328 #endif
1329         DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1330         if (ret < 0) {
1331                 WRAP_RETURN(ret);
1332         } else {
1333                 return (ssize_t)ret;
1334         }
1335 }
1336
1337 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1338                         const struct smb_filename *smb_fname,
1339                         char *list,
1340                         size_t size)
1341 {
1342         int ret;
1343         DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1344                         smb_fname->base_name, list, llu(size));
1345         ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1346         DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1347         if (ret < 0) {
1348                 WRAP_RETURN(ret);
1349         } else {
1350                 return (ssize_t)ret;
1351         }
1352 }
1353
1354 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1355 {
1356         int ret;
1357         DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1358 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1359         ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1360 #else
1361         ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1362 #endif
1363         DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1364         if (ret < 0) {
1365                 WRAP_RETURN(ret);
1366         } else {
1367                 return (ssize_t)ret;
1368         }
1369 }
1370
1371 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1372                                 const struct smb_filename *smb_fname,
1373                                 const char *name)
1374 {
1375         int ret;
1376         DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1377                         smb_fname->base_name, name);
1378         ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1379         DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1380         WRAP_RETURN(ret);
1381 }
1382
1383 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1384 {
1385         int ret;
1386         DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1387 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1388         ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1389 #else
1390         ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1391 #endif
1392         DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1393         WRAP_RETURN(ret);
1394 }
1395
1396 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1397                                 const struct smb_filename *smb_fname,
1398                                 const char *name,
1399                                 const void *value,
1400                                 size_t size,
1401                                 int flags)
1402 {
1403         int ret;
1404         DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1405                         smb_fname->base_name, name, value, llu(size), flags);
1406         ret = ceph_setxattr(handle->data, smb_fname->base_name,
1407                         name, value, size, flags);
1408         DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1409         WRAP_RETURN(ret);
1410 }
1411
1412 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1413 {
1414         int ret;
1415         DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1416 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1417         ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1418                              name, value, size, flags);
1419 #else
1420         ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1421 #endif
1422         DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1423         WRAP_RETURN(ret);
1424 }
1425
1426 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1427 {
1428
1429         /*
1430          * We do not support AIO yet.
1431          */
1432
1433         DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1434         errno = ENOTSUP;
1435         return false;
1436 }
1437
1438 static struct vfs_fn_pointers ceph_fns = {
1439         /* Disk operations */
1440
1441         .connect_fn = cephwrap_connect,
1442         .disconnect_fn = cephwrap_disconnect,
1443         .disk_free_fn = cephwrap_disk_free,
1444         .get_quota_fn = cephwrap_get_quota,
1445         .set_quota_fn = cephwrap_set_quota,
1446         .statvfs_fn = cephwrap_statvfs,
1447         .fs_capabilities_fn = cephwrap_fs_capabilities,
1448
1449         /* Directory operations */
1450
1451         .opendir_fn = cephwrap_opendir,
1452         .fdopendir_fn = cephwrap_fdopendir,
1453         .readdir_fn = cephwrap_readdir,
1454         .seekdir_fn = cephwrap_seekdir,
1455         .telldir_fn = cephwrap_telldir,
1456         .rewind_dir_fn = cephwrap_rewinddir,
1457         .mkdir_fn = cephwrap_mkdir,
1458         .rmdir_fn = cephwrap_rmdir,
1459         .closedir_fn = cephwrap_closedir,
1460
1461         /* File operations */
1462
1463         .open_fn = cephwrap_open,
1464         .close_fn = cephwrap_close,
1465         .pread_fn = cephwrap_pread,
1466         .write_fn = cephwrap_write,
1467         .pwrite_fn = cephwrap_pwrite,
1468         .lseek_fn = cephwrap_lseek,
1469         .sendfile_fn = cephwrap_sendfile,
1470         .recvfile_fn = cephwrap_recvfile,
1471         .rename_fn = cephwrap_rename,
1472         .fsync_send_fn = cephwrap_fsync_send,
1473         .fsync_recv_fn = cephwrap_fsync_recv,
1474         .stat_fn = cephwrap_stat,
1475         .fstat_fn = cephwrap_fstat,
1476         .lstat_fn = cephwrap_lstat,
1477         .unlink_fn = cephwrap_unlink,
1478         .chmod_fn = cephwrap_chmod,
1479         .fchmod_fn = cephwrap_fchmod,
1480         .chown_fn = cephwrap_chown,
1481         .fchown_fn = cephwrap_fchown,
1482         .lchown_fn = cephwrap_lchown,
1483         .chdir_fn = cephwrap_chdir,
1484         .getwd_fn = cephwrap_getwd,
1485         .ntimes_fn = cephwrap_ntimes,
1486         .ftruncate_fn = cephwrap_ftruncate,
1487         .lock_fn = cephwrap_lock,
1488         .kernel_flock_fn = cephwrap_kernel_flock,
1489         .linux_setlease_fn = cephwrap_linux_setlease,
1490         .getlock_fn = cephwrap_getlock,
1491         .symlink_fn = cephwrap_symlink,
1492         .readlink_fn = cephwrap_readlink,
1493         .link_fn = cephwrap_link,
1494         .mknod_fn = cephwrap_mknod,
1495         .realpath_fn = cephwrap_realpath,
1496         .chflags_fn = cephwrap_chflags,
1497         .get_real_filename_fn = cephwrap_get_real_filename,
1498         .connectpath_fn = cephwrap_connectpath,
1499
1500         /* EA operations. */
1501         .getxattr_fn = cephwrap_getxattr,
1502         .fgetxattr_fn = cephwrap_fgetxattr,
1503         .listxattr_fn = cephwrap_listxattr,
1504         .flistxattr_fn = cephwrap_flistxattr,
1505         .removexattr_fn = cephwrap_removexattr,
1506         .fremovexattr_fn = cephwrap_fremovexattr,
1507         .setxattr_fn = cephwrap_setxattr,
1508         .fsetxattr_fn = cephwrap_fsetxattr,
1509
1510         /* Posix ACL Operations */
1511         .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1512         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1513         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1514         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1515         .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1516         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1517         .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1518
1519         /* aio operations */
1520         .aio_force_fn = cephwrap_aio_force,
1521 };
1522
1523 static_decl_vfs;
1524 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1525 {
1526         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1527                                 "ceph", &ceph_fns);
1528 }