VFS: Remove SMB_VFS_LISTXATTR, no longer used
[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 catia_saved_errno = errno; \
442         catia_fetch_fsp_post_next((_cc), (fsp), __func__); \
443         errno = catia_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_openat(vfs_handle_struct *handle,
489                         const struct files_struct *dirfsp,
490                         const struct smb_filename *smb_fname_in,
491                         files_struct *fsp,
492                         int flags,
493                         mode_t mode)
494 {
495         struct smb_filename *smb_fname = NULL;
496         struct catia_cache *cc = NULL;
497         char *mapped_name = NULL;
498         NTSTATUS status;
499         int ret;
500         int saved_errno = 0;
501
502         status = catia_string_replace_allocate(handle->conn,
503                                                smb_fname_in->base_name,
504                                                &mapped_name,
505                                                vfs_translate_to_unix);
506         if (!NT_STATUS_IS_OK(status)) {
507                 return -1;
508         }
509
510         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
511         if (ret != 0) {
512                 TALLOC_FREE(mapped_name);
513                 return ret;
514         }
515
516         smb_fname = cp_smb_filename(talloc_tos(), smb_fname_in);
517         if (smb_fname == NULL) {
518                 TALLOC_FREE(mapped_name);
519                 errno = ENOMEM;
520                 return -1;
521         }
522         smb_fname->base_name = mapped_name;
523
524         ret = SMB_VFS_NEXT_OPENAT(handle,
525                                   dirfsp,
526                                   smb_fname,
527                                   fsp,
528                                   flags,
529                                   mode);
530
531         if (ret == -1) {
532                 saved_errno = errno;
533         }
534         TALLOC_FREE(smb_fname);
535         TALLOC_FREE(mapped_name);
536         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
537         if (saved_errno != 0) {
538                 errno = saved_errno;
539         }
540         return ret;
541 }
542
543 static int catia_renameat(vfs_handle_struct *handle,
544                         files_struct *srcfsp,
545                         const struct smb_filename *smb_fname_src,
546                         files_struct *dstfsp,
547                         const struct smb_filename *smb_fname_dst)
548 {
549         TALLOC_CTX *ctx = talloc_tos();
550         struct smb_filename *smb_fname_src_tmp = NULL;
551         struct smb_filename *smb_fname_dst_tmp = NULL;
552         char *src_name_mapped = NULL;
553         char *dst_name_mapped = NULL;
554         NTSTATUS status;
555         int ret = -1;
556
557         status = catia_string_replace_allocate(handle->conn,
558                                 smb_fname_src->base_name,
559                                 &src_name_mapped, vfs_translate_to_unix);
560         if (!NT_STATUS_IS_OK(status)) {
561                 errno = map_errno_from_nt_status(status);
562                 return -1;
563         }
564
565         status = catia_string_replace_allocate(handle->conn,
566                                 smb_fname_dst->base_name,
567                                 &dst_name_mapped, vfs_translate_to_unix);
568         if (!NT_STATUS_IS_OK(status)) {
569                 errno = map_errno_from_nt_status(status);
570                 return -1;
571         }
572
573         /* Setup temporary smb_filename structs. */
574         smb_fname_src_tmp = cp_smb_filename(ctx, smb_fname_src);
575         if (smb_fname_src_tmp == NULL) {
576                 errno = ENOMEM;
577                 goto out;
578         }
579
580         smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
581         if (smb_fname_dst_tmp == NULL) {
582                 errno = ENOMEM;
583                 goto out;
584         }
585
586         smb_fname_src_tmp->base_name = src_name_mapped;
587         smb_fname_dst_tmp->base_name = dst_name_mapped;
588         DEBUG(10, ("converted old name: %s\n",
589                                 smb_fname_str_dbg(smb_fname_src_tmp)));
590         DEBUG(10, ("converted new name: %s\n",
591                                 smb_fname_str_dbg(smb_fname_dst_tmp)));
592
593         ret = SMB_VFS_NEXT_RENAMEAT(handle,
594                         srcfsp,
595                         smb_fname_src_tmp,
596                         dstfsp,
597                         smb_fname_dst_tmp);
598
599 out:
600         TALLOC_FREE(src_name_mapped);
601         TALLOC_FREE(dst_name_mapped);
602         TALLOC_FREE(smb_fname_src_tmp);
603         TALLOC_FREE(smb_fname_dst_tmp);
604         return ret;
605 }
606
607
608 static int catia_stat(vfs_handle_struct *handle,
609                       struct smb_filename *smb_fname)
610 {
611         char *name = NULL;
612         char *tmp_base_name;
613         int ret;
614         NTSTATUS status;
615
616         status = catia_string_replace_allocate(handle->conn,
617                                 smb_fname->base_name,
618                                 &name, vfs_translate_to_unix);
619         if (!NT_STATUS_IS_OK(status)) {
620                 errno = map_errno_from_nt_status(status);
621                 return -1;
622         }
623
624         tmp_base_name = smb_fname->base_name;
625         smb_fname->base_name = name;
626
627         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
628         smb_fname->base_name = tmp_base_name;
629
630         TALLOC_FREE(name);
631         return ret;
632 }
633
634 static int catia_lstat(vfs_handle_struct *handle,
635                        struct smb_filename *smb_fname)
636 {
637         char *name = NULL;
638         char *tmp_base_name;
639         int ret;
640         NTSTATUS status;
641
642         status = catia_string_replace_allocate(handle->conn,
643                                 smb_fname->base_name,
644                                 &name, vfs_translate_to_unix);
645         if (!NT_STATUS_IS_OK(status)) {
646                 errno = map_errno_from_nt_status(status);
647                 return -1;
648         }
649
650         tmp_base_name = smb_fname->base_name;
651         smb_fname->base_name = name;
652
653         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
654         smb_fname->base_name = tmp_base_name;
655         TALLOC_FREE(name);
656
657         return ret;
658 }
659
660 static int catia_unlinkat(vfs_handle_struct *handle,
661                         struct files_struct *dirfsp,
662                         const struct smb_filename *smb_fname,
663                         int flags)
664 {
665         struct catia_cache *cc = NULL;
666         struct smb_filename *smb_fname_tmp = NULL;
667         char *name = NULL;
668         NTSTATUS status;
669         int ret;
670
671         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, dirfsp, &cc);
672         if (ret != 0) {
673                 return ret;
674         }
675
676         status = catia_string_replace_allocate(handle->conn,
677                                         smb_fname->base_name,
678                                         &name, vfs_translate_to_unix);
679         if (!NT_STATUS_IS_OK(status)) {
680                 errno = map_errno_from_nt_status(status);
681                 goto out;
682         }
683
684         /* Setup temporary smb_filename structs. */
685         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
686         if (smb_fname_tmp == NULL) {
687                 errno = ENOMEM;
688                 goto out;
689         }
690
691         smb_fname_tmp->base_name = name;
692         smb_fname_tmp->fsp = smb_fname->fsp;
693
694         ret = SMB_VFS_NEXT_UNLINKAT(handle,
695                         dirfsp,
696                         smb_fname_tmp,
697                         flags);
698         TALLOC_FREE(smb_fname_tmp);
699         TALLOC_FREE(name);
700
701 out:
702         CATIA_FETCH_FSP_POST_NEXT(&cc, dirfsp);
703         return ret;
704 }
705
706 static int catia_lchown(vfs_handle_struct *handle,
707                         const struct smb_filename *smb_fname,
708                         uid_t uid,
709                         gid_t gid)
710 {
711         char *name = NULL;
712         NTSTATUS status;
713         int ret;
714         int saved_errno;
715         struct smb_filename *catia_smb_fname = NULL;
716
717         status = catia_string_replace_allocate(handle->conn,
718                                         smb_fname->base_name,
719                                         &name,
720                                         vfs_translate_to_unix);
721         if (!NT_STATUS_IS_OK(status)) {
722                 errno = map_errno_from_nt_status(status);
723                 return -1;
724         }
725         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
726                                         name,
727                                         NULL,
728                                         &smb_fname->st,
729                                         smb_fname->twrp,
730                                         smb_fname->flags);
731         if (catia_smb_fname == NULL) {
732                 TALLOC_FREE(name);
733                 errno = ENOMEM;
734                 return -1;
735         }
736
737         ret = SMB_VFS_NEXT_LCHOWN(handle, catia_smb_fname, uid, gid);
738         saved_errno = errno;
739         TALLOC_FREE(name);
740         TALLOC_FREE(catia_smb_fname);
741         errno = saved_errno;
742         return ret;
743 }
744
745 static int catia_chmod(vfs_handle_struct *handle,
746                         const struct smb_filename *smb_fname,
747                         mode_t mode)
748 {
749         char *name = NULL;
750         NTSTATUS status;
751         int ret;
752         int saved_errno;
753         struct smb_filename *catia_smb_fname = NULL;
754
755         status = catia_string_replace_allocate(handle->conn,
756                                         smb_fname->base_name,
757                                         &name,
758                                         vfs_translate_to_unix);
759         if (!NT_STATUS_IS_OK(status)) {
760                 errno = map_errno_from_nt_status(status);
761                 return -1;
762         }
763         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
764                                         name,
765                                         NULL,
766                                         &smb_fname->st,
767                                         smb_fname->twrp,
768                                         smb_fname->flags);
769         if (catia_smb_fname == NULL) {
770                 TALLOC_FREE(name);
771                 errno = ENOMEM;
772                 return -1;
773         }
774
775         ret = SMB_VFS_NEXT_CHMOD(handle, catia_smb_fname, mode);
776         saved_errno = errno;
777         TALLOC_FREE(name);
778         TALLOC_FREE(catia_smb_fname);
779         errno = saved_errno;
780         return ret;
781 }
782
783 static int catia_mkdirat(vfs_handle_struct *handle,
784                         struct files_struct *dirfsp,
785                         const struct smb_filename *smb_fname,
786                         mode_t mode)
787 {
788         char *name = NULL;
789         NTSTATUS status;
790         int ret;
791         struct smb_filename *catia_smb_fname = NULL;
792
793         status = catia_string_replace_allocate(handle->conn,
794                                 smb_fname->base_name,
795                                 &name,
796                                 vfs_translate_to_unix);
797         if (!NT_STATUS_IS_OK(status)) {
798                 errno = map_errno_from_nt_status(status);
799                 return -1;
800         }
801         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
802                                         name,
803                                         NULL,
804                                         &smb_fname->st,
805                                         smb_fname->twrp,
806                                         smb_fname->flags);
807         if (catia_smb_fname == NULL) {
808                 TALLOC_FREE(name);
809                 errno = ENOMEM;
810                 return -1;
811         }
812
813         ret = SMB_VFS_NEXT_MKDIRAT(handle,
814                         dirfsp,
815                         catia_smb_fname,
816                         mode);
817         TALLOC_FREE(name);
818         TALLOC_FREE(catia_smb_fname);
819
820         return ret;
821 }
822
823 static int catia_chdir(vfs_handle_struct *handle,
824                         const struct smb_filename *smb_fname)
825 {
826         char *name = NULL;
827         struct smb_filename *catia_smb_fname = NULL;
828         NTSTATUS status;
829         int ret;
830
831         status = catia_string_replace_allocate(handle->conn,
832                                         smb_fname->base_name,
833                                         &name,
834                                         vfs_translate_to_unix);
835         if (!NT_STATUS_IS_OK(status)) {
836                 errno = map_errno_from_nt_status(status);
837                 return -1;
838         }
839
840         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
841                                         name,
842                                         NULL,
843                                         &smb_fname->st,
844                                         smb_fname->twrp,
845                                         smb_fname->flags);
846         if (catia_smb_fname == NULL) {
847                 TALLOC_FREE(name);
848                 errno = ENOMEM;
849                 return -1;
850         }
851         ret = SMB_VFS_NEXT_CHDIR(handle, catia_smb_fname);
852         TALLOC_FREE(name);
853         TALLOC_FREE(catia_smb_fname);
854
855         return ret;
856 }
857
858 static int catia_ntimes(vfs_handle_struct *handle,
859                         const struct smb_filename *smb_fname,
860                         struct smb_file_time *ft)
861 {
862         struct smb_filename *smb_fname_tmp = NULL;
863         char *name = NULL;
864         NTSTATUS status;
865         int ret;
866
867         status = catia_string_replace_allocate(handle->conn,
868                                 smb_fname->base_name,
869                                 &name, vfs_translate_to_unix);
870         if (!NT_STATUS_IS_OK(status)) {
871                 errno = map_errno_from_nt_status(status);
872                 return -1;
873         }
874
875         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
876         if (smb_fname_tmp == NULL) {
877                 errno = ENOMEM;
878                 return -1;
879         }
880
881         smb_fname_tmp->base_name = name;
882         smb_fname_tmp->fsp = smb_fname->fsp;
883
884         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
885         TALLOC_FREE(name);
886         TALLOC_FREE(smb_fname_tmp);
887
888         return ret;
889 }
890
891 static struct smb_filename *
892 catia_realpath(vfs_handle_struct *handle,
893                 TALLOC_CTX *ctx,
894                 const struct smb_filename *smb_fname)
895 {
896         char *mapped_name = NULL;
897         struct smb_filename *catia_smb_fname = NULL;
898         struct smb_filename *return_fname = NULL;
899         NTSTATUS status;
900
901         status = catia_string_replace_allocate(handle->conn,
902                                         smb_fname->base_name,
903                                         &mapped_name, vfs_translate_to_unix);
904         if (!NT_STATUS_IS_OK(status)) {
905                 errno = map_errno_from_nt_status(status);
906                 return NULL;
907         }
908
909         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
910                                         mapped_name,
911                                         NULL,
912                                         &smb_fname->st,
913                                         smb_fname->twrp,
914                                         smb_fname->flags);
915         if (catia_smb_fname == NULL) {
916                 TALLOC_FREE(mapped_name);
917                 errno = ENOMEM;
918                 return NULL;
919         }
920         return_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, catia_smb_fname);
921         TALLOC_FREE(mapped_name);
922         TALLOC_FREE(catia_smb_fname);
923         return return_fname;
924 }
925
926 static int catia_chflags(struct vfs_handle_struct *handle,
927                         const struct smb_filename *smb_fname,
928                         unsigned int flags)
929 {
930         char *name = NULL;
931         struct smb_filename *catia_smb_fname = NULL;
932         NTSTATUS status;
933         int ret;
934
935         status = catia_string_replace_allocate(handle->conn,
936                                 smb_fname->base_name,
937                                 &name,
938                                 vfs_translate_to_unix);
939         if (!NT_STATUS_IS_OK(status)) {
940                 errno = map_errno_from_nt_status(status);
941                 return -1;
942         }
943         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
944                                         name,
945                                         NULL,
946                                         &smb_fname->st,
947                                         smb_fname->twrp,
948                                         smb_fname->flags);
949         if (catia_smb_fname == NULL) {
950                 TALLOC_FREE(name);
951                 errno = ENOMEM;
952                 return -1;
953         }
954
955         ret = SMB_VFS_NEXT_CHFLAGS(handle, catia_smb_fname, flags);
956         TALLOC_FREE(name);
957         TALLOC_FREE(catia_smb_fname);
958
959         return ret;
960 }
961
962 static NTSTATUS
963 catia_streaminfo(struct vfs_handle_struct *handle,
964                  struct files_struct *fsp,
965                  const struct smb_filename *smb_fname,
966                  TALLOC_CTX *mem_ctx,
967                  unsigned int *_num_streams,
968                  struct stream_struct **_streams)
969 {
970         char *mapped_name = NULL;
971         NTSTATUS status;
972         unsigned int i;
973         struct smb_filename *catia_smb_fname = NULL;
974         unsigned int num_streams = 0;
975         struct stream_struct *streams = NULL;
976
977         *_num_streams = 0;
978         *_streams = NULL;
979
980         status = catia_string_replace_allocate(handle->conn,
981                                 smb_fname->base_name,
982                                 &mapped_name,
983                                 vfs_translate_to_unix);
984         if (!NT_STATUS_IS_OK(status)) {
985                 return status;
986         }
987
988         status = synthetic_pathref(talloc_tos(),
989                                         handle->conn->cwd_fsp,
990                                         mapped_name,
991                                         NULL,
992                                         &smb_fname->st,
993                                         smb_fname->twrp,
994                                         smb_fname->flags,
995                                         &catia_smb_fname);
996
997         if (!NT_STATUS_IS_OK(status)) {
998                 TALLOC_FREE(mapped_name);
999                 return status;
1000         }
1001
1002         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, catia_smb_fname,
1003                                          mem_ctx, &num_streams, &streams);
1004         TALLOC_FREE(mapped_name);
1005         TALLOC_FREE(catia_smb_fname);
1006         if (!NT_STATUS_IS_OK(status)) {
1007                 return status;
1008         }
1009
1010         /*
1011          * Translate stream names just like the base names
1012          */
1013         for (i = 0; i < num_streams; i++) {
1014                 /*
1015                  * Strip ":" prefix and ":$DATA" suffix to get a
1016                  * "pure" stream name and only translate that.
1017                  */
1018                 void *old_ptr = streams[i].name;
1019                 char *stream_name = streams[i].name + 1;
1020                 char *stream_type = strrchr_m(stream_name, ':');
1021
1022                 if (stream_type != NULL) {
1023                         *stream_type = '\0';
1024                         stream_type += 1;
1025                 }
1026
1027                 status = catia_string_replace_allocate(handle->conn, stream_name,
1028                                                        &mapped_name, vfs_translate_to_windows);
1029                 if (!NT_STATUS_IS_OK(status)) {
1030                         TALLOC_FREE(streams);
1031                         return status;
1032                 }
1033
1034                 if (stream_type != NULL) {
1035                         streams[i].name = talloc_asprintf(streams, ":%s:%s",
1036                                                           mapped_name, stream_type);
1037                 } else {
1038                         streams[i].name = talloc_asprintf(streams, ":%s",
1039                                                           mapped_name);
1040                 }
1041                 TALLOC_FREE(mapped_name);
1042                 TALLOC_FREE(old_ptr);
1043                 if (streams[i].name == NULL) {
1044                         TALLOC_FREE(streams);
1045                         return NT_STATUS_NO_MEMORY;
1046                 }
1047         }
1048
1049         *_num_streams = num_streams;
1050         *_streams = streams;
1051         return NT_STATUS_OK;
1052 }
1053
1054 static NTSTATUS catia_get_nt_acl_at(struct vfs_handle_struct *handle,
1055                                     struct files_struct *dirfsp,
1056                                     const struct smb_filename *smb_fname,
1057                                     uint32_t security_info,
1058                                     TALLOC_CTX *mem_ctx,
1059                                     struct security_descriptor **ppdesc)
1060 {
1061         char *mapped_name = NULL;
1062         const char *path = smb_fname->base_name;
1063         struct smb_filename *mapped_smb_fname = NULL;
1064         NTSTATUS status;
1065
1066         SMB_ASSERT(dirfsp == handle->conn->cwd_fsp);
1067
1068         status = catia_string_replace_allocate(handle->conn,
1069                                 path, &mapped_name, vfs_translate_to_unix);
1070         if (!NT_STATUS_IS_OK(status)) {
1071                 errno = map_errno_from_nt_status(status);
1072                 return status;
1073         }
1074         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1075                                         mapped_name,
1076                                         NULL,
1077                                         &smb_fname->st,
1078                                         smb_fname->twrp,
1079                                         smb_fname->flags);
1080         if (mapped_smb_fname == NULL) {
1081                 TALLOC_FREE(mapped_name);
1082                 return NT_STATUS_NO_MEMORY;
1083         }
1084
1085         status = SMB_VFS_NEXT_GET_NT_ACL_AT(handle,
1086                                         dirfsp,
1087                                         mapped_smb_fname,
1088                                         security_info,
1089                                         mem_ctx,
1090                                         ppdesc);
1091         TALLOC_FREE(mapped_name);
1092         TALLOC_FREE(mapped_smb_fname);
1093
1094         return status;
1095 }
1096
1097 static SMB_ACL_T
1098 catia_sys_acl_get_file(vfs_handle_struct *handle,
1099                         const struct smb_filename *smb_fname,
1100                         SMB_ACL_TYPE_T type,
1101                         TALLOC_CTX *mem_ctx)
1102 {
1103         char *mapped_name = NULL;
1104         struct smb_filename *mapped_smb_fname = NULL;
1105         NTSTATUS status;
1106         SMB_ACL_T ret;
1107         int saved_errno = 0;
1108
1109         status = catia_string_replace_allocate(handle->conn,
1110                                 smb_fname->base_name,
1111                                 &mapped_name,
1112                                 vfs_translate_to_unix);
1113         if (!NT_STATUS_IS_OK(status)) {
1114                 errno = map_errno_from_nt_status(status);
1115                 return (SMB_ACL_T)NULL;
1116         }
1117
1118         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1119                                         mapped_name,
1120                                         NULL,
1121                                         &smb_fname->st,
1122                                         smb_fname->twrp,
1123                                         smb_fname->flags);
1124         if (mapped_smb_fname == NULL) {
1125                 TALLOC_FREE(mapped_name);
1126                 errno = ENOMEM;
1127                 return (SMB_ACL_T)NULL;
1128         }
1129
1130         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, mapped_smb_fname,
1131                         type, mem_ctx);
1132         if (ret == (SMB_ACL_T)NULL) {
1133                 saved_errno = errno;
1134         }
1135         TALLOC_FREE(mapped_smb_fname);
1136         TALLOC_FREE(mapped_name);
1137         if (saved_errno != 0) {
1138                 errno = saved_errno;
1139         }
1140         return ret;
1141 }
1142
1143 static int
1144 catia_sys_acl_delete_def_file(vfs_handle_struct *handle,
1145                                 const struct smb_filename *smb_fname)
1146 {
1147         struct smb_filename *mapped_smb_fname = NULL;
1148         int saved_errno = 0;
1149         char *mapped_name = NULL;
1150         NTSTATUS status;
1151         int ret;
1152
1153         status = catia_string_replace_allocate(handle->conn,
1154                                 smb_fname->base_name,
1155                                 &mapped_name,
1156                                 vfs_translate_to_unix);
1157         if (!NT_STATUS_IS_OK(status)) {
1158                 errno = map_errno_from_nt_status(status);
1159                 return -1;
1160         }
1161
1162         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1163                                         mapped_name,
1164                                         NULL,
1165                                         &smb_fname->st,
1166                                         smb_fname->twrp,
1167                                         smb_fname->flags);
1168         if (mapped_smb_fname == NULL) {
1169                 TALLOC_FREE(mapped_name);
1170                 errno = ENOMEM;
1171                 return -1;
1172         }
1173         ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, mapped_smb_fname);
1174         if (ret == -1) {
1175                 saved_errno = errno;
1176         }
1177         TALLOC_FREE(mapped_smb_fname);
1178         TALLOC_FREE(mapped_name);
1179         if (saved_errno != 0) {
1180                 errno = saved_errno;
1181         }
1182         return ret;
1183 }
1184
1185 static ssize_t
1186 catia_getxattr(vfs_handle_struct *handle,
1187                         const struct smb_filename *smb_fname,
1188                         const char *name,
1189                         void *value,
1190                         size_t size)
1191 {
1192         struct smb_filename *mapped_smb_fname = NULL;
1193         char *mapped_name = NULL;
1194         char *mapped_ea_name = NULL;
1195         NTSTATUS status;
1196         ssize_t ret;
1197         int saved_errno = 0;
1198
1199         status = catia_string_replace_allocate(handle->conn,
1200                                 smb_fname->base_name,
1201                                 &mapped_name,
1202                                 vfs_translate_to_unix);
1203         if (!NT_STATUS_IS_OK(status)) {
1204                 errno = map_errno_from_nt_status(status);
1205                 return -1;
1206         }
1207
1208         status = catia_string_replace_allocate(handle->conn,
1209                                 name, &mapped_ea_name, vfs_translate_to_unix);
1210         if (!NT_STATUS_IS_OK(status)) {
1211                 TALLOC_FREE(mapped_name);
1212                 errno = map_errno_from_nt_status(status);
1213                 return -1;
1214         }
1215
1216         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1217                                         mapped_name,
1218                                         NULL,
1219                                         &smb_fname->st,
1220                                         smb_fname->twrp,
1221                                         smb_fname->flags);
1222         if (mapped_smb_fname == NULL) {
1223                 TALLOC_FREE(mapped_name);
1224                 TALLOC_FREE(mapped_ea_name);
1225                 errno = ENOMEM;
1226                 return -1;
1227         }
1228
1229         ret = SMB_VFS_NEXT_GETXATTR(handle, mapped_smb_fname,
1230                                 mapped_ea_name, value, size);
1231         if (ret == -1) {
1232                 saved_errno = errno;
1233         }
1234         TALLOC_FREE(mapped_name);
1235         TALLOC_FREE(mapped_ea_name);
1236         TALLOC_FREE(mapped_smb_fname);
1237         if (saved_errno != 0) {
1238                 errno = saved_errno;
1239         }
1240
1241         return ret;
1242 }
1243
1244 static int
1245 catia_removexattr(vfs_handle_struct *handle,
1246                         const struct smb_filename *smb_fname,
1247                         const char *name)
1248 {
1249         struct smb_filename *mapped_smb_fname = NULL;
1250         char *mapped_name = NULL;
1251         char *mapped_ea_name = NULL;
1252         NTSTATUS status;
1253         ssize_t ret;
1254         int saved_errno = 0;
1255
1256         status = catia_string_replace_allocate(handle->conn,
1257                                 smb_fname->base_name,
1258                                 &mapped_name,
1259                                 vfs_translate_to_unix);
1260         if (!NT_STATUS_IS_OK(status)) {
1261                 errno = map_errno_from_nt_status(status);
1262                 return -1;
1263         }
1264
1265         status = catia_string_replace_allocate(handle->conn,
1266                                 name, &mapped_ea_name, vfs_translate_to_unix);
1267         if (!NT_STATUS_IS_OK(status)) {
1268                 TALLOC_FREE(mapped_name);
1269                 errno = map_errno_from_nt_status(status);
1270                 return -1;
1271         }
1272
1273         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1274                                         mapped_name,
1275                                         NULL,
1276                                         &smb_fname->st,
1277                                         smb_fname->twrp,
1278                                         smb_fname->flags);
1279         if (mapped_smb_fname == NULL) {
1280                 TALLOC_FREE(mapped_name);
1281                 TALLOC_FREE(mapped_ea_name);
1282                 errno = ENOMEM;
1283                 return -1;
1284         }
1285
1286         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, mapped_smb_fname,
1287                                 mapped_ea_name);
1288         if (ret == -1) {
1289                 saved_errno = errno;
1290         }
1291         TALLOC_FREE(mapped_name);
1292         TALLOC_FREE(mapped_ea_name);
1293         TALLOC_FREE(mapped_smb_fname);
1294         if (saved_errno != 0) {
1295                 errno = saved_errno;
1296         }
1297
1298         return ret;
1299 }
1300
1301 static int
1302 catia_setxattr(vfs_handle_struct *handle,
1303                         const struct smb_filename *smb_fname,
1304                         const char *name,
1305                         const void *value,
1306                         size_t size,
1307                         int flags)
1308 {
1309         struct smb_filename *mapped_smb_fname = NULL;
1310         char *mapped_name = NULL;
1311         char *mapped_ea_name = NULL;
1312         NTSTATUS status;
1313         ssize_t ret;
1314         int saved_errno = 0;
1315
1316         status = catia_string_replace_allocate(handle->conn,
1317                                 smb_fname->base_name,
1318                                 &mapped_name,
1319                                 vfs_translate_to_unix);
1320         if (!NT_STATUS_IS_OK(status)) {
1321                 errno = map_errno_from_nt_status(status);
1322                 return -1;
1323         }
1324
1325         status = catia_string_replace_allocate(handle->conn,
1326                                 name, &mapped_ea_name, vfs_translate_to_unix);
1327         if (!NT_STATUS_IS_OK(status)) {
1328                 TALLOC_FREE(mapped_name);
1329                 errno = map_errno_from_nt_status(status);
1330                 return -1;
1331         }
1332
1333         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1334                                         mapped_name,
1335                                         NULL,
1336                                         &smb_fname->st,
1337                                         smb_fname->twrp,
1338                                         smb_fname->flags);
1339         if (mapped_smb_fname == NULL) {
1340                 TALLOC_FREE(mapped_name);
1341                 TALLOC_FREE(mapped_ea_name);
1342                 errno = ENOMEM;
1343                 return -1;
1344         }
1345
1346         ret = SMB_VFS_NEXT_SETXATTR(handle, mapped_smb_fname, mapped_ea_name,
1347                         value, size, flags);
1348         if (ret == -1) {
1349                 saved_errno = errno;
1350         }
1351         TALLOC_FREE(mapped_name);
1352         TALLOC_FREE(mapped_ea_name);
1353         TALLOC_FREE(mapped_smb_fname);
1354         if (saved_errno != 0) {
1355                 errno = saved_errno;
1356         }
1357
1358         return ret;
1359 }
1360
1361 static int catia_fstat(vfs_handle_struct *handle,
1362                        files_struct *fsp,
1363                        SMB_STRUCT_STAT *sbuf)
1364 {
1365         struct catia_cache *cc = NULL;
1366         int ret;
1367
1368         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1369         if (ret != 0) {
1370                 return ret;
1371         }
1372
1373         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1374
1375         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1376
1377         return ret;
1378 }
1379
1380 static ssize_t catia_pread(vfs_handle_struct *handle,
1381                            files_struct *fsp, void *data,
1382                            size_t n, off_t offset)
1383 {
1384         struct catia_cache *cc = NULL;
1385         ssize_t result;
1386         int ret;
1387
1388         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1389         if (ret != 0) {
1390                 return ret;
1391         }
1392
1393         result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
1394
1395         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1396
1397         return result;
1398 }
1399
1400 static ssize_t catia_pwrite(vfs_handle_struct *handle,
1401                             files_struct *fsp, const void *data,
1402                             size_t n, off_t offset)
1403 {
1404         struct catia_cache *cc = NULL;
1405         ssize_t result;
1406         int ret;
1407
1408         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1409         if (ret != 0) {
1410                 return ret;
1411         }
1412
1413         result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
1414
1415         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1416
1417         return result;
1418 }
1419
1420 static int catia_ftruncate(struct vfs_handle_struct *handle,
1421                            struct files_struct *fsp,
1422                            off_t offset)
1423 {
1424         struct catia_cache *cc = NULL;
1425         int ret;
1426
1427         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1428         if (ret != 0) {
1429                 return ret;
1430         }
1431
1432         ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
1433
1434         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1435
1436         return ret;
1437 }
1438
1439 static int catia_fallocate(struct vfs_handle_struct *handle,
1440                            struct files_struct *fsp,
1441                            uint32_t mode,
1442                            off_t offset,
1443                            off_t len)
1444 {
1445         struct catia_cache *cc = NULL;
1446         int ret;
1447
1448         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1449         if (ret != 0) {
1450                 return ret;
1451         }
1452
1453         ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
1454
1455         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1456
1457         return ret;
1458 }
1459
1460 static ssize_t catia_fgetxattr(struct vfs_handle_struct *handle,
1461                                struct files_struct *fsp,
1462                                const char *name,
1463                                void *value,
1464                                size_t size)
1465 {
1466         char *mapped_xattr_name = NULL;
1467         NTSTATUS status;
1468         ssize_t result;
1469
1470         status = catia_string_replace_allocate(handle->conn,
1471                                                name, &mapped_xattr_name,
1472                                                vfs_translate_to_unix);
1473         if (!NT_STATUS_IS_OK(status)) {
1474                 errno = map_errno_from_nt_status(status);
1475                 return -1;
1476         }
1477
1478         result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, mapped_xattr_name,
1479                                         value, size);
1480
1481         TALLOC_FREE(mapped_xattr_name);
1482
1483         return result;
1484 }
1485
1486 static ssize_t catia_flistxattr(struct vfs_handle_struct *handle,
1487                                 struct files_struct *fsp,
1488                                 char *list,
1489                                 size_t size)
1490 {
1491         struct catia_cache *cc = NULL;
1492         ssize_t result;
1493         int ret;
1494
1495         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1496         if (ret != 0) {
1497                 return ret;
1498         }
1499
1500         result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
1501
1502         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1503
1504         return result;
1505 }
1506
1507 static int catia_fremovexattr(struct vfs_handle_struct *handle,
1508                               struct files_struct *fsp,
1509                               const char *name)
1510 {
1511         char *mapped_name = NULL;
1512         NTSTATUS status;
1513         int ret;
1514
1515         status = catia_string_replace_allocate(handle->conn,
1516                                 name, &mapped_name, vfs_translate_to_unix);
1517         if (!NT_STATUS_IS_OK(status)) {
1518                 errno = map_errno_from_nt_status(status);
1519                 return -1;
1520         }
1521
1522         ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, mapped_name);
1523
1524         TALLOC_FREE(mapped_name);
1525
1526         return ret;
1527 }
1528
1529 static int catia_fsetxattr(struct vfs_handle_struct *handle,
1530                            struct files_struct *fsp,
1531                            const char *name,
1532                            const void *value,
1533                            size_t size,
1534                            int flags)
1535 {
1536         char *mapped_xattr_name = NULL;
1537         NTSTATUS status;
1538         int ret;
1539
1540         status = catia_string_replace_allocate(
1541                 handle->conn, name, &mapped_xattr_name, vfs_translate_to_unix);
1542         if (!NT_STATUS_IS_OK(status)) {
1543                 errno = map_errno_from_nt_status(status);
1544                 return -1;
1545         }
1546
1547         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, mapped_xattr_name,
1548                                      value, size, flags);
1549
1550         TALLOC_FREE(mapped_xattr_name);
1551
1552         return ret;
1553 }
1554
1555 static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle,
1556                                       files_struct *fsp,
1557                                       TALLOC_CTX *mem_ctx)
1558 {
1559         struct catia_cache *cc = NULL;
1560         struct smb_acl_t *result = NULL;
1561         int ret;
1562
1563         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1564         if (ret != 0) {
1565                 return NULL;
1566         }
1567
1568         result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
1569
1570         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1571
1572         return result;
1573 }
1574
1575 static int catia_sys_acl_blob_get_fd(vfs_handle_struct *handle,
1576                                      files_struct *fsp,
1577                                      TALLOC_CTX *mem_ctx,
1578                                      char **blob_description,
1579                                      DATA_BLOB *blob)
1580 {
1581         struct catia_cache *cc = NULL;
1582         int ret;
1583
1584         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1585         if (ret != 0) {
1586                 return ret;
1587         }
1588
1589         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
1590                                                blob_description, blob);
1591
1592         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1593
1594         return ret;
1595 }
1596
1597 static int catia_sys_acl_set_fd(vfs_handle_struct *handle,
1598                                 files_struct *fsp,
1599                                 SMB_ACL_TYPE_T type,
1600                                 SMB_ACL_T theacl)
1601 {
1602         struct catia_cache *cc = NULL;
1603         int ret;
1604
1605         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1606         if (ret != 0) {
1607                 return ret;
1608         }
1609
1610         ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, type, theacl);
1611
1612         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1613
1614         return ret;
1615 }
1616
1617 static NTSTATUS catia_fget_nt_acl(vfs_handle_struct *handle,
1618                                   files_struct *fsp,
1619                                   uint32_t security_info,
1620                                   TALLOC_CTX *mem_ctx,
1621                                   struct security_descriptor **ppdesc)
1622 {
1623         struct catia_cache *cc = NULL;
1624         NTSTATUS status;
1625         int ret;
1626
1627         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1628         if (ret != 0) {
1629                 return map_nt_error_from_unix(errno);
1630         }
1631
1632         status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1633                                           mem_ctx, ppdesc);
1634
1635         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1636
1637         return status;
1638 }
1639
1640 static NTSTATUS catia_fset_nt_acl(vfs_handle_struct *handle,
1641                                   files_struct *fsp,
1642                                   uint32_t security_info_sent,
1643                                   const struct security_descriptor *psd)
1644 {
1645         struct catia_cache *cc = NULL;
1646         NTSTATUS status;
1647         int ret;
1648
1649         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1650         if (ret != 0) {
1651                 return map_nt_error_from_unix(errno);
1652         }
1653
1654         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
1655
1656         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1657
1658         return status;
1659 }
1660
1661 static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle,
1662                                           struct files_struct *fsp,
1663                                           uint32_t dosmode)
1664 {
1665         struct catia_cache *cc = NULL;
1666         NTSTATUS status;
1667         int ret;
1668
1669         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1670         if (ret != 0) {
1671                 return map_nt_error_from_unix(errno);
1672         }
1673
1674         status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1675
1676         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1677
1678         return status;
1679 }
1680
1681 static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle,
1682                                           struct files_struct *fsp,
1683                                           uint32_t *dosmode)
1684 {
1685         struct catia_cache *cc = NULL;
1686         NTSTATUS status;
1687         int ret;
1688
1689         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1690         if (ret != 0) {
1691                 return map_nt_error_from_unix(errno);
1692         }
1693
1694         status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1695
1696         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1697
1698         return status;
1699 }
1700
1701 static int catia_fchown(vfs_handle_struct *handle,
1702                         files_struct *fsp,
1703                         uid_t uid,
1704                         gid_t gid)
1705 {
1706         struct catia_cache *cc = NULL;
1707         int ret;
1708
1709         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1710         if (ret != 0) {
1711                 return ret;
1712         }
1713
1714         ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
1715
1716         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1717
1718         return ret;
1719 }
1720
1721 static int catia_fchmod(vfs_handle_struct *handle,
1722                         files_struct *fsp,
1723                         mode_t mode)
1724 {
1725         struct catia_cache *cc = NULL;
1726         int ret;
1727
1728         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1729         if (ret != 0) {
1730                 return ret;
1731         }
1732
1733         ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1734
1735         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1736
1737         return ret;
1738 }
1739
1740 struct catia_pread_state {
1741         ssize_t ret;
1742         struct vfs_aio_state vfs_aio_state;
1743         struct files_struct *fsp;
1744         struct catia_cache *cc;
1745 };
1746
1747 static void catia_pread_done(struct tevent_req *subreq);
1748
1749 static struct tevent_req *catia_pread_send(struct vfs_handle_struct *handle,
1750                                            TALLOC_CTX *mem_ctx,
1751                                            struct tevent_context *ev,
1752                                            struct files_struct *fsp,
1753                                            void *data,
1754                                            size_t n,
1755                                            off_t offset)
1756 {
1757         struct tevent_req *req = NULL, *subreq = NULL;
1758         struct catia_pread_state *state = NULL;
1759         int ret;
1760
1761         req = tevent_req_create(mem_ctx, &state,
1762                                 struct catia_pread_state);
1763         if (req == NULL) {
1764                 return NULL;
1765         }
1766         state->fsp = fsp;
1767
1768         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1769         if (ret != 0) {
1770                 tevent_req_error(req, errno);
1771                 return tevent_req_post(req, ev);
1772         }
1773
1774         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
1775                                          n, offset);
1776         if (tevent_req_nomem(subreq, req)) {
1777                 return tevent_req_post(req, ev);
1778         }
1779         tevent_req_set_callback(subreq, catia_pread_done, req);
1780
1781         return req;
1782 }
1783
1784 static void catia_pread_done(struct tevent_req *subreq)
1785 {
1786         struct tevent_req *req = tevent_req_callback_data(
1787                 subreq, struct tevent_req);
1788         struct catia_pread_state *state = tevent_req_data(
1789                 req, struct catia_pread_state);
1790
1791         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
1792         TALLOC_FREE(subreq);
1793
1794         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1795
1796         tevent_req_done(req);
1797 }
1798
1799 static ssize_t catia_pread_recv(struct tevent_req *req,
1800                                 struct vfs_aio_state *vfs_aio_state)
1801 {
1802         struct catia_pread_state *state = tevent_req_data(
1803                 req, struct catia_pread_state);
1804
1805         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1806                 return -1;
1807         }
1808
1809         *vfs_aio_state = state->vfs_aio_state;
1810         return state->ret;
1811 }
1812
1813 struct catia_pwrite_state {
1814         ssize_t ret;
1815         struct vfs_aio_state vfs_aio_state;
1816         struct files_struct *fsp;
1817         struct catia_cache *cc;
1818 };
1819
1820 static void catia_pwrite_done(struct tevent_req *subreq);
1821
1822 static struct tevent_req *catia_pwrite_send(struct vfs_handle_struct *handle,
1823                                             TALLOC_CTX *mem_ctx,
1824                                             struct tevent_context *ev,
1825                                             struct files_struct *fsp,
1826                                             const void *data,
1827                                             size_t n,
1828                                             off_t offset)
1829 {
1830         struct tevent_req *req = NULL, *subreq = NULL;
1831         struct catia_pwrite_state *state = NULL;
1832         int ret;
1833
1834         req = tevent_req_create(mem_ctx, &state,
1835                                 struct catia_pwrite_state);
1836         if (req == NULL) {
1837                 return NULL;
1838         }
1839         state->fsp = fsp;
1840
1841         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1842         if (ret != 0) {
1843                 tevent_req_error(req, errno);
1844                 return tevent_req_post(req, ev);
1845         }
1846
1847         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
1848                                           n, offset);
1849         if (tevent_req_nomem(subreq, req)) {
1850                 return tevent_req_post(req, ev);
1851         }
1852         tevent_req_set_callback(subreq, catia_pwrite_done, req);
1853
1854         return req;
1855 }
1856
1857 static void catia_pwrite_done(struct tevent_req *subreq)
1858 {
1859         struct tevent_req *req = tevent_req_callback_data(
1860                 subreq, struct tevent_req);
1861         struct catia_pwrite_state *state = tevent_req_data(
1862                 req, struct catia_pwrite_state);
1863
1864         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
1865         TALLOC_FREE(subreq);
1866
1867         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1868
1869         tevent_req_done(req);
1870 }
1871
1872 static ssize_t catia_pwrite_recv(struct tevent_req *req,
1873                                 struct vfs_aio_state *vfs_aio_state)
1874 {
1875         struct catia_pwrite_state *state = tevent_req_data(
1876                 req, struct catia_pwrite_state);
1877
1878         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1879                 return -1;
1880         }
1881
1882         *vfs_aio_state = state->vfs_aio_state;
1883         return state->ret;
1884 }
1885
1886 static off_t catia_lseek(vfs_handle_struct *handle,
1887                          files_struct *fsp,
1888                          off_t offset,
1889                          int whence)
1890 {
1891         struct catia_cache *cc = NULL;
1892         ssize_t result;
1893         int ret;
1894
1895         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1896         if (ret != 0) {
1897                 return -1;
1898         }
1899
1900         result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
1901
1902         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1903
1904         return result;
1905 }
1906
1907 struct catia_fsync_state {
1908         int ret;
1909         struct vfs_aio_state vfs_aio_state;
1910         struct files_struct *fsp;
1911         struct catia_cache *cc;
1912 };
1913
1914 static void catia_fsync_done(struct tevent_req *subreq);
1915
1916 static struct tevent_req *catia_fsync_send(struct vfs_handle_struct *handle,
1917                                            TALLOC_CTX *mem_ctx,
1918                                            struct tevent_context *ev,
1919                                            struct files_struct *fsp)
1920 {
1921         struct tevent_req *req = NULL, *subreq = NULL;
1922         struct catia_fsync_state *state = NULL;
1923         int ret;
1924
1925         req = tevent_req_create(mem_ctx, &state,
1926                                 struct catia_fsync_state);
1927         if (req == NULL) {
1928                 return NULL;
1929         }
1930         state->fsp = fsp;
1931
1932         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1933         if (ret != 0) {
1934                 tevent_req_error(req, errno);
1935                 return tevent_req_post(req, ev);
1936         }
1937
1938         subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
1939         if (tevent_req_nomem(subreq, req)) {
1940                 return tevent_req_post(req, ev);
1941         }
1942         tevent_req_set_callback(subreq, catia_fsync_done, req);
1943
1944         return req;
1945 }
1946
1947 static void catia_fsync_done(struct tevent_req *subreq)
1948 {
1949         struct tevent_req *req = tevent_req_callback_data(
1950                 subreq, struct tevent_req);
1951         struct catia_fsync_state *state = tevent_req_data(
1952                 req, struct catia_fsync_state);
1953
1954         state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
1955         TALLOC_FREE(subreq);
1956
1957         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1958
1959         tevent_req_done(req);
1960 }
1961
1962 static int catia_fsync_recv(struct tevent_req *req,
1963                             struct vfs_aio_state *vfs_aio_state)
1964 {
1965         struct catia_fsync_state *state = tevent_req_data(
1966                 req, struct catia_fsync_state);
1967
1968         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1969                 return -1;
1970         }
1971
1972         *vfs_aio_state = state->vfs_aio_state;
1973         return state->ret;
1974 }
1975
1976 static bool catia_lock(vfs_handle_struct *handle,
1977                        files_struct *fsp,
1978                        int op,
1979                        off_t offset,
1980                        off_t count,
1981                        int type)
1982 {
1983         struct catia_cache *cc = NULL;
1984         bool ok;
1985         int ret;
1986
1987         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1988         if (ret != 0) {
1989                 return false;
1990         }
1991
1992         ok = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
1993
1994         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1995
1996         return ok;
1997 }
1998
1999 static int catia_kernel_flock(struct vfs_handle_struct *handle,
2000                               struct files_struct *fsp,
2001                               uint32_t share_access,
2002                               uint32_t access_mask)
2003 {
2004         struct catia_cache *cc = NULL;
2005         int ret;
2006
2007         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2008         if (ret != 0) {
2009                 return -1;
2010         }
2011
2012         ret = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_access, access_mask);
2013
2014         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2015
2016         return ret;
2017 }
2018
2019 static int catia_linux_setlease(vfs_handle_struct *handle,
2020                                 files_struct *fsp,
2021                                 int leasetype)
2022 {
2023         struct catia_cache *cc = NULL;
2024         int ret;
2025
2026         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2027         if (ret != 0) {
2028                 return -1;
2029         }
2030
2031         ret = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
2032
2033         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2034
2035         return ret;
2036 }
2037
2038 static bool catia_getlock(vfs_handle_struct *handle,
2039                           files_struct *fsp,
2040                           off_t *poffset,
2041                           off_t *pcount,
2042                           int *ptype,
2043                           pid_t *ppid)
2044 {
2045         struct catia_cache *cc = NULL;
2046         int ret;
2047         bool ok;
2048
2049         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2050         if (ret != 0) {
2051                 return false;
2052         }
2053
2054         ok = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
2055
2056         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2057
2058         return ok;
2059 }
2060
2061 static bool catia_strict_lock_check(struct vfs_handle_struct *handle,
2062                                     struct files_struct *fsp,
2063                                     struct lock_struct *plock)
2064 {
2065         struct catia_cache *cc = NULL;
2066         int ret;
2067         bool ok;
2068
2069         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2070         if (ret != 0) {
2071                 return false;
2072         }
2073
2074         ok = SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock);
2075
2076         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2077
2078         return ok;
2079 }
2080
2081 static NTSTATUS catia_fsctl(struct vfs_handle_struct *handle,
2082                             struct files_struct *fsp,
2083                             TALLOC_CTX *ctx,
2084                             uint32_t function,
2085                             uint16_t req_flags,
2086                             const uint8_t *_in_data,
2087                             uint32_t in_len,
2088                             uint8_t **_out_data,
2089                             uint32_t max_out_len,
2090                             uint32_t *out_len)
2091 {
2092         NTSTATUS result;
2093         struct catia_cache *cc = NULL;
2094         int ret;
2095
2096         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2097         if (ret != 0) {
2098                 return map_nt_error_from_unix(errno);
2099         }
2100
2101         result = SMB_VFS_NEXT_FSCTL(handle,
2102                                 fsp,
2103                                 ctx,
2104                                 function,
2105                                 req_flags,
2106                                 _in_data,
2107                                 in_len,
2108                                 _out_data,
2109                                 max_out_len,
2110                                 out_len);
2111
2112         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2113
2114         return result;
2115 }
2116
2117 static NTSTATUS catia_fget_compression(vfs_handle_struct *handle,
2118                                       TALLOC_CTX *mem_ctx,
2119                                       struct files_struct *fsp,
2120                                       uint16_t *_compression_fmt)
2121 {
2122         NTSTATUS result;
2123         struct catia_cache *cc = NULL;
2124         int ret;
2125
2126         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2127         if (ret != 0) {
2128                 return map_nt_error_from_unix(errno);
2129         }
2130
2131         result = SMB_VFS_NEXT_FGET_COMPRESSION(handle,
2132                                         mem_ctx,
2133                                         fsp,
2134                                         _compression_fmt);
2135
2136         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2137
2138         return result;
2139 }
2140
2141 static NTSTATUS catia_set_compression(vfs_handle_struct *handle,
2142                                       TALLOC_CTX *mem_ctx,
2143                                       struct files_struct *fsp,
2144                                       uint16_t compression_fmt)
2145 {
2146         NTSTATUS result;
2147         struct catia_cache *cc = NULL;
2148         int ret;
2149
2150         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2151         if (ret != 0) {
2152                 return map_nt_error_from_unix(errno);
2153         }
2154
2155         result = SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp,
2156                                               compression_fmt);
2157
2158         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2159
2160         return result;
2161 }
2162
2163 static NTSTATUS catia_readdir_attr(struct vfs_handle_struct *handle,
2164                                    const struct smb_filename *smb_fname_in,
2165                                    TALLOC_CTX *mem_ctx,
2166                                    struct readdir_attr_data **pattr_data)
2167 {
2168         struct smb_filename *smb_fname;
2169         char *fname = NULL;
2170         NTSTATUS status;
2171
2172         status = catia_string_replace_allocate(handle->conn,
2173                                                smb_fname_in->base_name,
2174                                                &fname,
2175                                                vfs_translate_to_unix);
2176         if (!NT_STATUS_IS_OK(status)) {
2177                 errno = map_errno_from_nt_status(status);
2178                 return status;
2179         }
2180
2181         smb_fname = synthetic_smb_fname(talloc_tos(),
2182                                         fname,
2183                                         NULL,
2184                                         &smb_fname_in->st,
2185                                         smb_fname_in->twrp,
2186                                         0);
2187
2188         status = SMB_VFS_NEXT_READDIR_ATTR(handle, smb_fname, mem_ctx, pattr_data);
2189
2190         TALLOC_FREE(smb_fname);
2191         TALLOC_FREE(fname);
2192         return status;
2193 }
2194
2195 static NTSTATUS catia_set_dos_attributes(struct vfs_handle_struct *handle,
2196                                          const struct smb_filename *smb_fname,
2197                                          uint32_t dosmode)
2198 {
2199         char *mapped_name = NULL;
2200         const char *path = smb_fname->base_name;
2201         struct smb_filename *mapped_smb_fname = NULL;
2202         NTSTATUS status;
2203
2204         status = catia_string_replace_allocate(handle->conn,
2205                                 path, &mapped_name, vfs_translate_to_unix);
2206         if (!NT_STATUS_IS_OK(status)) {
2207                 errno = map_errno_from_nt_status(status);
2208                 return status;
2209         }
2210         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2211                                         mapped_name,
2212                                         NULL,
2213                                         &smb_fname->st,
2214                                         smb_fname->twrp,
2215                                         smb_fname->flags);
2216         if (mapped_smb_fname == NULL) {
2217                 TALLOC_FREE(mapped_name);
2218                 return NT_STATUS_NO_MEMORY;
2219         }
2220
2221         status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
2222                                                  mapped_smb_fname,
2223                                                  dosmode);
2224         TALLOC_FREE(mapped_name);
2225         TALLOC_FREE(mapped_smb_fname);
2226
2227         return status;
2228 }
2229
2230 static NTSTATUS catia_create_dfs_pathat(struct vfs_handle_struct *handle,
2231                         struct files_struct *dirfsp,
2232                         const struct smb_filename *smb_fname,
2233                         const struct referral *reflist,
2234                         size_t referral_count)
2235 {
2236         char *mapped_name = NULL;
2237         const char *path = smb_fname->base_name;
2238         struct smb_filename *mapped_smb_fname = NULL;
2239         NTSTATUS status;
2240
2241         status = catia_string_replace_allocate(handle->conn,
2242                                         path,
2243                                         &mapped_name,
2244                                         vfs_translate_to_unix);
2245         if (!NT_STATUS_IS_OK(status)) {
2246                 errno = map_errno_from_nt_status(status);
2247                 return status;
2248         }
2249         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2250                                         mapped_name,
2251                                         NULL,
2252                                         &smb_fname->st,
2253                                         smb_fname->twrp,
2254                                         smb_fname->flags);
2255         if (mapped_smb_fname == NULL) {
2256                 TALLOC_FREE(mapped_name);
2257                 return NT_STATUS_NO_MEMORY;
2258         }
2259
2260         status = SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
2261                                         dirfsp,
2262                                         mapped_smb_fname,
2263                                         reflist,
2264                                         referral_count);
2265         TALLOC_FREE(mapped_name);
2266         TALLOC_FREE(mapped_smb_fname);
2267         return status;
2268 }
2269
2270 static NTSTATUS catia_read_dfs_pathat(struct vfs_handle_struct *handle,
2271                         TALLOC_CTX *mem_ctx,
2272                         struct files_struct *dirfsp,
2273                         struct smb_filename *smb_fname,
2274                         struct referral **ppreflist,
2275                         size_t *preferral_count)
2276 {
2277         char *mapped_name = NULL;
2278         const char *path = smb_fname->base_name;
2279         struct smb_filename *mapped_smb_fname = NULL;
2280         NTSTATUS status;
2281
2282         status = catia_string_replace_allocate(handle->conn,
2283                                         path,
2284                                         &mapped_name,
2285                                         vfs_translate_to_unix);
2286         if (!NT_STATUS_IS_OK(status)) {
2287                 errno = map_errno_from_nt_status(status);
2288                 return status;
2289         }
2290         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2291                                         mapped_name,
2292                                         NULL,
2293                                         &smb_fname->st,
2294                                         smb_fname->twrp,
2295                                         smb_fname->flags);
2296         if (mapped_smb_fname == NULL) {
2297                 TALLOC_FREE(mapped_name);
2298                 return NT_STATUS_NO_MEMORY;
2299         }
2300
2301         status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
2302                                         mem_ctx,
2303                                         dirfsp,
2304                                         mapped_smb_fname,
2305                                         ppreflist,
2306                                         preferral_count);
2307         if (NT_STATUS_IS_OK(status)) {
2308                 /* Return any stat(2) info. */
2309                 smb_fname->st = mapped_smb_fname->st;
2310         }
2311
2312         TALLOC_FREE(mapped_name);
2313         TALLOC_FREE(mapped_smb_fname);
2314         return status;
2315 }
2316
2317 static struct vfs_fn_pointers vfs_catia_fns = {
2318         .connect_fn = catia_connect,
2319
2320         /* Directory operations */
2321         .mkdirat_fn = catia_mkdirat,
2322         .readdir_attr_fn = catia_readdir_attr,
2323
2324         /* File operations */
2325         .openat_fn = catia_openat,
2326         .pread_fn = catia_pread,
2327         .pread_send_fn = catia_pread_send,
2328         .pread_recv_fn = catia_pread_recv,
2329         .pwrite_fn = catia_pwrite,
2330         .pwrite_send_fn = catia_pwrite_send,
2331         .pwrite_recv_fn = catia_pwrite_recv,
2332         .lseek_fn = catia_lseek,
2333         .renameat_fn = catia_renameat,
2334         .fsync_send_fn = catia_fsync_send,
2335         .fsync_recv_fn = catia_fsync_recv,
2336         .stat_fn = catia_stat,
2337         .fstat_fn = catia_fstat,
2338         .lstat_fn = catia_lstat,
2339         .unlinkat_fn = catia_unlinkat,
2340         .chmod_fn = catia_chmod,
2341         .fchmod_fn = catia_fchmod,
2342         .fchown_fn = catia_fchown,
2343         .lchown_fn = catia_lchown,
2344         .chdir_fn = catia_chdir,
2345         .ntimes_fn = catia_ntimes,
2346         .ftruncate_fn = catia_ftruncate,
2347         .fallocate_fn = catia_fallocate,
2348         .lock_fn = catia_lock,
2349         .kernel_flock_fn = catia_kernel_flock,
2350         .linux_setlease_fn = catia_linux_setlease,
2351         .getlock_fn = catia_getlock,
2352         .realpath_fn = catia_realpath,
2353         .chflags_fn = catia_chflags,
2354         .streaminfo_fn = catia_streaminfo,
2355         .strict_lock_check_fn = catia_strict_lock_check,
2356         .translate_name_fn = catia_translate_name,
2357         .fsctl_fn = catia_fsctl,
2358         .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
2359         .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
2360         .set_dos_attributes_fn = catia_set_dos_attributes,
2361         .fset_dos_attributes_fn = catia_fset_dos_attributes,
2362         .fget_dos_attributes_fn = catia_fget_dos_attributes,
2363         .fget_compression_fn = catia_fget_compression,
2364         .set_compression_fn = catia_set_compression,
2365         .create_dfs_pathat_fn = catia_create_dfs_pathat,
2366         .read_dfs_pathat_fn = catia_read_dfs_pathat,
2367
2368         /* NT ACL operations. */
2369         .get_nt_acl_at_fn = catia_get_nt_acl_at,
2370         .fget_nt_acl_fn = catia_fget_nt_acl,
2371         .fset_nt_acl_fn = catia_fset_nt_acl,
2372
2373         /* POSIX ACL operations. */
2374         .sys_acl_get_file_fn = catia_sys_acl_get_file,
2375         .sys_acl_get_fd_fn = catia_sys_acl_get_fd,
2376         .sys_acl_blob_get_fd_fn = catia_sys_acl_blob_get_fd,
2377         .sys_acl_set_fd_fn = catia_sys_acl_set_fd,
2378         .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file,
2379
2380         /* EA operations. */
2381         .getxattr_fn = catia_getxattr,
2382         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2383         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2384         .removexattr_fn = catia_removexattr,
2385         .setxattr_fn = catia_setxattr,
2386         .fgetxattr_fn = catia_fgetxattr,
2387         .flistxattr_fn = catia_flistxattr,
2388         .fremovexattr_fn = catia_fremovexattr,
2389         .fsetxattr_fn = catia_fsetxattr,
2390 };
2391
2392 static_decl_vfs;
2393 NTSTATUS vfs_catia_init(TALLOC_CTX *ctx)
2394 {
2395         NTSTATUS ret;
2396
2397         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
2398                                 &vfs_catia_fns);
2399         if (!NT_STATUS_IS_OK(ret))
2400                 return ret;
2401
2402         vfs_catia_debug_level = debug_add_class("catia");
2403         if (vfs_catia_debug_level == -1) {
2404                 vfs_catia_debug_level = DBGC_VFS;
2405                 DEBUG(0, ("vfs_catia: Couldn't register custom debugging "
2406                           "class!\n"));
2407         } else {
2408                 DEBUG(10, ("vfs_catia: Debug class number of "
2409                            "'catia': %d\n", vfs_catia_debug_level));
2410         }
2411
2412         return ret;
2413
2414 }