s3: VFS: catia. Remove get_nt_acl_fn().
[samba.git] / source3 / modules / vfs_catia.c
1 /*
2  * Catia VFS module
3  *
4  * Implement a fixed mapping of forbidden NT characters in filenames that are
5  * used a lot by the CAD package Catia.
6  *
7  * Catia V4 on AIX uses characters like "<*$ a *lot*, all forbidden under
8  * Windows...
9  *
10  * Copyright (C) Volker Lendecke, 2005
11  * Copyright (C) Aravind Srinivasan, 2009
12  * Copyright (C) Guenter Kukkukk, 2013
13  * Copyright (C) Ralph Boehme, 2017
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, see <http://www.gnu.org/licenses/>.
27  */
28
29
30 #include "includes.h"
31 #include "smbd/smbd.h"
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "string_replace.h"
35
36 static int vfs_catia_debug_level = DBGC_VFS;
37
38 #undef DBGC_CLASS
39 #define DBGC_CLASS vfs_catia_debug_level
40
41 struct share_mapping_entry {
42         int snum;
43         struct share_mapping_entry *next;
44         struct char_mappings **mappings;
45 };
46
47 struct catia_cache {
48         bool is_fsp_ext;
49         const struct catia_cache * const *busy;
50         char *orig_fname;
51         char *fname;
52         char *orig_base_fname;
53         char *base_fname;
54 };
55
56 static struct share_mapping_entry *srt_head = NULL;
57
58 static struct share_mapping_entry *get_srt(connection_struct *conn,
59                                            struct share_mapping_entry **global)
60 {
61         struct share_mapping_entry *share;
62
63         for (share = srt_head; share != NULL; share = share->next) {
64                 if (share->snum == GLOBAL_SECTION_SNUM)
65                         (*global) = share;
66
67                 if (share->snum == SNUM(conn))
68                         return share;
69         }
70
71         return share;
72 }
73
74 static struct share_mapping_entry *add_srt(int snum, const char **mappings)
75 {
76         struct share_mapping_entry *sme = NULL;
77
78         sme = TALLOC_ZERO(NULL, sizeof(struct share_mapping_entry));
79         if (sme == NULL)
80                 return sme;
81
82         sme->snum = snum;
83         sme->next = srt_head;
84         srt_head = sme;
85
86         if (mappings == NULL) {
87                 sme->mappings = NULL;
88                 return sme;
89         }
90
91         sme->mappings = string_replace_init_map(sme, mappings);
92
93         return sme;
94 }
95
96 static bool init_mappings(connection_struct *conn,
97                           struct share_mapping_entry **selected_out)
98 {
99         const char **mappings = NULL;
100         struct share_mapping_entry *share_level = NULL;
101         struct share_mapping_entry *global = NULL;
102
103         /* check srt cache */
104         share_level = get_srt(conn, &global);
105         if (share_level) {
106                 *selected_out = share_level;
107                 return (share_level->mappings != NULL);
108         }
109
110         /* see if we have a global setting */
111         if (!global) {
112                 /* global setting */
113                 mappings = lp_parm_string_list(-1, "catia", "mappings", NULL);
114                 global = add_srt(GLOBAL_SECTION_SNUM, mappings);
115         }
116
117         /* no global setting - what about share level ? */
118         mappings = lp_parm_string_list(SNUM(conn), "catia", "mappings", NULL);
119         share_level = add_srt(SNUM(conn), mappings);
120
121         if (share_level->mappings) {
122                 (*selected_out) = share_level;
123                 return True;
124         }
125         if (global->mappings) {
126                 share_level->mappings = global->mappings;
127                 (*selected_out) = share_level;
128                 return True;
129         }
130
131         return False;
132 }
133
134 static NTSTATUS catia_string_replace_allocate(connection_struct *conn,
135                                               const char *name_in,
136                                               char **mapped_name,
137                                         enum vfs_translate_direction direction)
138 {
139         struct share_mapping_entry *selected;
140         NTSTATUS status;
141
142         if (!init_mappings(conn, &selected)) {
143                 /* No mappings found. Just use the old name */
144                 *mapped_name = talloc_strdup(talloc_tos(), name_in);
145                 if (!*mapped_name) {
146                         errno = ENOMEM;
147                         return NT_STATUS_NO_MEMORY;
148                 }
149                 return NT_STATUS_OK;
150         }
151
152         status = string_replace_allocate(conn,
153                                          name_in,
154                                          selected->mappings,
155                                          talloc_tos(),
156                                          mapped_name,
157                                          direction);
158         return status;
159 }
160
161 static int catia_connect(struct vfs_handle_struct *handle,
162                          const char *service,
163                          const char *user)
164 {
165         /*
166          * Unless we have an async implementation of get_dos_attributes turn
167          * this off.
168          */
169         lp_do_parameter(SNUM(handle->conn), "smbd:async dosmode", "false");
170
171         return SMB_VFS_NEXT_CONNECT(handle, service, user);
172 }
173
174 /*
175  * TRANSLATE_NAME call which converts the given name to
176  * "WINDOWS displayable" name
177  */
178 static NTSTATUS catia_translate_name(struct vfs_handle_struct *handle,
179                                      const char *orig_name,
180                                      enum vfs_translate_direction direction,
181                                      TALLOC_CTX *mem_ctx,
182                                      char **pmapped_name)
183 {
184         char *name = NULL;
185         char *mapped_name;
186         NTSTATUS status, ret;
187
188         /*
189          * Copy the supplied name and free the memory for mapped_name,
190          * already allocated by the caller.
191          * We will be allocating new memory for mapped_name in
192          * catia_string_replace_allocate
193          */
194         name = talloc_strdup(talloc_tos(), orig_name);
195         if (!name) {
196                 errno = ENOMEM;
197                 return NT_STATUS_NO_MEMORY;
198         }
199         status = catia_string_replace_allocate(handle->conn, name,
200                         &mapped_name, direction);
201
202         TALLOC_FREE(name);
203         if (!NT_STATUS_IS_OK(status)) {
204                 return status;
205         }
206
207         ret = SMB_VFS_NEXT_TRANSLATE_NAME(handle, mapped_name, direction,
208                                           mem_ctx, pmapped_name);
209
210         if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
211                 *pmapped_name = talloc_move(mem_ctx, &mapped_name);
212                 /* we need to return the former translation result here */
213                 ret = status;
214         } else {
215                 TALLOC_FREE(mapped_name);
216         }
217
218         return ret;
219 }
220
221 #define CATIA_DEBUG_CC(lvl, cc, fsp) \
222         catia_debug_cc((lvl), (cc), (fsp), __location__);
223
224 static void catia_debug_cc(int lvl,
225                            struct catia_cache *cc,
226                            files_struct *fsp,
227                            const char *location)
228 {
229         DEBUG(lvl, ("%s: cc [%p] cc->busy [%p] "
230                     "is_fsp_ext [%s] "
231                     "fsp [%p] fsp name [%s] "
232                     "orig_fname [%s] "
233                     "fname [%s] "
234                     "orig_base_fname [%s] "
235                     "base_fname [%s]\n",
236                     location,
237                     cc, cc->busy,
238                     cc->is_fsp_ext ? "yes" : "no",
239                     fsp, fsp_str_dbg(fsp),
240                     cc->orig_fname, cc->fname,
241                     cc->orig_base_fname, cc->base_fname));
242 }
243
244 static void catia_free_cc(struct catia_cache **_cc,
245                           vfs_handle_struct *handle,
246                           files_struct *fsp)
247 {
248         struct catia_cache *cc = *_cc;
249
250         if (cc->is_fsp_ext) {
251                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
252                 cc = NULL;
253         } else {
254                 TALLOC_FREE(cc);
255         }
256
257         *_cc = NULL;
258 }
259
260 static struct catia_cache *catia_validate_and_apply_cc(
261                                        vfs_handle_struct *handle,
262                                        files_struct *fsp,
263                                        const struct catia_cache * const *busy,
264                                        bool *make_tmp_cache)
265 {
266         struct catia_cache *cc = NULL;
267
268         *make_tmp_cache = false;
269
270         cc = (struct catia_cache *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
271         if (cc == NULL) {
272                 return NULL;
273         }
274
275         if (cc->busy != NULL) {
276                 if (cc->busy == busy) {
277                         /* This should never happen */
278                         CATIA_DEBUG_CC(0, cc, fsp);
279                         smb_panic(__location__);
280                 }
281
282                 /*
283                  * Recursion. Validate names, the names in the fsp's should be
284                  * the translated names we had set.
285                  */
286
287                 if ((cc->fname != fsp->fsp_name->base_name)
288                     ||
289                     ((fsp->base_fsp != NULL) &&
290                      (cc->base_fname != fsp->base_fsp->fsp_name->base_name)))
291                 {
292                         CATIA_DEBUG_CC(10, cc, fsp);
293
294                         /*
295                          * Names changed. Setting don't expose the cache on the
296                          * fsp and ask the caller to create a temporary cache.
297                          */
298                         *make_tmp_cache = true;
299                         return NULL;
300                 }
301
302                 /*
303                  * Ok, a validated cache while in a recursion, just let the
304                  * caller detect that cc->busy is != busy and there's
305                  * nothing else to do.
306                  */
307                 CATIA_DEBUG_CC(10, cc, fsp);
308                 return cc;
309         }
310
311         /* Not in a recursion */
312
313         if ((cc->orig_fname != fsp->fsp_name->base_name)
314             ||
315             ((fsp->base_fsp != NULL) &&
316              (cc->orig_base_fname != fsp->base_fsp->fsp_name->base_name)))
317         {
318                 /*
319                  * fsp names changed, this can happen in an rename op.
320                  * Trigger recreation as a full fledged fsp extension.
321                  */
322
323                 CATIA_DEBUG_CC(10, cc, fsp);
324                 catia_free_cc(&cc, handle, fsp);
325                 return NULL;
326         }
327
328
329         /*
330          * Ok, we found a valid cache entry, no recursion. Just set translated
331          * names from the cache and mark the cc as busy.
332          */
333         fsp->fsp_name->base_name = cc->fname;
334         if (fsp->base_fsp != NULL) {
335                 fsp->base_fsp->fsp_name->base_name = cc->base_fname;
336         }
337
338         cc->busy = busy;
339         CATIA_DEBUG_CC(10, cc, fsp);
340         return cc;
341 }
342
343 #define CATIA_FETCH_FSP_PRE_NEXT(mem_ctx, handle, fsp, _cc) \
344         catia_fetch_fsp_pre_next((mem_ctx), (handle), (fsp), (_cc), __func__);
345
346 static int catia_fetch_fsp_pre_next(TALLOC_CTX *mem_ctx,
347                                     vfs_handle_struct *handle,
348                                     files_struct *fsp,
349                                     struct catia_cache **_cc,
350                                     const char *function)
351 {
352         const struct catia_cache * const *busy =
353                 (const struct catia_cache * const *)_cc;
354         struct catia_cache *cc = NULL;
355         NTSTATUS status;
356         bool make_tmp_cache = false;
357
358         *_cc = NULL;
359
360         DBG_DEBUG("Called from [%s]\n", function);
361
362         cc = catia_validate_and_apply_cc(handle,
363                                          fsp,
364                                          busy,
365                                          &make_tmp_cache);
366         if (cc != NULL) {
367                 if (cc->busy != busy) {
368                         return 0;
369                 }
370                 *_cc = cc;
371                 return 0;
372         }
373
374         if (!make_tmp_cache) {
375                 cc = VFS_ADD_FSP_EXTENSION(
376                         handle, fsp, struct catia_cache, NULL);
377                 if (cc == NULL) {
378                         return -1;
379                 }
380                 *cc = (struct catia_cache) {
381                         .is_fsp_ext = true,
382                 };
383
384                 mem_ctx = VFS_MEMCTX_FSP_EXTENSION(handle, fsp);
385                 if (mem_ctx == NULL) {
386                         DBG_ERR("VFS_MEMCTX_FSP_EXTENSION failed\n");
387                         catia_free_cc(&cc, handle, fsp);
388                         return -1;
389                 }
390         } else {
391                 cc = talloc_zero(mem_ctx, struct catia_cache);
392                 if (cc == NULL) {
393                         return -1;
394                 }
395                 mem_ctx = cc;
396         }
397
398
399         status = catia_string_replace_allocate(handle->conn,
400                                                fsp->fsp_name->base_name,
401                                                &cc->fname,
402                                                vfs_translate_to_unix);
403         if (!NT_STATUS_IS_OK(status)) {
404                 catia_free_cc(&cc, handle, fsp);
405                 errno = map_errno_from_nt_status(status);
406                 return -1;
407         }
408         talloc_steal(mem_ctx, cc->fname);
409
410         if (fsp->base_fsp != NULL) {
411                 status = catia_string_replace_allocate(
412                         handle->conn,
413                         fsp->base_fsp->fsp_name->base_name,
414                         &cc->base_fname,
415                         vfs_translate_to_unix);
416                 if (!NT_STATUS_IS_OK(status)) {
417                         catia_free_cc(&cc, handle, fsp);
418                         errno = map_errno_from_nt_status(status);
419                         return -1;
420                 }
421                 talloc_steal(mem_ctx, cc->base_fname);
422         }
423
424         cc->orig_fname = fsp->fsp_name->base_name;
425         fsp->fsp_name->base_name = cc->fname;
426
427         if (fsp->base_fsp != NULL) {
428                 cc->orig_base_fname = fsp->base_fsp->fsp_name->base_name;
429                 fsp->base_fsp->fsp_name->base_name = cc->base_fname;
430         }
431
432         cc->busy = busy;
433         CATIA_DEBUG_CC(10, cc, fsp);
434
435         *_cc = cc;
436
437         return 0;
438 }
439
440 #define CATIA_FETCH_FSP_POST_NEXT(_cc, fsp) do { \
441         int saved_errno = errno; \
442         catia_fetch_fsp_post_next((_cc), (fsp), __func__); \
443         errno = saved_errno; \
444 } while(0)
445
446 static void catia_fetch_fsp_post_next(struct catia_cache **_cc,
447                                       files_struct *fsp,
448                                       const char *function)
449 {
450         const struct catia_cache * const *busy =
451                 (const struct catia_cache * const *)_cc;
452         struct catia_cache *cc = *_cc;
453
454         DBG_DEBUG("Called from [%s]\n", function);
455
456         if (cc == NULL) {
457                 /*
458                  * This can happen when recursing in the VFS on the fsp when the
459                  * pre_next func noticed the recursion and set out cc pointer to
460                  * NULL.
461                  */
462                 return;
463         }
464
465         if (cc->busy != busy) {
466                 CATIA_DEBUG_CC(0, cc, fsp);
467                 smb_panic(__location__);
468                 return;
469         }
470
471         cc->busy = NULL;
472         *_cc = NULL;
473
474         fsp->fsp_name->base_name = cc->orig_fname;
475         if (fsp->base_fsp != NULL) {
476                 fsp->base_fsp->fsp_name->base_name = cc->orig_base_fname;
477         }
478
479         CATIA_DEBUG_CC(10, cc, fsp);
480
481         if (!cc->is_fsp_ext) {
482                 TALLOC_FREE(cc);
483         }
484
485         return;
486 }
487
488 static int catia_open(vfs_handle_struct *handle,
489                       struct smb_filename *smb_fname,
490                       files_struct *fsp,
491                       int flags,
492                       mode_t mode)
493 {
494         struct catia_cache *cc = NULL;
495         char *orig_smb_fname = smb_fname->base_name;
496         char *mapped_smb_fname = NULL;
497         NTSTATUS status;
498         int ret;
499
500         status = catia_string_replace_allocate(handle->conn,
501                                                smb_fname->base_name,
502                                                &mapped_smb_fname,
503                                                vfs_translate_to_unix);
504         if (!NT_STATUS_IS_OK(status)) {
505                 return -1;
506         }
507
508         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
509         if (ret != 0) {
510                 TALLOC_FREE(mapped_smb_fname);
511                 return ret;
512         }
513
514         smb_fname->base_name = mapped_smb_fname;
515         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
516         smb_fname->base_name = orig_smb_fname;
517
518         TALLOC_FREE(mapped_smb_fname);
519         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
520
521         return ret;
522 }
523
524 static int catia_renameat(vfs_handle_struct *handle,
525                         files_struct *srcfsp,
526                         const struct smb_filename *smb_fname_src,
527                         files_struct *dstfsp,
528                         const struct smb_filename *smb_fname_dst)
529 {
530         TALLOC_CTX *ctx = talloc_tos();
531         struct smb_filename *smb_fname_src_tmp = NULL;
532         struct smb_filename *smb_fname_dst_tmp = NULL;
533         char *src_name_mapped = NULL;
534         char *dst_name_mapped = NULL;
535         NTSTATUS status;
536         int ret = -1;
537
538         status = catia_string_replace_allocate(handle->conn,
539                                 smb_fname_src->base_name,
540                                 &src_name_mapped, vfs_translate_to_unix);
541         if (!NT_STATUS_IS_OK(status)) {
542                 errno = map_errno_from_nt_status(status);
543                 return -1;
544         }
545
546         status = catia_string_replace_allocate(handle->conn,
547                                 smb_fname_dst->base_name,
548                                 &dst_name_mapped, vfs_translate_to_unix);
549         if (!NT_STATUS_IS_OK(status)) {
550                 errno = map_errno_from_nt_status(status);
551                 return -1;
552         }
553
554         /* Setup temporary smb_filename structs. */
555         smb_fname_src_tmp = cp_smb_filename(ctx, smb_fname_src);
556         if (smb_fname_src_tmp == NULL) {
557                 errno = ENOMEM;
558                 goto out;
559         }
560
561         smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
562         if (smb_fname_dst_tmp == NULL) {
563                 errno = ENOMEM;
564                 goto out;
565         }
566
567         smb_fname_src_tmp->base_name = src_name_mapped;
568         smb_fname_dst_tmp->base_name = dst_name_mapped;
569         DEBUG(10, ("converted old name: %s\n",
570                                 smb_fname_str_dbg(smb_fname_src_tmp)));
571         DEBUG(10, ("converted new name: %s\n",
572                                 smb_fname_str_dbg(smb_fname_dst_tmp)));
573
574         ret = SMB_VFS_NEXT_RENAMEAT(handle,
575                         srcfsp,
576                         smb_fname_src_tmp,
577                         dstfsp,
578                         smb_fname_dst_tmp);
579
580 out:
581         TALLOC_FREE(src_name_mapped);
582         TALLOC_FREE(dst_name_mapped);
583         TALLOC_FREE(smb_fname_src_tmp);
584         TALLOC_FREE(smb_fname_dst_tmp);
585         return ret;
586 }
587
588
589 static int catia_stat(vfs_handle_struct *handle,
590                       struct smb_filename *smb_fname)
591 {
592         char *name = NULL;
593         char *tmp_base_name;
594         int ret;
595         NTSTATUS status;
596
597         status = catia_string_replace_allocate(handle->conn,
598                                 smb_fname->base_name,
599                                 &name, vfs_translate_to_unix);
600         if (!NT_STATUS_IS_OK(status)) {
601                 errno = map_errno_from_nt_status(status);
602                 return -1;
603         }
604
605         tmp_base_name = smb_fname->base_name;
606         smb_fname->base_name = name;
607
608         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
609         smb_fname->base_name = tmp_base_name;
610
611         TALLOC_FREE(name);
612         return ret;
613 }
614
615 static int catia_lstat(vfs_handle_struct *handle,
616                        struct smb_filename *smb_fname)
617 {
618         char *name = NULL;
619         char *tmp_base_name;
620         int ret;
621         NTSTATUS status;
622
623         status = catia_string_replace_allocate(handle->conn,
624                                 smb_fname->base_name,
625                                 &name, vfs_translate_to_unix);
626         if (!NT_STATUS_IS_OK(status)) {
627                 errno = map_errno_from_nt_status(status);
628                 return -1;
629         }
630
631         tmp_base_name = smb_fname->base_name;
632         smb_fname->base_name = name;
633
634         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
635         smb_fname->base_name = tmp_base_name;
636         TALLOC_FREE(name);
637
638         return ret;
639 }
640
641 static int catia_unlinkat(vfs_handle_struct *handle,
642                         struct files_struct *dirfsp,
643                         const struct smb_filename *smb_fname,
644                         int flags)
645 {
646         struct smb_filename *smb_fname_tmp = NULL;
647         char *name = NULL;
648         NTSTATUS status;
649         int ret;
650
651         status = catia_string_replace_allocate(handle->conn,
652                                         smb_fname->base_name,
653                                         &name, vfs_translate_to_unix);
654         if (!NT_STATUS_IS_OK(status)) {
655                 errno = map_errno_from_nt_status(status);
656                 return -1;
657         }
658
659         /* Setup temporary smb_filename structs. */
660         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
661         if (smb_fname_tmp == NULL) {
662                 errno = ENOMEM;
663                 return -1;
664         }
665
666         smb_fname_tmp->base_name = name;
667         ret = SMB_VFS_NEXT_UNLINKAT(handle,
668                         dirfsp,
669                         smb_fname_tmp,
670                         flags);
671         TALLOC_FREE(smb_fname_tmp);
672         TALLOC_FREE(name);
673
674         return ret;
675 }
676
677 static int catia_lchown(vfs_handle_struct *handle,
678                         const struct smb_filename *smb_fname,
679                         uid_t uid,
680                         gid_t gid)
681 {
682         char *name = NULL;
683         NTSTATUS status;
684         int ret;
685         int saved_errno;
686         struct smb_filename *catia_smb_fname = NULL;
687
688         status = catia_string_replace_allocate(handle->conn,
689                                         smb_fname->base_name,
690                                         &name,
691                                         vfs_translate_to_unix);
692         if (!NT_STATUS_IS_OK(status)) {
693                 errno = map_errno_from_nt_status(status);
694                 return -1;
695         }
696         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
697                                         name,
698                                         NULL,
699                                         &smb_fname->st,
700                                         smb_fname->twrp,
701                                         smb_fname->flags);
702         if (catia_smb_fname == NULL) {
703                 TALLOC_FREE(name);
704                 errno = ENOMEM;
705                 return -1;
706         }
707
708         ret = SMB_VFS_NEXT_LCHOWN(handle, catia_smb_fname, uid, gid);
709         saved_errno = errno;
710         TALLOC_FREE(name);
711         TALLOC_FREE(catia_smb_fname);
712         errno = saved_errno;
713         return ret;
714 }
715
716 static int catia_chmod(vfs_handle_struct *handle,
717                         const struct smb_filename *smb_fname,
718                         mode_t mode)
719 {
720         char *name = NULL;
721         NTSTATUS status;
722         int ret;
723         int saved_errno;
724         struct smb_filename *catia_smb_fname = NULL;
725
726         status = catia_string_replace_allocate(handle->conn,
727                                         smb_fname->base_name,
728                                         &name,
729                                         vfs_translate_to_unix);
730         if (!NT_STATUS_IS_OK(status)) {
731                 errno = map_errno_from_nt_status(status);
732                 return -1;
733         }
734         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
735                                         name,
736                                         NULL,
737                                         &smb_fname->st,
738                                         smb_fname->twrp,
739                                         smb_fname->flags);
740         if (catia_smb_fname == NULL) {
741                 TALLOC_FREE(name);
742                 errno = ENOMEM;
743                 return -1;
744         }
745
746         ret = SMB_VFS_NEXT_CHMOD(handle, catia_smb_fname, mode);
747         saved_errno = errno;
748         TALLOC_FREE(name);
749         TALLOC_FREE(catia_smb_fname);
750         errno = saved_errno;
751         return ret;
752 }
753
754 static int catia_mkdirat(vfs_handle_struct *handle,
755                         struct files_struct *dirfsp,
756                         const struct smb_filename *smb_fname,
757                         mode_t mode)
758 {
759         char *name = NULL;
760         NTSTATUS status;
761         int ret;
762         struct smb_filename *catia_smb_fname = NULL;
763
764         status = catia_string_replace_allocate(handle->conn,
765                                 smb_fname->base_name,
766                                 &name,
767                                 vfs_translate_to_unix);
768         if (!NT_STATUS_IS_OK(status)) {
769                 errno = map_errno_from_nt_status(status);
770                 return -1;
771         }
772         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
773                                         name,
774                                         NULL,
775                                         &smb_fname->st,
776                                         smb_fname->twrp,
777                                         smb_fname->flags);
778         if (catia_smb_fname == NULL) {
779                 TALLOC_FREE(name);
780                 errno = ENOMEM;
781                 return -1;
782         }
783
784         ret = SMB_VFS_NEXT_MKDIRAT(handle,
785                         dirfsp,
786                         catia_smb_fname,
787                         mode);
788         TALLOC_FREE(name);
789         TALLOC_FREE(catia_smb_fname);
790
791         return ret;
792 }
793
794 static int catia_chdir(vfs_handle_struct *handle,
795                         const struct smb_filename *smb_fname)
796 {
797         char *name = NULL;
798         struct smb_filename *catia_smb_fname = NULL;
799         NTSTATUS status;
800         int ret;
801
802         status = catia_string_replace_allocate(handle->conn,
803                                         smb_fname->base_name,
804                                         &name,
805                                         vfs_translate_to_unix);
806         if (!NT_STATUS_IS_OK(status)) {
807                 errno = map_errno_from_nt_status(status);
808                 return -1;
809         }
810
811         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
812                                         name,
813                                         NULL,
814                                         &smb_fname->st,
815                                         smb_fname->twrp,
816                                         smb_fname->flags);
817         if (catia_smb_fname == NULL) {
818                 TALLOC_FREE(name);
819                 errno = ENOMEM;
820                 return -1;
821         }
822         ret = SMB_VFS_NEXT_CHDIR(handle, catia_smb_fname);
823         TALLOC_FREE(name);
824         TALLOC_FREE(catia_smb_fname);
825
826         return ret;
827 }
828
829 static int catia_ntimes(vfs_handle_struct *handle,
830                         const struct smb_filename *smb_fname,
831                         struct smb_file_time *ft)
832 {
833         struct smb_filename *smb_fname_tmp = NULL;
834         char *name = NULL;
835         NTSTATUS status;
836         int ret;
837
838         status = catia_string_replace_allocate(handle->conn,
839                                 smb_fname->base_name,
840                                 &name, vfs_translate_to_unix);
841         if (!NT_STATUS_IS_OK(status)) {
842                 errno = map_errno_from_nt_status(status);
843                 return -1;
844         }
845
846         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
847         if (smb_fname_tmp == NULL) {
848                 errno = ENOMEM;
849                 return -1;
850         }
851
852         smb_fname_tmp->base_name = name;
853         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
854         TALLOC_FREE(name);
855         TALLOC_FREE(smb_fname_tmp);
856
857         return ret;
858 }
859
860 static struct smb_filename *
861 catia_realpath(vfs_handle_struct *handle,
862                 TALLOC_CTX *ctx,
863                 const struct smb_filename *smb_fname)
864 {
865         char *mapped_name = NULL;
866         struct smb_filename *catia_smb_fname = NULL;
867         struct smb_filename *return_fname = NULL;
868         NTSTATUS status;
869
870         status = catia_string_replace_allocate(handle->conn,
871                                         smb_fname->base_name,
872                                         &mapped_name, vfs_translate_to_unix);
873         if (!NT_STATUS_IS_OK(status)) {
874                 errno = map_errno_from_nt_status(status);
875                 return NULL;
876         }
877
878         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
879                                         mapped_name,
880                                         NULL,
881                                         &smb_fname->st,
882                                         smb_fname->twrp,
883                                         smb_fname->flags);
884         if (catia_smb_fname == NULL) {
885                 TALLOC_FREE(mapped_name);
886                 errno = ENOMEM;
887                 return NULL;
888         }
889         return_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, catia_smb_fname);
890         TALLOC_FREE(mapped_name);
891         TALLOC_FREE(catia_smb_fname);
892         return return_fname;
893 }
894
895 static int catia_chflags(struct vfs_handle_struct *handle,
896                         const struct smb_filename *smb_fname,
897                         unsigned int flags)
898 {
899         char *name = NULL;
900         struct smb_filename *catia_smb_fname = NULL;
901         NTSTATUS status;
902         int ret;
903
904         status = catia_string_replace_allocate(handle->conn,
905                                 smb_fname->base_name,
906                                 &name,
907                                 vfs_translate_to_unix);
908         if (!NT_STATUS_IS_OK(status)) {
909                 errno = map_errno_from_nt_status(status);
910                 return -1;
911         }
912         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
913                                         name,
914                                         NULL,
915                                         &smb_fname->st,
916                                         smb_fname->twrp,
917                                         smb_fname->flags);
918         if (catia_smb_fname == NULL) {
919                 TALLOC_FREE(name);
920                 errno = ENOMEM;
921                 return -1;
922         }
923
924         ret = SMB_VFS_NEXT_CHFLAGS(handle, catia_smb_fname, flags);
925         TALLOC_FREE(name);
926         TALLOC_FREE(catia_smb_fname);
927
928         return ret;
929 }
930
931 static NTSTATUS
932 catia_streaminfo(struct vfs_handle_struct *handle,
933                  struct files_struct *fsp,
934                  const struct smb_filename *smb_fname,
935                  TALLOC_CTX *mem_ctx,
936                  unsigned int *_num_streams,
937                  struct stream_struct **_streams)
938 {
939         char *mapped_name = NULL;
940         NTSTATUS status;
941         unsigned int i;
942         struct smb_filename *catia_smb_fname = NULL;
943         unsigned int num_streams = 0;
944         struct stream_struct *streams = NULL;
945
946         *_num_streams = 0;
947         *_streams = NULL;
948
949         status = catia_string_replace_allocate(handle->conn,
950                                 smb_fname->base_name,
951                                 &mapped_name,
952                                 vfs_translate_to_unix);
953         if (!NT_STATUS_IS_OK(status)) {
954                 errno = map_errno_from_nt_status(status);
955                 return status;
956         }
957
958         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
959                                         mapped_name,
960                                         NULL,
961                                         &smb_fname->st,
962                                         smb_fname->twrp,
963                                         smb_fname->flags);
964         if (catia_smb_fname == NULL) {
965                 TALLOC_FREE(mapped_name);
966                 return NT_STATUS_NO_MEMORY;
967         }
968
969         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, catia_smb_fname,
970                                          mem_ctx, &num_streams, &streams);
971         TALLOC_FREE(mapped_name);
972         TALLOC_FREE(catia_smb_fname);
973         if (!NT_STATUS_IS_OK(status)) {
974                 return status;
975         }
976
977         /*
978          * Translate stream names just like the base names
979          */
980         for (i = 0; i < num_streams; i++) {
981                 /*
982                  * Strip ":" prefix and ":$DATA" suffix to get a
983                  * "pure" stream name and only translate that.
984                  */
985                 void *old_ptr = streams[i].name;
986                 char *stream_name = streams[i].name + 1;
987                 char *stream_type = strrchr_m(stream_name, ':');
988
989                 if (stream_type != NULL) {
990                         *stream_type = '\0';
991                         stream_type += 1;
992                 }
993
994                 status = catia_string_replace_allocate(handle->conn, stream_name,
995                                                        &mapped_name, vfs_translate_to_windows);
996                 if (!NT_STATUS_IS_OK(status)) {
997                         TALLOC_FREE(streams);
998                         return status;
999                 }
1000
1001                 if (stream_type != NULL) {
1002                         streams[i].name = talloc_asprintf(streams, ":%s:%s",
1003                                                           mapped_name, stream_type);
1004                 } else {
1005                         streams[i].name = talloc_asprintf(streams, ":%s",
1006                                                           mapped_name);
1007                 }
1008                 TALLOC_FREE(mapped_name);
1009                 TALLOC_FREE(old_ptr);
1010                 if (streams[i].name == NULL) {
1011                         TALLOC_FREE(streams);
1012                         return NT_STATUS_NO_MEMORY;
1013                 }
1014         }
1015
1016         *_num_streams = num_streams;
1017         *_streams = streams;
1018         return NT_STATUS_OK;
1019 }
1020
1021 static NTSTATUS catia_get_nt_acl_at(struct vfs_handle_struct *handle,
1022                                     struct files_struct *dirfsp,
1023                                     const struct smb_filename *smb_fname,
1024                                     uint32_t security_info,
1025                                     TALLOC_CTX *mem_ctx,
1026                                     struct security_descriptor **ppdesc)
1027 {
1028         char *mapped_name = NULL;
1029         const char *path = smb_fname->base_name;
1030         struct smb_filename *mapped_smb_fname = NULL;
1031         NTSTATUS status;
1032
1033         SMB_ASSERT(dirfsp == handle->conn->cwd_fsp);
1034
1035         status = catia_string_replace_allocate(handle->conn,
1036                                 path, &mapped_name, vfs_translate_to_unix);
1037         if (!NT_STATUS_IS_OK(status)) {
1038                 errno = map_errno_from_nt_status(status);
1039                 return status;
1040         }
1041         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1042                                         mapped_name,
1043                                         NULL,
1044                                         &smb_fname->st,
1045                                         smb_fname->twrp,
1046                                         smb_fname->flags);
1047         if (mapped_smb_fname == NULL) {
1048                 TALLOC_FREE(mapped_name);
1049                 return NT_STATUS_NO_MEMORY;
1050         }
1051
1052         status = SMB_VFS_NEXT_GET_NT_ACL_AT(handle,
1053                                         dirfsp,
1054                                         mapped_smb_fname,
1055                                         security_info,
1056                                         mem_ctx,
1057                                         ppdesc);
1058         TALLOC_FREE(mapped_name);
1059         TALLOC_FREE(mapped_smb_fname);
1060
1061         return status;
1062 }
1063
1064 static SMB_ACL_T
1065 catia_sys_acl_get_file(vfs_handle_struct *handle,
1066                         const struct smb_filename *smb_fname,
1067                         SMB_ACL_TYPE_T type,
1068                         TALLOC_CTX *mem_ctx)
1069 {
1070         char *mapped_name = NULL;
1071         struct smb_filename *mapped_smb_fname = NULL;
1072         NTSTATUS status;
1073         SMB_ACL_T ret;
1074         int saved_errno = 0;
1075
1076         status = catia_string_replace_allocate(handle->conn,
1077                                 smb_fname->base_name,
1078                                 &mapped_name,
1079                                 vfs_translate_to_unix);
1080         if (!NT_STATUS_IS_OK(status)) {
1081                 errno = map_errno_from_nt_status(status);
1082                 return (SMB_ACL_T)NULL;
1083         }
1084
1085         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1086                                         mapped_name,
1087                                         NULL,
1088                                         &smb_fname->st,
1089                                         smb_fname->twrp,
1090                                         smb_fname->flags);
1091         if (mapped_smb_fname == NULL) {
1092                 TALLOC_FREE(mapped_name);
1093                 errno = ENOMEM;
1094                 return (SMB_ACL_T)NULL;
1095         }
1096
1097         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, mapped_smb_fname,
1098                         type, mem_ctx);
1099         if (ret == (SMB_ACL_T)NULL) {
1100                 saved_errno = errno;
1101         }
1102         TALLOC_FREE(mapped_smb_fname);
1103         TALLOC_FREE(mapped_name);
1104         if (saved_errno != 0) {
1105                 errno = saved_errno;
1106         }
1107         return ret;
1108 }
1109
1110 static int
1111 catia_sys_acl_set_file(vfs_handle_struct *handle,
1112                         const struct smb_filename *smb_fname,
1113                         SMB_ACL_TYPE_T type,
1114                         SMB_ACL_T theacl)
1115 {
1116         struct smb_filename *mapped_smb_fname = NULL;
1117         int saved_errno = 0;
1118         char *mapped_name = NULL;
1119         NTSTATUS status;
1120         int ret;
1121
1122         status = catia_string_replace_allocate(handle->conn,
1123                                 smb_fname->base_name,
1124                                 &mapped_name,
1125                                 vfs_translate_to_unix);
1126         if (!NT_STATUS_IS_OK(status)) {
1127                 errno = map_errno_from_nt_status(status);
1128                 return -1;
1129         }
1130
1131         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1132                                         mapped_name,
1133                                         NULL,
1134                                         &smb_fname->st,
1135                                         smb_fname->twrp,
1136                                         smb_fname->flags);
1137         if (mapped_smb_fname == NULL) {
1138                 TALLOC_FREE(mapped_name);
1139                 errno = ENOMEM;
1140                 return -1;
1141         }
1142
1143         ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, mapped_smb_fname,
1144                         type, theacl);
1145         if (ret == -1) {
1146                 saved_errno = errno;
1147         }
1148         TALLOC_FREE(mapped_smb_fname);
1149         TALLOC_FREE(mapped_name);
1150         if (saved_errno != 0) {
1151                 errno = saved_errno;
1152         }
1153         return ret;
1154 }
1155
1156 static int
1157 catia_sys_acl_delete_def_file(vfs_handle_struct *handle,
1158                                 const struct smb_filename *smb_fname)
1159 {
1160         struct smb_filename *mapped_smb_fname = NULL;
1161         int saved_errno = 0;
1162         char *mapped_name = NULL;
1163         NTSTATUS status;
1164         int ret;
1165
1166         status = catia_string_replace_allocate(handle->conn,
1167                                 smb_fname->base_name,
1168                                 &mapped_name,
1169                                 vfs_translate_to_unix);
1170         if (!NT_STATUS_IS_OK(status)) {
1171                 errno = map_errno_from_nt_status(status);
1172                 return -1;
1173         }
1174
1175         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1176                                         mapped_name,
1177                                         NULL,
1178                                         &smb_fname->st,
1179                                         smb_fname->twrp,
1180                                         smb_fname->flags);
1181         if (mapped_smb_fname == NULL) {
1182                 TALLOC_FREE(mapped_name);
1183                 errno = ENOMEM;
1184                 return -1;
1185         }
1186         ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, mapped_smb_fname);
1187         if (ret == -1) {
1188                 saved_errno = errno;
1189         }
1190         TALLOC_FREE(mapped_smb_fname);
1191         TALLOC_FREE(mapped_name);
1192         if (saved_errno != 0) {
1193                 errno = saved_errno;
1194         }
1195         return ret;
1196 }
1197
1198 static ssize_t
1199 catia_getxattr(vfs_handle_struct *handle,
1200                         const struct smb_filename *smb_fname,
1201                         const char *name,
1202                         void *value,
1203                         size_t size)
1204 {
1205         struct smb_filename *mapped_smb_fname = NULL;
1206         char *mapped_name = NULL;
1207         char *mapped_ea_name = NULL;
1208         NTSTATUS status;
1209         ssize_t ret;
1210         int saved_errno = 0;
1211
1212         status = catia_string_replace_allocate(handle->conn,
1213                                 smb_fname->base_name,
1214                                 &mapped_name,
1215                                 vfs_translate_to_unix);
1216         if (!NT_STATUS_IS_OK(status)) {
1217                 errno = map_errno_from_nt_status(status);
1218                 return -1;
1219         }
1220
1221         status = catia_string_replace_allocate(handle->conn,
1222                                 name, &mapped_ea_name, vfs_translate_to_unix);
1223         if (!NT_STATUS_IS_OK(status)) {
1224                 TALLOC_FREE(mapped_name);
1225                 errno = map_errno_from_nt_status(status);
1226                 return -1;
1227         }
1228
1229         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1230                                         mapped_name,
1231                                         NULL,
1232                                         &smb_fname->st,
1233                                         smb_fname->twrp,
1234                                         smb_fname->flags);
1235         if (mapped_smb_fname == NULL) {
1236                 TALLOC_FREE(mapped_name);
1237                 TALLOC_FREE(mapped_ea_name);
1238                 errno = ENOMEM;
1239                 return -1;
1240         }
1241
1242         ret = SMB_VFS_NEXT_GETXATTR(handle, mapped_smb_fname,
1243                                 mapped_ea_name, value, size);
1244         if (ret == -1) {
1245                 saved_errno = errno;
1246         }
1247         TALLOC_FREE(mapped_name);
1248         TALLOC_FREE(mapped_ea_name);
1249         TALLOC_FREE(mapped_smb_fname);
1250         if (saved_errno != 0) {
1251                 errno = saved_errno;
1252         }
1253
1254         return ret;
1255 }
1256
1257 static ssize_t
1258 catia_listxattr(vfs_handle_struct *handle,
1259                 const struct smb_filename *smb_fname,
1260                 char *list, size_t size)
1261 {
1262         struct smb_filename *mapped_smb_fname = NULL;
1263         char *mapped_name = NULL;
1264         NTSTATUS status;
1265         ssize_t ret;
1266         int saved_errno = 0;
1267
1268         status = catia_string_replace_allocate(handle->conn,
1269                                 smb_fname->base_name,
1270                                 &mapped_name,
1271                                 vfs_translate_to_unix);
1272         if (!NT_STATUS_IS_OK(status)) {
1273                 errno = map_errno_from_nt_status(status);
1274                 return -1;
1275         }
1276
1277         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1278                                         mapped_name,
1279                                         NULL,
1280                                         &smb_fname->st,
1281                                         smb_fname->twrp,
1282                                         smb_fname->flags);
1283         if (mapped_smb_fname == NULL) {
1284                 TALLOC_FREE(mapped_name);
1285                 errno = ENOMEM;
1286                 return -1;
1287         }
1288
1289         ret = SMB_VFS_NEXT_LISTXATTR(handle, mapped_smb_fname, list, size);
1290         if (ret == -1) {
1291                 saved_errno = errno;
1292         }
1293         TALLOC_FREE(mapped_name);
1294         TALLOC_FREE(mapped_smb_fname);
1295         if (saved_errno != 0) {
1296                 errno = saved_errno;
1297         }
1298
1299         return ret;
1300 }
1301
1302 static int
1303 catia_removexattr(vfs_handle_struct *handle,
1304                         const struct smb_filename *smb_fname,
1305                         const char *name)
1306 {
1307         struct smb_filename *mapped_smb_fname = NULL;
1308         char *mapped_name = NULL;
1309         char *mapped_ea_name = NULL;
1310         NTSTATUS status;
1311         ssize_t ret;
1312         int saved_errno = 0;
1313
1314         status = catia_string_replace_allocate(handle->conn,
1315                                 smb_fname->base_name,
1316                                 &mapped_name,
1317                                 vfs_translate_to_unix);
1318         if (!NT_STATUS_IS_OK(status)) {
1319                 errno = map_errno_from_nt_status(status);
1320                 return -1;
1321         }
1322
1323         status = catia_string_replace_allocate(handle->conn,
1324                                 name, &mapped_ea_name, vfs_translate_to_unix);
1325         if (!NT_STATUS_IS_OK(status)) {
1326                 TALLOC_FREE(mapped_name);
1327                 errno = map_errno_from_nt_status(status);
1328                 return -1;
1329         }
1330
1331         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1332                                         mapped_name,
1333                                         NULL,
1334                                         &smb_fname->st,
1335                                         smb_fname->twrp,
1336                                         smb_fname->flags);
1337         if (mapped_smb_fname == NULL) {
1338                 TALLOC_FREE(mapped_name);
1339                 TALLOC_FREE(mapped_ea_name);
1340                 errno = ENOMEM;
1341                 return -1;
1342         }
1343
1344         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, mapped_smb_fname,
1345                                 mapped_ea_name);
1346         if (ret == -1) {
1347                 saved_errno = errno;
1348         }
1349         TALLOC_FREE(mapped_name);
1350         TALLOC_FREE(mapped_ea_name);
1351         TALLOC_FREE(mapped_smb_fname);
1352         if (saved_errno != 0) {
1353                 errno = saved_errno;
1354         }
1355
1356         return ret;
1357 }
1358
1359 static int
1360 catia_setxattr(vfs_handle_struct *handle,
1361                         const struct smb_filename *smb_fname,
1362                         const char *name,
1363                         const void *value,
1364                         size_t size,
1365                         int flags)
1366 {
1367         struct smb_filename *mapped_smb_fname = NULL;
1368         char *mapped_name = NULL;
1369         char *mapped_ea_name = NULL;
1370         NTSTATUS status;
1371         ssize_t ret;
1372         int saved_errno = 0;
1373
1374         status = catia_string_replace_allocate(handle->conn,
1375                                 smb_fname->base_name,
1376                                 &mapped_name,
1377                                 vfs_translate_to_unix);
1378         if (!NT_STATUS_IS_OK(status)) {
1379                 errno = map_errno_from_nt_status(status);
1380                 return -1;
1381         }
1382
1383         status = catia_string_replace_allocate(handle->conn,
1384                                 name, &mapped_ea_name, vfs_translate_to_unix);
1385         if (!NT_STATUS_IS_OK(status)) {
1386                 TALLOC_FREE(mapped_name);
1387                 errno = map_errno_from_nt_status(status);
1388                 return -1;
1389         }
1390
1391         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1392                                         mapped_name,
1393                                         NULL,
1394                                         &smb_fname->st,
1395                                         smb_fname->twrp,
1396                                         smb_fname->flags);
1397         if (mapped_smb_fname == NULL) {
1398                 TALLOC_FREE(mapped_name);
1399                 TALLOC_FREE(mapped_ea_name);
1400                 errno = ENOMEM;
1401                 return -1;
1402         }
1403
1404         ret = SMB_VFS_NEXT_SETXATTR(handle, mapped_smb_fname, mapped_ea_name,
1405                         value, size, flags);
1406         if (ret == -1) {
1407                 saved_errno = errno;
1408         }
1409         TALLOC_FREE(mapped_name);
1410         TALLOC_FREE(mapped_ea_name);
1411         TALLOC_FREE(mapped_smb_fname);
1412         if (saved_errno != 0) {
1413                 errno = saved_errno;
1414         }
1415
1416         return ret;
1417 }
1418
1419 static int catia_fstat(vfs_handle_struct *handle,
1420                        files_struct *fsp,
1421                        SMB_STRUCT_STAT *sbuf)
1422 {
1423         struct catia_cache *cc = NULL;
1424         int ret;
1425
1426         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1427         if (ret != 0) {
1428                 return ret;
1429         }
1430
1431         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1432
1433         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1434
1435         return ret;
1436 }
1437
1438 static ssize_t catia_pread(vfs_handle_struct *handle,
1439                            files_struct *fsp, void *data,
1440                            size_t n, off_t offset)
1441 {
1442         struct catia_cache *cc = NULL;
1443         ssize_t result;
1444         int ret;
1445
1446         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1447         if (ret != 0) {
1448                 return ret;
1449         }
1450
1451         result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
1452
1453         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1454
1455         return result;
1456 }
1457
1458 static ssize_t catia_pwrite(vfs_handle_struct *handle,
1459                             files_struct *fsp, const void *data,
1460                             size_t n, off_t offset)
1461 {
1462         struct catia_cache *cc = NULL;
1463         ssize_t result;
1464         int ret;
1465
1466         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1467         if (ret != 0) {
1468                 return ret;
1469         }
1470
1471         result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
1472
1473         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1474
1475         return result;
1476 }
1477
1478 static int catia_ftruncate(struct vfs_handle_struct *handle,
1479                            struct files_struct *fsp,
1480                            off_t offset)
1481 {
1482         struct catia_cache *cc = NULL;
1483         int ret;
1484
1485         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1486         if (ret != 0) {
1487                 return ret;
1488         }
1489
1490         ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
1491
1492         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1493
1494         return ret;
1495 }
1496
1497 static int catia_fallocate(struct vfs_handle_struct *handle,
1498                            struct files_struct *fsp,
1499                            uint32_t mode,
1500                            off_t offset,
1501                            off_t len)
1502 {
1503         struct catia_cache *cc = NULL;
1504         int ret;
1505
1506         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1507         if (ret != 0) {
1508                 return ret;
1509         }
1510
1511         ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
1512
1513         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1514
1515         return ret;
1516 }
1517
1518 static ssize_t catia_fgetxattr(struct vfs_handle_struct *handle,
1519                                struct files_struct *fsp,
1520                                const char *name,
1521                                void *value,
1522                                size_t size)
1523 {
1524         char *mapped_xattr_name = NULL;
1525         NTSTATUS status;
1526         ssize_t result;
1527
1528         status = catia_string_replace_allocate(handle->conn,
1529                                                name, &mapped_xattr_name,
1530                                                vfs_translate_to_unix);
1531         if (!NT_STATUS_IS_OK(status)) {
1532                 errno = map_errno_from_nt_status(status);
1533                 return -1;
1534         }
1535
1536         result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, mapped_xattr_name,
1537                                         value, size);
1538
1539         TALLOC_FREE(mapped_xattr_name);
1540
1541         return result;
1542 }
1543
1544 static ssize_t catia_flistxattr(struct vfs_handle_struct *handle,
1545                                 struct files_struct *fsp,
1546                                 char *list,
1547                                 size_t size)
1548 {
1549         struct catia_cache *cc = NULL;
1550         ssize_t result;
1551         int ret;
1552
1553         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1554         if (ret != 0) {
1555                 return ret;
1556         }
1557
1558         result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
1559
1560         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1561
1562         return result;
1563 }
1564
1565 static int catia_fremovexattr(struct vfs_handle_struct *handle,
1566                               struct files_struct *fsp,
1567                               const char *name)
1568 {
1569         char *mapped_name = NULL;
1570         NTSTATUS status;
1571         int ret;
1572
1573         status = catia_string_replace_allocate(handle->conn,
1574                                 name, &mapped_name, vfs_translate_to_unix);
1575         if (!NT_STATUS_IS_OK(status)) {
1576                 errno = map_errno_from_nt_status(status);
1577                 return -1;
1578         }
1579
1580         ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, mapped_name);
1581
1582         TALLOC_FREE(mapped_name);
1583
1584         return ret;
1585 }
1586
1587 static int catia_fsetxattr(struct vfs_handle_struct *handle,
1588                            struct files_struct *fsp,
1589                            const char *name,
1590                            const void *value,
1591                            size_t size,
1592                            int flags)
1593 {
1594         char *mapped_xattr_name = NULL;
1595         NTSTATUS status;
1596         int ret;
1597
1598         status = catia_string_replace_allocate(
1599                 handle->conn, name, &mapped_xattr_name, vfs_translate_to_unix);
1600         if (!NT_STATUS_IS_OK(status)) {
1601                 errno = map_errno_from_nt_status(status);
1602                 return -1;
1603         }
1604
1605         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, mapped_xattr_name,
1606                                      value, size, flags);
1607
1608         TALLOC_FREE(mapped_xattr_name);
1609
1610         return ret;
1611 }
1612
1613 static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle,
1614                                       files_struct *fsp,
1615                                       TALLOC_CTX *mem_ctx)
1616 {
1617         struct catia_cache *cc = NULL;
1618         struct smb_acl_t *result = NULL;
1619         int ret;
1620
1621         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1622         if (ret != 0) {
1623                 return NULL;
1624         }
1625
1626         result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
1627
1628         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1629
1630         return result;
1631 }
1632
1633 static int catia_sys_acl_blob_get_fd(vfs_handle_struct *handle,
1634                                      files_struct *fsp,
1635                                      TALLOC_CTX *mem_ctx,
1636                                      char **blob_description,
1637                                      DATA_BLOB *blob)
1638 {
1639         struct catia_cache *cc = NULL;
1640         int ret;
1641
1642         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1643         if (ret != 0) {
1644                 return ret;
1645         }
1646
1647         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
1648                                                blob_description, blob);
1649
1650         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1651
1652         return ret;
1653 }
1654
1655 static int catia_sys_acl_set_fd(vfs_handle_struct *handle,
1656                                 files_struct *fsp,
1657                                 SMB_ACL_T theacl)
1658 {
1659         struct catia_cache *cc = NULL;
1660         int ret;
1661
1662         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1663         if (ret != 0) {
1664                 return ret;
1665         }
1666
1667         ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
1668
1669         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1670
1671         return ret;
1672 }
1673
1674 static NTSTATUS catia_fget_nt_acl(vfs_handle_struct *handle,
1675                                   files_struct *fsp,
1676                                   uint32_t security_info,
1677                                   TALLOC_CTX *mem_ctx,
1678                                   struct security_descriptor **ppdesc)
1679 {
1680         struct catia_cache *cc = NULL;
1681         NTSTATUS status;
1682         int ret;
1683
1684         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1685         if (ret != 0) {
1686                 return map_nt_error_from_unix(errno);
1687         }
1688
1689         status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1690                                           mem_ctx, ppdesc);
1691
1692         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1693
1694         return status;
1695 }
1696
1697 static NTSTATUS catia_fset_nt_acl(vfs_handle_struct *handle,
1698                                   files_struct *fsp,
1699                                   uint32_t security_info_sent,
1700                                   const struct security_descriptor *psd)
1701 {
1702         struct catia_cache *cc = NULL;
1703         NTSTATUS status;
1704         int ret;
1705
1706         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1707         if (ret != 0) {
1708                 return map_nt_error_from_unix(errno);
1709         }
1710
1711         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
1712
1713         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1714
1715         return status;
1716 }
1717
1718 static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle,
1719                                           struct files_struct *fsp,
1720                                           uint32_t dosmode)
1721 {
1722         struct catia_cache *cc = NULL;
1723         NTSTATUS status;
1724         int ret;
1725
1726         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1727         if (ret != 0) {
1728                 return map_nt_error_from_unix(errno);
1729         }
1730
1731         status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1732
1733         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1734
1735         return status;
1736 }
1737
1738 static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle,
1739                                           struct files_struct *fsp,
1740                                           uint32_t *dosmode)
1741 {
1742         struct catia_cache *cc = NULL;
1743         NTSTATUS status;
1744         int ret;
1745
1746         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1747         if (ret != 0) {
1748                 return map_nt_error_from_unix(errno);
1749         }
1750
1751         status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1752
1753         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1754
1755         return status;
1756 }
1757
1758 static int catia_fchown(vfs_handle_struct *handle,
1759                         files_struct *fsp,
1760                         uid_t uid,
1761                         gid_t gid)
1762 {
1763         struct catia_cache *cc = NULL;
1764         int ret;
1765
1766         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1767         if (ret != 0) {
1768                 return ret;
1769         }
1770
1771         ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
1772
1773         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1774
1775         return ret;
1776 }
1777
1778 static int catia_fchmod(vfs_handle_struct *handle,
1779                         files_struct *fsp,
1780                         mode_t mode)
1781 {
1782         struct catia_cache *cc = NULL;
1783         int ret;
1784
1785         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1786         if (ret != 0) {
1787                 return ret;
1788         }
1789
1790         ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1791
1792         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1793
1794         return ret;
1795 }
1796
1797 struct catia_pread_state {
1798         ssize_t ret;
1799         struct vfs_aio_state vfs_aio_state;
1800         struct files_struct *fsp;
1801         struct catia_cache *cc;
1802 };
1803
1804 static void catia_pread_done(struct tevent_req *subreq);
1805
1806 static struct tevent_req *catia_pread_send(struct vfs_handle_struct *handle,
1807                                            TALLOC_CTX *mem_ctx,
1808                                            struct tevent_context *ev,
1809                                            struct files_struct *fsp,
1810                                            void *data,
1811                                            size_t n,
1812                                            off_t offset)
1813 {
1814         struct tevent_req *req = NULL, *subreq = NULL;
1815         struct catia_pread_state *state = NULL;
1816         int ret;
1817
1818         req = tevent_req_create(mem_ctx, &state,
1819                                 struct catia_pread_state);
1820         if (req == NULL) {
1821                 return NULL;
1822         }
1823         state->fsp = fsp;
1824
1825         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1826         if (ret != 0) {
1827                 tevent_req_error(req, errno);
1828                 return tevent_req_post(req, ev);
1829         }
1830
1831         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
1832                                          n, offset);
1833         if (tevent_req_nomem(subreq, req)) {
1834                 return tevent_req_post(req, ev);
1835         }
1836         tevent_req_set_callback(subreq, catia_pread_done, req);
1837
1838         return req;
1839 }
1840
1841 static void catia_pread_done(struct tevent_req *subreq)
1842 {
1843         struct tevent_req *req = tevent_req_callback_data(
1844                 subreq, struct tevent_req);
1845         struct catia_pread_state *state = tevent_req_data(
1846                 req, struct catia_pread_state);
1847
1848         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
1849         TALLOC_FREE(subreq);
1850
1851         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1852
1853         tevent_req_done(req);
1854 }
1855
1856 static ssize_t catia_pread_recv(struct tevent_req *req,
1857                                 struct vfs_aio_state *vfs_aio_state)
1858 {
1859         struct catia_pread_state *state = tevent_req_data(
1860                 req, struct catia_pread_state);
1861
1862         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1863                 return -1;
1864         }
1865
1866         *vfs_aio_state = state->vfs_aio_state;
1867         return state->ret;
1868 }
1869
1870 struct catia_pwrite_state {
1871         ssize_t ret;
1872         struct vfs_aio_state vfs_aio_state;
1873         struct files_struct *fsp;
1874         struct catia_cache *cc;
1875 };
1876
1877 static void catia_pwrite_done(struct tevent_req *subreq);
1878
1879 static struct tevent_req *catia_pwrite_send(struct vfs_handle_struct *handle,
1880                                             TALLOC_CTX *mem_ctx,
1881                                             struct tevent_context *ev,
1882                                             struct files_struct *fsp,
1883                                             const void *data,
1884                                             size_t n,
1885                                             off_t offset)
1886 {
1887         struct tevent_req *req = NULL, *subreq = NULL;
1888         struct catia_pwrite_state *state = NULL;
1889         int ret;
1890
1891         req = tevent_req_create(mem_ctx, &state,
1892                                 struct catia_pwrite_state);
1893         if (req == NULL) {
1894                 return NULL;
1895         }
1896         state->fsp = fsp;
1897
1898         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1899         if (ret != 0) {
1900                 tevent_req_error(req, errno);
1901                 return tevent_req_post(req, ev);
1902         }
1903
1904         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
1905                                           n, offset);
1906         if (tevent_req_nomem(subreq, req)) {
1907                 return tevent_req_post(req, ev);
1908         }
1909         tevent_req_set_callback(subreq, catia_pwrite_done, req);
1910
1911         return req;
1912 }
1913
1914 static void catia_pwrite_done(struct tevent_req *subreq)
1915 {
1916         struct tevent_req *req = tevent_req_callback_data(
1917                 subreq, struct tevent_req);
1918         struct catia_pwrite_state *state = tevent_req_data(
1919                 req, struct catia_pwrite_state);
1920
1921         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
1922         TALLOC_FREE(subreq);
1923
1924         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1925
1926         tevent_req_done(req);
1927 }
1928
1929 static ssize_t catia_pwrite_recv(struct tevent_req *req,
1930                                 struct vfs_aio_state *vfs_aio_state)
1931 {
1932         struct catia_pwrite_state *state = tevent_req_data(
1933                 req, struct catia_pwrite_state);
1934
1935         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1936                 return -1;
1937         }
1938
1939         *vfs_aio_state = state->vfs_aio_state;
1940         return state->ret;
1941 }
1942
1943 static off_t catia_lseek(vfs_handle_struct *handle,
1944                          files_struct *fsp,
1945                          off_t offset,
1946                          int whence)
1947 {
1948         struct catia_cache *cc = NULL;
1949         ssize_t result;
1950         int ret;
1951
1952         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1953         if (ret != 0) {
1954                 return -1;
1955         }
1956
1957         result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
1958
1959         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1960
1961         return result;
1962 }
1963
1964 struct catia_fsync_state {
1965         int ret;
1966         struct vfs_aio_state vfs_aio_state;
1967         struct files_struct *fsp;
1968         struct catia_cache *cc;
1969 };
1970
1971 static void catia_fsync_done(struct tevent_req *subreq);
1972
1973 static struct tevent_req *catia_fsync_send(struct vfs_handle_struct *handle,
1974                                            TALLOC_CTX *mem_ctx,
1975                                            struct tevent_context *ev,
1976                                            struct files_struct *fsp)
1977 {
1978         struct tevent_req *req = NULL, *subreq = NULL;
1979         struct catia_fsync_state *state = NULL;
1980         int ret;
1981
1982         req = tevent_req_create(mem_ctx, &state,
1983                                 struct catia_fsync_state);
1984         if (req == NULL) {
1985                 return NULL;
1986         }
1987         state->fsp = fsp;
1988
1989         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1990         if (ret != 0) {
1991                 tevent_req_error(req, errno);
1992                 return tevent_req_post(req, ev);
1993         }
1994
1995         subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
1996         if (tevent_req_nomem(subreq, req)) {
1997                 return tevent_req_post(req, ev);
1998         }
1999         tevent_req_set_callback(subreq, catia_fsync_done, req);
2000
2001         return req;
2002 }
2003
2004 static void catia_fsync_done(struct tevent_req *subreq)
2005 {
2006         struct tevent_req *req = tevent_req_callback_data(
2007                 subreq, struct tevent_req);
2008         struct catia_fsync_state *state = tevent_req_data(
2009                 req, struct catia_fsync_state);
2010
2011         state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
2012         TALLOC_FREE(subreq);
2013
2014         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
2015
2016         tevent_req_done(req);
2017 }
2018
2019 static int catia_fsync_recv(struct tevent_req *req,
2020                             struct vfs_aio_state *vfs_aio_state)
2021 {
2022         struct catia_fsync_state *state = tevent_req_data(
2023                 req, struct catia_fsync_state);
2024
2025         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2026                 return -1;
2027         }
2028
2029         *vfs_aio_state = state->vfs_aio_state;
2030         return state->ret;
2031 }
2032
2033 static bool catia_lock(vfs_handle_struct *handle,
2034                        files_struct *fsp,
2035                        int op,
2036                        off_t offset,
2037                        off_t count,
2038                        int type)
2039 {
2040         struct catia_cache *cc = NULL;
2041         bool ok;
2042         int ret;
2043
2044         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2045         if (ret != 0) {
2046                 return false;
2047         }
2048
2049         ok = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
2050
2051         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2052
2053         return ok;
2054 }
2055
2056 static int catia_kernel_flock(struct vfs_handle_struct *handle,
2057                               struct files_struct *fsp,
2058                               uint32_t share_access,
2059                               uint32_t access_mask)
2060 {
2061         struct catia_cache *cc = NULL;
2062         int ret;
2063
2064         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2065         if (ret != 0) {
2066                 return -1;
2067         }
2068
2069         ret = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_access, access_mask);
2070
2071         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2072
2073         return ret;
2074 }
2075
2076 static int catia_linux_setlease(vfs_handle_struct *handle,
2077                                 files_struct *fsp,
2078                                 int leasetype)
2079 {
2080         struct catia_cache *cc = NULL;
2081         int ret;
2082
2083         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2084         if (ret != 0) {
2085                 return -1;
2086         }
2087
2088         ret = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
2089
2090         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2091
2092         return ret;
2093 }
2094
2095 static bool catia_getlock(vfs_handle_struct *handle,
2096                           files_struct *fsp,
2097                           off_t *poffset,
2098                           off_t *pcount,
2099                           int *ptype,
2100                           pid_t *ppid)
2101 {
2102         struct catia_cache *cc = NULL;
2103         int ret;
2104         bool ok;
2105
2106         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2107         if (ret != 0) {
2108                 return false;
2109         }
2110
2111         ok = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
2112
2113         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2114
2115         return ok;
2116 }
2117
2118 static bool catia_strict_lock_check(struct vfs_handle_struct *handle,
2119                                     struct files_struct *fsp,
2120                                     struct lock_struct *plock)
2121 {
2122         struct catia_cache *cc = NULL;
2123         int ret;
2124         bool ok;
2125
2126         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2127         if (ret != 0) {
2128                 return false;
2129         }
2130
2131         ok = SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock);
2132
2133         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2134
2135         return ok;
2136 }
2137
2138 static NTSTATUS catia_fsctl(struct vfs_handle_struct *handle,
2139                             struct files_struct *fsp,
2140                             TALLOC_CTX *ctx,
2141                             uint32_t function,
2142                             uint16_t req_flags,
2143                             const uint8_t *_in_data,
2144                             uint32_t in_len,
2145                             uint8_t **_out_data,
2146                             uint32_t max_out_len,
2147                             uint32_t *out_len)
2148 {
2149         NTSTATUS result;
2150         struct catia_cache *cc = NULL;
2151         int ret;
2152
2153         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2154         if (ret != 0) {
2155                 return map_nt_error_from_unix(errno);
2156         }
2157
2158         result = SMB_VFS_NEXT_FSCTL(handle,
2159                                 fsp,
2160                                 ctx,
2161                                 function,
2162                                 req_flags,
2163                                 _in_data,
2164                                 in_len,
2165                                 _out_data,
2166                                 max_out_len,
2167                                 out_len);
2168
2169         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2170
2171         return result;
2172 }
2173
2174 static NTSTATUS catia_get_compression(vfs_handle_struct *handle,
2175                                       TALLOC_CTX *mem_ctx,
2176                                       struct files_struct *fsp,
2177                                       struct smb_filename *smb_fname,
2178                                       uint16_t *_compression_fmt)
2179 {
2180         NTSTATUS result;
2181         struct catia_cache *cc = NULL;
2182         int ret;
2183         struct smb_filename *mapped_smb_fname = NULL;
2184         char *mapped_name = NULL;
2185
2186         if (fsp != NULL) {
2187                 ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2188                 if (ret != 0) {
2189                         return map_nt_error_from_unix(errno);
2190                 }
2191                 mapped_smb_fname = fsp->fsp_name;
2192         } else {
2193                 result = catia_string_replace_allocate(handle->conn,
2194                                 smb_fname->base_name,
2195                                 &mapped_name,
2196                                 vfs_translate_to_unix);
2197                 if (!NT_STATUS_IS_OK(result)) {
2198                         return result;
2199                 }
2200
2201                 mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2202                                                 mapped_name,
2203                                                 NULL,
2204                                                 &smb_fname->st,
2205                                                 smb_fname->twrp,
2206                                                 smb_fname->flags);
2207                 if (mapped_smb_fname == NULL) {
2208                         TALLOC_FREE(mapped_name);
2209                         return NT_STATUS_NO_MEMORY;
2210                 }
2211
2212                 TALLOC_FREE(mapped_name);
2213         }
2214
2215         result = SMB_VFS_NEXT_GET_COMPRESSION(handle,
2216                                         mem_ctx,
2217                                         fsp,
2218                                         mapped_smb_fname,
2219                                         _compression_fmt);
2220
2221         if (fsp != NULL) {
2222                 CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2223         } else {
2224                 TALLOC_FREE(mapped_smb_fname);
2225         }
2226
2227         return result;
2228 }
2229
2230 static NTSTATUS catia_set_compression(vfs_handle_struct *handle,
2231                                       TALLOC_CTX *mem_ctx,
2232                                       struct files_struct *fsp,
2233                                       uint16_t compression_fmt)
2234 {
2235         NTSTATUS result;
2236         struct catia_cache *cc = NULL;
2237         int ret;
2238
2239         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2240         if (ret != 0) {
2241                 return map_nt_error_from_unix(errno);
2242         }
2243
2244         result = SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp,
2245                                               compression_fmt);
2246
2247         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2248
2249         return result;
2250 }
2251
2252 static NTSTATUS catia_readdir_attr(struct vfs_handle_struct *handle,
2253                                    const struct smb_filename *smb_fname_in,
2254                                    TALLOC_CTX *mem_ctx,
2255                                    struct readdir_attr_data **pattr_data)
2256 {
2257         struct smb_filename *smb_fname;
2258         char *fname = NULL;
2259         NTSTATUS status;
2260
2261         status = catia_string_replace_allocate(handle->conn,
2262                                                smb_fname_in->base_name,
2263                                                &fname,
2264                                                vfs_translate_to_unix);
2265         if (!NT_STATUS_IS_OK(status)) {
2266                 errno = map_errno_from_nt_status(status);
2267                 return status;
2268         }
2269
2270         smb_fname = synthetic_smb_fname(talloc_tos(),
2271                                         fname,
2272                                         NULL,
2273                                         &smb_fname_in->st,
2274                                         smb_fname_in->twrp,
2275                                         0);
2276
2277         status = SMB_VFS_NEXT_READDIR_ATTR(handle, smb_fname, mem_ctx, pattr_data);
2278
2279         TALLOC_FREE(smb_fname);
2280         TALLOC_FREE(fname);
2281         return status;
2282 }
2283
2284 static NTSTATUS catia_get_dos_attributes(struct vfs_handle_struct *handle,
2285                                          struct smb_filename *smb_fname,
2286                                          uint32_t *dosmode)
2287 {
2288         char *mapped_name = NULL;
2289         const char *path = smb_fname->base_name;
2290         struct smb_filename *mapped_smb_fname = NULL;
2291         NTSTATUS status;
2292
2293         status = catia_string_replace_allocate(handle->conn,
2294                                 path, &mapped_name, vfs_translate_to_unix);
2295         if (!NT_STATUS_IS_OK(status)) {
2296                 errno = map_errno_from_nt_status(status);
2297                 return status;
2298         }
2299         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2300                                         mapped_name,
2301                                         NULL,
2302                                         &smb_fname->st,
2303                                         smb_fname->twrp,
2304                                         smb_fname->flags);
2305         if (mapped_smb_fname == NULL) {
2306                 TALLOC_FREE(mapped_name);
2307                 return NT_STATUS_NO_MEMORY;
2308         }
2309
2310         status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle,
2311                                                  mapped_smb_fname,
2312                                                  dosmode);
2313         if (NT_STATUS_IS_OK(status)) {
2314                 smb_fname->st = mapped_smb_fname->st;
2315         }
2316
2317         TALLOC_FREE(mapped_name);
2318         TALLOC_FREE(mapped_smb_fname);
2319
2320         return status;
2321 }
2322
2323 static NTSTATUS catia_set_dos_attributes(struct vfs_handle_struct *handle,
2324                                          const struct smb_filename *smb_fname,
2325                                          uint32_t dosmode)
2326 {
2327         char *mapped_name = NULL;
2328         const char *path = smb_fname->base_name;
2329         struct smb_filename *mapped_smb_fname = NULL;
2330         NTSTATUS status;
2331
2332         status = catia_string_replace_allocate(handle->conn,
2333                                 path, &mapped_name, vfs_translate_to_unix);
2334         if (!NT_STATUS_IS_OK(status)) {
2335                 errno = map_errno_from_nt_status(status);
2336                 return status;
2337         }
2338         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2339                                         mapped_name,
2340                                         NULL,
2341                                         &smb_fname->st,
2342                                         smb_fname->twrp,
2343                                         smb_fname->flags);
2344         if (mapped_smb_fname == NULL) {
2345                 TALLOC_FREE(mapped_name);
2346                 return NT_STATUS_NO_MEMORY;
2347         }
2348
2349         status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
2350                                                  mapped_smb_fname,
2351                                                  dosmode);
2352         TALLOC_FREE(mapped_name);
2353         TALLOC_FREE(mapped_smb_fname);
2354
2355         return status;
2356 }
2357
2358 static NTSTATUS catia_create_dfs_pathat(struct vfs_handle_struct *handle,
2359                         struct files_struct *dirfsp,
2360                         const struct smb_filename *smb_fname,
2361                         const struct referral *reflist,
2362                         size_t referral_count)
2363 {
2364         char *mapped_name = NULL;
2365         const char *path = smb_fname->base_name;
2366         struct smb_filename *mapped_smb_fname = NULL;
2367         NTSTATUS status;
2368
2369         status = catia_string_replace_allocate(handle->conn,
2370                                         path,
2371                                         &mapped_name,
2372                                         vfs_translate_to_unix);
2373         if (!NT_STATUS_IS_OK(status)) {
2374                 errno = map_errno_from_nt_status(status);
2375                 return status;
2376         }
2377         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2378                                         mapped_name,
2379                                         NULL,
2380                                         &smb_fname->st,
2381                                         smb_fname->twrp,
2382                                         smb_fname->flags);
2383         if (mapped_smb_fname == NULL) {
2384                 TALLOC_FREE(mapped_name);
2385                 return NT_STATUS_NO_MEMORY;
2386         }
2387
2388         status = SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
2389                                         dirfsp,
2390                                         mapped_smb_fname,
2391                                         reflist,
2392                                         referral_count);
2393         TALLOC_FREE(mapped_name);
2394         TALLOC_FREE(mapped_smb_fname);
2395         return status;
2396 }
2397
2398 static NTSTATUS catia_read_dfs_pathat(struct vfs_handle_struct *handle,
2399                         TALLOC_CTX *mem_ctx,
2400                         struct files_struct *dirfsp,
2401                         const struct smb_filename *smb_fname,
2402                         struct referral **ppreflist,
2403                         size_t *preferral_count)
2404 {
2405         char *mapped_name = NULL;
2406         const char *path = smb_fname->base_name;
2407         struct smb_filename *mapped_smb_fname = NULL;
2408         NTSTATUS status;
2409
2410         status = catia_string_replace_allocate(handle->conn,
2411                                         path,
2412                                         &mapped_name,
2413                                         vfs_translate_to_unix);
2414         if (!NT_STATUS_IS_OK(status)) {
2415                 errno = map_errno_from_nt_status(status);
2416                 return status;
2417         }
2418         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2419                                         mapped_name,
2420                                         NULL,
2421                                         &smb_fname->st,
2422                                         smb_fname->twrp,
2423                                         smb_fname->flags);
2424         if (mapped_smb_fname == NULL) {
2425                 TALLOC_FREE(mapped_name);
2426                 return NT_STATUS_NO_MEMORY;
2427         }
2428
2429         status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
2430                                         mem_ctx,
2431                                         dirfsp,
2432                                         mapped_smb_fname,
2433                                         ppreflist,
2434                                         preferral_count);
2435         TALLOC_FREE(mapped_name);
2436         TALLOC_FREE(mapped_smb_fname);
2437         return status;
2438 }
2439
2440 static struct vfs_fn_pointers vfs_catia_fns = {
2441         .connect_fn = catia_connect,
2442
2443         /* Directory operations */
2444         .mkdirat_fn = catia_mkdirat,
2445         .readdir_attr_fn = catia_readdir_attr,
2446
2447         /* File operations */
2448         .open_fn = catia_open,
2449         .pread_fn = catia_pread,
2450         .pread_send_fn = catia_pread_send,
2451         .pread_recv_fn = catia_pread_recv,
2452         .pwrite_fn = catia_pwrite,
2453         .pwrite_send_fn = catia_pwrite_send,
2454         .pwrite_recv_fn = catia_pwrite_recv,
2455         .lseek_fn = catia_lseek,
2456         .renameat_fn = catia_renameat,
2457         .fsync_send_fn = catia_fsync_send,
2458         .fsync_recv_fn = catia_fsync_recv,
2459         .stat_fn = catia_stat,
2460         .fstat_fn = catia_fstat,
2461         .lstat_fn = catia_lstat,
2462         .unlinkat_fn = catia_unlinkat,
2463         .chmod_fn = catia_chmod,
2464         .fchmod_fn = catia_fchmod,
2465         .fchown_fn = catia_fchown,
2466         .lchown_fn = catia_lchown,
2467         .chdir_fn = catia_chdir,
2468         .ntimes_fn = catia_ntimes,
2469         .ftruncate_fn = catia_ftruncate,
2470         .fallocate_fn = catia_fallocate,
2471         .lock_fn = catia_lock,
2472         .kernel_flock_fn = catia_kernel_flock,
2473         .linux_setlease_fn = catia_linux_setlease,
2474         .getlock_fn = catia_getlock,
2475         .realpath_fn = catia_realpath,
2476         .chflags_fn = catia_chflags,
2477         .streaminfo_fn = catia_streaminfo,
2478         .strict_lock_check_fn = catia_strict_lock_check,
2479         .translate_name_fn = catia_translate_name,
2480         .fsctl_fn = catia_fsctl,
2481         .get_dos_attributes_fn = catia_get_dos_attributes,
2482         .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
2483         .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
2484         .set_dos_attributes_fn = catia_set_dos_attributes,
2485         .fset_dos_attributes_fn = catia_fset_dos_attributes,
2486         .fget_dos_attributes_fn = catia_fget_dos_attributes,
2487         .get_compression_fn = catia_get_compression,
2488         .set_compression_fn = catia_set_compression,
2489         .create_dfs_pathat_fn = catia_create_dfs_pathat,
2490         .read_dfs_pathat_fn = catia_read_dfs_pathat,
2491
2492         /* NT ACL operations. */
2493         .get_nt_acl_at_fn = catia_get_nt_acl_at,
2494         .fget_nt_acl_fn = catia_fget_nt_acl,
2495         .fset_nt_acl_fn = catia_fset_nt_acl,
2496
2497         /* POSIX ACL operations. */
2498         .sys_acl_get_file_fn = catia_sys_acl_get_file,
2499         .sys_acl_get_fd_fn = catia_sys_acl_get_fd,
2500         .sys_acl_blob_get_fd_fn = catia_sys_acl_blob_get_fd,
2501         .sys_acl_set_file_fn = catia_sys_acl_set_file,
2502         .sys_acl_set_fd_fn = catia_sys_acl_set_fd,
2503         .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file,
2504
2505         /* EA operations. */
2506         .getxattr_fn = catia_getxattr,
2507         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2508         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2509         .listxattr_fn = catia_listxattr,
2510         .removexattr_fn = catia_removexattr,
2511         .setxattr_fn = catia_setxattr,
2512         .fgetxattr_fn = catia_fgetxattr,
2513         .flistxattr_fn = catia_flistxattr,
2514         .fremovexattr_fn = catia_fremovexattr,
2515         .fsetxattr_fn = catia_fsetxattr,
2516 };
2517
2518 static_decl_vfs;
2519 NTSTATUS vfs_catia_init(TALLOC_CTX *ctx)
2520 {
2521         NTSTATUS ret;
2522
2523         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
2524                                 &vfs_catia_fns);
2525         if (!NT_STATUS_IS_OK(ret))
2526                 return ret;
2527
2528         vfs_catia_debug_level = debug_add_class("catia");
2529         if (vfs_catia_debug_level == -1) {
2530                 vfs_catia_debug_level = DBGC_VFS;
2531                 DEBUG(0, ("vfs_catia: Couldn't register custom debugging "
2532                           "class!\n"));
2533         } else {
2534                 DEBUG(10, ("vfs_catia: Debug class number of "
2535                            "'catia': %d\n", vfs_catia_debug_level));
2536         }
2537
2538         return ret;
2539
2540 }