s3: VFS: Change SMB_VFS_CHFLAGS to use const struct smb_filename * instead of const...
[kamenim/samba-autobuild/.git] / source3 / modules / vfs_catia.c
index d4420884dddd83f06b5102234b6f1d3b91e5127b..ed16e43aa38f4198d811d7ad14ed6cc776b3c4d0 100644 (file)
-/* 
+/*
  * Catia VFS module
  *
  * Implement a fixed mapping of forbidden NT characters in filenames that are
  * used a lot by the CAD package Catia.
  *
- * Yes, this a BAD BAD UGLY INCOMPLETE hack, but it helps quite some people
- * out there. Catia V4 on AIX uses characters like "<*$ a *lot*, all forbidden
- * under Windows...
+ * Catia V4 on AIX uses characters like "<*$ a *lot*, all forbidden under
+ * Windows...
  *
  * Copyright (C) Volker Lendecke, 2005
+ * Copyright (C) Aravind Srinivasan, 2009
+ * Copyright (C) Guenter Kukkukk, 2013
+ * Copyright (C) Ralph Boehme, 2017
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 
 #include "includes.h"
+#include "smbd/smbd.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
+
+static int vfs_catia_debug_level = DBGC_VFS;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_catia_debug_level
+
+#define GLOBAL_SNUM     0xFFFFFFF
+#define MAP_SIZE        0xFF
+#define MAP_NUM         0x101 /* max unicode charval / MAP_SIZE */
+#define T_OFFSET(_v_)   ((_v_ % MAP_SIZE))
+#define T_START(_v_)    (((_v_ / MAP_SIZE) * MAP_SIZE))
+#define T_PICK(_v_)     ((_v_ / MAP_SIZE))
+
+struct char_mappings {
+       smb_ucs2_t entry[MAP_SIZE][2];
+};
+
+struct share_mapping_entry {
+       int snum;
+       struct share_mapping_entry *next;
+       struct char_mappings **mappings;
+};
+
+struct catia_cache {
+       bool is_fsp_ext;
+       const struct catia_cache * const *busy;
+       char *orig_fname;
+       char *fname;
+       char *orig_base_fname;
+       char *base_fname;
+};
+
+struct share_mapping_entry *srt_head = NULL;
+
+static bool build_table(struct char_mappings **cmaps, int value)
+{
+       int i;
+       int start = T_START(value);
+
+       (*cmaps) = talloc_zero(NULL, struct char_mappings);
+
+       if (!*cmaps)
+               return False;
+
+       for (i = 0; i < MAP_SIZE;i++) {
+               (*cmaps)->entry[i][vfs_translate_to_unix] = start + i;
+               (*cmaps)->entry[i][vfs_translate_to_windows] = start + i;
+       }
+
+       return True;
+}
+
+static void set_tables(struct char_mappings **cmaps,
+                      long unix_map,
+                      long windows_map)
+{
+       int i;
+
+       /* set unix -> windows */
+       i = T_OFFSET(unix_map);
+       cmaps[T_PICK(unix_map)]->entry[i][vfs_translate_to_windows] = windows_map;
+
+       /* set windows -> unix */
+       i = T_OFFSET(windows_map);
+       cmaps[T_PICK(windows_map)]->entry[i][vfs_translate_to_unix] = unix_map;
+}
+
+static bool build_ranges(struct char_mappings **cmaps,
+                        long unix_map,
+                        long windows_map)
+{
+
+       if (!cmaps[T_PICK(unix_map)]) {
+               if (!build_table(&cmaps[T_PICK(unix_map)], unix_map))
+                       return False;
+       }
+
+       if (!cmaps[T_PICK(windows_map)]) {
+               if (!build_table(&cmaps[T_PICK(windows_map)], windows_map))
+                       return False;
+       }
+
+       set_tables(cmaps, unix_map, windows_map);
+
+       return True;
+}
+
+static struct share_mapping_entry *get_srt(connection_struct *conn,
+                                          struct share_mapping_entry **global)
+{
+       struct share_mapping_entry *share;
+
+       for (share = srt_head; share != NULL; share = share->next) {
+               if (share->snum == GLOBAL_SNUM)
+                       (*global) = share;
+
+               if (share->snum == SNUM(conn))
+                       return share;
+       }
+
+       return share;
+}
+
+static struct share_mapping_entry *add_srt(int snum, const char **mappings)
+{
+
+       char *tmp;
+       fstring mapping;
+       int i;
+       long unix_map, windows_map;
+       struct share_mapping_entry *ret = NULL;
+
+       ret = (struct share_mapping_entry *)
+               TALLOC_ZERO(NULL, sizeof(struct share_mapping_entry) +
+               (mappings ? (MAP_NUM * sizeof(struct char_mappings *)) : 0));
+
+       if (!ret)
+               return ret;
+
+       ret->snum = snum;
+
+       ret->next = srt_head;
+       srt_head = ret;
+
+       if (mappings) {
+               ret->mappings = (struct char_mappings**) ((unsigned char*) ret +
+                   sizeof(struct share_mapping_entry));
+               memset(ret->mappings, 0,
+                   MAP_NUM * sizeof(struct char_mappings *));
+       } else {
+               ret->mappings = NULL;
+               return ret;
+       }
+
+       /*
+        * catia mappings are of the form :
+        * UNIX char (in 0xnn hex) : WINDOWS char (in 0xnn hex)
+        *
+        * multiple mappings are comma separated in smb.conf
+        */
+       for (i=0;mappings[i];i++) {
+               fstrcpy(mapping, mappings[i]);
+               unix_map = strtol(mapping, &tmp, 16);
+               if (unix_map == 0 && errno == EINVAL) {
+                       DEBUG(0, ("INVALID CATIA MAPPINGS - %s\n", mapping));
+                       continue;
+               }
+               windows_map = strtol(++tmp, NULL, 16);
+               if (windows_map == 0 && errno == EINVAL) {
+                       DEBUG(0, ("INVALID CATIA MAPPINGS - %s\n", mapping));
+                       continue;
+               }
+
+               if (!build_ranges(ret->mappings, unix_map, windows_map)) {
+                       DEBUG(0, ("TABLE ERROR - CATIA MAPPINGS - %s\n", mapping));
+                       continue;
+               }
+       }
+
+       return ret;
+}
+
+static bool init_mappings(connection_struct *conn,
+                         struct share_mapping_entry **selected_out)
+{
+       const char **mappings = NULL;
+       struct share_mapping_entry *share_level = NULL;
+       struct share_mapping_entry *global = NULL;
+
+       /* check srt cache */
+       share_level = get_srt(conn, &global);
+       if (share_level) {
+               *selected_out = share_level;
+               return (share_level->mappings != NULL);
+       }
+
+       /* see if we have a global setting */
+       if (!global) {
+               /* global setting */
+               mappings = lp_parm_string_list(-1, "catia", "mappings", NULL);
+               global = add_srt(GLOBAL_SNUM, mappings);
+       }
+
+       /* no global setting - what about share level ? */
+       mappings = lp_parm_string_list(SNUM(conn), "catia", "mappings", NULL);
+       share_level = add_srt(SNUM(conn), mappings);
+
+       if (share_level->mappings) {
+               (*selected_out) = share_level;
+               return True;
+       }
+       if (global->mappings) {
+               share_level->mappings = global->mappings;
+               (*selected_out) = share_level;
+               return True;
+       }
+
+       return False;
+}
+
+static NTSTATUS catia_string_replace_allocate(connection_struct *conn,
+                                             const char *name_in,
+                                             char **mapped_name,
+                                       enum vfs_translate_direction direction)
+{
+       static smb_ucs2_t *tmpbuf = NULL;
+       smb_ucs2_t *ptr;
+       struct share_mapping_entry *selected;
+       struct char_mappings *map = NULL;
+       size_t converted_size;
+       TALLOC_CTX *ctx = talloc_tos();
+
+       if (!init_mappings(conn, &selected)) {
+               /* No mappings found. Just use the old name */
+               *mapped_name = talloc_strdup(NULL, name_in);
+               if (!*mapped_name) {
+                       errno = ENOMEM;
+                       return NT_STATUS_NO_MEMORY;
+               }
+               return NT_STATUS_OK;
+       }
+
+       if ((push_ucs2_talloc(ctx, &tmpbuf, name_in,
+                             &converted_size)) == false) {
+               return map_nt_error_from_unix(errno);
+       }
+       ptr = tmpbuf;
+       for(;*ptr;ptr++) {
+               if (*ptr == 0)
+                       break;
+               map = selected->mappings[T_PICK((*ptr))];
+
+               /* nothing to do */
+               if (!map)
+                       continue;
+
+               *ptr = map->entry[T_OFFSET((*ptr))][direction];
+       }
 
-static void catia_string_replace(char *s, unsigned char oldc, unsigned 
-                                char newc)
+       if ((pull_ucs2_talloc(ctx, mapped_name, tmpbuf,
+                             &converted_size)) == false) {
+               TALLOC_FREE(tmpbuf);
+               return map_nt_error_from_unix(errno);
+       }
+       TALLOC_FREE(tmpbuf);
+       return NT_STATUS_OK;
+}
+
+static DIR *catia_opendir(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       const char *mask,
+                       uint32_t attr)
 {
-        static smb_ucs2_t tmpbuf[sizeof(pstring)];
-        smb_ucs2_t *ptr = tmpbuf;
-        smb_ucs2_t old = oldc;
+       char *name_mapped = NULL;
+       NTSTATUS status;
+       DIR *ret;
+       struct smb_filename *mapped_smb_fname = NULL;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &name_mapped,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return NULL;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                               name_mapped,
+                               NULL,
+                               NULL,
+                               smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_smb_fname);
+               errno = ENOMEM;
+               return NULL;
+       }
 
-        push_ucs2(NULL, tmpbuf, s, sizeof(tmpbuf), STR_TERMINATE);
+       ret = SMB_VFS_NEXT_OPENDIR(handle, mapped_smb_fname, mask, attr);
 
-        for (;*ptr;ptr++)
-                if (*ptr==old) *ptr=newc;
+       TALLOC_FREE(name_mapped);
+       TALLOC_FREE(mapped_smb_fname);
 
-        pull_ucs2(NULL, s, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
+       return ret;
 }
 
-static void from_unix(char *s)
+/*
+ * TRANSLATE_NAME call which converts the given name to
+ * "WINDOWS displayable" name
+ */
+static NTSTATUS catia_translate_name(struct vfs_handle_struct *handle,
+                                    const char *orig_name,
+                                    enum vfs_translate_direction direction,
+                                    TALLOC_CTX *mem_ctx,
+                                    char **pmapped_name)
 {
-        catia_string_replace(s, '\x22', '\xa8');
-        catia_string_replace(s, '\x2a', '\xa4');
-        catia_string_replace(s, '\x2f', '\xf8');
-        catia_string_replace(s, '\x3a', '\xf7');
-        catia_string_replace(s, '\x3c', '\xab');
-        catia_string_replace(s, '\x3e', '\xbb');
-        catia_string_replace(s, '\x3f', '\xbf');
-        catia_string_replace(s, '\x5c', '\xff');
-        catia_string_replace(s, '\x7c', '\xa6');
-        catia_string_replace(s, ' ', '\xb1');
+       char *name = NULL;
+       char *mapped_name;
+       NTSTATUS status, ret;
+
+       /*
+        * Copy the supplied name and free the memory for mapped_name,
+        * already allocated by the caller.
+        * We will be allocating new memory for mapped_name in
+        * catia_string_replace_allocate
+        */
+       name = talloc_strdup(talloc_tos(), orig_name);
+       if (!name) {
+               errno = ENOMEM;
+               return NT_STATUS_NO_MEMORY;
+       }
+       status = catia_string_replace_allocate(handle->conn, name,
+                       &mapped_name, direction);
+
+       TALLOC_FREE(name);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       ret = SMB_VFS_NEXT_TRANSLATE_NAME(handle, mapped_name, direction,
+                                         mem_ctx, pmapped_name);
+
+       if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
+               *pmapped_name = talloc_move(mem_ctx, &mapped_name);
+               /* we need to return the former translation result here */
+               ret = status;
+       } else {
+               TALLOC_FREE(mapped_name);
+       }
+
+       return ret;
 }
 
-static void to_unix(char *s)
+#define CATIA_DEBUG_CC(lvl, cc, fsp) \
+       catia_debug_cc((lvl), (cc), (fsp), __location__);
+
+static void catia_debug_cc(int lvl,
+                          struct catia_cache *cc,
+                          files_struct *fsp,
+                          const char *location)
 {
-        catia_string_replace(s, '\xa8', '\x22');
-        catia_string_replace(s, '\xa4', '\x2a');
-        catia_string_replace(s, '\xf8', '\x2f');
-        catia_string_replace(s, '\xf7', '\x3a');
-        catia_string_replace(s, '\xab', '\x3c');
-        catia_string_replace(s, '\xbb', '\x3e');
-        catia_string_replace(s, '\xbf', '\x3f');
-        catia_string_replace(s, '\xff', '\x5c');
-        catia_string_replace(s, '\xa6', '\x7c');
-        catia_string_replace(s, '\xb1', ' ');
+       DEBUG(lvl, ("%s: cc [0x%p] cc->busy [0x%p] "
+                   "is_fsp_ext [%s] "
+                   "fsp [0x%p] fsp name [%s] "
+                   "orig_fname [%s] "
+                   "fname [%s] "
+                   "orig_base_fname [%s] "
+                   "base_fname [%s]\n",
+                   location,
+                   cc, cc->busy,
+                   cc->is_fsp_ext ? "yes" : "no",
+                   fsp, fsp_str_dbg(fsp),
+                   cc->orig_fname, cc->fname,
+                   cc->orig_base_fname, cc->base_fname));
 }
 
-static DIR *catia_opendir(vfs_handle_struct *handle, connection_struct 
-                         *conn, const char *fname, const char *mask, uint32 attr)
+static void catia_free_cc(struct catia_cache **_cc,
+                         vfs_handle_struct *handle,
+                         files_struct *fsp)
 {
-        pstring name;
-        pstrcpy(name, fname);
-        to_unix(name);
+       struct catia_cache *cc = *_cc;
+
+       if (cc->is_fsp_ext) {
+               VFS_REMOVE_FSP_EXTENSION(handle, fsp);
+               cc = NULL;
+       } else {
+               TALLOC_FREE(cc);
+       }
 
-        return SMB_VFS_NEXT_OPENDIR(handle, conn, name, mask, attr);
+       *_cc = NULL;
 }
 
-static SMB_STRUCT_DIRENT *catia_readdir(vfs_handle_struct *handle, 
-                                       connection_struct *conn, DIR *dirp)
+static struct catia_cache *catia_validate_and_apply_cc(
+                                      vfs_handle_struct *handle,
+                                      files_struct *fsp,
+                                      const struct catia_cache * const *busy,
+                                      bool *make_tmp_cache)
 {
-        SMB_STRUCT_DIRENT *result = SMB_VFS_NEXT_READDIR(handle, conn, dirp);
+       struct catia_cache *cc = NULL;
+
+       *make_tmp_cache = false;
+
+       cc = (struct catia_cache *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+       if (cc == NULL) {
+               return NULL;
+       }
+
+       if (cc->busy != NULL) {
+               if (cc->busy == busy) {
+                       /* This should never happen */
+                       CATIA_DEBUG_CC(0, cc, fsp);
+                       smb_panic(__location__);
+               }
+
+               /*
+                * Recursion. Validate names, the names in the fsp's should be
+                * the translated names we had set.
+                */
 
-        if (result == NULL)
-                return result;
+               if ((cc->fname != fsp->fsp_name->base_name)
+                   ||
+                   ((fsp->base_fsp != NULL) &&
+                    (cc->base_fname != fsp->base_fsp->fsp_name->base_name)))
+               {
+                       CATIA_DEBUG_CC(10, cc, fsp);
 
-        from_unix(result->d_name);
-        return result;
+                       /*
+                        * Names changed. Setting don't expose the cache on the
+                        * fsp and ask the caller to create a temporary cache.
+                        */
+                       *make_tmp_cache = true;
+                       return NULL;
+               }
+
+               /*
+                * Ok, a validated cache while in a recursion, just let the
+                * caller detect that cc->busy is != busy and there's
+                * nothing else to do.
+                */
+               CATIA_DEBUG_CC(10, cc, fsp);
+               return cc;
+       }
+
+       /* Not in a recursion */
+
+       if ((cc->orig_fname != fsp->fsp_name->base_name)
+           ||
+           ((fsp->base_fsp != NULL) &&
+            (cc->orig_base_fname != fsp->base_fsp->fsp_name->base_name)))
+       {
+               /*
+                * fsp names changed, this can happen in an rename op.
+                * Trigger recreation as a full fledged fsp extension.
+                */
+
+               CATIA_DEBUG_CC(10, cc, fsp);
+               catia_free_cc(&cc, handle, fsp);
+               return NULL;
+       }
+
+
+       /*
+        * Ok, we found a valid cache entry, no recursion. Just set translated
+        * names from the cache and mark the cc as busy.
+        */
+       fsp->fsp_name->base_name = cc->fname;
+       if (fsp->base_fsp != NULL) {
+               fsp->base_fsp->fsp_name->base_name = cc->base_fname;
+       }
+
+       cc->busy = busy;
+       CATIA_DEBUG_CC(10, cc, fsp);
+       return cc;
 }
 
-static int catia_open(vfs_handle_struct *handle, connection_struct *conn, 
-                     const char *fname, int flags, mode_t mode)
+#define CATIA_FETCH_FSP_PRE_NEXT(mem_ctx, handle, fsp, _cc) \
+       catia_fetch_fsp_pre_next((mem_ctx), (handle), (fsp), (_cc), __func__);
+
+static int catia_fetch_fsp_pre_next(TALLOC_CTX *mem_ctx,
+                                   vfs_handle_struct *handle,
+                                   files_struct *fsp,
+                                   struct catia_cache **_cc,
+                                   const char *function)
 {
-        pstring name;
+       const struct catia_cache * const *busy =
+               (const struct catia_cache * const *)_cc;
+       struct catia_cache *cc = NULL;
+       NTSTATUS status;
+       bool make_tmp_cache = false;
+
+       *_cc = NULL;
+
+       DBG_DEBUG("Called from [%s]\n", function);
+
+       cc = catia_validate_and_apply_cc(handle,
+                                        fsp,
+                                        busy,
+                                        &make_tmp_cache);
+       if (cc != NULL) {
+               if (cc->busy != busy) {
+                       return 0;
+               }
+               *_cc = cc;
+               return 0;
+       }
+
+       if (!make_tmp_cache) {
+               cc = (struct catia_cache *)VFS_ADD_FSP_EXTENSION(
+                       handle, fsp, struct catia_cache, NULL);
+               if (cc == NULL) {
+                       return -1;
+               }
+               *cc = (struct catia_cache) {
+                       .is_fsp_ext = true,
+               };
+
+               mem_ctx = VFS_MEMCTX_FSP_EXTENSION(handle, fsp);
+               if (mem_ctx == NULL) {
+                       DBG_ERR("VFS_MEMCTX_FSP_EXTENSION failed\n");
+                       catia_free_cc(&cc, handle, fsp);
+                       return -1;
+               }
+       } else {
+               cc = talloc_zero(mem_ctx, struct catia_cache);
+               if (cc == NULL) {
+                       return -1;
+               }
+               mem_ctx = cc;
+       }
+
+
+       status = catia_string_replace_allocate(handle->conn,
+                                              fsp->fsp_name->base_name,
+                                              &cc->fname,
+                                              vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               catia_free_cc(&cc, handle, fsp);
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+       talloc_steal(mem_ctx, cc->fname);
+
+       if (fsp->base_fsp != NULL) {
+               status = catia_string_replace_allocate(
+                       handle->conn,
+                       fsp->base_fsp->fsp_name->base_name,
+                       &cc->base_fname,
+                       vfs_translate_to_unix);
+               if (!NT_STATUS_IS_OK(status)) {
+                       catia_free_cc(&cc, handle, fsp);
+                       errno = map_errno_from_nt_status(status);
+                       return -1;
+               }
+               talloc_steal(mem_ctx, cc->base_fname);
+       }
 
-        pstrcpy(name, fname);
-        to_unix(name);
-        return SMB_VFS_NEXT_OPEN(handle, conn, name, flags, mode);
+       cc->orig_fname = fsp->fsp_name->base_name;
+       fsp->fsp_name->base_name = cc->fname;
+
+       if (fsp->base_fsp != NULL) {
+               cc->orig_base_fname = fsp->base_fsp->fsp_name->base_name;
+               fsp->base_fsp->fsp_name->base_name = cc->base_fname;
+       }
+
+       cc->busy = busy;
+       CATIA_DEBUG_CC(10, cc, fsp);
+
+       *_cc = cc;
+
+       return 0;
 }
 
-static int catia_rename(vfs_handle_struct *handle, connection_struct *conn,
-                       const char *oldname, const char *newname)
+#define CATIA_FETCH_FSP_POST_NEXT(_cc, fsp) do { \
+       int saved_errno = errno; \
+       catia_fetch_fsp_post_next((_cc), (fsp), __func__); \
+       errno = saved_errno; \
+} while(0)
+
+static void catia_fetch_fsp_post_next(struct catia_cache **_cc,
+                                     files_struct *fsp,
+                                     const char *function)
 {
-        pstring oname, nname;
+       const struct catia_cache * const *busy =
+               (const struct catia_cache * const *)_cc;
+       struct catia_cache *cc = *_cc;
+
+       DBG_DEBUG("Called from [%s]\n", function);
+
+       if (cc == NULL) {
+               /*
+                * This can happen when recursing in the VFS on the fsp when the
+                * pre_next func noticed the recursion and set out cc pointer to
+                * NULL.
+                */
+               return;
+       }
+
+       if (cc->busy != busy) {
+               CATIA_DEBUG_CC(0, cc, fsp);
+               smb_panic(__location__);
+               return;
+       }
 
-        pstrcpy(oname, oldname);
-        to_unix(oname);
-        pstrcpy(nname, newname);
-        to_unix(nname);
+       cc->busy = NULL;
+       *_cc = NULL;
 
-        DEBUG(10, ("converted old name: %s\n", oname));
-        DEBUG(10, ("converted new name: %s\n", nname));
-        return SMB_VFS_NEXT_RENAME(handle, conn, oname, nname);
+       fsp->fsp_name->base_name = cc->orig_fname;
+       if (fsp->base_fsp != NULL) {
+               fsp->base_fsp->fsp_name->base_name = cc->orig_base_fname;
+       }
+
+       CATIA_DEBUG_CC(10, cc, fsp);
+
+       if (!cc->is_fsp_ext) {
+               TALLOC_FREE(cc);
+       }
+
+       return;
 }
 
-static int catia_stat(vfs_handle_struct *handle, connection_struct *conn, 
-                     const char *fname, SMB_STRUCT_STAT *sbuf)
+static int catia_open(vfs_handle_struct *handle,
+                     struct smb_filename *smb_fname,
+                     files_struct *fsp,
+                     int flags,
+                     mode_t mode)
 {
-        pstring name;
-        pstrcpy(name, fname);
-        to_unix(name);
+       struct catia_cache *cc = NULL;
+       char *orig_smb_fname = smb_fname->base_name;
+       char *mapped_smb_fname = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn,
+                                              smb_fname->base_name,
+                                              &mapped_smb_fname,
+                                              vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               return -1;
+       }
 
-        return SMB_VFS_NEXT_STAT(handle, conn, name, sbuf);
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               TALLOC_FREE(mapped_smb_fname);
+               return ret;
+       }
+
+       smb_fname->base_name = mapped_smb_fname;
+       ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+       smb_fname->base_name = orig_smb_fname;
+
+       TALLOC_FREE(mapped_smb_fname);
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
 }
 
-static int catia_lstat(vfs_handle_struct *handle, connection_struct *conn, 
-                      const char *path, SMB_STRUCT_STAT *sbuf)
+static int catia_rename(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname_src,
+                       const struct smb_filename *smb_fname_dst)
 {
-        pstring name;
-        pstrcpy(name, path);
-        to_unix(name);
+       TALLOC_CTX *ctx = talloc_tos();
+       struct smb_filename *smb_fname_src_tmp = NULL;
+       struct smb_filename *smb_fname_dst_tmp = NULL;
+       char *src_name_mapped = NULL;
+       char *dst_name_mapped = NULL;
+       NTSTATUS status;
+       int ret = -1;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname_src->base_name,
+                               &src_name_mapped, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
 
-        return SMB_VFS_NEXT_LSTAT(handle, conn, name, sbuf);
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname_dst->base_name,
+                               &dst_name_mapped, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       /* Setup temporary smb_filename structs. */
+       smb_fname_src_tmp = cp_smb_filename(ctx, smb_fname_src);
+       if (smb_fname_src_tmp == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
+
+       smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
+       if (smb_fname_dst_tmp == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
+
+       smb_fname_src_tmp->base_name = src_name_mapped;
+       smb_fname_dst_tmp->base_name = dst_name_mapped; 
+       DEBUG(10, ("converted old name: %s\n",
+                               smb_fname_str_dbg(smb_fname_src_tmp)));
+       DEBUG(10, ("converted new name: %s\n",
+                               smb_fname_str_dbg(smb_fname_dst_tmp)));
+
+       ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_tmp,
+                       smb_fname_dst_tmp);
+out:
+       TALLOC_FREE(src_name_mapped);
+       TALLOC_FREE(dst_name_mapped);
+       TALLOC_FREE(smb_fname_src_tmp);
+       TALLOC_FREE(smb_fname_dst_tmp);
+       return ret;
 }
 
-static int catia_unlink(vfs_handle_struct *handle, connection_struct *conn,
-                       const char *path)
+static int catia_stat(vfs_handle_struct *handle,
+                     struct smb_filename *smb_fname)
 {
-        pstring name;
-        pstrcpy(name, path);
-        to_unix(name);
+       char *name = NULL;
+       char *tmp_base_name;
+       int ret;
+       NTSTATUS status;
 
-        return SMB_VFS_NEXT_UNLINK(handle, conn, name);
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       tmp_base_name = smb_fname->base_name;
+       smb_fname->base_name = name;
+
+       ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+       smb_fname->base_name = tmp_base_name;
+
+       TALLOC_FREE(name);
+       return ret;
 }
 
-static int catia_chmod(vfs_handle_struct *handle, connection_struct *conn, 
-                      const char *path, mode_t mode)
+static int catia_lstat(vfs_handle_struct *handle,
+                      struct smb_filename *smb_fname)
 {
-        pstring name;
-        pstrcpy(name, path);
-        to_unix(name);
+       char *name = NULL;
+       char *tmp_base_name;
+       int ret;
+       NTSTATUS status;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
 
-        return SMB_VFS_NEXT_CHMOD(handle, conn, name, mode);
+       tmp_base_name = smb_fname->base_name;
+       smb_fname->base_name = name;
+
+       ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+       smb_fname->base_name = tmp_base_name;
+       TALLOC_FREE(name);
+
+       return ret;
 }
 
-static int catia_chown(vfs_handle_struct *handle, connection_struct *conn, 
-                      const char *path, uid_t uid, gid_t gid)
+static int catia_unlink(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname)
 {
-        pstring name;
-        pstrcpy(name, path);
-        to_unix(name);
+       struct smb_filename *smb_fname_tmp = NULL;
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn,
+                                       smb_fname->base_name,
+                                       &name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       /* Setup temporary smb_filename structs. */
+       smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
+       if (smb_fname_tmp == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
 
-        return SMB_VFS_NEXT_CHOWN(handle, conn, name, uid, gid);
+       smb_fname_tmp->base_name = name;
+       ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
+       TALLOC_FREE(smb_fname_tmp);
+       TALLOC_FREE(name);
+
+       return ret;
 }
 
-static int catia_chdir(vfs_handle_struct *handle, connection_struct *conn, 
+static int catia_chown(vfs_handle_struct *handle,
+                      const struct smb_filename *smb_fname,
+                      uid_t uid,
+                      gid_t gid)
+{
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+       int saved_errno;
+       struct smb_filename *catia_smb_fname = NULL;
+
+       status = catia_string_replace_allocate(handle->conn,
+                                       smb_fname->base_name,
+                                       &name,
+                                       vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+       catia_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (catia_smb_fname == NULL) {
+               TALLOC_FREE(name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_CHOWN(handle, catia_smb_fname, uid, gid);
+       saved_errno = errno;
+       TALLOC_FREE(name);
+       TALLOC_FREE(catia_smb_fname);
+       errno = saved_errno;
+       return ret;
+}
+
+static int catia_lchown(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       uid_t uid,
+                       gid_t gid)
+{
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+       int saved_errno;
+       struct smb_filename *catia_smb_fname = NULL;
+
+       status = catia_string_replace_allocate(handle->conn,
+                                       smb_fname->base_name,
+                                       &name,
+                                       vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+       catia_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (catia_smb_fname == NULL) {
+               TALLOC_FREE(name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_LCHOWN(handle, catia_smb_fname, uid, gid);
+       saved_errno = errno;
+       TALLOC_FREE(name);
+       TALLOC_FREE(catia_smb_fname);
+       errno = saved_errno;
+       return ret;
+}
+
+static int catia_chmod(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       mode_t mode)
+{
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+       int saved_errno;
+       struct smb_filename *catia_smb_fname = NULL;
+
+       status = catia_string_replace_allocate(handle->conn,
+                                       smb_fname->base_name,
+                                       &name,
+                                       vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+       catia_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (catia_smb_fname == NULL) {
+               TALLOC_FREE(name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_CHMOD(handle, catia_smb_fname, mode);
+       saved_errno = errno;
+       TALLOC_FREE(name);
+       TALLOC_FREE(catia_smb_fname);
+       errno = saved_errno;
+       return ret;
+}
+
+static int catia_rmdir(vfs_handle_struct *handle,
+                      const struct smb_filename *smb_fname)
+{
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+       struct smb_filename *catia_smb_fname = NULL;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+       catia_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (catia_smb_fname == NULL) {
+               TALLOC_FREE(name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_RMDIR(handle, catia_smb_fname);
+       TALLOC_FREE(name);
+       TALLOC_FREE(catia_smb_fname);
+
+       return ret;
+}
+
+static int catia_mkdir(vfs_handle_struct *handle,
+                      const struct smb_filename *smb_fname,
+                      mode_t mode)
+{
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+       struct smb_filename *catia_smb_fname = NULL;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+       catia_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (catia_smb_fname == NULL) {
+               TALLOC_FREE(name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_MKDIR(handle, catia_smb_fname, mode);
+       TALLOC_FREE(name);
+       TALLOC_FREE(catia_smb_fname);
+
+       return ret;
+}
+
+static int catia_chdir(vfs_handle_struct *handle,
                       const char *path)
 {
-        pstring name;
-        pstrcpy(name, path);
-        to_unix(name);
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn, path,
+                                       &name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_CHDIR(handle, name);
+       TALLOC_FREE(name);
+
+       return ret;
+}
+
+static int catia_ntimes(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       struct smb_file_time *ft)
+{
+       struct smb_filename *smb_fname_tmp = NULL;
+       char *name = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
+       if (smb_fname_tmp == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       smb_fname_tmp->base_name = name;
+       ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
+       TALLOC_FREE(name);
+       TALLOC_FREE(smb_fname_tmp);
+
+       return ret;
+}
+
+static char *
+catia_realpath(vfs_handle_struct *handle, const char *path)
+{
+       char *mapped_name = NULL;
+       NTSTATUS status;
+       char *ret = NULL;
+
+       status = catia_string_replace_allocate(handle->conn, path,
+                                       &mapped_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return NULL;
+       }
+
+       ret = SMB_VFS_NEXT_REALPATH(handle, mapped_name);
+       TALLOC_FREE(mapped_name);
+
+       return ret;
+}
+
+static int catia_chflags(struct vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       unsigned int flags)
+{
+       char *name = NULL;
+       struct smb_filename *catia_smb_fname = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+       catia_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (catia_smb_fname == NULL) {
+               TALLOC_FREE(name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_CHFLAGS(handle, catia_smb_fname, flags);
+       TALLOC_FREE(name);
+       TALLOC_FREE(catia_smb_fname);
+
+       return ret;
+}
+
+static NTSTATUS
+catia_streaminfo(struct vfs_handle_struct *handle,
+                struct files_struct *fsp,
+                const struct smb_filename *smb_fname,
+                TALLOC_CTX *mem_ctx,
+                unsigned int *_num_streams,
+                struct stream_struct **_streams)
+{
+       char *mapped_name = NULL;
+       NTSTATUS status;
+       unsigned int i;
+       struct smb_filename *catia_smb_fname = NULL;
+       unsigned int num_streams = 0;
+       struct stream_struct *streams = NULL;
+
+       *_num_streams = 0;
+       *_streams = NULL;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return status;
+       }
+
+       catia_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (catia_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, catia_smb_fname,
+                                        mem_ctx, &num_streams, &streams);
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(catia_smb_fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /*
+        * Translate stream names just like the base names
+        */
+       for (i = 0; i < num_streams; i++) {
+               /*
+                * Strip ":" prefix and ":$DATA" suffix to get a
+                * "pure" stream name and only translate that.
+                */
+               void *old_ptr = streams[i].name;
+               char *stream_name = streams[i].name + 1;
+               char *stream_type = strrchr_m(stream_name, ':');
+
+               if (stream_type != NULL) {
+                       *stream_type = '\0';
+                       stream_type += 1;
+               }
+
+               status = catia_string_replace_allocate(handle->conn, stream_name,
+                                                      &mapped_name, vfs_translate_to_windows);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(streams);
+                       return status;
+               }
+
+               if (stream_type != NULL) {
+                       streams[i].name = talloc_asprintf(streams, ":%s:%s",
+                                                         mapped_name, stream_type);
+               } else {
+                       streams[i].name = talloc_asprintf(streams, ":%s",
+                                                         mapped_name);
+               }
+               TALLOC_FREE(mapped_name);
+               TALLOC_FREE(old_ptr);
+               if (streams[i].name == NULL) {
+                       TALLOC_FREE(streams);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       *_num_streams = num_streams;
+       *_streams = streams;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS
+catia_get_nt_acl(struct vfs_handle_struct *handle,
+                const struct smb_filename *smb_fname,
+                uint32_t security_info,
+                TALLOC_CTX *mem_ctx,
+                struct security_descriptor **ppdesc)
+{
+       char *mapped_name = NULL;
+       const char *path = smb_fname->base_name;
+       struct smb_filename *mapped_smb_fname = NULL;
+       NTSTATUS status;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               path, &mapped_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return status;
+       }
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = SMB_VFS_NEXT_GET_NT_ACL(handle, mapped_smb_fname,
+                                        security_info, mem_ctx, ppdesc);
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_smb_fname);
+
+       return status;
+}
+
+static int
+catia_chmod_acl(vfs_handle_struct *handle,
+               const struct smb_filename *smb_fname,
+               mode_t mode)
+{
+       char *mapped_name = NULL;
+       struct smb_filename *mapped_smb_fname = NULL;
+       NTSTATUS status;
+       int ret;
+       int saved_errno;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               errno = ENOMEM;
+               return -1;
+       }
+       ret = SMB_VFS_NEXT_CHMOD_ACL(handle, mapped_smb_fname, mode);
+       saved_errno = errno;
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_smb_fname);
+       errno = saved_errno;
+       return ret;
+}
+
+static SMB_ACL_T
+catia_sys_acl_get_file(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       SMB_ACL_TYPE_T type,
+                       TALLOC_CTX *mem_ctx)
+{
+       char *mapped_name = NULL;
+       struct smb_filename *mapped_smb_fname = NULL;
+       NTSTATUS status;
+       SMB_ACL_T ret;
+       int saved_errno = 0;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return (SMB_ACL_T)NULL;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               errno = ENOMEM;
+               return (SMB_ACL_T)NULL;
+       }
+
+       ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, mapped_smb_fname,
+                       type, mem_ctx);
+       if (ret == (SMB_ACL_T)NULL) {
+               saved_errno = errno;
+       }
+       TALLOC_FREE(mapped_smb_fname);
+       TALLOC_FREE(mapped_name);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+       return ret;
+}
+
+static int
+catia_sys_acl_set_file(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       SMB_ACL_TYPE_T type,
+                       SMB_ACL_T theacl)
+{
+       struct smb_filename *mapped_smb_fname = NULL;
+       int saved_errno = 0;
+       char *mapped_name = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, mapped_smb_fname,
+                       type, theacl);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+       TALLOC_FREE(mapped_smb_fname);
+       TALLOC_FREE(mapped_name);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+       return ret;
+}
+
+static int
+catia_sys_acl_delete_def_file(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname)
+{
+       struct smb_filename *mapped_smb_fname = NULL;
+       int saved_errno = 0;
+       char *mapped_name = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               errno = ENOMEM;
+               return -1;
+       }
+       ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, mapped_smb_fname);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+       TALLOC_FREE(mapped_smb_fname);
+       TALLOC_FREE(mapped_name);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+       return ret;
+}
+
+static ssize_t
+catia_getxattr(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       const char *name,
+                       void *value,
+                       size_t size)
+{
+       struct smb_filename *mapped_smb_fname = NULL;
+       char *mapped_name = NULL;
+       char *mapped_ea_name = NULL;
+       NTSTATUS status;
+       ssize_t ret;
+       int saved_errno = 0;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       status = catia_string_replace_allocate(handle->conn,
+                               name, &mapped_ea_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(mapped_name);
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               TALLOC_FREE(mapped_ea_name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_GETXATTR(handle, mapped_smb_fname,
+                               mapped_ea_name, value, size);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_ea_name);
+       TALLOC_FREE(mapped_smb_fname);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+
+       return ret;
+}
+
+static ssize_t
+catia_listxattr(vfs_handle_struct *handle,
+               const struct smb_filename *smb_fname,
+               char *list, size_t size)
+{
+       struct smb_filename *mapped_smb_fname = NULL;
+       char *mapped_name = NULL;
+       NTSTATUS status;
+       ssize_t ret;
+       int saved_errno = 0;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_LISTXATTR(handle, mapped_smb_fname, list, size);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_smb_fname);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+
+       return ret;
+}
+
+static int
+catia_removexattr(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       const char *name)
+{
+       struct smb_filename *mapped_smb_fname = NULL;
+       char *mapped_name = NULL;
+       char *mapped_ea_name = NULL;
+       NTSTATUS status;
+       ssize_t ret;
+       int saved_errno = 0;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       status = catia_string_replace_allocate(handle->conn,
+                               name, &mapped_ea_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(mapped_name);
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               TALLOC_FREE(mapped_ea_name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_REMOVEXATTR(handle, mapped_smb_fname,
+                               mapped_ea_name);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_ea_name);
+       TALLOC_FREE(mapped_smb_fname);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+
+       return ret;
+}
+
+static int
+catia_setxattr(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       const char *name,
+                       const void *value,
+                       size_t size,
+                       int flags)
+{
+       struct smb_filename *mapped_smb_fname = NULL;
+       char *mapped_name = NULL;
+       char *mapped_ea_name = NULL;
+       NTSTATUS status;
+       ssize_t ret;
+       int saved_errno = 0;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               smb_fname->base_name,
+                               &mapped_name,
+                               vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       status = catia_string_replace_allocate(handle->conn,
+                               name, &mapped_ea_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(mapped_name);
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               TALLOC_FREE(mapped_ea_name);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_SETXATTR(handle, mapped_smb_fname, mapped_ea_name,
+                       value, size, flags);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_ea_name);
+       TALLOC_FREE(mapped_smb_fname);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+
+       return ret;
+}
+
+static int catia_fstat(vfs_handle_struct *handle,
+                      files_struct *fsp,
+                      SMB_STRUCT_STAT *sbuf)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
+}
+
+static ssize_t catia_pread(vfs_handle_struct *handle,
+                          files_struct *fsp, void *data,
+                          size_t n, off_t offset)
+{
+       struct catia_cache *cc = NULL;
+       ssize_t result;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static ssize_t catia_pwrite(vfs_handle_struct *handle,
+                           files_struct *fsp, const void *data,
+                           size_t n, off_t offset)
+{
+       struct catia_cache *cc = NULL;
+       ssize_t result;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static int catia_ftruncate(struct vfs_handle_struct *handle,
+                          struct files_struct *fsp,
+                          off_t offset)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
+}
+
+static int catia_fallocate(struct vfs_handle_struct *handle,
+                          struct files_struct *fsp,
+                          uint32_t mode,
+                          off_t offset,
+                          off_t len)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
 
-        return SMB_VFS_NEXT_CHDIR(handle, conn, name);
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
 }
 
-static char *catia_getwd(vfs_handle_struct *handle, connection_struct *conn,
-                        char *buf)
+static ssize_t catia_fgetxattr(struct vfs_handle_struct *handle,
+                              struct files_struct *fsp,
+                              const char *name,
+                              void *value,
+                              size_t size)
 {
-        return SMB_VFS_NEXT_GETWD(handle, conn, buf);
+       char *mapped_xattr_name = NULL;
+       NTSTATUS status;
+       ssize_t result;
+
+       status = catia_string_replace_allocate(handle->conn,
+                                              name, &mapped_xattr_name,
+                                              vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, mapped_xattr_name,
+                                       value, size);
+
+       TALLOC_FREE(mapped_xattr_name);
+
+       return result;
 }
 
-static int catia_utime(vfs_handle_struct *handle, connection_struct *conn, 
-                      const char *path, struct utimbuf *times)
+static ssize_t catia_flistxattr(struct vfs_handle_struct *handle,
+                               struct files_struct *fsp,
+                               char *list,
+                               size_t size)
 {
-        return SMB_VFS_NEXT_UTIME(handle, conn, path, times);
+       struct catia_cache *cc = NULL;
+       ssize_t result;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static int catia_fremovexattr(struct vfs_handle_struct *handle,
+                             struct files_struct *fsp,
+                             const char *name)
+{
+       char *mapped_name = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               name, &mapped_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, mapped_name);
+
+       TALLOC_FREE(mapped_name);
+
+       return ret;
+}
+
+static int catia_fsetxattr(struct vfs_handle_struct *handle,
+                          struct files_struct *fsp,
+                          const char *name,
+                          const void *value,
+                          size_t size,
+                          int flags)
+{
+       char *mapped_xattr_name = NULL;
+       NTSTATUS status;
+       int ret;
+
+       status = catia_string_replace_allocate(
+               handle->conn, name, &mapped_xattr_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, mapped_xattr_name,
+                                    value, size, flags);
+
+       TALLOC_FREE(mapped_xattr_name);
+
+       return ret;
+}
+
+static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle,
+                                     files_struct *fsp,
+                                     TALLOC_CTX *mem_ctx)
+{
+       struct catia_cache *cc = NULL;
+       struct smb_acl_t *result = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return NULL;
+       }
+
+       result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static int catia_sys_acl_blob_get_fd(vfs_handle_struct *handle,
+                                    files_struct *fsp,
+                                    TALLOC_CTX *mem_ctx,
+                                    char **blob_description,
+                                    DATA_BLOB *blob)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
+                                              blob_description, blob);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
 }
 
-static BOOL catia_symlink(vfs_handle_struct *handle, connection_struct *conn,
-                         const char *oldpath, const char *newpath)
+static int catia_sys_acl_set_fd(vfs_handle_struct *handle,
+                               files_struct *fsp,
+                               SMB_ACL_T theacl)
 {
-        return SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath);
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
 }
 
-static BOOL catia_readlink(vfs_handle_struct *handle, connection_struct *conn,
-                          const char *path, char *buf, size_t bufsiz)
+static int catia_fchmod_acl(vfs_handle_struct *handle,
+                           files_struct *fsp,
+                           mode_t mode)
 {
-        return SMB_VFS_NEXT_READLINK(handle, conn, path, buf, bufsiz);
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
 }
 
-static int catia_link(vfs_handle_struct *handle, connection_struct *conn, 
-                     const char *oldpath, const char *newpath)
+static NTSTATUS catia_fget_nt_acl(vfs_handle_struct *handle,
+                                 files_struct *fsp,
+                                 uint32_t security_info,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct security_descriptor **ppdesc)
 {
-        return SMB_VFS_NEXT_LINK(handle, conn, oldpath, newpath);
+       struct catia_cache *cc = NULL;
+       NTSTATUS status;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
+                                         mem_ctx, ppdesc);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return status;
 }
 
-static int catia_mknod(vfs_handle_struct *handle, connection_struct *conn, 
-                      const char *path, mode_t mode, SMB_DEV_T dev)
+static NTSTATUS catia_fset_nt_acl(vfs_handle_struct *handle,
+                                 files_struct *fsp,
+                                 uint32_t security_info_sent,
+                                 const struct security_descriptor *psd)
 {
-        return SMB_VFS_NEXT_MKNOD(handle, conn, path, mode, dev);
+       struct catia_cache *cc = NULL;
+       NTSTATUS status;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return status;
 }
 
-static char *catia_realpath(vfs_handle_struct *handle, connection_struct *conn,
-                           const char *path, char *resolved_path)
+static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle,
+                                         struct files_struct *fsp,
+                                         uint32_t dosmode)
 {
-        return SMB_VFS_NEXT_REALPATH(handle, conn, path, resolved_path);
+       struct catia_cache *cc = NULL;
+       NTSTATUS status;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return status;
 }
 
-static size_t catia_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
-                              const char *name, uint32 security_info,
-                              struct  security_descriptor_info **ppdesc)
+static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle,
+                                         struct files_struct *fsp,
+                                         uint32_t *dosmode)
 {
-        return SMB_VFS_NEXT_GET_NT_ACL(handle, fsp, name, security_info,
-                                      ppdesc);
+       struct catia_cache *cc = NULL;
+       NTSTATUS status;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return status;
 }
 
-static BOOL catia_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, 
-                            const char *name, uint32 security_info_sent,
-                            struct security_descriptor_info *psd)
+static int catia_fchown(vfs_handle_struct *handle,
+                       files_struct *fsp,
+                       uid_t uid,
+                       gid_t gid)
 {
-        return SMB_VFS_NEXT_SET_NT_ACL(handle, fsp, name, security_info_sent,
-                                      psd);
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
 }
 
-static int catia_chmod_acl(vfs_handle_struct *handle, connection_struct *conn,
-                          const char *name, mode_t mode)
+static int catia_fchmod(vfs_handle_struct *handle,
+                       files_struct *fsp,
+                       mode_t mode)
 {
-        /* If the underlying VFS doesn't have ACL support... */
-        if (!handle->vfs_next.ops.chmod_acl) {
-                errno = ENOSYS;
-                return -1;
-        }
-        return SMB_VFS_NEXT_CHMOD_ACL(handle, conn, name, mode);
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
 }
 
-/* VFS operations structure */
+struct catia_pread_state {
+       ssize_t ret;
+       struct vfs_aio_state vfs_aio_state;
+       struct files_struct *fsp;
+       struct catia_cache *cc;
+};
+
+static void catia_pread_done(struct tevent_req *subreq);
+
+static struct tevent_req *catia_pread_send(struct vfs_handle_struct *handle,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct files_struct *fsp,
+                                          void *data,
+                                          size_t n,
+                                          off_t offset)
+{
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct catia_pread_state *state = NULL;
+       int ret;
 
-static vfs_op_tuple catia_op_tuples[] = {
+       req = tevent_req_create(mem_ctx, &state,
+                               struct catia_pread_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->fsp = fsp;
 
-        /* Directory operations */
+       ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
+       if (ret != 0) {
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
 
-        {SMB_VFS_OP(catia_opendir), SMB_VFS_OP_OPENDIR, 
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_readdir), SMB_VFS_OP_READDIR, 
-SMB_VFS_LAYER_TRANSPARENT},
+       subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
+                                        n, offset);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, catia_pread_done, req);
 
-        /* File operations */
+       return req;
+}
+
+static void catia_pread_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct catia_pread_state *state = tevent_req_data(
+               req, struct catia_pread_state);
 
-        {SMB_VFS_OP(catia_open), SMB_VFS_OP_OPEN, 
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_rename),                      SMB_VFS_OP_RENAME, 
-        SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_stat), SMB_VFS_OP_STAT, 
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_lstat),                       SMB_VFS_OP_LSTAT,  
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_unlink),                      SMB_VFS_OP_UNLINK, 
-        SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_chmod),                       SMB_VFS_OP_CHMOD,  
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_chown),                       SMB_VFS_OP_CHOWN,  
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_chdir),                       SMB_VFS_OP_CHDIR,  
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_getwd),                       SMB_VFS_OP_GETWD,  
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_utime),                       SMB_VFS_OP_UTIME,  
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_symlink), SMB_VFS_OP_SYMLINK, 
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_readlink), SMB_VFS_OP_READLINK, 
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_link), SMB_VFS_OP_LINK, 
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_mknod),                       SMB_VFS_OP_MKNOD,  
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_realpath), SMB_VFS_OP_REALPATH, 
-SMB_VFS_LAYER_TRANSPARENT},
+       state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
 
-        /* NT File ACL operations */
+       CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
 
-        {SMB_VFS_OP(catia_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, 
-SMB_VFS_LAYER_TRANSPARENT},
-        {SMB_VFS_OP(catia_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, 
-SMB_VFS_LAYER_TRANSPARENT},
+       tevent_req_done(req);
+}
 
-        /* POSIX ACL operations */
+static ssize_t catia_pread_recv(struct tevent_req *req,
+                               struct vfs_aio_state *vfs_aio_state)
+{
+       struct catia_pread_state *state = tevent_req_data(
+               req, struct catia_pread_state);
 
-        {SMB_VFS_OP(catia_chmod_acl), SMB_VFS_OP_CHMOD_ACL, 
-SMB_VFS_LAYER_TRANSPARENT},
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
 
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
+}
 
-        {NULL,                                          SMB_VFS_OP_NOOP,   
-SMB_VFS_LAYER_NOOP}
+struct catia_pwrite_state {
+       ssize_t ret;
+       struct vfs_aio_state vfs_aio_state;
+       struct files_struct *fsp;
+       struct catia_cache *cc;
 };
 
-NTSTATUS init_module(void)
+static void catia_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *catia_pwrite_send(struct vfs_handle_struct *handle,
+                                           TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           struct files_struct *fsp,
+                                           const void *data,
+                                           size_t n,
+                                           off_t offset)
 {
-        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia", 
-catia_op_tuples);
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct catia_pwrite_state *state = NULL;
+       int ret;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct catia_pwrite_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->fsp = fsp;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
+       if (ret != 0) {
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
+                                         n, offset);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, catia_pwrite_done, req);
+
+       return req;
+}
+
+static void catia_pwrite_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct catia_pwrite_state *state = tevent_req_data(
+               req, struct catia_pwrite_state);
+
+       state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+
+       CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
+
+       tevent_req_done(req);
+}
+
+static ssize_t catia_pwrite_recv(struct tevent_req *req,
+                               struct vfs_aio_state *vfs_aio_state)
+{
+       struct catia_pwrite_state *state = tevent_req_data(
+               req, struct catia_pwrite_state);
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
+
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
+}
+
+static off_t catia_lseek(vfs_handle_struct *handle,
+                        files_struct *fsp,
+                        off_t offset,
+                        int whence)
+{
+       struct catia_cache *cc = NULL;
+       ssize_t result;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return -1;
+       }
+
+       result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static int catia_fsync(vfs_handle_struct *handle, files_struct *fsp)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_FSYNC(handle, fsp);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
+}
+
+struct catia_fsync_state {
+       int ret;
+       struct vfs_aio_state vfs_aio_state;
+       struct files_struct *fsp;
+       struct catia_cache *cc;
+};
+
+static void catia_fsync_done(struct tevent_req *subreq);
+
+static struct tevent_req *catia_fsync_send(struct vfs_handle_struct *handle,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct files_struct *fsp)
+{
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct catia_fsync_state *state = NULL;
+       int ret;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct catia_fsync_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->fsp = fsp;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
+       if (ret != 0) {
+               tevent_req_error(req, errno);
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, catia_fsync_done, req);
+
+       return req;
+}
+
+static void catia_fsync_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct catia_fsync_state *state = tevent_req_data(
+               req, struct catia_fsync_state);
+
+       state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+
+       CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
+
+       tevent_req_done(req);
+}
+
+static int catia_fsync_recv(struct tevent_req *req,
+                           struct vfs_aio_state *vfs_aio_state)
+{
+       struct catia_fsync_state *state = tevent_req_data(
+               req, struct catia_fsync_state);
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
+
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
+}
+
+static bool catia_lock(vfs_handle_struct *handle,
+                      files_struct *fsp,
+                      int op,
+                      off_t offset,
+                      off_t count,
+                      int type)
+{
+       struct catia_cache *cc = NULL;
+       bool ok;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return -1;
+       }
+
+       ok = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ok;
+}
+
+static int catia_kernel_flock(struct vfs_handle_struct *handle,
+                             struct files_struct *fsp,
+                             uint32_t share_mode,
+                             uint32_t access_mask)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode, access_mask);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
+}
+
+static int catia_linux_setlease(vfs_handle_struct *handle,
+                               files_struct *fsp,
+                               int leasetype)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ret;
+}
+
+static bool catia_getlock(vfs_handle_struct *handle,
+                         files_struct *fsp,
+                         off_t *poffset,
+                         off_t *pcount,
+                         int *ptype,
+                         pid_t *ppid)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+       bool ok;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return -1;
+       }
+
+       ok = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ok;
+}
+
+static bool catia_strict_lock(struct vfs_handle_struct *handle,
+                             struct files_struct *fsp,
+                             struct lock_struct *plock)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+       bool ok;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return -1;
+       }
+
+       ok = SMB_VFS_NEXT_STRICT_LOCK(handle, fsp, plock);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return ok;
+}
+
+static void catia_strict_unlock(struct vfs_handle_struct *handle,
+                               struct files_struct *fsp,
+                               struct lock_struct *plock)
+{
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               smb_panic("CATIA_FETCH_FSP_PRE_NEXT failed\n");
+       }
+
+       SMB_VFS_NEXT_STRICT_UNLOCK(handle, fsp, plock);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+}
+
+static NTSTATUS catia_fsctl(struct vfs_handle_struct *handle,
+                           struct files_struct *fsp,
+                           TALLOC_CTX *ctx,
+                           uint32_t function,
+                           uint16_t req_flags,
+                           const uint8_t *_in_data,
+                           uint32_t in_len,
+                           uint8_t **_out_data,
+                           uint32_t max_out_len,
+                           uint32_t *out_len)
+{
+       NTSTATUS result;
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       result = SMB_VFS_NEXT_FSCTL(handle,
+                               fsp,
+                               ctx,
+                               function,
+                               req_flags,
+                               _in_data,
+                               in_len,
+                               _out_data,
+                               max_out_len,
+                               out_len);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static NTSTATUS catia_get_compression(vfs_handle_struct *handle,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct files_struct *fsp,
+                                     struct smb_filename *smb_fname,
+                                     uint16_t *_compression_fmt)
+{
+       NTSTATUS result;
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       result = SMB_VFS_NEXT_GET_COMPRESSION(handle, mem_ctx, fsp, smb_fname,
+                                             _compression_fmt);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static NTSTATUS catia_set_compression(vfs_handle_struct *handle,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct files_struct *fsp,
+                                     uint16_t compression_fmt)
+{
+       NTSTATUS result;
+       struct catia_cache *cc = NULL;
+       int ret;
+
+       ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
+       if (ret != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       result = SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp,
+                                             compression_fmt);
+
+       CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
+
+       return result;
+}
+
+static NTSTATUS catia_readdir_attr(struct vfs_handle_struct *handle,
+                                  const struct smb_filename *smb_fname_in,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct readdir_attr_data **pattr_data)
+{
+       struct smb_filename *smb_fname;
+       char *fname = NULL;
+       NTSTATUS status;
+
+       status = catia_string_replace_allocate(handle->conn,
+                                              smb_fname_in->base_name,
+                                              &fname,
+                                              vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return status;
+       }
+
+       smb_fname = synthetic_smb_fname(talloc_tos(), fname, NULL,
+                                       &smb_fname_in->st, 0);
+
+       status = SMB_VFS_NEXT_READDIR_ATTR(handle, smb_fname, mem_ctx, pattr_data);
+
+       TALLOC_FREE(smb_fname);
+       return status;
+}
+
+static NTSTATUS catia_get_dos_attributes(struct vfs_handle_struct *handle,
+                                        struct smb_filename *smb_fname,
+                                        uint32_t *dosmode)
+{
+       char *mapped_name = NULL;
+       const char *path = smb_fname->base_name;
+       struct smb_filename *mapped_smb_fname = NULL;
+       NTSTATUS status;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               path, &mapped_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return status;
+       }
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle,
+                                                mapped_smb_fname,
+                                                dosmode);
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_smb_fname);
+
+       return status;
+}
+
+static NTSTATUS catia_set_dos_attributes(struct vfs_handle_struct *handle,
+                                        const struct smb_filename *smb_fname,
+                                        uint32_t dosmode)
+{
+       char *mapped_name = NULL;
+       const char *path = smb_fname->base_name;
+       struct smb_filename *mapped_smb_fname = NULL;
+       NTSTATUS status;
+
+       status = catia_string_replace_allocate(handle->conn,
+                               path, &mapped_name, vfs_translate_to_unix);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return status;
+       }
+       mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       mapped_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (mapped_smb_fname == NULL) {
+               TALLOC_FREE(mapped_name);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
+                                                mapped_smb_fname,
+                                                dosmode);
+       TALLOC_FREE(mapped_name);
+       TALLOC_FREE(mapped_smb_fname);
+
+       return status;
+}
+
+static struct vfs_fn_pointers vfs_catia_fns = {
+       /* Directory operations */
+       .mkdir_fn = catia_mkdir,
+       .rmdir_fn = catia_rmdir,
+       .opendir_fn = catia_opendir,
+       .readdir_attr_fn = catia_readdir_attr,
+
+       /* File operations */
+       .open_fn = catia_open,
+       .pread_fn = catia_pread,
+       .pread_send_fn = catia_pread_send,
+       .pread_recv_fn = catia_pread_recv,
+       .pwrite_fn = catia_pwrite,
+       .pwrite_send_fn = catia_pwrite_send,
+       .pwrite_recv_fn = catia_pwrite_recv,
+       .lseek_fn = catia_lseek,
+       .rename_fn = catia_rename,
+       .fsync_fn = catia_fsync,
+       .fsync_send_fn = catia_fsync_send,
+       .fsync_recv_fn = catia_fsync_recv,
+       .stat_fn = catia_stat,
+       .fstat_fn = catia_fstat,
+       .lstat_fn = catia_lstat,
+       .unlink_fn = catia_unlink,
+       .chmod_fn = catia_chmod,
+       .fchmod_fn = catia_fchmod,
+       .chown_fn = catia_chown,
+       .fchown_fn = catia_fchown,
+       .lchown_fn = catia_lchown,
+       .chdir_fn = catia_chdir,
+       .ntimes_fn = catia_ntimes,
+       .ftruncate_fn = catia_ftruncate,
+       .fallocate_fn = catia_fallocate,
+       .lock_fn = catia_lock,
+       .kernel_flock_fn = catia_kernel_flock,
+       .linux_setlease_fn = catia_linux_setlease,
+       .getlock_fn = catia_getlock,
+       .realpath_fn = catia_realpath,
+       .chflags_fn = catia_chflags,
+       .streaminfo_fn = catia_streaminfo,
+       .strict_lock_fn = catia_strict_lock,
+       .strict_unlock_fn = catia_strict_unlock,
+       .translate_name_fn = catia_translate_name,
+       .fsctl_fn = catia_fsctl,
+       .get_dos_attributes_fn = catia_get_dos_attributes,
+       .set_dos_attributes_fn = catia_set_dos_attributes,
+       .fset_dos_attributes_fn = catia_fset_dos_attributes,
+       .fget_dos_attributes_fn = catia_fget_dos_attributes,
+       .get_compression_fn = catia_get_compression,
+       .set_compression_fn = catia_set_compression,
+
+       /* NT ACL operations. */
+       .get_nt_acl_fn = catia_get_nt_acl,
+       .fget_nt_acl_fn = catia_fget_nt_acl,
+       .fset_nt_acl_fn = catia_fset_nt_acl,
+
+       /* POSIX ACL operations. */
+       .chmod_acl_fn = catia_chmod_acl,
+       .fchmod_acl_fn = catia_fchmod_acl,
+
+       .sys_acl_get_file_fn = catia_sys_acl_get_file,
+       .sys_acl_get_fd_fn = catia_sys_acl_get_fd,
+       .sys_acl_blob_get_fd_fn = catia_sys_acl_blob_get_fd,
+       .sys_acl_set_file_fn = catia_sys_acl_set_file,
+       .sys_acl_set_fd_fn = catia_sys_acl_set_fd,
+       .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file,
+
+       /* EA operations. */
+       .getxattr_fn = catia_getxattr,
+       .listxattr_fn = catia_listxattr,
+       .removexattr_fn = catia_removexattr,
+       .setxattr_fn = catia_setxattr,
+       .fgetxattr_fn = catia_fgetxattr,
+       .flistxattr_fn = catia_flistxattr,
+       .fremovexattr_fn = catia_fremovexattr,
+       .fsetxattr_fn = catia_fsetxattr,
+};
+
+static_decl_vfs;
+NTSTATUS vfs_catia_init(TALLOC_CTX *ctx)
+{
+       NTSTATUS ret;
+
+        ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
+                               &vfs_catia_fns);
+       if (!NT_STATUS_IS_OK(ret))
+               return ret;
+
+       vfs_catia_debug_level = debug_add_class("catia");
+       if (vfs_catia_debug_level == -1) {
+               vfs_catia_debug_level = DBGC_VFS;
+               DEBUG(0, ("vfs_catia: Couldn't register custom debugging "
+                         "class!\n"));
+       } else {
+               DEBUG(10, ("vfs_catia: Debug class number of "
+                          "'catia': %d\n", vfs_catia_debug_level));
+       }
+
+       return ret;
+
 }