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