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