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