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