vfs: change openat propotype to match linux openat2
[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, 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_is_alternate_stream(fsp) &&
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_is_alternate_stream(fsp) &&
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_is_alternate_stream(fsp)) {
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_is_alternate_stream(fsp)) {
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_is_alternate_stream(fsp)) {
428                 cc->orig_base_fname = fsp->base_fsp->fsp_name->base_name;
429                 fsp->base_fsp->fsp_name->base_name = cc->base_fname;
430         }
431
432         cc->busy = busy;
433         CATIA_DEBUG_CC(10, cc, fsp);
434
435         *_cc = cc;
436
437         return 0;
438 }
439
440 #define CATIA_FETCH_FSP_POST_NEXT(_cc, fsp) do { \
441         int catia_saved_errno = errno; \
442         catia_fetch_fsp_post_next((_cc), (fsp), __func__); \
443         errno = catia_saved_errno; \
444 } while(0)
445
446 static void catia_fetch_fsp_post_next(struct catia_cache **_cc,
447                                       files_struct *fsp,
448                                       const char *function)
449 {
450         const struct catia_cache * const *busy =
451                 (const struct catia_cache * const *)_cc;
452         struct catia_cache *cc = *_cc;
453
454         DBG_DEBUG("Called from [%s]\n", function);
455
456         if (cc == NULL) {
457                 /*
458                  * This can happen when recursing in the VFS on the fsp when the
459                  * pre_next func noticed the recursion and set out cc pointer to
460                  * NULL.
461                  */
462                 return;
463         }
464
465         if (cc->busy != busy) {
466                 CATIA_DEBUG_CC(0, cc, fsp);
467                 smb_panic(__location__);
468                 return;
469         }
470
471         cc->busy = NULL;
472         *_cc = NULL;
473
474         fsp->fsp_name->base_name = cc->orig_fname;
475         if (fsp_is_alternate_stream(fsp)) {
476                 fsp->base_fsp->fsp_name->base_name = cc->orig_base_fname;
477         }
478
479         CATIA_DEBUG_CC(10, cc, fsp);
480
481         if (!cc->is_fsp_ext) {
482                 TALLOC_FREE(cc);
483         }
484
485         return;
486 }
487
488 static int catia_openat(vfs_handle_struct *handle,
489                         const struct files_struct *dirfsp,
490                         const struct smb_filename *smb_fname_in,
491                         files_struct *fsp,
492                         const struct vfs_open_how *how)
493 {
494         struct smb_filename *smb_fname = NULL;
495         struct catia_cache *cc = NULL;
496         char *mapped_name = NULL;
497         NTSTATUS status;
498         int ret;
499         int saved_errno = 0;
500
501         status = catia_string_replace_allocate(handle->conn,
502                                                smb_fname_in->base_name,
503                                                &mapped_name,
504                                                vfs_translate_to_unix);
505         if (!NT_STATUS_IS_OK(status)) {
506                 return -1;
507         }
508
509         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
510         if (ret != 0) {
511                 TALLOC_FREE(mapped_name);
512                 return ret;
513         }
514
515         smb_fname = cp_smb_filename(talloc_tos(), smb_fname_in);
516         if (smb_fname == NULL) {
517                 TALLOC_FREE(mapped_name);
518                 errno = ENOMEM;
519                 return -1;
520         }
521         smb_fname->base_name = mapped_name;
522
523         ret = SMB_VFS_NEXT_OPENAT(handle,
524                                   dirfsp,
525                                   smb_fname,
526                                   fsp,
527                                   how);
528         if (ret == -1) {
529                 saved_errno = errno;
530         }
531         TALLOC_FREE(smb_fname);
532         TALLOC_FREE(mapped_name);
533         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
534         if (saved_errno != 0) {
535                 errno = saved_errno;
536         }
537         return ret;
538 }
539
540 static int catia_renameat(vfs_handle_struct *handle,
541                         files_struct *srcfsp,
542                         const struct smb_filename *smb_fname_src,
543                         files_struct *dstfsp,
544                         const struct smb_filename *smb_fname_dst)
545 {
546         TALLOC_CTX *ctx = talloc_tos();
547         struct smb_filename *smb_fname_src_tmp = NULL;
548         struct smb_filename *smb_fname_dst_tmp = NULL;
549         char *src_name_mapped = NULL;
550         char *dst_name_mapped = NULL;
551         NTSTATUS status;
552         int ret = -1;
553
554         status = catia_string_replace_allocate(handle->conn,
555                                 smb_fname_src->base_name,
556                                 &src_name_mapped, vfs_translate_to_unix);
557         if (!NT_STATUS_IS_OK(status)) {
558                 errno = map_errno_from_nt_status(status);
559                 return -1;
560         }
561
562         status = catia_string_replace_allocate(handle->conn,
563                                 smb_fname_dst->base_name,
564                                 &dst_name_mapped, vfs_translate_to_unix);
565         if (!NT_STATUS_IS_OK(status)) {
566                 errno = map_errno_from_nt_status(status);
567                 return -1;
568         }
569
570         /* Setup temporary smb_filename structs. */
571         smb_fname_src_tmp = cp_smb_filename(ctx, smb_fname_src);
572         if (smb_fname_src_tmp == NULL) {
573                 errno = ENOMEM;
574                 goto out;
575         }
576
577         smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
578         if (smb_fname_dst_tmp == NULL) {
579                 errno = ENOMEM;
580                 goto out;
581         }
582
583         smb_fname_src_tmp->base_name = src_name_mapped;
584         smb_fname_dst_tmp->base_name = dst_name_mapped;
585         DEBUG(10, ("converted old name: %s\n",
586                                 smb_fname_str_dbg(smb_fname_src_tmp)));
587         DEBUG(10, ("converted new name: %s\n",
588                                 smb_fname_str_dbg(smb_fname_dst_tmp)));
589
590         ret = SMB_VFS_NEXT_RENAMEAT(handle,
591                         srcfsp,
592                         smb_fname_src_tmp,
593                         dstfsp,
594                         smb_fname_dst_tmp);
595
596 out:
597         TALLOC_FREE(src_name_mapped);
598         TALLOC_FREE(dst_name_mapped);
599         TALLOC_FREE(smb_fname_src_tmp);
600         TALLOC_FREE(smb_fname_dst_tmp);
601         return ret;
602 }
603
604
605 static int catia_stat(vfs_handle_struct *handle,
606                       struct smb_filename *smb_fname)
607 {
608         char *name = NULL;
609         char *tmp_base_name;
610         int ret;
611         NTSTATUS status;
612
613         status = catia_string_replace_allocate(handle->conn,
614                                 smb_fname->base_name,
615                                 &name, vfs_translate_to_unix);
616         if (!NT_STATUS_IS_OK(status)) {
617                 errno = map_errno_from_nt_status(status);
618                 return -1;
619         }
620
621         tmp_base_name = smb_fname->base_name;
622         smb_fname->base_name = name;
623
624         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
625         smb_fname->base_name = tmp_base_name;
626
627         TALLOC_FREE(name);
628         return ret;
629 }
630
631 static int catia_lstat(vfs_handle_struct *handle,
632                        struct smb_filename *smb_fname)
633 {
634         char *name = NULL;
635         char *tmp_base_name;
636         int ret;
637         NTSTATUS status;
638
639         status = catia_string_replace_allocate(handle->conn,
640                                 smb_fname->base_name,
641                                 &name, vfs_translate_to_unix);
642         if (!NT_STATUS_IS_OK(status)) {
643                 errno = map_errno_from_nt_status(status);
644                 return -1;
645         }
646
647         tmp_base_name = smb_fname->base_name;
648         smb_fname->base_name = name;
649
650         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
651         smb_fname->base_name = tmp_base_name;
652         TALLOC_FREE(name);
653
654         return ret;
655 }
656
657 static int catia_unlinkat(vfs_handle_struct *handle,
658                         struct files_struct *dirfsp,
659                         const struct smb_filename *smb_fname,
660                         int flags)
661 {
662         struct catia_cache *cc = NULL;
663         struct smb_filename *smb_fname_tmp = NULL;
664         char *name = NULL;
665         NTSTATUS status;
666         int ret;
667
668         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, dirfsp, &cc);
669         if (ret != 0) {
670                 return ret;
671         }
672
673         status = catia_string_replace_allocate(handle->conn,
674                                         smb_fname->base_name,
675                                         &name, vfs_translate_to_unix);
676         if (!NT_STATUS_IS_OK(status)) {
677                 errno = map_errno_from_nt_status(status);
678                 goto out;
679         }
680
681         /* Setup temporary smb_filename structs. */
682         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
683         if (smb_fname_tmp == NULL) {
684                 errno = ENOMEM;
685                 goto out;
686         }
687
688         smb_fname_tmp->base_name = name;
689         smb_fname_tmp->fsp = smb_fname->fsp;
690
691         ret = SMB_VFS_NEXT_UNLINKAT(handle,
692                         dirfsp,
693                         smb_fname_tmp,
694                         flags);
695         TALLOC_FREE(smb_fname_tmp);
696         TALLOC_FREE(name);
697
698 out:
699         CATIA_FETCH_FSP_POST_NEXT(&cc, dirfsp);
700         return ret;
701 }
702
703 static int catia_lchown(vfs_handle_struct *handle,
704                         const struct smb_filename *smb_fname,
705                         uid_t uid,
706                         gid_t gid)
707 {
708         char *name = NULL;
709         NTSTATUS status;
710         int ret;
711         int saved_errno;
712         struct smb_filename *catia_smb_fname = NULL;
713
714         status = catia_string_replace_allocate(handle->conn,
715                                         smb_fname->base_name,
716                                         &name,
717                                         vfs_translate_to_unix);
718         if (!NT_STATUS_IS_OK(status)) {
719                 errno = map_errno_from_nt_status(status);
720                 return -1;
721         }
722         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
723                                         name,
724                                         NULL,
725                                         &smb_fname->st,
726                                         smb_fname->twrp,
727                                         smb_fname->flags);
728         if (catia_smb_fname == NULL) {
729                 TALLOC_FREE(name);
730                 errno = ENOMEM;
731                 return -1;
732         }
733
734         ret = SMB_VFS_NEXT_LCHOWN(handle, catia_smb_fname, uid, gid);
735         saved_errno = errno;
736         TALLOC_FREE(name);
737         TALLOC_FREE(catia_smb_fname);
738         errno = saved_errno;
739         return ret;
740 }
741
742 static int catia_mkdirat(vfs_handle_struct *handle,
743                         struct files_struct *dirfsp,
744                         const struct smb_filename *smb_fname,
745                         mode_t mode)
746 {
747         char *name = NULL;
748         NTSTATUS status;
749         int ret;
750         struct smb_filename *catia_smb_fname = NULL;
751
752         status = catia_string_replace_allocate(handle->conn,
753                                 smb_fname->base_name,
754                                 &name,
755                                 vfs_translate_to_unix);
756         if (!NT_STATUS_IS_OK(status)) {
757                 errno = map_errno_from_nt_status(status);
758                 return -1;
759         }
760         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
761                                         name,
762                                         NULL,
763                                         &smb_fname->st,
764                                         smb_fname->twrp,
765                                         smb_fname->flags);
766         if (catia_smb_fname == NULL) {
767                 TALLOC_FREE(name);
768                 errno = ENOMEM;
769                 return -1;
770         }
771
772         ret = SMB_VFS_NEXT_MKDIRAT(handle,
773                         dirfsp,
774                         catia_smb_fname,
775                         mode);
776         TALLOC_FREE(name);
777         TALLOC_FREE(catia_smb_fname);
778
779         return ret;
780 }
781
782 static int catia_chdir(vfs_handle_struct *handle,
783                         const struct smb_filename *smb_fname)
784 {
785         char *name = NULL;
786         struct smb_filename *catia_smb_fname = NULL;
787         NTSTATUS status;
788         int ret;
789
790         status = catia_string_replace_allocate(handle->conn,
791                                         smb_fname->base_name,
792                                         &name,
793                                         vfs_translate_to_unix);
794         if (!NT_STATUS_IS_OK(status)) {
795                 errno = map_errno_from_nt_status(status);
796                 return -1;
797         }
798
799         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
800                                         name,
801                                         NULL,
802                                         &smb_fname->st,
803                                         smb_fname->twrp,
804                                         smb_fname->flags);
805         if (catia_smb_fname == NULL) {
806                 TALLOC_FREE(name);
807                 errno = ENOMEM;
808                 return -1;
809         }
810         ret = SMB_VFS_NEXT_CHDIR(handle, catia_smb_fname);
811         TALLOC_FREE(name);
812         TALLOC_FREE(catia_smb_fname);
813
814         return ret;
815 }
816
817 static int catia_fntimes(vfs_handle_struct *handle,
818                          files_struct *fsp,
819                          struct smb_file_time *ft)
820 {
821         struct catia_cache *cc = NULL;
822         int ret;
823
824         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
825         if (ret != 0) {
826                 return ret;
827         }
828
829         ret = SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
830
831         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
832
833         return ret;
834 }
835
836 static struct smb_filename *
837 catia_realpath(vfs_handle_struct *handle,
838                 TALLOC_CTX *ctx,
839                 const struct smb_filename *smb_fname)
840 {
841         char *mapped_name = NULL;
842         struct smb_filename *catia_smb_fname = NULL;
843         struct smb_filename *return_fname = NULL;
844         NTSTATUS status;
845
846         status = catia_string_replace_allocate(handle->conn,
847                                         smb_fname->base_name,
848                                         &mapped_name, vfs_translate_to_unix);
849         if (!NT_STATUS_IS_OK(status)) {
850                 errno = map_errno_from_nt_status(status);
851                 return NULL;
852         }
853
854         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
855                                         mapped_name,
856                                         NULL,
857                                         &smb_fname->st,
858                                         smb_fname->twrp,
859                                         smb_fname->flags);
860         if (catia_smb_fname == NULL) {
861                 TALLOC_FREE(mapped_name);
862                 errno = ENOMEM;
863                 return NULL;
864         }
865         return_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, catia_smb_fname);
866         TALLOC_FREE(mapped_name);
867         TALLOC_FREE(catia_smb_fname);
868         return return_fname;
869 }
870
871 static NTSTATUS
872 catia_fstreaminfo(struct vfs_handle_struct *handle,
873                  struct files_struct *fsp,
874                  TALLOC_CTX *mem_ctx,
875                  unsigned int *_num_streams,
876                  struct stream_struct **_streams)
877 {
878         char *mapped_name = NULL;
879         NTSTATUS status;
880         unsigned int i;
881         struct smb_filename *catia_smb_fname = NULL;
882         struct smb_filename *smb_fname = NULL;
883         unsigned int num_streams = 0;
884         struct stream_struct *streams = NULL;
885
886         smb_fname = fsp->fsp_name;
887         *_num_streams = 0;
888         *_streams = NULL;
889
890         status = catia_string_replace_allocate(handle->conn,
891                                 smb_fname->base_name,
892                                 &mapped_name,
893                                 vfs_translate_to_unix);
894         if (!NT_STATUS_IS_OK(status)) {
895                 return status;
896         }
897
898         status = synthetic_pathref(talloc_tos(),
899                                         handle->conn->cwd_fsp,
900                                         mapped_name,
901                                         NULL,
902                                         &smb_fname->st,
903                                         smb_fname->twrp,
904                                         smb_fname->flags,
905                                         &catia_smb_fname);
906
907         if (!NT_STATUS_IS_OK(status)) {
908                 TALLOC_FREE(mapped_name);
909                 return status;
910         }
911
912         status = SMB_VFS_NEXT_FSTREAMINFO(handle,
913                                           catia_smb_fname->fsp,
914                                           mem_ctx,
915                                           &num_streams,
916                                           &streams);
917         TALLOC_FREE(mapped_name);
918         TALLOC_FREE(catia_smb_fname);
919         if (!NT_STATUS_IS_OK(status)) {
920                 return status;
921         }
922
923         /*
924          * Translate stream names just like the base names
925          */
926         for (i = 0; i < num_streams; i++) {
927                 /*
928                  * Strip ":" prefix and ":$DATA" suffix to get a
929                  * "pure" stream name and only translate that.
930                  */
931                 void *old_ptr = streams[i].name;
932                 char *stream_name = streams[i].name + 1;
933                 char *stream_type = strrchr_m(stream_name, ':');
934
935                 if (stream_type != NULL) {
936                         *stream_type = '\0';
937                         stream_type += 1;
938                 }
939
940                 status = catia_string_replace_allocate(handle->conn,
941                                                 stream_name,
942                                                 &mapped_name,
943                                                 vfs_translate_to_windows);
944                 if (!NT_STATUS_IS_OK(status)) {
945                         TALLOC_FREE(streams);
946                         return status;
947                 }
948
949                 if (stream_type != NULL) {
950                         streams[i].name = talloc_asprintf(streams,
951                                                           ":%s:%s",
952                                                           mapped_name,
953                                                           stream_type);
954                 } else {
955                         streams[i].name = talloc_asprintf(streams,
956                                                           ":%s",
957                                                           mapped_name);
958                 }
959                 TALLOC_FREE(mapped_name);
960                 TALLOC_FREE(old_ptr);
961                 if (streams[i].name == NULL) {
962                         TALLOC_FREE(streams);
963                         return NT_STATUS_NO_MEMORY;
964                 }
965         }
966
967         *_num_streams = num_streams;
968         *_streams = streams;
969         return NT_STATUS_OK;
970 }
971
972 static int catia_fstat(vfs_handle_struct *handle,
973                        files_struct *fsp,
974                        SMB_STRUCT_STAT *sbuf)
975 {
976         struct catia_cache *cc = NULL;
977         int ret;
978
979         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
980         if (ret != 0) {
981                 return ret;
982         }
983
984         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
985
986         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
987
988         return ret;
989 }
990
991 static ssize_t catia_pread(vfs_handle_struct *handle,
992                            files_struct *fsp, void *data,
993                            size_t n, off_t offset)
994 {
995         struct catia_cache *cc = NULL;
996         ssize_t result;
997         int ret;
998
999         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1000         if (ret != 0) {
1001                 return ret;
1002         }
1003
1004         result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
1005
1006         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1007
1008         return result;
1009 }
1010
1011 static ssize_t catia_pwrite(vfs_handle_struct *handle,
1012                             files_struct *fsp, const void *data,
1013                             size_t n, off_t offset)
1014 {
1015         struct catia_cache *cc = NULL;
1016         ssize_t result;
1017         int ret;
1018
1019         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1020         if (ret != 0) {
1021                 return ret;
1022         }
1023
1024         result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
1025
1026         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1027
1028         return result;
1029 }
1030
1031 static int catia_ftruncate(struct vfs_handle_struct *handle,
1032                            struct files_struct *fsp,
1033                            off_t offset)
1034 {
1035         struct catia_cache *cc = NULL;
1036         int ret;
1037
1038         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1039         if (ret != 0) {
1040                 return ret;
1041         }
1042
1043         ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
1044
1045         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1046
1047         return ret;
1048 }
1049
1050 static int catia_fallocate(struct vfs_handle_struct *handle,
1051                            struct files_struct *fsp,
1052                            uint32_t mode,
1053                            off_t offset,
1054                            off_t len)
1055 {
1056         struct catia_cache *cc = NULL;
1057         int ret;
1058
1059         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1060         if (ret != 0) {
1061                 return ret;
1062         }
1063
1064         ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
1065
1066         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1067
1068         return ret;
1069 }
1070
1071 static ssize_t catia_fgetxattr(struct vfs_handle_struct *handle,
1072                                struct files_struct *fsp,
1073                                const char *name,
1074                                void *value,
1075                                size_t size)
1076 {
1077         char *mapped_xattr_name = NULL;
1078         NTSTATUS status;
1079         ssize_t result;
1080
1081         status = catia_string_replace_allocate(handle->conn,
1082                                                name, &mapped_xattr_name,
1083                                                vfs_translate_to_unix);
1084         if (!NT_STATUS_IS_OK(status)) {
1085                 errno = map_errno_from_nt_status(status);
1086                 return -1;
1087         }
1088
1089         result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, mapped_xattr_name,
1090                                         value, size);
1091
1092         TALLOC_FREE(mapped_xattr_name);
1093
1094         return result;
1095 }
1096
1097 static ssize_t catia_flistxattr(struct vfs_handle_struct *handle,
1098                                 struct files_struct *fsp,
1099                                 char *list,
1100                                 size_t size)
1101 {
1102         struct catia_cache *cc = NULL;
1103         ssize_t result;
1104         int ret;
1105
1106         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1107         if (ret != 0) {
1108                 return ret;
1109         }
1110
1111         result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
1112
1113         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1114
1115         return result;
1116 }
1117
1118 static int catia_fremovexattr(struct vfs_handle_struct *handle,
1119                               struct files_struct *fsp,
1120                               const char *name)
1121 {
1122         char *mapped_name = NULL;
1123         NTSTATUS status;
1124         int ret;
1125
1126         status = catia_string_replace_allocate(handle->conn,
1127                                 name, &mapped_name, vfs_translate_to_unix);
1128         if (!NT_STATUS_IS_OK(status)) {
1129                 errno = map_errno_from_nt_status(status);
1130                 return -1;
1131         }
1132
1133         ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, mapped_name);
1134
1135         TALLOC_FREE(mapped_name);
1136
1137         return ret;
1138 }
1139
1140 static int catia_fsetxattr(struct vfs_handle_struct *handle,
1141                            struct files_struct *fsp,
1142                            const char *name,
1143                            const void *value,
1144                            size_t size,
1145                            int flags)
1146 {
1147         char *mapped_xattr_name = NULL;
1148         NTSTATUS status;
1149         int ret;
1150
1151         status = catia_string_replace_allocate(
1152                 handle->conn, name, &mapped_xattr_name, vfs_translate_to_unix);
1153         if (!NT_STATUS_IS_OK(status)) {
1154                 errno = map_errno_from_nt_status(status);
1155                 return -1;
1156         }
1157
1158         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, mapped_xattr_name,
1159                                      value, size, flags);
1160
1161         TALLOC_FREE(mapped_xattr_name);
1162
1163         return ret;
1164 }
1165
1166 static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle,
1167                                       files_struct *fsp,
1168                                       SMB_ACL_TYPE_T type,
1169                                       TALLOC_CTX *mem_ctx)
1170 {
1171         struct catia_cache *cc = NULL;
1172         struct smb_acl_t *result = NULL;
1173         int ret;
1174
1175         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1176         if (ret != 0) {
1177                 return NULL;
1178         }
1179
1180         result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, type, mem_ctx);
1181
1182         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1183
1184         return result;
1185 }
1186
1187 static int catia_sys_acl_blob_get_fd(vfs_handle_struct *handle,
1188                                      files_struct *fsp,
1189                                      TALLOC_CTX *mem_ctx,
1190                                      char **blob_description,
1191                                      DATA_BLOB *blob)
1192 {
1193         struct catia_cache *cc = NULL;
1194         int ret;
1195
1196         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1197         if (ret != 0) {
1198                 return ret;
1199         }
1200
1201         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
1202                                                blob_description, blob);
1203
1204         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1205
1206         return ret;
1207 }
1208
1209 static int catia_sys_acl_set_fd(vfs_handle_struct *handle,
1210                                 files_struct *fsp,
1211                                 SMB_ACL_TYPE_T type,
1212                                 SMB_ACL_T theacl)
1213 {
1214         struct catia_cache *cc = NULL;
1215         int ret;
1216
1217         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1218         if (ret != 0) {
1219                 return ret;
1220         }
1221
1222         ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, type, theacl);
1223
1224         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1225
1226         return ret;
1227 }
1228
1229 static NTSTATUS catia_fget_nt_acl(vfs_handle_struct *handle,
1230                                   files_struct *fsp,
1231                                   uint32_t security_info,
1232                                   TALLOC_CTX *mem_ctx,
1233                                   struct security_descriptor **ppdesc)
1234 {
1235         struct catia_cache *cc = NULL;
1236         NTSTATUS status;
1237         int ret;
1238
1239         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1240         if (ret != 0) {
1241                 return map_nt_error_from_unix(errno);
1242         }
1243
1244         status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1245                                           mem_ctx, ppdesc);
1246
1247         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1248
1249         return status;
1250 }
1251
1252 static NTSTATUS catia_fset_nt_acl(vfs_handle_struct *handle,
1253                                   files_struct *fsp,
1254                                   uint32_t security_info_sent,
1255                                   const struct security_descriptor *psd)
1256 {
1257         struct catia_cache *cc = NULL;
1258         NTSTATUS status;
1259         int ret;
1260
1261         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1262         if (ret != 0) {
1263                 return map_nt_error_from_unix(errno);
1264         }
1265
1266         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
1267
1268         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1269
1270         return status;
1271 }
1272
1273 static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle,
1274                                           struct files_struct *fsp,
1275                                           uint32_t dosmode)
1276 {
1277         struct catia_cache *cc = NULL;
1278         NTSTATUS status;
1279         int ret;
1280
1281         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1282         if (ret != 0) {
1283                 return map_nt_error_from_unix(errno);
1284         }
1285
1286         status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1287
1288         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1289
1290         return status;
1291 }
1292
1293 static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle,
1294                                           struct files_struct *fsp,
1295                                           uint32_t *dosmode)
1296 {
1297         struct catia_cache *cc = NULL;
1298         NTSTATUS status;
1299         int ret;
1300
1301         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1302         if (ret != 0) {
1303                 return map_nt_error_from_unix(errno);
1304         }
1305
1306         status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1307
1308         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1309
1310         return status;
1311 }
1312
1313 static int catia_fchown(vfs_handle_struct *handle,
1314                         files_struct *fsp,
1315                         uid_t uid,
1316                         gid_t gid)
1317 {
1318         struct catia_cache *cc = NULL;
1319         int ret;
1320
1321         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1322         if (ret != 0) {
1323                 return ret;
1324         }
1325
1326         ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
1327
1328         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1329
1330         return ret;
1331 }
1332
1333 static int catia_fchmod(vfs_handle_struct *handle,
1334                         files_struct *fsp,
1335                         mode_t mode)
1336 {
1337         struct catia_cache *cc = NULL;
1338         int ret;
1339
1340         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1341         if (ret != 0) {
1342                 return ret;
1343         }
1344
1345         ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1346
1347         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1348
1349         return ret;
1350 }
1351
1352 struct catia_pread_state {
1353         ssize_t ret;
1354         struct vfs_aio_state vfs_aio_state;
1355         struct files_struct *fsp;
1356         struct catia_cache *cc;
1357 };
1358
1359 static void catia_pread_done(struct tevent_req *subreq);
1360
1361 static struct tevent_req *catia_pread_send(struct vfs_handle_struct *handle,
1362                                            TALLOC_CTX *mem_ctx,
1363                                            struct tevent_context *ev,
1364                                            struct files_struct *fsp,
1365                                            void *data,
1366                                            size_t n,
1367                                            off_t offset)
1368 {
1369         struct tevent_req *req = NULL, *subreq = NULL;
1370         struct catia_pread_state *state = NULL;
1371         int ret;
1372
1373         req = tevent_req_create(mem_ctx, &state,
1374                                 struct catia_pread_state);
1375         if (req == NULL) {
1376                 return NULL;
1377         }
1378         state->fsp = fsp;
1379
1380         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1381         if (ret != 0) {
1382                 tevent_req_error(req, errno);
1383                 return tevent_req_post(req, ev);
1384         }
1385
1386         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
1387                                          n, offset);
1388         if (tevent_req_nomem(subreq, req)) {
1389                 return tevent_req_post(req, ev);
1390         }
1391         tevent_req_set_callback(subreq, catia_pread_done, req);
1392
1393         return req;
1394 }
1395
1396 static void catia_pread_done(struct tevent_req *subreq)
1397 {
1398         struct tevent_req *req = tevent_req_callback_data(
1399                 subreq, struct tevent_req);
1400         struct catia_pread_state *state = tevent_req_data(
1401                 req, struct catia_pread_state);
1402
1403         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
1404         TALLOC_FREE(subreq);
1405
1406         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1407
1408         tevent_req_done(req);
1409 }
1410
1411 static ssize_t catia_pread_recv(struct tevent_req *req,
1412                                 struct vfs_aio_state *vfs_aio_state)
1413 {
1414         struct catia_pread_state *state = tevent_req_data(
1415                 req, struct catia_pread_state);
1416
1417         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1418                 return -1;
1419         }
1420
1421         *vfs_aio_state = state->vfs_aio_state;
1422         return state->ret;
1423 }
1424
1425 struct catia_pwrite_state {
1426         ssize_t ret;
1427         struct vfs_aio_state vfs_aio_state;
1428         struct files_struct *fsp;
1429         struct catia_cache *cc;
1430 };
1431
1432 static void catia_pwrite_done(struct tevent_req *subreq);
1433
1434 static struct tevent_req *catia_pwrite_send(struct vfs_handle_struct *handle,
1435                                             TALLOC_CTX *mem_ctx,
1436                                             struct tevent_context *ev,
1437                                             struct files_struct *fsp,
1438                                             const void *data,
1439                                             size_t n,
1440                                             off_t offset)
1441 {
1442         struct tevent_req *req = NULL, *subreq = NULL;
1443         struct catia_pwrite_state *state = NULL;
1444         int ret;
1445
1446         req = tevent_req_create(mem_ctx, &state,
1447                                 struct catia_pwrite_state);
1448         if (req == NULL) {
1449                 return NULL;
1450         }
1451         state->fsp = fsp;
1452
1453         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1454         if (ret != 0) {
1455                 tevent_req_error(req, errno);
1456                 return tevent_req_post(req, ev);
1457         }
1458
1459         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
1460                                           n, offset);
1461         if (tevent_req_nomem(subreq, req)) {
1462                 return tevent_req_post(req, ev);
1463         }
1464         tevent_req_set_callback(subreq, catia_pwrite_done, req);
1465
1466         return req;
1467 }
1468
1469 static void catia_pwrite_done(struct tevent_req *subreq)
1470 {
1471         struct tevent_req *req = tevent_req_callback_data(
1472                 subreq, struct tevent_req);
1473         struct catia_pwrite_state *state = tevent_req_data(
1474                 req, struct catia_pwrite_state);
1475
1476         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
1477         TALLOC_FREE(subreq);
1478
1479         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1480
1481         tevent_req_done(req);
1482 }
1483
1484 static ssize_t catia_pwrite_recv(struct tevent_req *req,
1485                                 struct vfs_aio_state *vfs_aio_state)
1486 {
1487         struct catia_pwrite_state *state = tevent_req_data(
1488                 req, struct catia_pwrite_state);
1489
1490         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1491                 return -1;
1492         }
1493
1494         *vfs_aio_state = state->vfs_aio_state;
1495         return state->ret;
1496 }
1497
1498 static off_t catia_lseek(vfs_handle_struct *handle,
1499                          files_struct *fsp,
1500                          off_t offset,
1501                          int whence)
1502 {
1503         struct catia_cache *cc = NULL;
1504         ssize_t result;
1505         int ret;
1506
1507         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1508         if (ret != 0) {
1509                 return -1;
1510         }
1511
1512         result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
1513
1514         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1515
1516         return result;
1517 }
1518
1519 struct catia_fsync_state {
1520         int ret;
1521         struct vfs_aio_state vfs_aio_state;
1522         struct files_struct *fsp;
1523         struct catia_cache *cc;
1524 };
1525
1526 static void catia_fsync_done(struct tevent_req *subreq);
1527
1528 static struct tevent_req *catia_fsync_send(struct vfs_handle_struct *handle,
1529                                            TALLOC_CTX *mem_ctx,
1530                                            struct tevent_context *ev,
1531                                            struct files_struct *fsp)
1532 {
1533         struct tevent_req *req = NULL, *subreq = NULL;
1534         struct catia_fsync_state *state = NULL;
1535         int ret;
1536
1537         req = tevent_req_create(mem_ctx, &state,
1538                                 struct catia_fsync_state);
1539         if (req == NULL) {
1540                 return NULL;
1541         }
1542         state->fsp = fsp;
1543
1544         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1545         if (ret != 0) {
1546                 tevent_req_error(req, errno);
1547                 return tevent_req_post(req, ev);
1548         }
1549
1550         subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
1551         if (tevent_req_nomem(subreq, req)) {
1552                 return tevent_req_post(req, ev);
1553         }
1554         tevent_req_set_callback(subreq, catia_fsync_done, req);
1555
1556         return req;
1557 }
1558
1559 static void catia_fsync_done(struct tevent_req *subreq)
1560 {
1561         struct tevent_req *req = tevent_req_callback_data(
1562                 subreq, struct tevent_req);
1563         struct catia_fsync_state *state = tevent_req_data(
1564                 req, struct catia_fsync_state);
1565
1566         state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
1567         TALLOC_FREE(subreq);
1568
1569         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1570
1571         tevent_req_done(req);
1572 }
1573
1574 static int catia_fsync_recv(struct tevent_req *req,
1575                             struct vfs_aio_state *vfs_aio_state)
1576 {
1577         struct catia_fsync_state *state = tevent_req_data(
1578                 req, struct catia_fsync_state);
1579
1580         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1581                 return -1;
1582         }
1583
1584         *vfs_aio_state = state->vfs_aio_state;
1585         return state->ret;
1586 }
1587
1588 static bool catia_lock(vfs_handle_struct *handle,
1589                        files_struct *fsp,
1590                        int op,
1591                        off_t offset,
1592                        off_t count,
1593                        int type)
1594 {
1595         struct catia_cache *cc = NULL;
1596         bool ok;
1597         int ret;
1598
1599         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1600         if (ret != 0) {
1601                 return false;
1602         }
1603
1604         ok = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
1605
1606         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1607
1608         return ok;
1609 }
1610
1611 static int catia_filesystem_sharemode(struct vfs_handle_struct *handle,
1612                                       struct files_struct *fsp,
1613                                       uint32_t share_access,
1614                                       uint32_t access_mask)
1615 {
1616         struct catia_cache *cc = NULL;
1617         int ret;
1618
1619         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1620         if (ret != 0) {
1621                 return -1;
1622         }
1623
1624         ret = SMB_VFS_NEXT_FILESYSTEM_SHAREMODE(handle,
1625                                                 fsp,
1626                                                 share_access,
1627                                                 access_mask);
1628
1629         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1630
1631         return ret;
1632 }
1633
1634 static int catia_linux_setlease(vfs_handle_struct *handle,
1635                                 files_struct *fsp,
1636                                 int leasetype)
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 -1;
1644         }
1645
1646         ret = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
1647
1648         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1649
1650         return ret;
1651 }
1652
1653 static bool catia_getlock(vfs_handle_struct *handle,
1654                           files_struct *fsp,
1655                           off_t *poffset,
1656                           off_t *pcount,
1657                           int *ptype,
1658                           pid_t *ppid)
1659 {
1660         struct catia_cache *cc = NULL;
1661         int ret;
1662         bool ok;
1663
1664         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1665         if (ret != 0) {
1666                 return false;
1667         }
1668
1669         ok = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
1670
1671         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1672
1673         return ok;
1674 }
1675
1676 static bool catia_strict_lock_check(struct vfs_handle_struct *handle,
1677                                     struct files_struct *fsp,
1678                                     struct lock_struct *plock)
1679 {
1680         struct catia_cache *cc = NULL;
1681         int ret;
1682         bool ok;
1683
1684         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1685         if (ret != 0) {
1686                 return false;
1687         }
1688
1689         ok = SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock);
1690
1691         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1692
1693         return ok;
1694 }
1695
1696 static NTSTATUS catia_fsctl(struct vfs_handle_struct *handle,
1697                             struct files_struct *fsp,
1698                             TALLOC_CTX *ctx,
1699                             uint32_t function,
1700                             uint16_t req_flags,
1701                             const uint8_t *_in_data,
1702                             uint32_t in_len,
1703                             uint8_t **_out_data,
1704                             uint32_t max_out_len,
1705                             uint32_t *out_len)
1706 {
1707         NTSTATUS result;
1708         struct catia_cache *cc = NULL;
1709         int ret;
1710
1711         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1712         if (ret != 0) {
1713                 return map_nt_error_from_unix(errno);
1714         }
1715
1716         result = SMB_VFS_NEXT_FSCTL(handle,
1717                                 fsp,
1718                                 ctx,
1719                                 function,
1720                                 req_flags,
1721                                 _in_data,
1722                                 in_len,
1723                                 _out_data,
1724                                 max_out_len,
1725                                 out_len);
1726
1727         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1728
1729         return result;
1730 }
1731
1732 static NTSTATUS catia_fget_compression(vfs_handle_struct *handle,
1733                                       TALLOC_CTX *mem_ctx,
1734                                       struct files_struct *fsp,
1735                                       uint16_t *_compression_fmt)
1736 {
1737         NTSTATUS result;
1738         struct catia_cache *cc = NULL;
1739         int ret;
1740
1741         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1742         if (ret != 0) {
1743                 return map_nt_error_from_unix(errno);
1744         }
1745
1746         result = SMB_VFS_NEXT_FGET_COMPRESSION(handle,
1747                                         mem_ctx,
1748                                         fsp,
1749                                         _compression_fmt);
1750
1751         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1752
1753         return result;
1754 }
1755
1756 static NTSTATUS catia_set_compression(vfs_handle_struct *handle,
1757                                       TALLOC_CTX *mem_ctx,
1758                                       struct files_struct *fsp,
1759                                       uint16_t compression_fmt)
1760 {
1761         NTSTATUS result;
1762         struct catia_cache *cc = NULL;
1763         int ret;
1764
1765         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1766         if (ret != 0) {
1767                 return map_nt_error_from_unix(errno);
1768         }
1769
1770         result = SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp,
1771                                               compression_fmt);
1772
1773         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1774
1775         return result;
1776 }
1777
1778 static NTSTATUS catia_create_dfs_pathat(struct vfs_handle_struct *handle,
1779                         struct files_struct *dirfsp,
1780                         const struct smb_filename *smb_fname,
1781                         const struct referral *reflist,
1782                         size_t referral_count)
1783 {
1784         char *mapped_name = NULL;
1785         const char *path = smb_fname->base_name;
1786         struct smb_filename *mapped_smb_fname = NULL;
1787         NTSTATUS status;
1788
1789         status = catia_string_replace_allocate(handle->conn,
1790                                         path,
1791                                         &mapped_name,
1792                                         vfs_translate_to_unix);
1793         if (!NT_STATUS_IS_OK(status)) {
1794                 errno = map_errno_from_nt_status(status);
1795                 return status;
1796         }
1797         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1798                                         mapped_name,
1799                                         NULL,
1800                                         &smb_fname->st,
1801                                         smb_fname->twrp,
1802                                         smb_fname->flags);
1803         if (mapped_smb_fname == NULL) {
1804                 TALLOC_FREE(mapped_name);
1805                 return NT_STATUS_NO_MEMORY;
1806         }
1807
1808         status = SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
1809                                         dirfsp,
1810                                         mapped_smb_fname,
1811                                         reflist,
1812                                         referral_count);
1813         TALLOC_FREE(mapped_name);
1814         TALLOC_FREE(mapped_smb_fname);
1815         return status;
1816 }
1817
1818 static NTSTATUS catia_read_dfs_pathat(struct vfs_handle_struct *handle,
1819                         TALLOC_CTX *mem_ctx,
1820                         struct files_struct *dirfsp,
1821                         struct smb_filename *smb_fname,
1822                         struct referral **ppreflist,
1823                         size_t *preferral_count)
1824 {
1825         char *mapped_name = NULL;
1826         const char *path = smb_fname->base_name;
1827         struct smb_filename *mapped_smb_fname = NULL;
1828         NTSTATUS status;
1829
1830         status = catia_string_replace_allocate(handle->conn,
1831                                         path,
1832                                         &mapped_name,
1833                                         vfs_translate_to_unix);
1834         if (!NT_STATUS_IS_OK(status)) {
1835                 errno = map_errno_from_nt_status(status);
1836                 return status;
1837         }
1838         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1839                                         mapped_name,
1840                                         NULL,
1841                                         &smb_fname->st,
1842                                         smb_fname->twrp,
1843                                         smb_fname->flags);
1844         if (mapped_smb_fname == NULL) {
1845                 TALLOC_FREE(mapped_name);
1846                 return NT_STATUS_NO_MEMORY;
1847         }
1848
1849         status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
1850                                         mem_ctx,
1851                                         dirfsp,
1852                                         mapped_smb_fname,
1853                                         ppreflist,
1854                                         preferral_count);
1855         if (NT_STATUS_IS_OK(status)) {
1856                 /* Return any stat(2) info. */
1857                 smb_fname->st = mapped_smb_fname->st;
1858         }
1859
1860         TALLOC_FREE(mapped_name);
1861         TALLOC_FREE(mapped_smb_fname);
1862         return status;
1863 }
1864
1865 static struct vfs_fn_pointers vfs_catia_fns = {
1866         .connect_fn = catia_connect,
1867
1868         /* Directory operations */
1869         .mkdirat_fn = catia_mkdirat,
1870
1871         /* File operations */
1872         .openat_fn = catia_openat,
1873         .pread_fn = catia_pread,
1874         .pread_send_fn = catia_pread_send,
1875         .pread_recv_fn = catia_pread_recv,
1876         .pwrite_fn = catia_pwrite,
1877         .pwrite_send_fn = catia_pwrite_send,
1878         .pwrite_recv_fn = catia_pwrite_recv,
1879         .lseek_fn = catia_lseek,
1880         .renameat_fn = catia_renameat,
1881         .fsync_send_fn = catia_fsync_send,
1882         .fsync_recv_fn = catia_fsync_recv,
1883         .stat_fn = catia_stat,
1884         .fstat_fn = catia_fstat,
1885         .lstat_fn = catia_lstat,
1886         .unlinkat_fn = catia_unlinkat,
1887         .fchmod_fn = catia_fchmod,
1888         .fchown_fn = catia_fchown,
1889         .lchown_fn = catia_lchown,
1890         .chdir_fn = catia_chdir,
1891         .fntimes_fn = catia_fntimes,
1892         .ftruncate_fn = catia_ftruncate,
1893         .fallocate_fn = catia_fallocate,
1894         .lock_fn = catia_lock,
1895         .filesystem_sharemode_fn = catia_filesystem_sharemode,
1896         .linux_setlease_fn = catia_linux_setlease,
1897         .getlock_fn = catia_getlock,
1898         .realpath_fn = catia_realpath,
1899         .fstreaminfo_fn = catia_fstreaminfo,
1900         .strict_lock_check_fn = catia_strict_lock_check,
1901         .translate_name_fn = catia_translate_name,
1902         .fsctl_fn = catia_fsctl,
1903         .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
1904         .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
1905         .fset_dos_attributes_fn = catia_fset_dos_attributes,
1906         .fget_dos_attributes_fn = catia_fget_dos_attributes,
1907         .fget_compression_fn = catia_fget_compression,
1908         .set_compression_fn = catia_set_compression,
1909         .create_dfs_pathat_fn = catia_create_dfs_pathat,
1910         .read_dfs_pathat_fn = catia_read_dfs_pathat,
1911
1912         /* NT ACL operations. */
1913         .fget_nt_acl_fn = catia_fget_nt_acl,
1914         .fset_nt_acl_fn = catia_fset_nt_acl,
1915
1916         /* POSIX ACL operations. */
1917         .sys_acl_get_fd_fn = catia_sys_acl_get_fd,
1918         .sys_acl_blob_get_fd_fn = catia_sys_acl_blob_get_fd,
1919         .sys_acl_set_fd_fn = catia_sys_acl_set_fd,
1920
1921         /* EA operations. */
1922         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1923         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1924         .fgetxattr_fn = catia_fgetxattr,
1925         .flistxattr_fn = catia_flistxattr,
1926         .fremovexattr_fn = catia_fremovexattr,
1927         .fsetxattr_fn = catia_fsetxattr,
1928 };
1929
1930 static_decl_vfs;
1931 NTSTATUS vfs_catia_init(TALLOC_CTX *ctx)
1932 {
1933         NTSTATUS ret;
1934
1935         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
1936                                 &vfs_catia_fns);
1937         if (!NT_STATUS_IS_OK(ret))
1938                 return ret;
1939
1940         vfs_catia_debug_level = debug_add_class("catia");
1941         if (vfs_catia_debug_level == -1) {
1942                 vfs_catia_debug_level = DBGC_VFS;
1943                 DEBUG(0, ("vfs_catia: Couldn't register custom debugging "
1944                           "class!\n"));
1945         } else {
1946                 DEBUG(10, ("vfs_catia: Debug class number of "
1947                            "'catia': %d\n", vfs_catia_debug_level));
1948         }
1949
1950         return ret;
1951
1952 }