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