s3: VFS: vfs_catia. Remove mkdir_fn(). No longer used.
[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_unlink(vfs_handle_struct *handle,
680                         const struct smb_filename *smb_fname)
681 {
682         struct smb_filename *smb_fname_tmp = NULL;
683         char *name = NULL;
684         NTSTATUS status;
685         int ret;
686
687         status = catia_string_replace_allocate(handle->conn,
688                                         smb_fname->base_name,
689                                         &name, vfs_translate_to_unix);
690         if (!NT_STATUS_IS_OK(status)) {
691                 errno = map_errno_from_nt_status(status);
692                 return -1;
693         }
694
695         /* Setup temporary smb_filename structs. */
696         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
697         if (smb_fname_tmp == NULL) {
698                 errno = ENOMEM;
699                 return -1;
700         }
701
702         smb_fname_tmp->base_name = name;
703         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
704         TALLOC_FREE(smb_fname_tmp);
705         TALLOC_FREE(name);
706
707         return ret;
708 }
709
710 static int catia_chown(vfs_handle_struct *handle,
711                        const struct smb_filename *smb_fname,
712                        uid_t uid,
713                        gid_t gid)
714 {
715         char *name = NULL;
716         NTSTATUS status;
717         int ret;
718         int saved_errno;
719         struct smb_filename *catia_smb_fname = NULL;
720
721         status = catia_string_replace_allocate(handle->conn,
722                                         smb_fname->base_name,
723                                         &name,
724                                         vfs_translate_to_unix);
725         if (!NT_STATUS_IS_OK(status)) {
726                 errno = map_errno_from_nt_status(status);
727                 return -1;
728         }
729         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
730                                         name,
731                                         NULL,
732                                         &smb_fname->st,
733                                         smb_fname->flags);
734         if (catia_smb_fname == NULL) {
735                 TALLOC_FREE(name);
736                 errno = ENOMEM;
737                 return -1;
738         }
739
740         ret = SMB_VFS_NEXT_CHOWN(handle, catia_smb_fname, uid, gid);
741         saved_errno = errno;
742         TALLOC_FREE(name);
743         TALLOC_FREE(catia_smb_fname);
744         errno = saved_errno;
745         return ret;
746 }
747
748 static int catia_lchown(vfs_handle_struct *handle,
749                         const struct smb_filename *smb_fname,
750                         uid_t uid,
751                         gid_t gid)
752 {
753         char *name = NULL;
754         NTSTATUS status;
755         int ret;
756         int saved_errno;
757         struct smb_filename *catia_smb_fname = NULL;
758
759         status = catia_string_replace_allocate(handle->conn,
760                                         smb_fname->base_name,
761                                         &name,
762                                         vfs_translate_to_unix);
763         if (!NT_STATUS_IS_OK(status)) {
764                 errno = map_errno_from_nt_status(status);
765                 return -1;
766         }
767         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
768                                         name,
769                                         NULL,
770                                         &smb_fname->st,
771                                         smb_fname->flags);
772         if (catia_smb_fname == NULL) {
773                 TALLOC_FREE(name);
774                 errno = ENOMEM;
775                 return -1;
776         }
777
778         ret = SMB_VFS_NEXT_LCHOWN(handle, catia_smb_fname, uid, gid);
779         saved_errno = errno;
780         TALLOC_FREE(name);
781         TALLOC_FREE(catia_smb_fname);
782         errno = saved_errno;
783         return ret;
784 }
785
786 static int catia_chmod(vfs_handle_struct *handle,
787                         const struct smb_filename *smb_fname,
788                         mode_t mode)
789 {
790         char *name = NULL;
791         NTSTATUS status;
792         int ret;
793         int saved_errno;
794         struct smb_filename *catia_smb_fname = NULL;
795
796         status = catia_string_replace_allocate(handle->conn,
797                                         smb_fname->base_name,
798                                         &name,
799                                         vfs_translate_to_unix);
800         if (!NT_STATUS_IS_OK(status)) {
801                 errno = map_errno_from_nt_status(status);
802                 return -1;
803         }
804         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
805                                         name,
806                                         NULL,
807                                         &smb_fname->st,
808                                         smb_fname->flags);
809         if (catia_smb_fname == NULL) {
810                 TALLOC_FREE(name);
811                 errno = ENOMEM;
812                 return -1;
813         }
814
815         ret = SMB_VFS_NEXT_CHMOD(handle, catia_smb_fname, mode);
816         saved_errno = errno;
817         TALLOC_FREE(name);
818         TALLOC_FREE(catia_smb_fname);
819         errno = saved_errno;
820         return ret;
821 }
822
823 static int catia_rmdir(vfs_handle_struct *handle,
824                        const struct smb_filename *smb_fname)
825 {
826         char *name = NULL;
827         NTSTATUS status;
828         int ret;
829         struct smb_filename *catia_smb_fname = NULL;
830
831         status = catia_string_replace_allocate(handle->conn,
832                                 smb_fname->base_name,
833                                 &name,
834                                 vfs_translate_to_unix);
835         if (!NT_STATUS_IS_OK(status)) {
836                 errno = map_errno_from_nt_status(status);
837                 return -1;
838         }
839         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
840                                         name,
841                                         NULL,
842                                         &smb_fname->st,
843                                         smb_fname->flags);
844         if (catia_smb_fname == NULL) {
845                 TALLOC_FREE(name);
846                 errno = ENOMEM;
847                 return -1;
848         }
849
850         ret = SMB_VFS_NEXT_RMDIR(handle, catia_smb_fname);
851         TALLOC_FREE(name);
852         TALLOC_FREE(catia_smb_fname);
853
854         return ret;
855 }
856
857 static int catia_mkdirat(vfs_handle_struct *handle,
858                         struct files_struct *dirfsp,
859                         const struct smb_filename *smb_fname,
860                         mode_t mode)
861 {
862         char *name = NULL;
863         NTSTATUS status;
864         int ret;
865         struct smb_filename *catia_smb_fname = NULL;
866
867         status = catia_string_replace_allocate(handle->conn,
868                                 smb_fname->base_name,
869                                 &name,
870                                 vfs_translate_to_unix);
871         if (!NT_STATUS_IS_OK(status)) {
872                 errno = map_errno_from_nt_status(status);
873                 return -1;
874         }
875         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
876                                         name,
877                                         NULL,
878                                         &smb_fname->st,
879                                         smb_fname->flags);
880         if (catia_smb_fname == NULL) {
881                 TALLOC_FREE(name);
882                 errno = ENOMEM;
883                 return -1;
884         }
885
886         ret = SMB_VFS_NEXT_MKDIRAT(handle,
887                         dirfsp,
888                         catia_smb_fname,
889                         mode);
890         TALLOC_FREE(name);
891         TALLOC_FREE(catia_smb_fname);
892
893         return ret;
894 }
895
896 static int catia_chdir(vfs_handle_struct *handle,
897                         const struct smb_filename *smb_fname)
898 {
899         char *name = NULL;
900         struct smb_filename *catia_smb_fname = NULL;
901         NTSTATUS status;
902         int ret;
903
904         status = catia_string_replace_allocate(handle->conn,
905                                         smb_fname->base_name,
906                                         &name,
907                                         vfs_translate_to_unix);
908         if (!NT_STATUS_IS_OK(status)) {
909                 errno = map_errno_from_nt_status(status);
910                 return -1;
911         }
912
913         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
914                                         name,
915                                         NULL,
916                                         &smb_fname->st,
917                                         smb_fname->flags);
918         if (catia_smb_fname == NULL) {
919                 TALLOC_FREE(name);
920                 errno = ENOMEM;
921                 return -1;
922         }
923         ret = SMB_VFS_NEXT_CHDIR(handle, catia_smb_fname);
924         TALLOC_FREE(name);
925         TALLOC_FREE(catia_smb_fname);
926
927         return ret;
928 }
929
930 static int catia_ntimes(vfs_handle_struct *handle,
931                         const struct smb_filename *smb_fname,
932                         struct smb_file_time *ft)
933 {
934         struct smb_filename *smb_fname_tmp = NULL;
935         char *name = NULL;
936         NTSTATUS status;
937         int ret;
938
939         status = catia_string_replace_allocate(handle->conn,
940                                 smb_fname->base_name,
941                                 &name, vfs_translate_to_unix);
942         if (!NT_STATUS_IS_OK(status)) {
943                 errno = map_errno_from_nt_status(status);
944                 return -1;
945         }
946
947         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
948         if (smb_fname_tmp == NULL) {
949                 errno = ENOMEM;
950                 return -1;
951         }
952
953         smb_fname_tmp->base_name = name;
954         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
955         TALLOC_FREE(name);
956         TALLOC_FREE(smb_fname_tmp);
957
958         return ret;
959 }
960
961 static struct smb_filename *
962 catia_realpath(vfs_handle_struct *handle,
963                 TALLOC_CTX *ctx,
964                 const struct smb_filename *smb_fname)
965 {
966         char *mapped_name = NULL;
967         struct smb_filename *catia_smb_fname = NULL;
968         struct smb_filename *return_fname = NULL;
969         NTSTATUS status;
970
971         status = catia_string_replace_allocate(handle->conn,
972                                         smb_fname->base_name,
973                                         &mapped_name, vfs_translate_to_unix);
974         if (!NT_STATUS_IS_OK(status)) {
975                 errno = map_errno_from_nt_status(status);
976                 return NULL;
977         }
978
979         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
980                                         mapped_name,
981                                         NULL,
982                                         &smb_fname->st,
983                                         smb_fname->flags);
984         if (catia_smb_fname == NULL) {
985                 TALLOC_FREE(mapped_name);
986                 errno = ENOMEM;
987                 return NULL;
988         }
989         return_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, catia_smb_fname);
990         TALLOC_FREE(mapped_name);
991         TALLOC_FREE(catia_smb_fname);
992         return return_fname;
993 }
994
995 static int catia_chflags(struct vfs_handle_struct *handle,
996                         const struct smb_filename *smb_fname,
997                         unsigned int flags)
998 {
999         char *name = NULL;
1000         struct smb_filename *catia_smb_fname = NULL;
1001         NTSTATUS status;
1002         int ret;
1003
1004         status = catia_string_replace_allocate(handle->conn,
1005                                 smb_fname->base_name,
1006                                 &name,
1007                                 vfs_translate_to_unix);
1008         if (!NT_STATUS_IS_OK(status)) {
1009                 errno = map_errno_from_nt_status(status);
1010                 return -1;
1011         }
1012         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
1013                                         name,
1014                                         NULL,
1015                                         &smb_fname->st,
1016                                         smb_fname->flags);
1017         if (catia_smb_fname == NULL) {
1018                 TALLOC_FREE(name);
1019                 errno = ENOMEM;
1020                 return -1;
1021         }
1022
1023         ret = SMB_VFS_NEXT_CHFLAGS(handle, catia_smb_fname, flags);
1024         TALLOC_FREE(name);
1025         TALLOC_FREE(catia_smb_fname);
1026
1027         return ret;
1028 }
1029
1030 static NTSTATUS
1031 catia_streaminfo(struct vfs_handle_struct *handle,
1032                  struct files_struct *fsp,
1033                  const struct smb_filename *smb_fname,
1034                  TALLOC_CTX *mem_ctx,
1035                  unsigned int *_num_streams,
1036                  struct stream_struct **_streams)
1037 {
1038         char *mapped_name = NULL;
1039         NTSTATUS status;
1040         unsigned int i;
1041         struct smb_filename *catia_smb_fname = NULL;
1042         unsigned int num_streams = 0;
1043         struct stream_struct *streams = NULL;
1044
1045         *_num_streams = 0;
1046         *_streams = NULL;
1047
1048         status = catia_string_replace_allocate(handle->conn,
1049                                 smb_fname->base_name,
1050                                 &mapped_name,
1051                                 vfs_translate_to_unix);
1052         if (!NT_STATUS_IS_OK(status)) {
1053                 errno = map_errno_from_nt_status(status);
1054                 return status;
1055         }
1056
1057         catia_smb_fname = synthetic_smb_fname(talloc_tos(),
1058                                         mapped_name,
1059                                         NULL,
1060                                         &smb_fname->st,
1061                                         smb_fname->flags);
1062         if (catia_smb_fname == NULL) {
1063                 TALLOC_FREE(mapped_name);
1064                 return NT_STATUS_NO_MEMORY;
1065         }
1066
1067         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, catia_smb_fname,
1068                                          mem_ctx, &num_streams, &streams);
1069         TALLOC_FREE(mapped_name);
1070         TALLOC_FREE(catia_smb_fname);
1071         if (!NT_STATUS_IS_OK(status)) {
1072                 return status;
1073         }
1074
1075         /*
1076          * Translate stream names just like the base names
1077          */
1078         for (i = 0; i < num_streams; i++) {
1079                 /*
1080                  * Strip ":" prefix and ":$DATA" suffix to get a
1081                  * "pure" stream name and only translate that.
1082                  */
1083                 void *old_ptr = streams[i].name;
1084                 char *stream_name = streams[i].name + 1;
1085                 char *stream_type = strrchr_m(stream_name, ':');
1086
1087                 if (stream_type != NULL) {
1088                         *stream_type = '\0';
1089                         stream_type += 1;
1090                 }
1091
1092                 status = catia_string_replace_allocate(handle->conn, stream_name,
1093                                                        &mapped_name, vfs_translate_to_windows);
1094                 if (!NT_STATUS_IS_OK(status)) {
1095                         TALLOC_FREE(streams);
1096                         return status;
1097                 }
1098
1099                 if (stream_type != NULL) {
1100                         streams[i].name = talloc_asprintf(streams, ":%s:%s",
1101                                                           mapped_name, stream_type);
1102                 } else {
1103                         streams[i].name = talloc_asprintf(streams, ":%s",
1104                                                           mapped_name);
1105                 }
1106                 TALLOC_FREE(mapped_name);
1107                 TALLOC_FREE(old_ptr);
1108                 if (streams[i].name == NULL) {
1109                         TALLOC_FREE(streams);
1110                         return NT_STATUS_NO_MEMORY;
1111                 }
1112         }
1113
1114         *_num_streams = num_streams;
1115         *_streams = streams;
1116         return NT_STATUS_OK;
1117 }
1118
1119 static NTSTATUS
1120 catia_get_nt_acl(struct vfs_handle_struct *handle,
1121                  const struct smb_filename *smb_fname,
1122                  uint32_t security_info,
1123                  TALLOC_CTX *mem_ctx,
1124                  struct security_descriptor **ppdesc)
1125 {
1126         char *mapped_name = NULL;
1127         const char *path = smb_fname->base_name;
1128         struct smb_filename *mapped_smb_fname = NULL;
1129         NTSTATUS status;
1130
1131         status = catia_string_replace_allocate(handle->conn,
1132                                 path, &mapped_name, vfs_translate_to_unix);
1133         if (!NT_STATUS_IS_OK(status)) {
1134                 errno = map_errno_from_nt_status(status);
1135                 return status;
1136         }
1137         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1138                                         mapped_name,
1139                                         NULL,
1140                                         &smb_fname->st,
1141                                         smb_fname->flags);
1142         if (mapped_smb_fname == NULL) {
1143                 TALLOC_FREE(mapped_name);
1144                 return NT_STATUS_NO_MEMORY;
1145         }
1146
1147         status = SMB_VFS_NEXT_GET_NT_ACL(handle, mapped_smb_fname,
1148                                          security_info, mem_ctx, ppdesc);
1149         TALLOC_FREE(mapped_name);
1150         TALLOC_FREE(mapped_smb_fname);
1151
1152         return status;
1153 }
1154
1155 static SMB_ACL_T
1156 catia_sys_acl_get_file(vfs_handle_struct *handle,
1157                         const struct smb_filename *smb_fname,
1158                         SMB_ACL_TYPE_T type,
1159                         TALLOC_CTX *mem_ctx)
1160 {
1161         char *mapped_name = NULL;
1162         struct smb_filename *mapped_smb_fname = NULL;
1163         NTSTATUS status;
1164         SMB_ACL_T ret;
1165         int saved_errno = 0;
1166
1167         status = catia_string_replace_allocate(handle->conn,
1168                                 smb_fname->base_name,
1169                                 &mapped_name,
1170                                 vfs_translate_to_unix);
1171         if (!NT_STATUS_IS_OK(status)) {
1172                 errno = map_errno_from_nt_status(status);
1173                 return (SMB_ACL_T)NULL;
1174         }
1175
1176         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1177                                         mapped_name,
1178                                         NULL,
1179                                         &smb_fname->st,
1180                                         smb_fname->flags);
1181         if (mapped_smb_fname == NULL) {
1182                 TALLOC_FREE(mapped_name);
1183                 errno = ENOMEM;
1184                 return (SMB_ACL_T)NULL;
1185         }
1186
1187         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, mapped_smb_fname,
1188                         type, mem_ctx);
1189         if (ret == (SMB_ACL_T)NULL) {
1190                 saved_errno = errno;
1191         }
1192         TALLOC_FREE(mapped_smb_fname);
1193         TALLOC_FREE(mapped_name);
1194         if (saved_errno != 0) {
1195                 errno = saved_errno;
1196         }
1197         return ret;
1198 }
1199
1200 static int
1201 catia_sys_acl_set_file(vfs_handle_struct *handle,
1202                         const struct smb_filename *smb_fname,
1203                         SMB_ACL_TYPE_T type,
1204                         SMB_ACL_T theacl)
1205 {
1206         struct smb_filename *mapped_smb_fname = NULL;
1207         int saved_errno = 0;
1208         char *mapped_name = NULL;
1209         NTSTATUS status;
1210         int ret;
1211
1212         status = catia_string_replace_allocate(handle->conn,
1213                                 smb_fname->base_name,
1214                                 &mapped_name,
1215                                 vfs_translate_to_unix);
1216         if (!NT_STATUS_IS_OK(status)) {
1217                 errno = map_errno_from_nt_status(status);
1218                 return -1;
1219         }
1220
1221         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1222                                         mapped_name,
1223                                         NULL,
1224                                         &smb_fname->st,
1225                                         smb_fname->flags);
1226         if (mapped_smb_fname == NULL) {
1227                 TALLOC_FREE(mapped_name);
1228                 errno = ENOMEM;
1229                 return -1;
1230         }
1231
1232         ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, mapped_smb_fname,
1233                         type, theacl);
1234         if (ret == -1) {
1235                 saved_errno = errno;
1236         }
1237         TALLOC_FREE(mapped_smb_fname);
1238         TALLOC_FREE(mapped_name);
1239         if (saved_errno != 0) {
1240                 errno = saved_errno;
1241         }
1242         return ret;
1243 }
1244
1245 static int
1246 catia_sys_acl_delete_def_file(vfs_handle_struct *handle,
1247                                 const struct smb_filename *smb_fname)
1248 {
1249         struct smb_filename *mapped_smb_fname = NULL;
1250         int saved_errno = 0;
1251         char *mapped_name = NULL;
1252         NTSTATUS status;
1253         int ret;
1254
1255         status = catia_string_replace_allocate(handle->conn,
1256                                 smb_fname->base_name,
1257                                 &mapped_name,
1258                                 vfs_translate_to_unix);
1259         if (!NT_STATUS_IS_OK(status)) {
1260                 errno = map_errno_from_nt_status(status);
1261                 return -1;
1262         }
1263
1264         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1265                                         mapped_name,
1266                                         NULL,
1267                                         &smb_fname->st,
1268                                         smb_fname->flags);
1269         if (mapped_smb_fname == NULL) {
1270                 TALLOC_FREE(mapped_name);
1271                 errno = ENOMEM;
1272                 return -1;
1273         }
1274         ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, mapped_smb_fname);
1275         if (ret == -1) {
1276                 saved_errno = errno;
1277         }
1278         TALLOC_FREE(mapped_smb_fname);
1279         TALLOC_FREE(mapped_name);
1280         if (saved_errno != 0) {
1281                 errno = saved_errno;
1282         }
1283         return ret;
1284 }
1285
1286 static ssize_t
1287 catia_getxattr(vfs_handle_struct *handle,
1288                         const struct smb_filename *smb_fname,
1289                         const char *name,
1290                         void *value,
1291                         size_t size)
1292 {
1293         struct smb_filename *mapped_smb_fname = NULL;
1294         char *mapped_name = NULL;
1295         char *mapped_ea_name = NULL;
1296         NTSTATUS status;
1297         ssize_t ret;
1298         int saved_errno = 0;
1299
1300         status = catia_string_replace_allocate(handle->conn,
1301                                 smb_fname->base_name,
1302                                 &mapped_name,
1303                                 vfs_translate_to_unix);
1304         if (!NT_STATUS_IS_OK(status)) {
1305                 errno = map_errno_from_nt_status(status);
1306                 return -1;
1307         }
1308
1309         status = catia_string_replace_allocate(handle->conn,
1310                                 name, &mapped_ea_name, vfs_translate_to_unix);
1311         if (!NT_STATUS_IS_OK(status)) {
1312                 TALLOC_FREE(mapped_name);
1313                 errno = map_errno_from_nt_status(status);
1314                 return -1;
1315         }
1316
1317         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1318                                         mapped_name,
1319                                         NULL,
1320                                         &smb_fname->st,
1321                                         smb_fname->flags);
1322         if (mapped_smb_fname == NULL) {
1323                 TALLOC_FREE(mapped_name);
1324                 TALLOC_FREE(mapped_ea_name);
1325                 errno = ENOMEM;
1326                 return -1;
1327         }
1328
1329         ret = SMB_VFS_NEXT_GETXATTR(handle, mapped_smb_fname,
1330                                 mapped_ea_name, value, size);
1331         if (ret == -1) {
1332                 saved_errno = errno;
1333         }
1334         TALLOC_FREE(mapped_name);
1335         TALLOC_FREE(mapped_ea_name);
1336         TALLOC_FREE(mapped_smb_fname);
1337         if (saved_errno != 0) {
1338                 errno = saved_errno;
1339         }
1340
1341         return ret;
1342 }
1343
1344 static ssize_t
1345 catia_listxattr(vfs_handle_struct *handle,
1346                 const struct smb_filename *smb_fname,
1347                 char *list, size_t size)
1348 {
1349         struct smb_filename *mapped_smb_fname = NULL;
1350         char *mapped_name = NULL;
1351         NTSTATUS status;
1352         ssize_t ret;
1353         int saved_errno = 0;
1354
1355         status = catia_string_replace_allocate(handle->conn,
1356                                 smb_fname->base_name,
1357                                 &mapped_name,
1358                                 vfs_translate_to_unix);
1359         if (!NT_STATUS_IS_OK(status)) {
1360                 errno = map_errno_from_nt_status(status);
1361                 return -1;
1362         }
1363
1364         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1365                                         mapped_name,
1366                                         NULL,
1367                                         &smb_fname->st,
1368                                         smb_fname->flags);
1369         if (mapped_smb_fname == NULL) {
1370                 TALLOC_FREE(mapped_name);
1371                 errno = ENOMEM;
1372                 return -1;
1373         }
1374
1375         ret = SMB_VFS_NEXT_LISTXATTR(handle, mapped_smb_fname, list, size);
1376         if (ret == -1) {
1377                 saved_errno = errno;
1378         }
1379         TALLOC_FREE(mapped_name);
1380         TALLOC_FREE(mapped_smb_fname);
1381         if (saved_errno != 0) {
1382                 errno = saved_errno;
1383         }
1384
1385         return ret;
1386 }
1387
1388 static int
1389 catia_removexattr(vfs_handle_struct *handle,
1390                         const struct smb_filename *smb_fname,
1391                         const char *name)
1392 {
1393         struct smb_filename *mapped_smb_fname = NULL;
1394         char *mapped_name = NULL;
1395         char *mapped_ea_name = NULL;
1396         NTSTATUS status;
1397         ssize_t ret;
1398         int saved_errno = 0;
1399
1400         status = catia_string_replace_allocate(handle->conn,
1401                                 smb_fname->base_name,
1402                                 &mapped_name,
1403                                 vfs_translate_to_unix);
1404         if (!NT_STATUS_IS_OK(status)) {
1405                 errno = map_errno_from_nt_status(status);
1406                 return -1;
1407         }
1408
1409         status = catia_string_replace_allocate(handle->conn,
1410                                 name, &mapped_ea_name, vfs_translate_to_unix);
1411         if (!NT_STATUS_IS_OK(status)) {
1412                 TALLOC_FREE(mapped_name);
1413                 errno = map_errno_from_nt_status(status);
1414                 return -1;
1415         }
1416
1417         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1418                                         mapped_name,
1419                                         NULL,
1420                                         &smb_fname->st,
1421                                         smb_fname->flags);
1422         if (mapped_smb_fname == NULL) {
1423                 TALLOC_FREE(mapped_name);
1424                 TALLOC_FREE(mapped_ea_name);
1425                 errno = ENOMEM;
1426                 return -1;
1427         }
1428
1429         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, mapped_smb_fname,
1430                                 mapped_ea_name);
1431         if (ret == -1) {
1432                 saved_errno = errno;
1433         }
1434         TALLOC_FREE(mapped_name);
1435         TALLOC_FREE(mapped_ea_name);
1436         TALLOC_FREE(mapped_smb_fname);
1437         if (saved_errno != 0) {
1438                 errno = saved_errno;
1439         }
1440
1441         return ret;
1442 }
1443
1444 static int
1445 catia_setxattr(vfs_handle_struct *handle,
1446                         const struct smb_filename *smb_fname,
1447                         const char *name,
1448                         const void *value,
1449                         size_t size,
1450                         int flags)
1451 {
1452         struct smb_filename *mapped_smb_fname = NULL;
1453         char *mapped_name = NULL;
1454         char *mapped_ea_name = NULL;
1455         NTSTATUS status;
1456         ssize_t ret;
1457         int saved_errno = 0;
1458
1459         status = catia_string_replace_allocate(handle->conn,
1460                                 smb_fname->base_name,
1461                                 &mapped_name,
1462                                 vfs_translate_to_unix);
1463         if (!NT_STATUS_IS_OK(status)) {
1464                 errno = map_errno_from_nt_status(status);
1465                 return -1;
1466         }
1467
1468         status = catia_string_replace_allocate(handle->conn,
1469                                 name, &mapped_ea_name, vfs_translate_to_unix);
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 TALLOC_FREE(mapped_name);
1472                 errno = map_errno_from_nt_status(status);
1473                 return -1;
1474         }
1475
1476         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
1477                                         mapped_name,
1478                                         NULL,
1479                                         &smb_fname->st,
1480                                         smb_fname->flags);
1481         if (mapped_smb_fname == NULL) {
1482                 TALLOC_FREE(mapped_name);
1483                 TALLOC_FREE(mapped_ea_name);
1484                 errno = ENOMEM;
1485                 return -1;
1486         }
1487
1488         ret = SMB_VFS_NEXT_SETXATTR(handle, mapped_smb_fname, mapped_ea_name,
1489                         value, size, flags);
1490         if (ret == -1) {
1491                 saved_errno = errno;
1492         }
1493         TALLOC_FREE(mapped_name);
1494         TALLOC_FREE(mapped_ea_name);
1495         TALLOC_FREE(mapped_smb_fname);
1496         if (saved_errno != 0) {
1497                 errno = saved_errno;
1498         }
1499
1500         return ret;
1501 }
1502
1503 static int catia_fstat(vfs_handle_struct *handle,
1504                        files_struct *fsp,
1505                        SMB_STRUCT_STAT *sbuf)
1506 {
1507         struct catia_cache *cc = NULL;
1508         int ret;
1509
1510         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1511         if (ret != 0) {
1512                 return ret;
1513         }
1514
1515         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1516
1517         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1518
1519         return ret;
1520 }
1521
1522 static ssize_t catia_pread(vfs_handle_struct *handle,
1523                            files_struct *fsp, void *data,
1524                            size_t n, off_t offset)
1525 {
1526         struct catia_cache *cc = NULL;
1527         ssize_t result;
1528         int ret;
1529
1530         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1531         if (ret != 0) {
1532                 return ret;
1533         }
1534
1535         result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
1536
1537         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1538
1539         return result;
1540 }
1541
1542 static ssize_t catia_pwrite(vfs_handle_struct *handle,
1543                             files_struct *fsp, const void *data,
1544                             size_t n, off_t offset)
1545 {
1546         struct catia_cache *cc = NULL;
1547         ssize_t result;
1548         int ret;
1549
1550         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1551         if (ret != 0) {
1552                 return ret;
1553         }
1554
1555         result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
1556
1557         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1558
1559         return result;
1560 }
1561
1562 static int catia_ftruncate(struct vfs_handle_struct *handle,
1563                            struct files_struct *fsp,
1564                            off_t offset)
1565 {
1566         struct catia_cache *cc = NULL;
1567         int ret;
1568
1569         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1570         if (ret != 0) {
1571                 return ret;
1572         }
1573
1574         ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
1575
1576         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1577
1578         return ret;
1579 }
1580
1581 static int catia_fallocate(struct vfs_handle_struct *handle,
1582                            struct files_struct *fsp,
1583                            uint32_t mode,
1584                            off_t offset,
1585                            off_t len)
1586 {
1587         struct catia_cache *cc = NULL;
1588         int ret;
1589
1590         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1591         if (ret != 0) {
1592                 return ret;
1593         }
1594
1595         ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
1596
1597         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1598
1599         return ret;
1600 }
1601
1602 static ssize_t catia_fgetxattr(struct vfs_handle_struct *handle,
1603                                struct files_struct *fsp,
1604                                const char *name,
1605                                void *value,
1606                                size_t size)
1607 {
1608         char *mapped_xattr_name = NULL;
1609         NTSTATUS status;
1610         ssize_t result;
1611
1612         status = catia_string_replace_allocate(handle->conn,
1613                                                name, &mapped_xattr_name,
1614                                                vfs_translate_to_unix);
1615         if (!NT_STATUS_IS_OK(status)) {
1616                 errno = map_errno_from_nt_status(status);
1617                 return -1;
1618         }
1619
1620         result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, mapped_xattr_name,
1621                                         value, size);
1622
1623         TALLOC_FREE(mapped_xattr_name);
1624
1625         return result;
1626 }
1627
1628 static ssize_t catia_flistxattr(struct vfs_handle_struct *handle,
1629                                 struct files_struct *fsp,
1630                                 char *list,
1631                                 size_t size)
1632 {
1633         struct catia_cache *cc = NULL;
1634         ssize_t result;
1635         int ret;
1636
1637         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1638         if (ret != 0) {
1639                 return ret;
1640         }
1641
1642         result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
1643
1644         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1645
1646         return result;
1647 }
1648
1649 static int catia_fremovexattr(struct vfs_handle_struct *handle,
1650                               struct files_struct *fsp,
1651                               const char *name)
1652 {
1653         char *mapped_name = NULL;
1654         NTSTATUS status;
1655         int ret;
1656
1657         status = catia_string_replace_allocate(handle->conn,
1658                                 name, &mapped_name, vfs_translate_to_unix);
1659         if (!NT_STATUS_IS_OK(status)) {
1660                 errno = map_errno_from_nt_status(status);
1661                 return -1;
1662         }
1663
1664         ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, mapped_name);
1665
1666         TALLOC_FREE(mapped_name);
1667
1668         return ret;
1669 }
1670
1671 static int catia_fsetxattr(struct vfs_handle_struct *handle,
1672                            struct files_struct *fsp,
1673                            const char *name,
1674                            const void *value,
1675                            size_t size,
1676                            int flags)
1677 {
1678         char *mapped_xattr_name = NULL;
1679         NTSTATUS status;
1680         int ret;
1681
1682         status = catia_string_replace_allocate(
1683                 handle->conn, name, &mapped_xattr_name, vfs_translate_to_unix);
1684         if (!NT_STATUS_IS_OK(status)) {
1685                 errno = map_errno_from_nt_status(status);
1686                 return -1;
1687         }
1688
1689         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, mapped_xattr_name,
1690                                      value, size, flags);
1691
1692         TALLOC_FREE(mapped_xattr_name);
1693
1694         return ret;
1695 }
1696
1697 static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle,
1698                                       files_struct *fsp,
1699                                       TALLOC_CTX *mem_ctx)
1700 {
1701         struct catia_cache *cc = NULL;
1702         struct smb_acl_t *result = NULL;
1703         int ret;
1704
1705         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1706         if (ret != 0) {
1707                 return NULL;
1708         }
1709
1710         result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
1711
1712         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1713
1714         return result;
1715 }
1716
1717 static int catia_sys_acl_blob_get_fd(vfs_handle_struct *handle,
1718                                      files_struct *fsp,
1719                                      TALLOC_CTX *mem_ctx,
1720                                      char **blob_description,
1721                                      DATA_BLOB *blob)
1722 {
1723         struct catia_cache *cc = NULL;
1724         int ret;
1725
1726         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1727         if (ret != 0) {
1728                 return ret;
1729         }
1730
1731         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
1732                                                blob_description, blob);
1733
1734         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1735
1736         return ret;
1737 }
1738
1739 static int catia_sys_acl_set_fd(vfs_handle_struct *handle,
1740                                 files_struct *fsp,
1741                                 SMB_ACL_T theacl)
1742 {
1743         struct catia_cache *cc = NULL;
1744         int ret;
1745
1746         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1747         if (ret != 0) {
1748                 return ret;
1749         }
1750
1751         ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
1752
1753         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1754
1755         return ret;
1756 }
1757
1758 static NTSTATUS catia_fget_nt_acl(vfs_handle_struct *handle,
1759                                   files_struct *fsp,
1760                                   uint32_t security_info,
1761                                   TALLOC_CTX *mem_ctx,
1762                                   struct security_descriptor **ppdesc)
1763 {
1764         struct catia_cache *cc = NULL;
1765         NTSTATUS status;
1766         int ret;
1767
1768         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1769         if (ret != 0) {
1770                 return map_nt_error_from_unix(errno);
1771         }
1772
1773         status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1774                                           mem_ctx, ppdesc);
1775
1776         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1777
1778         return status;
1779 }
1780
1781 static NTSTATUS catia_fset_nt_acl(vfs_handle_struct *handle,
1782                                   files_struct *fsp,
1783                                   uint32_t security_info_sent,
1784                                   const struct security_descriptor *psd)
1785 {
1786         struct catia_cache *cc = NULL;
1787         NTSTATUS status;
1788         int ret;
1789
1790         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1791         if (ret != 0) {
1792                 return map_nt_error_from_unix(errno);
1793         }
1794
1795         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
1796
1797         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1798
1799         return status;
1800 }
1801
1802 static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle,
1803                                           struct files_struct *fsp,
1804                                           uint32_t dosmode)
1805 {
1806         struct catia_cache *cc = NULL;
1807         NTSTATUS status;
1808         int ret;
1809
1810         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1811         if (ret != 0) {
1812                 return map_nt_error_from_unix(errno);
1813         }
1814
1815         status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1816
1817         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1818
1819         return status;
1820 }
1821
1822 static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle,
1823                                           struct files_struct *fsp,
1824                                           uint32_t *dosmode)
1825 {
1826         struct catia_cache *cc = NULL;
1827         NTSTATUS status;
1828         int ret;
1829
1830         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1831         if (ret != 0) {
1832                 return map_nt_error_from_unix(errno);
1833         }
1834
1835         status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1836
1837         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1838
1839         return status;
1840 }
1841
1842 static int catia_fchown(vfs_handle_struct *handle,
1843                         files_struct *fsp,
1844                         uid_t uid,
1845                         gid_t gid)
1846 {
1847         struct catia_cache *cc = NULL;
1848         int ret;
1849
1850         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1851         if (ret != 0) {
1852                 return ret;
1853         }
1854
1855         ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
1856
1857         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1858
1859         return ret;
1860 }
1861
1862 static int catia_fchmod(vfs_handle_struct *handle,
1863                         files_struct *fsp,
1864                         mode_t mode)
1865 {
1866         struct catia_cache *cc = NULL;
1867         int ret;
1868
1869         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
1870         if (ret != 0) {
1871                 return ret;
1872         }
1873
1874         ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1875
1876         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
1877
1878         return ret;
1879 }
1880
1881 struct catia_pread_state {
1882         ssize_t ret;
1883         struct vfs_aio_state vfs_aio_state;
1884         struct files_struct *fsp;
1885         struct catia_cache *cc;
1886 };
1887
1888 static void catia_pread_done(struct tevent_req *subreq);
1889
1890 static struct tevent_req *catia_pread_send(struct vfs_handle_struct *handle,
1891                                            TALLOC_CTX *mem_ctx,
1892                                            struct tevent_context *ev,
1893                                            struct files_struct *fsp,
1894                                            void *data,
1895                                            size_t n,
1896                                            off_t offset)
1897 {
1898         struct tevent_req *req = NULL, *subreq = NULL;
1899         struct catia_pread_state *state = NULL;
1900         int ret;
1901
1902         req = tevent_req_create(mem_ctx, &state,
1903                                 struct catia_pread_state);
1904         if (req == NULL) {
1905                 return NULL;
1906         }
1907         state->fsp = fsp;
1908
1909         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1910         if (ret != 0) {
1911                 tevent_req_error(req, errno);
1912                 return tevent_req_post(req, ev);
1913         }
1914
1915         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
1916                                          n, offset);
1917         if (tevent_req_nomem(subreq, req)) {
1918                 return tevent_req_post(req, ev);
1919         }
1920         tevent_req_set_callback(subreq, catia_pread_done, req);
1921
1922         return req;
1923 }
1924
1925 static void catia_pread_done(struct tevent_req *subreq)
1926 {
1927         struct tevent_req *req = tevent_req_callback_data(
1928                 subreq, struct tevent_req);
1929         struct catia_pread_state *state = tevent_req_data(
1930                 req, struct catia_pread_state);
1931
1932         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
1933         TALLOC_FREE(subreq);
1934
1935         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
1936
1937         tevent_req_done(req);
1938 }
1939
1940 static ssize_t catia_pread_recv(struct tevent_req *req,
1941                                 struct vfs_aio_state *vfs_aio_state)
1942 {
1943         struct catia_pread_state *state = tevent_req_data(
1944                 req, struct catia_pread_state);
1945
1946         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1947                 return -1;
1948         }
1949
1950         *vfs_aio_state = state->vfs_aio_state;
1951         return state->ret;
1952 }
1953
1954 struct catia_pwrite_state {
1955         ssize_t ret;
1956         struct vfs_aio_state vfs_aio_state;
1957         struct files_struct *fsp;
1958         struct catia_cache *cc;
1959 };
1960
1961 static void catia_pwrite_done(struct tevent_req *subreq);
1962
1963 static struct tevent_req *catia_pwrite_send(struct vfs_handle_struct *handle,
1964                                             TALLOC_CTX *mem_ctx,
1965                                             struct tevent_context *ev,
1966                                             struct files_struct *fsp,
1967                                             const void *data,
1968                                             size_t n,
1969                                             off_t offset)
1970 {
1971         struct tevent_req *req = NULL, *subreq = NULL;
1972         struct catia_pwrite_state *state = NULL;
1973         int ret;
1974
1975         req = tevent_req_create(mem_ctx, &state,
1976                                 struct catia_pwrite_state);
1977         if (req == NULL) {
1978                 return NULL;
1979         }
1980         state->fsp = fsp;
1981
1982         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
1983         if (ret != 0) {
1984                 tevent_req_error(req, errno);
1985                 return tevent_req_post(req, ev);
1986         }
1987
1988         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
1989                                           n, offset);
1990         if (tevent_req_nomem(subreq, req)) {
1991                 return tevent_req_post(req, ev);
1992         }
1993         tevent_req_set_callback(subreq, catia_pwrite_done, req);
1994
1995         return req;
1996 }
1997
1998 static void catia_pwrite_done(struct tevent_req *subreq)
1999 {
2000         struct tevent_req *req = tevent_req_callback_data(
2001                 subreq, struct tevent_req);
2002         struct catia_pwrite_state *state = tevent_req_data(
2003                 req, struct catia_pwrite_state);
2004
2005         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
2006         TALLOC_FREE(subreq);
2007
2008         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
2009
2010         tevent_req_done(req);
2011 }
2012
2013 static ssize_t catia_pwrite_recv(struct tevent_req *req,
2014                                 struct vfs_aio_state *vfs_aio_state)
2015 {
2016         struct catia_pwrite_state *state = tevent_req_data(
2017                 req, struct catia_pwrite_state);
2018
2019         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2020                 return -1;
2021         }
2022
2023         *vfs_aio_state = state->vfs_aio_state;
2024         return state->ret;
2025 }
2026
2027 static off_t catia_lseek(vfs_handle_struct *handle,
2028                          files_struct *fsp,
2029                          off_t offset,
2030                          int whence)
2031 {
2032         struct catia_cache *cc = NULL;
2033         ssize_t result;
2034         int ret;
2035
2036         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2037         if (ret != 0) {
2038                 return -1;
2039         }
2040
2041         result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
2042
2043         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2044
2045         return result;
2046 }
2047
2048 struct catia_fsync_state {
2049         int ret;
2050         struct vfs_aio_state vfs_aio_state;
2051         struct files_struct *fsp;
2052         struct catia_cache *cc;
2053 };
2054
2055 static void catia_fsync_done(struct tevent_req *subreq);
2056
2057 static struct tevent_req *catia_fsync_send(struct vfs_handle_struct *handle,
2058                                            TALLOC_CTX *mem_ctx,
2059                                            struct tevent_context *ev,
2060                                            struct files_struct *fsp)
2061 {
2062         struct tevent_req *req = NULL, *subreq = NULL;
2063         struct catia_fsync_state *state = NULL;
2064         int ret;
2065
2066         req = tevent_req_create(mem_ctx, &state,
2067                                 struct catia_fsync_state);
2068         if (req == NULL) {
2069                 return NULL;
2070         }
2071         state->fsp = fsp;
2072
2073         ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc);
2074         if (ret != 0) {
2075                 tevent_req_error(req, errno);
2076                 return tevent_req_post(req, ev);
2077         }
2078
2079         subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
2080         if (tevent_req_nomem(subreq, req)) {
2081                 return tevent_req_post(req, ev);
2082         }
2083         tevent_req_set_callback(subreq, catia_fsync_done, req);
2084
2085         return req;
2086 }
2087
2088 static void catia_fsync_done(struct tevent_req *subreq)
2089 {
2090         struct tevent_req *req = tevent_req_callback_data(
2091                 subreq, struct tevent_req);
2092         struct catia_fsync_state *state = tevent_req_data(
2093                 req, struct catia_fsync_state);
2094
2095         state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
2096         TALLOC_FREE(subreq);
2097
2098         CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp);
2099
2100         tevent_req_done(req);
2101 }
2102
2103 static int catia_fsync_recv(struct tevent_req *req,
2104                             struct vfs_aio_state *vfs_aio_state)
2105 {
2106         struct catia_fsync_state *state = tevent_req_data(
2107                 req, struct catia_fsync_state);
2108
2109         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2110                 return -1;
2111         }
2112
2113         *vfs_aio_state = state->vfs_aio_state;
2114         return state->ret;
2115 }
2116
2117 static bool catia_lock(vfs_handle_struct *handle,
2118                        files_struct *fsp,
2119                        int op,
2120                        off_t offset,
2121                        off_t count,
2122                        int type)
2123 {
2124         struct catia_cache *cc = NULL;
2125         bool ok;
2126         int ret;
2127
2128         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2129         if (ret != 0) {
2130                 return false;
2131         }
2132
2133         ok = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
2134
2135         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2136
2137         return ok;
2138 }
2139
2140 static int catia_kernel_flock(struct vfs_handle_struct *handle,
2141                               struct files_struct *fsp,
2142                               uint32_t share_mode,
2143                               uint32_t access_mask)
2144 {
2145         struct catia_cache *cc = NULL;
2146         int ret;
2147
2148         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2149         if (ret != 0) {
2150                 return -1;
2151         }
2152
2153         ret = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode, access_mask);
2154
2155         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2156
2157         return ret;
2158 }
2159
2160 static int catia_linux_setlease(vfs_handle_struct *handle,
2161                                 files_struct *fsp,
2162                                 int leasetype)
2163 {
2164         struct catia_cache *cc = NULL;
2165         int ret;
2166
2167         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2168         if (ret != 0) {
2169                 return -1;
2170         }
2171
2172         ret = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
2173
2174         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2175
2176         return ret;
2177 }
2178
2179 static bool catia_getlock(vfs_handle_struct *handle,
2180                           files_struct *fsp,
2181                           off_t *poffset,
2182                           off_t *pcount,
2183                           int *ptype,
2184                           pid_t *ppid)
2185 {
2186         struct catia_cache *cc = NULL;
2187         int ret;
2188         bool ok;
2189
2190         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2191         if (ret != 0) {
2192                 return false;
2193         }
2194
2195         ok = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
2196
2197         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2198
2199         return ok;
2200 }
2201
2202 static bool catia_strict_lock_check(struct vfs_handle_struct *handle,
2203                                     struct files_struct *fsp,
2204                                     struct lock_struct *plock)
2205 {
2206         struct catia_cache *cc = NULL;
2207         int ret;
2208         bool ok;
2209
2210         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2211         if (ret != 0) {
2212                 return false;
2213         }
2214
2215         ok = SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock);
2216
2217         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2218
2219         return ok;
2220 }
2221
2222 static NTSTATUS catia_fsctl(struct vfs_handle_struct *handle,
2223                             struct files_struct *fsp,
2224                             TALLOC_CTX *ctx,
2225                             uint32_t function,
2226                             uint16_t req_flags,
2227                             const uint8_t *_in_data,
2228                             uint32_t in_len,
2229                             uint8_t **_out_data,
2230                             uint32_t max_out_len,
2231                             uint32_t *out_len)
2232 {
2233         NTSTATUS result;
2234         struct catia_cache *cc = NULL;
2235         int ret;
2236
2237         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2238         if (ret != 0) {
2239                 return map_nt_error_from_unix(errno);
2240         }
2241
2242         result = SMB_VFS_NEXT_FSCTL(handle,
2243                                 fsp,
2244                                 ctx,
2245                                 function,
2246                                 req_flags,
2247                                 _in_data,
2248                                 in_len,
2249                                 _out_data,
2250                                 max_out_len,
2251                                 out_len);
2252
2253         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2254
2255         return result;
2256 }
2257
2258 static NTSTATUS catia_get_compression(vfs_handle_struct *handle,
2259                                       TALLOC_CTX *mem_ctx,
2260                                       struct files_struct *fsp,
2261                                       struct smb_filename *smb_fname,
2262                                       uint16_t *_compression_fmt)
2263 {
2264         NTSTATUS result;
2265         struct catia_cache *cc = NULL;
2266         int ret;
2267         struct smb_filename *mapped_smb_fname = NULL;
2268         char *mapped_name = NULL;
2269
2270         if (fsp != NULL) {
2271                 ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2272                 if (ret != 0) {
2273                         return map_nt_error_from_unix(errno);
2274                 }
2275                 mapped_smb_fname = fsp->fsp_name;
2276         } else {
2277                 result = catia_string_replace_allocate(handle->conn,
2278                                 smb_fname->base_name,
2279                                 &mapped_name,
2280                                 vfs_translate_to_unix);
2281                 if (!NT_STATUS_IS_OK(result)) {
2282                         return result;
2283                 }
2284
2285                 mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2286                                                 mapped_name,
2287                                                 NULL,
2288                                                 &smb_fname->st,
2289                                                 smb_fname->flags);
2290                 if (mapped_smb_fname == NULL) {
2291                         TALLOC_FREE(mapped_name);
2292                         return NT_STATUS_NO_MEMORY;
2293                 }
2294
2295                 TALLOC_FREE(mapped_name);
2296         }
2297
2298         result = SMB_VFS_NEXT_GET_COMPRESSION(handle,
2299                                         mem_ctx,
2300                                         fsp,
2301                                         mapped_smb_fname,
2302                                         _compression_fmt);
2303
2304         if (fsp != NULL) {
2305                 CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2306         } else {
2307                 TALLOC_FREE(mapped_smb_fname);
2308         }
2309
2310         return result;
2311 }
2312
2313 static NTSTATUS catia_set_compression(vfs_handle_struct *handle,
2314                                       TALLOC_CTX *mem_ctx,
2315                                       struct files_struct *fsp,
2316                                       uint16_t compression_fmt)
2317 {
2318         NTSTATUS result;
2319         struct catia_cache *cc = NULL;
2320         int ret;
2321
2322         ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc);
2323         if (ret != 0) {
2324                 return map_nt_error_from_unix(errno);
2325         }
2326
2327         result = SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp,
2328                                               compression_fmt);
2329
2330         CATIA_FETCH_FSP_POST_NEXT(&cc, fsp);
2331
2332         return result;
2333 }
2334
2335 static NTSTATUS catia_readdir_attr(struct vfs_handle_struct *handle,
2336                                    const struct smb_filename *smb_fname_in,
2337                                    TALLOC_CTX *mem_ctx,
2338                                    struct readdir_attr_data **pattr_data)
2339 {
2340         struct smb_filename *smb_fname;
2341         char *fname = NULL;
2342         NTSTATUS status;
2343
2344         status = catia_string_replace_allocate(handle->conn,
2345                                                smb_fname_in->base_name,
2346                                                &fname,
2347                                                vfs_translate_to_unix);
2348         if (!NT_STATUS_IS_OK(status)) {
2349                 errno = map_errno_from_nt_status(status);
2350                 return status;
2351         }
2352
2353         smb_fname = synthetic_smb_fname(talloc_tos(), fname, NULL,
2354                                         &smb_fname_in->st, 0);
2355
2356         status = SMB_VFS_NEXT_READDIR_ATTR(handle, smb_fname, mem_ctx, pattr_data);
2357
2358         TALLOC_FREE(smb_fname);
2359         TALLOC_FREE(fname);
2360         return status;
2361 }
2362
2363 static NTSTATUS catia_get_dos_attributes(struct vfs_handle_struct *handle,
2364                                          struct smb_filename *smb_fname,
2365                                          uint32_t *dosmode)
2366 {
2367         char *mapped_name = NULL;
2368         const char *path = smb_fname->base_name;
2369         struct smb_filename *mapped_smb_fname = NULL;
2370         NTSTATUS status;
2371
2372         status = catia_string_replace_allocate(handle->conn,
2373                                 path, &mapped_name, vfs_translate_to_unix);
2374         if (!NT_STATUS_IS_OK(status)) {
2375                 errno = map_errno_from_nt_status(status);
2376                 return status;
2377         }
2378         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2379                                         mapped_name,
2380                                         NULL,
2381                                         &smb_fname->st,
2382                                         smb_fname->flags);
2383         if (mapped_smb_fname == NULL) {
2384                 TALLOC_FREE(mapped_name);
2385                 return NT_STATUS_NO_MEMORY;
2386         }
2387
2388         status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle,
2389                                                  mapped_smb_fname,
2390                                                  dosmode);
2391         if (NT_STATUS_IS_OK(status)) {
2392                 smb_fname->st = mapped_smb_fname->st;
2393         }
2394
2395         TALLOC_FREE(mapped_name);
2396         TALLOC_FREE(mapped_smb_fname);
2397
2398         return status;
2399 }
2400
2401 static NTSTATUS catia_set_dos_attributes(struct vfs_handle_struct *handle,
2402                                          const struct smb_filename *smb_fname,
2403                                          uint32_t dosmode)
2404 {
2405         char *mapped_name = NULL;
2406         const char *path = smb_fname->base_name;
2407         struct smb_filename *mapped_smb_fname = NULL;
2408         NTSTATUS status;
2409
2410         status = catia_string_replace_allocate(handle->conn,
2411                                 path, &mapped_name, vfs_translate_to_unix);
2412         if (!NT_STATUS_IS_OK(status)) {
2413                 errno = map_errno_from_nt_status(status);
2414                 return status;
2415         }
2416         mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
2417                                         mapped_name,
2418                                         NULL,
2419                                         &smb_fname->st,
2420                                         smb_fname->flags);
2421         if (mapped_smb_fname == NULL) {
2422                 TALLOC_FREE(mapped_name);
2423                 return NT_STATUS_NO_MEMORY;
2424         }
2425
2426         status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
2427                                                  mapped_smb_fname,
2428                                                  dosmode);
2429         TALLOC_FREE(mapped_name);
2430         TALLOC_FREE(mapped_smb_fname);
2431
2432         return status;
2433 }
2434
2435 static struct vfs_fn_pointers vfs_catia_fns = {
2436         .connect_fn = catia_connect,
2437
2438         /* Directory operations */
2439         .mkdirat_fn = catia_mkdirat,
2440         .rmdir_fn = catia_rmdir,
2441         .opendir_fn = catia_opendir,
2442         .readdir_attr_fn = catia_readdir_attr,
2443
2444         /* File operations */
2445         .open_fn = catia_open,
2446         .pread_fn = catia_pread,
2447         .pread_send_fn = catia_pread_send,
2448         .pread_recv_fn = catia_pread_recv,
2449         .pwrite_fn = catia_pwrite,
2450         .pwrite_send_fn = catia_pwrite_send,
2451         .pwrite_recv_fn = catia_pwrite_recv,
2452         .lseek_fn = catia_lseek,
2453         .renameat_fn = catia_renameat,
2454         .fsync_send_fn = catia_fsync_send,
2455         .fsync_recv_fn = catia_fsync_recv,
2456         .stat_fn = catia_stat,
2457         .fstat_fn = catia_fstat,
2458         .lstat_fn = catia_lstat,
2459         .unlink_fn = catia_unlink,
2460         .chmod_fn = catia_chmod,
2461         .fchmod_fn = catia_fchmod,
2462         .chown_fn = catia_chown,
2463         .fchown_fn = catia_fchown,
2464         .lchown_fn = catia_lchown,
2465         .chdir_fn = catia_chdir,
2466         .ntimes_fn = catia_ntimes,
2467         .ftruncate_fn = catia_ftruncate,
2468         .fallocate_fn = catia_fallocate,
2469         .lock_fn = catia_lock,
2470         .kernel_flock_fn = catia_kernel_flock,
2471         .linux_setlease_fn = catia_linux_setlease,
2472         .getlock_fn = catia_getlock,
2473         .realpath_fn = catia_realpath,
2474         .chflags_fn = catia_chflags,
2475         .streaminfo_fn = catia_streaminfo,
2476         .strict_lock_check_fn = catia_strict_lock_check,
2477         .translate_name_fn = catia_translate_name,
2478         .fsctl_fn = catia_fsctl,
2479         .get_dos_attributes_fn = catia_get_dos_attributes,
2480         .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
2481         .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
2482         .set_dos_attributes_fn = catia_set_dos_attributes,
2483         .fset_dos_attributes_fn = catia_fset_dos_attributes,
2484         .fget_dos_attributes_fn = catia_fget_dos_attributes,
2485         .get_compression_fn = catia_get_compression,
2486         .set_compression_fn = catia_set_compression,
2487
2488         /* NT ACL operations. */
2489         .get_nt_acl_fn = catia_get_nt_acl,
2490         .fget_nt_acl_fn = catia_fget_nt_acl,
2491         .fset_nt_acl_fn = catia_fset_nt_acl,
2492
2493         /* POSIX ACL operations. */
2494         .sys_acl_get_file_fn = catia_sys_acl_get_file,
2495         .sys_acl_get_fd_fn = catia_sys_acl_get_fd,
2496         .sys_acl_blob_get_fd_fn = catia_sys_acl_blob_get_fd,
2497         .sys_acl_set_file_fn = catia_sys_acl_set_file,
2498         .sys_acl_set_fd_fn = catia_sys_acl_set_fd,
2499         .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file,
2500
2501         /* EA operations. */
2502         .getxattr_fn = catia_getxattr,
2503         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2504         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2505         .listxattr_fn = catia_listxattr,
2506         .removexattr_fn = catia_removexattr,
2507         .setxattr_fn = catia_setxattr,
2508         .fgetxattr_fn = catia_fgetxattr,
2509         .flistxattr_fn = catia_flistxattr,
2510         .fremovexattr_fn = catia_fremovexattr,
2511         .fsetxattr_fn = catia_fsetxattr,
2512 };
2513
2514 static_decl_vfs;
2515 NTSTATUS vfs_catia_init(TALLOC_CTX *ctx)
2516 {
2517         NTSTATUS ret;
2518
2519         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
2520                                 &vfs_catia_fns);
2521         if (!NT_STATUS_IS_OK(ret))
2522                 return ret;
2523
2524         vfs_catia_debug_level = debug_add_class("catia");
2525         if (vfs_catia_debug_level == -1) {
2526                 vfs_catia_debug_level = DBGC_VFS;
2527                 DEBUG(0, ("vfs_catia: Couldn't register custom debugging "
2528                           "class!\n"));
2529         } else {
2530                 DEBUG(10, ("vfs_catia: Debug class number of "
2531                            "'catia': %d\n", vfs_catia_debug_level));
2532         }
2533
2534         return ret;
2535
2536 }