vfs_fruit: unpack AppleDouble xattr header if present
[vlendec/samba-autobuild/.git] / source3 / modules / string_replace.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * Copyright (C) Volker Lendecke, 2005
5  * Copyright (C) Aravind Srinivasan, 2009
6  * Copyright (C) Guenter Kukkukk, 2013
7  * Copyright (C) Ralph Boehme, 2017
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24 #include "smbd/smbd.h"
25 #include "string_replace.h"
26
27 #define MAP_SIZE        0xFF
28 #define MAP_NUM         0x101 /* max unicode charval / MAP_SIZE */
29 #define T_OFFSET(_v_)   ((_v_ % MAP_SIZE))
30 #define T_START(_v_)    (((_v_ / MAP_SIZE) * MAP_SIZE))
31 #define T_PICK(_v_)     ((_v_ / MAP_SIZE))
32
33 struct char_mappings {
34         smb_ucs2_t entry[MAP_SIZE][2];
35 };
36
37 static bool build_table(struct char_mappings **cmaps, int value)
38 {
39         int i;
40         int start = T_START(value);
41
42         (*cmaps) = talloc_zero(NULL, struct char_mappings);
43
44         if (!*cmaps)
45                 return False;
46
47         for (i = 0; i < MAP_SIZE;i++) {
48                 (*cmaps)->entry[i][vfs_translate_to_unix] = start + i;
49                 (*cmaps)->entry[i][vfs_translate_to_windows] = start + i;
50         }
51
52         return True;
53 }
54
55 static void set_tables(struct char_mappings **cmaps,
56                        long unix_map,
57                        long windows_map)
58 {
59         int i;
60
61         /* set unix -> windows */
62         i = T_OFFSET(unix_map);
63         cmaps[T_PICK(unix_map)]->entry[i][vfs_translate_to_windows] = windows_map;
64
65         /* set windows -> unix */
66         i = T_OFFSET(windows_map);
67         cmaps[T_PICK(windows_map)]->entry[i][vfs_translate_to_unix] = unix_map;
68 }
69
70 static bool build_ranges(struct char_mappings **cmaps,
71                          long unix_map,
72                          long windows_map)
73 {
74
75         if (!cmaps[T_PICK(unix_map)]) {
76                 if (!build_table(&cmaps[T_PICK(unix_map)], unix_map))
77                         return False;
78         }
79
80         if (!cmaps[T_PICK(windows_map)]) {
81                 if (!build_table(&cmaps[T_PICK(windows_map)], windows_map))
82                         return False;
83         }
84
85         set_tables(cmaps, unix_map, windows_map);
86
87         return True;
88 }
89
90 struct char_mappings **string_replace_init_map(const char **mappings)
91 {
92         int i;
93         char *tmp;
94         fstring mapping;
95         long unix_map, windows_map;
96         struct char_mappings **cmaps = NULL;
97
98         if (mappings == NULL) {
99                 return NULL;
100         }
101
102         cmaps = TALLOC_ZERO(NULL, MAP_NUM * sizeof(struct char_mappings *));
103         if (cmaps == NULL) {
104                 return NULL;
105         }
106
107         /*
108          * catia mappings are of the form :
109          * UNIX char (in 0xnn hex) : WINDOWS char (in 0xnn hex)
110          *
111          * multiple mappings are comma separated in smb.conf
112          */
113
114         for (i = 0; mappings[i]; i++) {
115                 fstrcpy(mapping, mappings[i]);
116                 unix_map = strtol(mapping, &tmp, 16);
117                 if (unix_map == 0 && errno == EINVAL) {
118                         DEBUG(0, ("INVALID CATIA MAPPINGS - %s\n", mapping));
119                         continue;
120                 }
121                 windows_map = strtol(++tmp, NULL, 16);
122                 if (windows_map == 0 && errno == EINVAL) {
123                         DEBUG(0, ("INVALID CATIA MAPPINGS - %s\n", mapping));
124                         continue;
125                 }
126
127                 if (!build_ranges(cmaps, unix_map, windows_map)) {
128                         DEBUG(0, ("TABLE ERROR - CATIA MAPPINGS - %s\n", mapping));
129                         continue;
130                 }
131         }
132
133         return cmaps;
134 }
135
136 NTSTATUS string_replace_allocate(connection_struct *conn,
137                                  const char *name_in,
138                                  struct char_mappings **cmaps,
139                                  TALLOC_CTX *mem_ctx,
140                                  char **mapped_name,
141                                  enum vfs_translate_direction direction)
142 {
143         static smb_ucs2_t *tmpbuf = NULL;
144         smb_ucs2_t *ptr = NULL;
145         struct char_mappings *map = NULL;
146         size_t converted_size;
147         bool ok;
148
149         ok = push_ucs2_talloc(talloc_tos(), &tmpbuf, name_in,
150                               &converted_size);
151         if (!ok) {
152                 return map_nt_error_from_unix(errno);
153         }
154
155         for (ptr = tmpbuf; *ptr; ptr++) {
156                 if (*ptr == 0) {
157                         break;
158                 }
159                 if (cmaps == NULL) {
160                         continue;
161                 }
162                 map = cmaps[T_PICK((*ptr))];
163                 if (map == NULL) {
164                         /* nothing to do */
165                         continue;
166                 }
167
168                 *ptr = map->entry[T_OFFSET((*ptr))][direction];
169         }
170
171         ok = pull_ucs2_talloc(mem_ctx, mapped_name, tmpbuf,
172                               &converted_size);
173         TALLOC_FREE(tmpbuf);
174         if (!ok) {
175                 return map_nt_error_from_unix(errno);
176         }
177         return NT_STATUS_OK;
178 }