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