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