4088affc08974578ad2238c1d3482ec6f08ffa1a
[gd/samba-autobuild/.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 [0x%p] cc->busy [0x%p] "
255                     "is_fsp_ext [%s] "
256                     "fsp [0x%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 = (struct catia_cache *)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 int
1132 catia_chmod_acl(vfs_handle_struct *handle,
1133                 const struct smb_filename *smb_fname,
1134                 mode_t mode)
1135 {
1136         char *mapped_name = NULL;
1137         struct smb_filename *mapped_smb_fname = NULL;
1138         NTSTATUS status;
1139         int ret;
1140         int saved_errno;
1141
1142         status = catia_string_replace_allocate(handle->conn,
1143                                 smb_fname->base_name,
1144                                 &mapped_name,
1145                                 vfs_translate_to_unix);
1146         if (!NT_STATUS_IS_OK(status)) {
1147                 errno = map_errno_from_nt_status(status);
1148                 return -1;
1149         }
1150
1151         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1152                                         mapped_name,
1153                                         NULL,
1154                                         NULL,
1155                                         smb_fname->flags);
1156         if (mapped_smb_fname == NULL) {
1157                 TALLOC_FREE(mapped_name);
1158                 errno = ENOMEM;
1159                 return -1;
1160         }
1161         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, mapped_smb_fname, mode);
1162         saved_errno = errno;
1163         TALLOC_FREE(mapped_name);
1164         TALLOC_FREE(mapped_smb_fname);
1165         errno = saved_errno;
1166         return ret;
1167 }
1168
1169 static SMB_ACL_T
1170 catia_sys_acl_get_file(vfs_handle_struct *handle,
1171                         const struct smb_filename *smb_fname,
1172                         SMB_ACL_TYPE_T type,
1173                         TALLOC_CTX *mem_ctx)
1174 {
1175         char *mapped_name = NULL;
1176         struct smb_filename *mapped_smb_fname = NULL;
1177         NTSTATUS status;
1178         SMB_ACL_T ret;
1179         int saved_errno = 0;
1180
1181         status = catia_string_replace_allocate(handle->conn,
1182                                 smb_fname->base_name,
1183                                 &mapped_name,
1184                                 vfs_translate_to_unix);
1185         if (!NT_STATUS_IS_OK(status)) {
1186                 errno = map_errno_from_nt_status(status);
1187                 return (SMB_ACL_T)NULL;
1188         }
1189
1190         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1191                                         mapped_name,
1192                                         NULL,
1193                                         NULL,
1194                                         smb_fname->flags);
1195         if (mapped_smb_fname == NULL) {
1196                 TALLOC_FREE(mapped_name);
1197                 errno = ENOMEM;
1198                 return (SMB_ACL_T)NULL;
1199         }
1200
1201         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, mapped_smb_fname,
1202                         type, mem_ctx);
1203         if (ret == (SMB_ACL_T)NULL) {
1204                 saved_errno = errno;
1205         }
1206         TALLOC_FREE(mapped_smb_fname);
1207         TALLOC_FREE(mapped_name);
1208         if (saved_errno != 0) {
1209                 errno = saved_errno;
1210         }
1211         return ret;
1212 }
1213
1214 static int
1215 catia_sys_acl_set_file(vfs_handle_struct *handle,
1216                         const struct smb_filename *smb_fname,
1217                         SMB_ACL_TYPE_T type,
1218                         SMB_ACL_T theacl)
1219 {
1220         struct smb_filename *mapped_smb_fname = NULL;
1221         int saved_errno = 0;
1222         char *mapped_name = NULL;
1223         NTSTATUS status;
1224         int ret;
1225
1226         status = catia_string_replace_allocate(handle->conn,
1227                                 smb_fname->base_name,
1228                                 &mapped_name,
1229                                 vfs_translate_to_unix);
1230         if (!NT_STATUS_IS_OK(status)) {
1231                 errno = map_errno_from_nt_status(status);
1232                 return -1;
1233         }
1234
1235         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1236                                         mapped_name,
1237                                         NULL,
1238                                         NULL,
1239                                         smb_fname->flags);
1240         if (mapped_smb_fname == NULL) {
1241                 TALLOC_FREE(mapped_name);
1242                 errno = ENOMEM;
1243                 return -1;
1244         }
1245
1246         ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, mapped_smb_fname,
1247                         type, theacl);
1248         if (ret == -1) {
1249                 saved_errno = errno;
1250         }
1251         TALLOC_FREE(mapped_smb_fname);
1252         TALLOC_FREE(mapped_name);
1253         if (saved_errno != 0) {
1254                 errno = saved_errno;
1255         }
1256         return ret;
1257 }
1258
1259 static int
1260 catia_sys_acl_delete_def_file(vfs_handle_struct *handle,
1261                                 const struct smb_filename *smb_fname)
1262 {
1263         struct smb_filename *mapped_smb_fname = NULL;
1264         int saved_errno = 0;
1265         char *mapped_name = NULL;
1266         NTSTATUS status;
1267         int ret;
1268
1269         status = catia_string_replace_allocate(handle->conn,
1270                                 smb_fname->base_name,
1271                                 &mapped_name,
1272                                 vfs_translate_to_unix);
1273         if (!NT_STATUS_IS_OK(status)) {
1274                 errno = map_errno_from_nt_status(status);
1275                 return -1;
1276         }
1277
1278         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1279                                         mapped_name,
1280                                         NULL,
1281                                         NULL,
1282                                         smb_fname->flags);
1283         if (mapped_smb_fname == NULL) {
1284                 TALLOC_FREE(mapped_name);
1285                 errno = ENOMEM;
1286                 return -1;
1287         }
1288         ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, mapped_smb_fname);
1289         if (ret == -1) {
1290                 saved_errno = errno;
1291         }
1292         TALLOC_FREE(mapped_smb_fname);
1293         TALLOC_FREE(mapped_name);
1294         if (saved_errno != 0) {
1295                 errno = saved_errno;
1296         }
1297         return ret;
1298 }
1299
1300 static ssize_t
1301 catia_getxattr(vfs_handle_struct *handle,
1302                         const struct smb_filename *smb_fname,
1303                         const char *name,
1304                         void *value,
1305                         size_t size)
1306 {
1307         struct smb_filename *mapped_smb_fname = NULL;
1308         char *mapped_name = NULL;
1309         char *mapped_ea_name = NULL;
1310         NTSTATUS status;
1311         ssize_t ret;
1312         int saved_errno = 0;
1313
1314         status = catia_string_replace_allocate(handle->conn,
1315                                 smb_fname->base_name,
1316                                 &mapped_name,
1317                                 vfs_translate_to_unix);
1318         if (!NT_STATUS_IS_OK(status)) {
1319                 errno = map_errno_from_nt_status(status);
1320                 return -1;
1321         }
1322
1323         status = catia_string_replace_allocate(handle->conn,
1324                                 name, &mapped_ea_name, vfs_translate_to_unix);
1325         if (!NT_STATUS_IS_OK(status)) {
1326                 TALLOC_FREE(mapped_name);
1327                 errno = map_errno_from_nt_status(status);
1328                 return -1;
1329         }
1330
1331         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1332                                         mapped_name,
1333                                         NULL,
1334                                         NULL,
1335                                         smb_fname->flags);
1336         if (mapped_smb_fname == NULL) {
1337                 TALLOC_FREE(mapped_name);
1338                 TALLOC_FREE(mapped_ea_name);
1339                 errno = ENOMEM;
1340                 return -1;
1341         }
1342
1343         ret = SMB_VFS_NEXT_GETXATTR(handle, mapped_smb_fname,
1344                                 mapped_ea_name, value, size);
1345         if (ret == -1) {
1346                 saved_errno = errno;
1347         }
1348         TALLOC_FREE(mapped_name);
1349         TALLOC_FREE(mapped_ea_name);
1350         TALLOC_FREE(mapped_smb_fname);
1351         if (saved_errno != 0) {
1352                 errno = saved_errno;
1353         }
1354
1355         return ret;
1356 }
1357
1358 static ssize_t
1359 catia_listxattr(vfs_handle_struct *handle,
1360                 const struct smb_filename *smb_fname,
1361                 char *list, size_t size)
1362 {
1363         struct smb_filename *mapped_smb_fname = NULL;
1364         char *mapped_name = NULL;
1365         NTSTATUS status;
1366         ssize_t ret;
1367         int saved_errno = 0;
1368
1369         status = catia_string_replace_allocate(handle->conn,
1370                                 smb_fname->base_name,
1371                                 &mapped_name,
1372                                 vfs_translate_to_unix);
1373         if (!NT_STATUS_IS_OK(status)) {
1374                 errno = map_errno_from_nt_status(status);
1375                 return -1;
1376         }
1377
1378         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1379                                         mapped_name,
1380                                         NULL,
1381                                         NULL,
1382                                         smb_fname->flags);
1383         if (mapped_smb_fname == NULL) {
1384                 TALLOC_FREE(mapped_name);
1385                 errno = ENOMEM;
1386                 return -1;
1387         }
1388
1389         ret = SMB_VFS_NEXT_LISTXATTR(handle, mapped_smb_fname, list, size);
1390         if (ret == -1) {
1391                 saved_errno = errno;
1392         }
1393         TALLOC_FREE(mapped_name);
1394         TALLOC_FREE(mapped_smb_fname);
1395         if (saved_errno != 0) {
1396                 errno = saved_errno;
1397         }
1398
1399         return ret;
1400 }
1401
1402 static int
1403 catia_removexattr(vfs_handle_struct *handle,
1404                         const struct smb_filename *smb_fname,
1405                         const char *name)
1406 {
1407         struct smb_filename *mapped_smb_fname = NULL;
1408         char *mapped_name = NULL;
1409         char *mapped_ea_name = NULL;
1410         NTSTATUS status;
1411         ssize_t ret;
1412         int saved_errno = 0;
1413
1414         status = catia_string_replace_allocate(handle->conn,
1415                                 smb_fname->base_name,
1416                                 &mapped_name,
1417                                 vfs_translate_to_unix);
1418         if (!NT_STATUS_IS_OK(status)) {
1419                 errno = map_errno_from_nt_status(status);
1420                 return -1;
1421         }
1422
1423         status = catia_string_replace_allocate(handle->conn,
1424                                 name, &mapped_ea_name, vfs_translate_to_unix);
1425         if (!NT_STATUS_IS_OK(status)) {
1426                 TALLOC_FREE(mapped_name);
1427                 errno = map_errno_from_nt_status(status);
1428                 return -1;
1429         }
1430
1431         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1432                                         mapped_name,
1433                                         NULL,
1434                                         NULL,
1435                                         smb_fname->flags);
1436         if (mapped_smb_fname == NULL) {
1437                 TALLOC_FREE(mapped_name);
1438                 TALLOC_FREE(mapped_ea_name);
1439                 errno = ENOMEM;
1440                 return -1;
1441         }
1442
1443         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, mapped_smb_fname,
1444                                 mapped_ea_name);
1445         if (ret == -1) {
1446                 saved_errno = errno;
1447         }
1448         TALLOC_FREE(mapped_name);
1449         TALLOC_FREE(mapped_ea_name);
1450         TALLOC_FREE(mapped_smb_fname);
1451         if (saved_errno != 0) {
1452                 errno = saved_errno;
1453         }
1454
1455         return ret;
1456 }
1457
1458 static int
1459 catia_setxattr(vfs_handle_struct *handle,
1460                         const struct smb_filename *smb_fname,
1461                         const char *name,
1462                         const void *value,
1463                         size_t size,
1464                         int flags)
1465 {
1466         struct smb_filename *mapped_smb_fname = NULL;
1467         char *mapped_name = NULL;
1468         char *mapped_ea_name = NULL;
1469         NTSTATUS status;
1470         ssize_t ret;
1471         int saved_errno = 0;
1472
1473         status = catia_string_replace_allocate(handle->conn,
1474                                 smb_fname->base_name,
1475                                 &mapped_name,
1476                                 vfs_translate_to_unix);
1477         if (!NT_STATUS_IS_OK(status)) {
1478                 errno = map_errno_from_nt_status(status);
1479                 return -1;
1480         }
1481
1482         status = catia_string_replace_allocate(handle->conn,
1483                                 name, &mapped_ea_name, vfs_translate_to_unix);
1484         if (!NT_STATUS_IS_OK(status)) {
1485                 TALLOC_FREE(mapped_name);
1486                 errno = map_errno_from_nt_status(status);
1487                 return -1;
1488         }
1489
1490         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1491                                         mapped_name,
1492                                         NULL,
1493                                         NULL,
1494                                         smb_fname->flags);
1495         if (mapped_smb_fname == NULL) {
1496                 TALLOC_FREE(mapped_name);
1497                 TALLOC_FREE(mapped_ea_name);
1498                 errno = ENOMEM;
1499                 return -1;
1500         }
1501
1502         ret = SMB_VFS_NEXT_SETXATTR(handle, mapped_smb_fname, mapped_ea_name,
1503                         value, size, flags);
1504         if (ret == -1) {
1505                 saved_errno = errno;
1506         }
1507         TALLOC_FREE(mapped_name);
1508         TALLOC_FREE(mapped_ea_name);
1509         TALLOC_FREE(mapped_smb_fname);
1510         if (saved_errno != 0) {
1511                 errno = saved_errno;
1512         }
1513
1514         return ret;
1515 }
1516
1517 static int catia_fstat(vfs_handle_struct *handle,
1518                        files_struct *fsp,
1519                        SMB_STRUCT_STAT *sbuf)
1520 {
1521         struct catia_cache *cc = NULL;
1522         int ret;
1523
1524         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1525         if (ret != 0) {
1526                 return ret;
1527         }
1528
1529         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1530
1531         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1532
1533         return ret;
1534 }
1535
1536 static ssize_t catia_pread(vfs_handle_struct *handle,
1537                            files_struct *fsp, void *data,
1538                            size_t n, off_t offset)
1539 {
1540         struct catia_cache *cc = NULL;
1541         ssize_t result;
1542         int ret;
1543
1544         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1545         if (ret != 0) {
1546                 return ret;
1547         }
1548
1549         result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
1550
1551         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1552
1553         return result;
1554 }
1555
1556 static ssize_t catia_pwrite(vfs_handle_struct *handle,
1557                             files_struct *fsp, const void *data,
1558                             size_t n, off_t offset)
1559 {
1560         struct catia_cache *cc = NULL;
1561         ssize_t result;
1562         int ret;
1563
1564         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1565         if (ret != 0) {
1566                 return ret;
1567         }
1568
1569         result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
1570
1571         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1572
1573         return result;
1574 }
1575
1576 static int catia_ftruncate(struct vfs_handle_struct *handle,
1577                            struct files_struct *fsp,
1578                            off_t offset)
1579 {
1580         struct catia_cache *cc = NULL;
1581         int ret;
1582
1583         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1584         if (ret != 0) {
1585                 return ret;
1586         }
1587
1588         ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
1589
1590         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1591
1592         return ret;
1593 }
1594
1595 static int catia_fallocate(struct vfs_handle_struct *handle,
1596                            struct files_struct *fsp,
1597                            uint32_t mode,
1598                            off_t offset,
1599                            off_t len)
1600 {
1601         struct catia_cache *cc = NULL;
1602         int ret;
1603
1604         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1605         if (ret != 0) {
1606                 return ret;
1607         }
1608
1609         ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
1610
1611         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1612
1613         return ret;
1614 }
1615
1616 static ssize_t catia_fgetxattr(struct vfs_handle_struct *handle,
1617                                struct files_struct *fsp,
1618                                const char *name,
1619                                void *value,
1620                                size_t size)
1621 {
1622         char *mapped_xattr_name = NULL;
1623         NTSTATUS status;
1624         ssize_t result;
1625
1626         status = catia_string_replace_allocate(handle->conn,
1627                                                name, &mapped_xattr_name,
1628                                                vfs_translate_to_unix);
1629         if (!NT_STATUS_IS_OK(status)) {
1630                 errno = map_errno_from_nt_status(status);
1631                 return -1;
1632         }
1633
1634         result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, mapped_xattr_name,
1635                                         value, size);
1636
1637         TALLOC_FREE(mapped_xattr_name);
1638
1639         return result;
1640 }
1641
1642 static ssize_t catia_flistxattr(struct vfs_handle_struct *handle,
1643                                 struct files_struct *fsp,
1644                                 char *list,
1645                                 size_t size)
1646 {
1647         struct catia_cache *cc = NULL;
1648         ssize_t result;
1649         int ret;
1650
1651         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1652         if (ret != 0) {
1653                 return ret;
1654         }
1655
1656         result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
1657
1658         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1659
1660         return result;
1661 }
1662
1663 static int catia_fremovexattr(struct vfs_handle_struct *handle,
1664                               struct files_struct *fsp,
1665                               const char *name)
1666 {
1667         char *mapped_name = NULL;
1668         NTSTATUS status;
1669         int ret;
1670
1671         status = catia_string_replace_allocate(handle->conn,
1672                                 name, &mapped_name, vfs_translate_to_unix);
1673         if (!NT_STATUS_IS_OK(status)) {
1674                 errno = map_errno_from_nt_status(status);
1675                 return -1;
1676         }
1677
1678         ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, mapped_name);
1679
1680         TALLOC_FREE(mapped_name);
1681
1682         return ret;
1683 }
1684
1685 static int catia_fsetxattr(struct vfs_handle_struct *handle,
1686                            struct files_struct *fsp,
1687                            const char *name,
1688                            const void *value,
1689                            size_t size,
1690                            int flags)
1691 {
1692         char *mapped_xattr_name = NULL;
1693         NTSTATUS status;
1694         int ret;
1695
1696         status = catia_string_replace_allocate(
1697                 handle->conn, name, &mapped_xattr_name, vfs_translate_to_unix);
1698         if (!NT_STATUS_IS_OK(status)) {
1699                 errno = map_errno_from_nt_status(status);
1700                 return -1;
1701         }
1702
1703         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, mapped_xattr_name,
1704                                      value, size, flags);
1705
1706         TALLOC_FREE(mapped_xattr_name);
1707
1708         return ret;
1709 }
1710
1711 static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle,
1712                                       files_struct *fsp,
1713                                       TALLOC_CTX *mem_ctx)
1714 {
1715         struct catia_cache *cc = NULL;
1716         struct smb_acl_t *result = NULL;
1717         int ret;
1718
1719         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1720         if (ret != 0) {
1721                 return NULL;
1722         }
1723
1724         result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
1725
1726         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1727
1728         return result;
1729 }
1730
1731 static int catia_sys_acl_blob_get_fd(vfs_handle_struct *handle,
1732                                      files_struct *fsp,
1733                                      TALLOC_CTX *mem_ctx,
1734                                      char **blob_description,
1735                                      DATA_BLOB *blob)
1736 {
1737         struct catia_cache *cc = NULL;
1738         int ret;
1739
1740         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1741         if (ret != 0) {
1742                 return ret;
1743         }
1744
1745         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
1746                                                blob_description, blob);
1747
1748         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1749
1750         return ret;
1751 }
1752
1753 static int catia_sys_acl_set_fd(vfs_handle_struct *handle,
1754                                 files_struct *fsp,
1755                                 SMB_ACL_T theacl)
1756 {
1757         struct catia_cache *cc = NULL;
1758         int ret;
1759
1760         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1761         if (ret != 0) {
1762                 return ret;
1763         }
1764
1765         ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
1766
1767         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1768
1769         return ret;
1770 }
1771
1772 static int catia_fchmod_acl(vfs_handle_struct *handle,
1773                             files_struct *fsp,
1774                             mode_t mode)
1775 {
1776         struct catia_cache *cc = NULL;
1777         int ret;
1778
1779         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1780         if (ret != 0) {
1781                 return ret;
1782         }
1783
1784         ret = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1785
1786         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1787
1788         return ret;
1789 }
1790
1791 static NTSTATUS catia_fget_nt_acl(vfs_handle_struct *handle,
1792                                   files_struct *fsp,
1793                                   uint32_t security_info,
1794                                   TALLOC_CTX *mem_ctx,
1795                                   struct security_descriptor **ppdesc)
1796 {
1797         struct catia_cache *cc = NULL;
1798         NTSTATUS status;
1799         int ret;
1800
1801         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1802         if (ret != 0) {
1803                 return map_nt_error_from_unix(errno);
1804         }
1805
1806         status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1807                                           mem_ctx, ppdesc);
1808
1809         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1810
1811         return status;
1812 }
1813
1814 static NTSTATUS catia_fset_nt_acl(vfs_handle_struct *handle,
1815                                   files_struct *fsp,
1816                                   uint32_t security_info_sent,
1817                                   const struct security_descriptor *psd)
1818 {
1819         struct catia_cache *cc = NULL;
1820         NTSTATUS status;
1821         int ret;
1822
1823         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1824         if (ret != 0) {
1825                 return map_nt_error_from_unix(errno);
1826         }
1827
1828         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
1829
1830         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1831
1832         return status;
1833 }
1834
1835 static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle,
1836                                           struct files_struct *fsp,
1837                                           uint32_t dosmode)
1838 {
1839         struct catia_cache *cc = NULL;
1840         NTSTATUS status;
1841         int ret;
1842
1843         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1844         if (ret != 0) {
1845                 return map_nt_error_from_unix(errno);
1846         }
1847
1848         status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1849
1850         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1851
1852         return status;
1853 }
1854
1855 static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle,
1856                                           struct files_struct *fsp,
1857                                           uint32_t *dosmode)
1858 {
1859         struct catia_cache *cc = NULL;
1860         NTSTATUS status;
1861         int ret;
1862
1863         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1864         if (ret != 0) {
1865                 return map_nt_error_from_unix(errno);
1866         }
1867
1868         status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1869
1870         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1871
1872         return status;
1873 }
1874
1875 static int catia_fchown(vfs_handle_struct *handle,
1876                         files_struct *fsp,
1877                         uid_t uid,
1878                         gid_t gid)
1879 {
1880         struct catia_cache *cc = NULL;
1881         int ret;
1882
1883         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1884         if (ret != 0) {
1885                 return ret;
1886         }
1887
1888         ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
1889
1890         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1891
1892         return ret;
1893 }
1894
1895 static int catia_fchmod(vfs_handle_struct *handle,
1896                         files_struct *fsp,
1897                         mode_t mode)
1898 {
1899         struct catia_cache *cc = NULL;
1900         int ret;
1901
1902         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1903         if (ret != 0) {
1904                 return ret;
1905         }
1906
1907         ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1908
1909         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1910
1911         return ret;
1912 }
1913
1914 struct catia_pread_state {
1915         ssize_t ret;
1916         struct vfs_aio_state vfs_aio_state;
1917         struct files_struct *fsp;
1918         struct catia_cache *cc;
1919 };
1920
1921 static void catia_pread_done(struct tevent_req *subreq);
1922
1923 static struct tevent_req *catia_pread_send(struct vfs_handle_struct *handle,
1924                                            TALLOC_CTX *mem_ctx,
1925                                            struct tevent_context *ev,
1926                                            struct files_struct *fsp,
1927                                            void *data,
1928                                            size_t n,
1929                                            off_t offset)
1930 {
1931         struct tevent_req *req = NULL, *subreq = NULL;
1932         struct catia_pread_state *state = NULL;
1933         int ret;
1934
1935         req = tevent_req_create(mem_ctx, &state,
1936                                 struct catia_pread_state);
1937         if (req == NULL) {
1938                 return NULL;
1939         }
1940         state->fsp = fsp;
1941
1942         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1943         if (ret != 0) {
1944                 tevent_req_error(req, errno);
1945                 return tevent_req_post(req, ev);
1946         }
1947
1948         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
1949                                          n, offset);
1950         if (tevent_req_nomem(subreq, req)) {
1951                 return tevent_req_post(req, ev);
1952         }
1953         tevent_req_set_callback(subreq, catia_pread_done, req);
1954
1955         return req;
1956 }
1957
1958 static void catia_pread_done(struct tevent_req *subreq)
1959 {
1960         struct tevent_req *req = tevent_req_callback_data(
1961                 subreq, struct tevent_req);
1962         struct catia_pread_state *state = tevent_req_data(
1963                 req, struct catia_pread_state);
1964
1965         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
1966         TALLOC_FREE(subreq);
1967
1968         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1969
1970         tevent_req_done(req);
1971 }
1972
1973 static ssize_t catia_pread_recv(struct tevent_req *req,
1974                                 struct vfs_aio_state *vfs_aio_state)
1975 {
1976         struct catia_pread_state *state = tevent_req_data(
1977                 req, struct catia_pread_state);
1978
1979         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1980                 return -1;
1981         }
1982
1983         *vfs_aio_state = state->vfs_aio_state;
1984         return state->ret;
1985 }
1986
1987 struct catia_pwrite_state {
1988         ssize_t ret;
1989         struct vfs_aio_state vfs_aio_state;
1990         struct files_struct *fsp;
1991         struct catia_cache *cc;
1992 };
1993
1994 static void catia_pwrite_done(struct tevent_req *subreq);
1995
1996 static struct tevent_req *catia_pwrite_send(struct vfs_handle_struct *handle,
1997                                             TALLOC_CTX *mem_ctx,
1998                                             struct tevent_context *ev,
1999                                             struct files_struct *fsp,
2000                                             const void *data,
2001                                             size_t n,
2002                                             off_t offset)
2003 {
2004         struct tevent_req *req = NULL, *subreq = NULL;
2005         struct catia_pwrite_state *state = NULL;
2006         int ret;
2007
2008         req = tevent_req_create(mem_ctx, &state,
2009                                 struct catia_pwrite_state);
2010         if (req == NULL) {
2011                 return NULL;
2012         }
2013         state->fsp = fsp;
2014
2015         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
2016         if (ret != 0) {
2017                 tevent_req_error(req, errno);
2018                 return tevent_req_post(req, ev);
2019         }
2020
2021         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
2022                                           n, offset);
2023         if (tevent_req_nomem(subreq, req)) {
2024                 return tevent_req_post(req, ev);
2025         }
2026         tevent_req_set_callback(subreq, catia_pwrite_done, req);
2027
2028         return req;
2029 }
2030
2031 static void catia_pwrite_done(struct tevent_req *subreq)
2032 {
2033         struct tevent_req *req = tevent_req_callback_data(
2034                 subreq, struct tevent_req);
2035         struct catia_pwrite_state *state = tevent_req_data(
2036                 req, struct catia_pwrite_state);
2037
2038         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
2039         TALLOC_FREE(subreq);
2040
2041         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
2042
2043         tevent_req_done(req);
2044 }
2045
2046 static ssize_t catia_pwrite_recv(struct tevent_req *req,
2047                                 struct vfs_aio_state *vfs_aio_state)
2048 {
2049         struct catia_pwrite_state *state = tevent_req_data(
2050                 req, struct catia_pwrite_state);
2051
2052         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2053                 return -1;
2054         }
2055
2056         *vfs_aio_state = state->vfs_aio_state;
2057         return state->ret;
2058 }
2059
2060 static off_t catia_lseek(vfs_handle_struct *handle,
2061                          files_struct *fsp,
2062                          off_t offset,
2063                          int whence)
2064 {
2065         struct catia_cache *cc = NULL;
2066         ssize_t result;
2067         int ret;
2068
2069         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2070         if (ret != 0) {
2071                 return -1;
2072         }
2073
2074         result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
2075
2076         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2077
2078         return result;
2079 }
2080
2081 static int catia_fsync(vfs_handle_struct *handle, files_struct *fsp)
2082 {
2083         struct catia_cache *cc = NULL;
2084         int ret;
2085
2086         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2087         if (ret != 0) {
2088                 return -1;
2089         }
2090
2091         ret = SMB_VFS_NEXT_FSYNC(handle, fsp);
2092
2093         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2094
2095         return ret;
2096 }
2097
2098 struct catia_fsync_state {
2099         int ret;
2100         struct vfs_aio_state vfs_aio_state;
2101         struct files_struct *fsp;
2102         struct catia_cache *cc;
2103 };
2104
2105 static void catia_fsync_done(struct tevent_req *subreq);
2106
2107 static struct tevent_req *catia_fsync_send(struct vfs_handle_struct *handle,
2108                                            TALLOC_CTX *mem_ctx,
2109                                            struct tevent_context *ev,
2110                                            struct files_struct *fsp)
2111 {
2112         struct tevent_req *req = NULL, *subreq = NULL;
2113         struct catia_fsync_state *state = NULL;
2114         int ret;
2115
2116         req = tevent_req_create(mem_ctx, &state,
2117                                 struct catia_fsync_state);
2118         if (req == NULL) {
2119                 return NULL;
2120         }
2121         state->fsp = fsp;
2122
2123         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
2124         if (ret != 0) {
2125                 tevent_req_error(req, errno);
2126                 return tevent_req_post(req, ev);
2127         }
2128
2129         subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
2130         if (tevent_req_nomem(subreq, req)) {
2131                 return tevent_req_post(req, ev);
2132         }
2133         tevent_req_set_callback(subreq, catia_fsync_done, req);
2134
2135         return req;
2136 }
2137
2138 static void catia_fsync_done(struct tevent_req *subreq)
2139 {
2140         struct tevent_req *req = tevent_req_callback_data(
2141                 subreq, struct tevent_req);
2142         struct catia_fsync_state *state = tevent_req_data(
2143                 req, struct catia_fsync_state);
2144
2145         state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
2146         TALLOC_FREE(subreq);
2147
2148         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
2149
2150         tevent_req_done(req);
2151 }
2152
2153 static int catia_fsync_recv(struct tevent_req *req,
2154                             struct vfs_aio_state *vfs_aio_state)
2155 {
2156         struct catia_fsync_state *state = tevent_req_data(
2157                 req, struct catia_fsync_state);
2158
2159         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2160                 return -1;
2161         }
2162
2163         *vfs_aio_state = state->vfs_aio_state;
2164         return state->ret;
2165 }
2166
2167 static bool catia_lock(vfs_handle_struct *handle,
2168                        files_struct *fsp,
2169                        int op,
2170                        off_t offset,
2171                        off_t count,
2172                        int type)
2173 {
2174         struct catia_cache *cc = NULL;
2175         bool ok;
2176         int ret;
2177
2178         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2179         if (ret != 0) {
2180                 return -1;
2181         }
2182
2183         ok = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
2184
2185         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2186
2187         return ok;
2188 }
2189
2190 static int catia_kernel_flock(struct vfs_handle_struct *handle,
2191                               struct files_struct *fsp,
2192                               uint32_t share_mode,
2193                               uint32_t access_mask)
2194 {
2195         struct catia_cache *cc = NULL;
2196         int ret;
2197
2198         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2199         if (ret != 0) {
2200                 return -1;
2201         }
2202
2203         ret = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode, access_mask);
2204
2205         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2206
2207         return ret;
2208 }
2209
2210 static int catia_linux_setlease(vfs_handle_struct *handle,
2211                                 files_struct *fsp,
2212                                 int leasetype)
2213 {
2214         struct catia_cache *cc = NULL;
2215         int ret;
2216
2217         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2218         if (ret != 0) {
2219                 return -1;
2220         }
2221
2222         ret = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
2223
2224         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2225
2226         return ret;
2227 }
2228
2229 static bool catia_getlock(vfs_handle_struct *handle,
2230                           files_struct *fsp,
2231                           off_t *poffset,
2232                           off_t *pcount,
2233                           int *ptype,
2234                           pid_t *ppid)
2235 {
2236         struct catia_cache *cc = NULL;
2237         int ret;
2238         bool ok;
2239
2240         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2241         if (ret != 0) {
2242                 return -1;
2243         }
2244
2245         ok = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
2246
2247         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2248
2249         return ok;
2250 }
2251
2252 static bool catia_strict_lock_check(struct vfs_handle_struct *handle,
2253                                     struct files_struct *fsp,
2254                                     struct lock_struct *plock)
2255 {
2256         struct catia_cache *cc = NULL;
2257         int ret;
2258         bool ok;
2259
2260         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2261         if (ret != 0) {
2262                 return -1;
2263         }
2264
2265         ok = SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock);
2266
2267         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2268
2269         return ok;
2270 }
2271
2272 static NTSTATUS catia_fsctl(struct vfs_handle_struct *handle,
2273                             struct files_struct *fsp,
2274                             TALLOC_CTX *ctx,
2275                             uint32_t function,
2276                             uint16_t req_flags,
2277                             const uint8_t *_in_data,
2278                             uint32_t in_len,
2279                             uint8_t **_out_data,
2280                             uint32_t max_out_len,
2281                             uint32_t *out_len)
2282 {
2283         NTSTATUS result;
2284         struct catia_cache *cc = NULL;
2285         int ret;
2286
2287         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2288         if (ret != 0) {
2289                 return map_nt_error_from_unix(errno);
2290         }
2291
2292         result = SMB_VFS_NEXT_FSCTL(handle,
2293                                 fsp,
2294                                 ctx,
2295                                 function,
2296                                 req_flags,
2297                                 _in_data,
2298                                 in_len,
2299                                 _out_data,
2300                                 max_out_len,
2301                                 out_len);
2302
2303         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2304
2305         return result;
2306 }
2307
2308 static NTSTATUS catia_get_compression(vfs_handle_struct *handle,
2309                                       TALLOC_CTX *mem_ctx,
2310                                       struct files_struct *fsp,
2311                                       struct smb_filename *smb_fname,
2312                                       uint16_t *_compression_fmt)
2313 {
2314         NTSTATUS result;
2315         struct catia_cache *cc = NULL;
2316         int ret;
2317         struct smb_filename *mapped_smb_fname = NULL;
2318         char *mapped_name = NULL;
2319
2320         if (fsp != NULL) {
2321                 ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2322                 if (ret != 0) {
2323                         return map_nt_error_from_unix(errno);
2324                 }
2325                 mapped_smb_fname = fsp->fsp_name;
2326         } else {
2327                 result = catia_string_replace_allocate(handle->conn,
2328                                 smb_fname->base_name,
2329                                 &mapped_name,
2330                                 vfs_translate_to_unix);
2331                 if (!NT_STATUS_IS_OK(result)) {
2332                         return result;
2333                 }
2334
2335                 mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2336                                                 mapped_name,
2337                                                 NULL,
2338                                                 NULL,
2339                                                 smb_fname->flags);
2340                 if (mapped_smb_fname == NULL) {
2341                         TALLOC_FREE(mapped_name);
2342                         return NT_STATUS_NO_MEMORY;
2343                 }
2344
2345                 TALLOC_FREE(mapped_name);
2346         }
2347
2348         result = SMB_VFS_NEXT_GET_COMPRESSION(handle,
2349                                         mem_ctx,
2350                                         fsp,
2351                                         mapped_smb_fname,
2352                                         _compression_fmt);
2353
2354         if (fsp != NULL) {
2355                 CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2356         } else {
2357                 TALLOC_FREE(mapped_smb_fname);
2358         }
2359
2360         return result;
2361 }
2362
2363 static NTSTATUS catia_set_compression(vfs_handle_struct *handle,
2364                                       TALLOC_CTX *mem_ctx,
2365                                       struct files_struct *fsp,
2366                                       uint16_t compression_fmt)
2367 {
2368         NTSTATUS result;
2369         struct catia_cache *cc = NULL;
2370         int ret;
2371
2372         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2373         if (ret != 0) {
2374                 return map_nt_error_from_unix(errno);
2375         }
2376
2377         result = SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp,
2378                                               compression_fmt);
2379
2380         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2381
2382         return result;
2383 }
2384
2385 static NTSTATUS catia_readdir_attr(struct vfs_handle_struct *handle,
2386                                    const struct smb_filename *smb_fname_in,
2387                                    TALLOC_CTX *mem_ctx,
2388                                    struct readdir_attr_data **pattr_data)
2389 {
2390         struct smb_filename *smb_fname;
2391         char *fname = NULL;
2392         NTSTATUS status;
2393
2394         status = catia_string_replace_allocate(handle->conn,
2395                                                smb_fname_in->base_name,
2396                                                &fname,
2397                                                vfs_translate_to_unix);
2398         if (!NT_STATUS_IS_OK(status)) {
2399                 errno = map_errno_from_nt_status(status);
2400                 return status;
2401         }
2402
2403         smb_fname = synthetic_smb_fname(talloc_tos(), fname, NULL,
2404                                         &smb_fname_in->st, 0);
2405
2406         status = SMB_VFS_NEXT_READDIR_ATTR(handle, smb_fname, mem_ctx, pattr_data);
2407
2408         TALLOC_FREE(smb_fname);
2409         TALLOC_FREE(fname);
2410         return status;
2411 }
2412
2413 static NTSTATUS catia_get_dos_attributes(struct vfs_handle_struct *handle,
2414                                          struct smb_filename *smb_fname,
2415                                          uint32_t *dosmode)
2416 {
2417         char *mapped_name = NULL;
2418         const char *path = smb_fname->base_name;
2419         struct smb_filename *mapped_smb_fname = NULL;
2420         NTSTATUS status;
2421
2422         status = catia_string_replace_allocate(handle->conn,
2423                                 path, &mapped_name, vfs_translate_to_unix);
2424         if (!NT_STATUS_IS_OK(status)) {
2425                 errno = map_errno_from_nt_status(status);
2426                 return status;
2427         }
2428         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2429                                         mapped_name,
2430                                         NULL,
2431                                         NULL,
2432                                         smb_fname->flags);
2433         if (mapped_smb_fname == NULL) {
2434                 TALLOC_FREE(mapped_name);
2435                 return NT_STATUS_NO_MEMORY;
2436         }
2437
2438         status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle,
2439                                                  mapped_smb_fname,
2440                                                  dosmode);
2441         TALLOC_FREE(mapped_name);
2442         TALLOC_FREE(mapped_smb_fname);
2443
2444         return status;
2445 }
2446
2447 static NTSTATUS catia_set_dos_attributes(struct vfs_handle_struct *handle,
2448                                          const struct smb_filename *smb_fname,
2449                                          uint32_t dosmode)
2450 {
2451         char *mapped_name = NULL;
2452         const char *path = smb_fname->base_name;
2453         struct smb_filename *mapped_smb_fname = NULL;
2454         NTSTATUS status;
2455
2456         status = catia_string_replace_allocate(handle->conn,
2457                                 path, &mapped_name, vfs_translate_to_unix);
2458         if (!NT_STATUS_IS_OK(status)) {
2459                 errno = map_errno_from_nt_status(status);
2460                 return status;
2461         }
2462         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2463                                         mapped_name,
2464                                         NULL,
2465                                         NULL,
2466                                         smb_fname->flags);
2467         if (mapped_smb_fname == NULL) {
2468                 TALLOC_FREE(mapped_name);
2469                 return NT_STATUS_NO_MEMORY;
2470         }
2471
2472         status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
2473                                                  mapped_smb_fname,
2474                                                  dosmode);
2475         TALLOC_FREE(mapped_name);
2476         TALLOC_FREE(mapped_smb_fname);
2477
2478         return status;
2479 }
2480
2481 static struct vfs_fn_pointers vfs_catia_fns = {
2482         /* Directory operations */
2483         .mkdir_fn = catia_mkdir,
2484         .rmdir_fn = catia_rmdir,
2485         .opendir_fn = catia_opendir,
2486         .readdir_attr_fn = catia_readdir_attr,
2487
2488         /* File operations */
2489         .open_fn = catia_open,
2490         .pread_fn = catia_pread,
2491         .pread_send_fn = catia_pread_send,
2492         .pread_recv_fn = catia_pread_recv,
2493         .pwrite_fn = catia_pwrite,
2494         .pwrite_send_fn = catia_pwrite_send,
2495         .pwrite_recv_fn = catia_pwrite_recv,
2496         .lseek_fn = catia_lseek,
2497         .rename_fn = catia_rename,
2498         .fsync_fn = catia_fsync,
2499         .fsync_send_fn = catia_fsync_send,
2500         .fsync_recv_fn = catia_fsync_recv,
2501         .stat_fn = catia_stat,
2502         .fstat_fn = catia_fstat,
2503         .lstat_fn = catia_lstat,
2504         .unlink_fn = catia_unlink,
2505         .chmod_fn = catia_chmod,
2506         .fchmod_fn = catia_fchmod,
2507         .chown_fn = catia_chown,
2508         .fchown_fn = catia_fchown,
2509         .lchown_fn = catia_lchown,
2510         .chdir_fn = catia_chdir,
2511         .ntimes_fn = catia_ntimes,
2512         .ftruncate_fn = catia_ftruncate,
2513         .fallocate_fn = catia_fallocate,
2514         .lock_fn = catia_lock,
2515         .kernel_flock_fn = catia_kernel_flock,
2516         .linux_setlease_fn = catia_linux_setlease,
2517         .getlock_fn = catia_getlock,
2518         .realpath_fn = catia_realpath,
2519         .chflags_fn = catia_chflags,
2520         .streaminfo_fn = catia_streaminfo,
2521         .strict_lock_check_fn = catia_strict_lock_check,
2522         .translate_name_fn = catia_translate_name,
2523         .fsctl_fn = catia_fsctl,
2524         .get_dos_attributes_fn = catia_get_dos_attributes,
2525         .set_dos_attributes_fn = catia_set_dos_attributes,
2526         .fset_dos_attributes_fn = catia_fset_dos_attributes,
2527         .fget_dos_attributes_fn = catia_fget_dos_attributes,
2528         .get_compression_fn = catia_get_compression,
2529         .set_compression_fn = catia_set_compression,
2530
2531         /* NT ACL operations. */
2532         .get_nt_acl_fn = catia_get_nt_acl,
2533         .fget_nt_acl_fn = catia_fget_nt_acl,
2534         .fset_nt_acl_fn = catia_fset_nt_acl,
2535
2536         /* POSIX ACL operations. */
2537         .chmod_acl_fn = catia_chmod_acl,
2538         .fchmod_acl_fn = catia_fchmod_acl,
2539
2540         .sys_acl_get_file_fn = catia_sys_acl_get_file,
2541         .sys_acl_get_fd_fn = catia_sys_acl_get_fd,
2542         .sys_acl_blob_get_fd_fn = catia_sys_acl_blob_get_fd,
2543         .sys_acl_set_file_fn = catia_sys_acl_set_file,
2544         .sys_acl_set_fd_fn = catia_sys_acl_set_fd,
2545         .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file,
2546
2547         /* EA operations. */
2548         .getxattr_fn = catia_getxattr,
2549         .listxattr_fn = catia_listxattr,
2550         .removexattr_fn = catia_removexattr,
2551         .setxattr_fn = catia_setxattr,
2552         .fgetxattr_fn = catia_fgetxattr,
2553         .flistxattr_fn = catia_flistxattr,
2554         .fremovexattr_fn = catia_fremovexattr,
2555         .fsetxattr_fn = catia_fsetxattr,
2556 };
2557
2558 static_decl_vfs;
2559 NTSTATUS vfs_catia_init(TALLOC_CTX *ctx)
2560 {
2561         NTSTATUS ret;
2562
2563         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
2564                                 &vfs_catia_fns);
2565         if (!NT_STATUS_IS_OK(ret))
2566                 return ret;
2567
2568         vfs_catia_debug_level = debug_add_class("catia");
2569         if (vfs_catia_debug_level == -1) {
2570                 vfs_catia_debug_level = DBGC_VFS;
2571                 DEBUG(0, ("vfs_catia: Couldn't register custom debugging "
2572                           "class!\n"));
2573         } else {
2574                 DEBUG(10, ("vfs_catia: Debug class number of "
2575                            "'catia': %d\n", vfs_catia_debug_level));
2576         }
2577
2578         return ret;
2579
2580 }