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