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