bootstrap/config.py: mv locale setup from bootstrap.sh
[gd/samba-autobuild/.git] / source3 / modules / vfs_fruit.c
1 /*
2  * OS X and Netatalk interoperability VFS module for Samba-3.x
3  *
4  * Copyright (C) Ralph Boehme, 2013, 2014
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "MacExtensions.h"
22 #include "smbd/smbd.h"
23 #include "system/filesys.h"
24 #include "lib/util/time.h"
25 #include "../lib/crypto/md5.h"
26 #include "system/shmem.h"
27 #include "locking/proto.h"
28 #include "smbd/globals.h"
29 #include "messages.h"
30 #include "libcli/security/security.h"
31 #include "../libcli/smb/smb2_create_ctx.h"
32 #include "lib/util/sys_rw.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "lib/util/tevent_unix.h"
35 #include "offload_token.h"
36 #include "string_replace.h"
37
38 /*
39  * Enhanced OS X and Netatalk compatibility
40  * ========================================
41  *
42  * This modules takes advantage of vfs_streams_xattr and
43  * vfs_catia. VFS modules vfs_fruit and vfs_streams_xattr must be
44  * loaded in the correct order:
45  *
46  *   vfs modules = catia fruit streams_xattr
47  *
48  * The module intercepts the OS X special streams "AFP_AfpInfo" and
49  * "AFP_Resource" and handles them in a special way. All other named
50  * streams are deferred to vfs_streams_xattr.
51  *
52  * The OS X client maps all NTFS illegal characters to the Unicode
53  * private range. This module optionally stores the charcters using
54  * their native ASCII encoding using vfs_catia. If you're not enabling
55  * this feature, you can skip catia from vfs modules.
56  *
57  * Finally, open modes are optionally checked against Netatalk AFP
58  * share modes.
59  *
60  * The "AFP_AfpInfo" named stream is a binary blob containing OS X
61  * extended metadata for files and directories. This module optionally
62  * reads and stores this metadata in a way compatible with Netatalk 3
63  * which stores the metadata in an EA "org.netatalk.metadata". Cf
64  * source3/include/MacExtensions.h for a description of the binary
65  * blobs content.
66  *
67  * The "AFP_Resource" named stream may be arbitrarily large, thus it
68  * can't be stored in an xattr on most filesystem. ZFS on Solaris is
69  * the only available filesystem where xattrs can be of any size and
70  * the OS supports using the file APIs for xattrs.
71  *
72  * The AFP_Resource stream is stored in an AppleDouble file prepending
73  * "._" to the filename. On Solaris with ZFS the stream is optionally
74  * stored in an EA "org.netatalk.resource".
75  *
76  *
77  * Extended Attributes
78  * ===================
79  *
80  * The OS X SMB client sends xattrs as ADS too. For xattr interop with
81  * other protocols you may want to adjust the xattr names the VFS
82  * module vfs_streams_xattr uses for storing ADS's. This defaults to
83  * user.DosStream.ADS_NAME:$DATA and can be changed by specifying
84  * these module parameters:
85  *
86  *   streams_xattr:prefix = user.
87  *   streams_xattr:store_stream_type = false
88  *
89  *
90  * TODO
91  * ====
92  *
93  * - log diagnostic if any needed VFS module is not loaded
94  *   (eg with lp_vfs_objects())
95  * - add tests
96  */
97
98 static int vfs_fruit_debug_level = DBGC_VFS;
99
100 static struct global_fruit_config {
101         bool nego_aapl; /* client negotiated AAPL */
102
103 } global_fruit_config;
104
105 #undef DBGC_CLASS
106 #define DBGC_CLASS vfs_fruit_debug_level
107
108 #define FRUIT_PARAM_TYPE_NAME "fruit"
109 #define ADOUBLE_NAME_PREFIX "._"
110
111 #define NETATALK_META_XATTR "org.netatalk.Metadata"
112 #define NETATALK_RSRC_XATTR "org.netatalk.ResourceFork"
113
114 #if defined(HAVE_ATTROPEN)
115 #define AFPINFO_EA_NETATALK NETATALK_META_XATTR
116 #define AFPRESOURCE_EA_NETATALK NETATALK_RSRC_XATTR
117 #else
118 #define AFPINFO_EA_NETATALK "user." NETATALK_META_XATTR
119 #define AFPRESOURCE_EA_NETATALK "user." NETATALK_RSRC_XATTR
120 #endif
121
122 enum apple_fork {APPLE_FORK_DATA, APPLE_FORK_RSRC};
123
124 enum fruit_rsrc {FRUIT_RSRC_STREAM, FRUIT_RSRC_ADFILE, FRUIT_RSRC_XATTR};
125 enum fruit_meta {FRUIT_META_STREAM, FRUIT_META_NETATALK};
126 enum fruit_locking {FRUIT_LOCKING_NETATALK, FRUIT_LOCKING_NONE};
127 enum fruit_encoding {FRUIT_ENC_NATIVE, FRUIT_ENC_PRIVATE};
128
129 struct fruit_config_data {
130         enum fruit_rsrc rsrc;
131         enum fruit_meta meta;
132         enum fruit_locking locking;
133         enum fruit_encoding encoding;
134         bool use_aapl;          /* config from smb.conf */
135         bool use_copyfile;
136         bool readdir_attr_enabled;
137         bool unix_info_enabled;
138         bool copyfile_enabled;
139         bool veto_appledouble;
140         bool posix_rename;
141         bool aapl_zero_file_id;
142         const char *model;
143         bool time_machine;
144         off_t time_machine_max_size;
145         bool wipe_intentionally_left_blank_rfork;
146         bool delete_empty_adfiles;
147
148         /*
149          * Additional options, all enabled by default,
150          * possibly useful for analyzing performance. The associated
151          * operations with each of them may be expensive, so having
152          * the chance to disable them individually gives a chance
153          * tweaking the setup for the particular usecase.
154          */
155         bool readdir_attr_rsize;
156         bool readdir_attr_finder_info;
157         bool readdir_attr_max_access;
158 };
159
160 static const struct enum_list fruit_rsrc[] = {
161         {FRUIT_RSRC_STREAM, "stream"}, /* pass on to vfs_streams_xattr */
162         {FRUIT_RSRC_ADFILE, "file"}, /* ._ AppleDouble file */
163         {FRUIT_RSRC_XATTR, "xattr"}, /* Netatalk compatible xattr (ZFS only) */
164         { -1, NULL}
165 };
166
167 static const struct enum_list fruit_meta[] = {
168         {FRUIT_META_STREAM, "stream"}, /* pass on to vfs_streams_xattr */
169         {FRUIT_META_NETATALK, "netatalk"}, /* Netatalk compatible xattr */
170         { -1, NULL}
171 };
172
173 static const struct enum_list fruit_locking[] = {
174         {FRUIT_LOCKING_NETATALK, "netatalk"}, /* synchronize locks with Netatalk */
175         {FRUIT_LOCKING_NONE, "none"},
176         { -1, NULL}
177 };
178
179 static const struct enum_list fruit_encoding[] = {
180         {FRUIT_ENC_NATIVE, "native"}, /* map unicode private chars to ASCII */
181         {FRUIT_ENC_PRIVATE, "private"}, /* keep unicode private chars */
182         { -1, NULL}
183 };
184
185 static const char *fruit_catia_maps =
186         "0x01:0xf001,0x02:0xf002,0x03:0xf003,0x04:0xf004,"
187         "0x05:0xf005,0x06:0xf006,0x07:0xf007,0x08:0xf008,"
188         "0x09:0xf009,0x0a:0xf00a,0x0b:0xf00b,0x0c:0xf00c,"
189         "0x0d:0xf00d,0x0e:0xf00e,0x0f:0xf00f,0x10:0xf010,"
190         "0x11:0xf011,0x12:0xf012,0x13:0xf013,0x14:0xf014,"
191         "0x15:0xf015,0x16:0xf016,0x17:0xf017,0x18:0xf018,"
192         "0x19:0xf019,0x1a:0xf01a,0x1b:0xf01b,0x1c:0xf01c,"
193         "0x1d:0xf01d,0x1e:0xf01e,0x1f:0xf01f,"
194         "0x22:0xf020,0x2a:0xf021,0x3a:0xf022,0x3c:0xf023,"
195         "0x3e:0xf024,0x3f:0xf025,0x5c:0xf026,0x7c:0xf027,"
196         "0x0d:0xf00d";
197
198 /*****************************************************************************
199  * Defines, functions and data structures that deal with AppleDouble
200  *****************************************************************************/
201
202 /*
203  * There are two AppleDouble blobs we deal with:
204  *
205  * - ADOUBLE_META - AppleDouble blob used by Netatalk for storing
206  *   metadata in an xattr
207  *
208  * - ADOUBLE_RSRC - AppleDouble blob used by OS X and Netatalk in
209  *   ._ files
210  */
211 typedef enum {ADOUBLE_META, ADOUBLE_RSRC} adouble_type_t;
212
213 /* Version info */
214 #define AD_VERSION2     0x00020000
215 #define AD_VERSION      AD_VERSION2
216
217 /*
218  * AppleDouble entry IDs.
219  */
220 #define ADEID_DFORK         1
221 #define ADEID_RFORK         2
222 #define ADEID_NAME          3
223 #define ADEID_COMMENT       4
224 #define ADEID_ICONBW        5
225 #define ADEID_ICONCOL       6
226 #define ADEID_FILEI         7
227 #define ADEID_FILEDATESI    8
228 #define ADEID_FINDERI       9
229 #define ADEID_MACFILEI      10
230 #define ADEID_PRODOSFILEI   11
231 #define ADEID_MSDOSFILEI    12
232 #define ADEID_SHORTNAME     13
233 #define ADEID_AFPFILEI      14
234 #define ADEID_DID           15
235
236 /* Private Netatalk entries */
237 #define ADEID_PRIVDEV       16
238 #define ADEID_PRIVINO       17
239 #define ADEID_PRIVSYN       18
240 #define ADEID_PRIVID        19
241 #define ADEID_MAX           (ADEID_PRIVID + 1)
242
243 /*
244  * These are the real ids for the private entries,
245  * as stored in the adouble file
246  */
247 #define AD_DEV              0x80444556
248 #define AD_INO              0x80494E4F
249 #define AD_SYN              0x8053594E
250 #define AD_ID               0x8053567E
251
252 /* Number of actually used entries */
253 #define ADEID_NUM_XATTR      8
254 #define ADEID_NUM_DOT_UND    2
255 #define ADEID_NUM_RSRC_XATTR 1
256
257 /* AppleDouble magic */
258 #define AD_APPLESINGLE_MAGIC 0x00051600
259 #define AD_APPLEDOUBLE_MAGIC 0x00051607
260 #define AD_MAGIC             AD_APPLEDOUBLE_MAGIC
261
262 /* Sizes of relevant entry bits */
263 #define ADEDLEN_MAGIC       4
264 #define ADEDLEN_VERSION     4
265 #define ADEDLEN_FILLER      16
266 #define AD_FILLER_TAG       "Netatalk        " /* should be 16 bytes */
267 #define AD_FILLER_TAG_OSX   "Mac OS X        " /* should be 16 bytes */
268 #define ADEDLEN_NENTRIES    2
269 #define AD_HEADER_LEN       (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
270                              ADEDLEN_FILLER + ADEDLEN_NENTRIES) /* 26 */
271 #define AD_ENTRY_LEN_EID    4
272 #define AD_ENTRY_LEN_OFF    4
273 #define AD_ENTRY_LEN_LEN    4
274 #define AD_ENTRY_LEN (AD_ENTRY_LEN_EID + AD_ENTRY_LEN_OFF + AD_ENTRY_LEN_LEN)
275
276 /* Field widths */
277 #define ADEDLEN_NAME            255
278 #define ADEDLEN_COMMENT         200
279 #define ADEDLEN_FILEI           16
280 #define ADEDLEN_FINDERI         32
281 #define ADEDLEN_FILEDATESI      16
282 #define ADEDLEN_SHORTNAME       12 /* length up to 8.3 */
283 #define ADEDLEN_AFPFILEI        4
284 #define ADEDLEN_MACFILEI        4
285 #define ADEDLEN_PRODOSFILEI     8
286 #define ADEDLEN_MSDOSFILEI      2
287 #define ADEDLEN_DID             4
288 #define ADEDLEN_PRIVDEV         8
289 #define ADEDLEN_PRIVINO         8
290 #define ADEDLEN_PRIVSYN         8
291 #define ADEDLEN_PRIVID          4
292
293 /* Offsets */
294 #define ADEDOFF_MAGIC         0
295 #define ADEDOFF_VERSION       (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
296 #define ADEDOFF_FILLER        (ADEDOFF_VERSION + ADEDLEN_VERSION)
297 #define ADEDOFF_NENTRIES      (ADEDOFF_FILLER + ADEDLEN_FILLER)
298
299 #define ADEDOFF_FINDERI_XATTR    (AD_HEADER_LEN + \
300                                   (ADEID_NUM_XATTR * AD_ENTRY_LEN))
301 #define ADEDOFF_COMMENT_XATTR    (ADEDOFF_FINDERI_XATTR    + ADEDLEN_FINDERI)
302 #define ADEDOFF_FILEDATESI_XATTR (ADEDOFF_COMMENT_XATTR    + ADEDLEN_COMMENT)
303 #define ADEDOFF_AFPFILEI_XATTR   (ADEDOFF_FILEDATESI_XATTR + \
304                                   ADEDLEN_FILEDATESI)
305 #define ADEDOFF_PRIVDEV_XATTR    (ADEDOFF_AFPFILEI_XATTR   + ADEDLEN_AFPFILEI)
306 #define ADEDOFF_PRIVINO_XATTR    (ADEDOFF_PRIVDEV_XATTR    + ADEDLEN_PRIVDEV)
307 #define ADEDOFF_PRIVSYN_XATTR    (ADEDOFF_PRIVINO_XATTR    + ADEDLEN_PRIVINO)
308 #define ADEDOFF_PRIVID_XATTR     (ADEDOFF_PRIVSYN_XATTR    + ADEDLEN_PRIVSYN)
309
310 #define ADEDOFF_FINDERI_DOT_UND  (AD_HEADER_LEN + \
311                                   (ADEID_NUM_DOT_UND * AD_ENTRY_LEN))
312 #define ADEDOFF_RFORK_DOT_UND    (ADEDOFF_FINDERI_DOT_UND + ADEDLEN_FINDERI)
313
314 #define AD_DATASZ_XATTR (AD_HEADER_LEN + \
315                          (ADEID_NUM_XATTR * AD_ENTRY_LEN) + \
316                          ADEDLEN_FINDERI + ADEDLEN_COMMENT + \
317                          ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + \
318                          ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \
319                          ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
320
321 #if AD_DATASZ_XATTR != 402
322 #error bad size for AD_DATASZ_XATTR
323 #endif
324
325 #define AD_DATASZ_DOT_UND (AD_HEADER_LEN + \
326                            (ADEID_NUM_DOT_UND * AD_ENTRY_LEN) + \
327                            ADEDLEN_FINDERI)
328 #if AD_DATASZ_DOT_UND != 82
329 #error bad size for AD_DATASZ_DOT_UND
330 #endif
331
332 /*
333  * Sharemode locks fcntl() offsets
334  */
335 #if _FILE_OFFSET_BITS == 64 || defined(HAVE_LARGEFILE)
336 #define AD_FILELOCK_BASE (UINT64_C(0x7FFFFFFFFFFFFFFF) - 9)
337 #else
338 #define AD_FILELOCK_BASE (UINT32_C(0x7FFFFFFF) - 9)
339 #endif
340 #define BYTELOCK_MAX (AD_FILELOCK_BASE - 1)
341
342 #define AD_FILELOCK_OPEN_WR        (AD_FILELOCK_BASE + 0)
343 #define AD_FILELOCK_OPEN_RD        (AD_FILELOCK_BASE + 1)
344 #define AD_FILELOCK_RSRC_OPEN_WR   (AD_FILELOCK_BASE + 2)
345 #define AD_FILELOCK_RSRC_OPEN_RD   (AD_FILELOCK_BASE + 3)
346 #define AD_FILELOCK_DENY_WR        (AD_FILELOCK_BASE + 4)
347 #define AD_FILELOCK_DENY_RD        (AD_FILELOCK_BASE + 5)
348 #define AD_FILELOCK_RSRC_DENY_WR   (AD_FILELOCK_BASE + 6)
349 #define AD_FILELOCK_RSRC_DENY_RD   (AD_FILELOCK_BASE + 7)
350 #define AD_FILELOCK_OPEN_NONE      (AD_FILELOCK_BASE + 8)
351 #define AD_FILELOCK_RSRC_OPEN_NONE (AD_FILELOCK_BASE + 9)
352
353 /* Time stuff we overload the bits a little */
354 #define AD_DATE_CREATE         0
355 #define AD_DATE_MODIFY         4
356 #define AD_DATE_BACKUP         8
357 #define AD_DATE_ACCESS        12
358 #define AD_DATE_MASK          (AD_DATE_CREATE | AD_DATE_MODIFY | \
359                                AD_DATE_BACKUP | AD_DATE_ACCESS)
360 #define AD_DATE_UNIX          (1 << 10)
361 #define AD_DATE_START         0x80000000
362 #define AD_DATE_DELTA         946684800
363 #define AD_DATE_FROM_UNIX(x)  (htonl((x) - AD_DATE_DELTA))
364 #define AD_DATE_TO_UNIX(x)    (ntohl(x) + AD_DATE_DELTA)
365
366 #define AD_XATTR_HDR_MAGIC    0x41545452 /* 'ATTR' */
367 #define AD_XATTR_MAX_ENTRIES  1024 /* Some arbitrarily enforced limit */
368 #define AD_XATTR_HDR_SIZE     36
369 #define AD_XATTR_MAX_HDR_SIZE 65536
370
371 /* Accessor macros */
372 #define ad_getentrylen(ad,eid)     ((ad)->ad_eid[(eid)].ade_len)
373 #define ad_getentryoff(ad,eid)     ((ad)->ad_eid[(eid)].ade_off)
374 #define ad_setentrylen(ad,eid,len) ((ad)->ad_eid[(eid)].ade_len = (len))
375 #define ad_setentryoff(ad,eid,off) ((ad)->ad_eid[(eid)].ade_off = (off))
376
377 /*
378  * Both struct ad_xattr_header and struct ad_xattr_entry describe the in memory
379  * representation as well as the on-disk format.
380  *
381  * The ad_xattr_header follows the FinderInfo data in the FinderInfo entry if
382  * the length of the FinderInfo entry is larger then 32 bytes. It is then
383  * preceeded with 2 bytes padding.
384  *
385  * Cf: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/vfs/vfs_xattr.c
386  */
387
388 struct ad_xattr_header {
389         uint32_t adx_magic;        /* ATTR_HDR_MAGIC */
390         uint32_t adx_debug_tag;    /* for debugging == file id of owning file */
391         uint32_t adx_total_size;   /* file offset of end of attribute header + entries + data */
392         uint32_t adx_data_start;   /* file offset to attribute data area */
393         uint32_t adx_data_length;  /* length of attribute data area */
394         uint32_t adx_reserved[3];
395         uint16_t adx_flags;
396         uint16_t adx_num_attrs;
397 };
398
399 /* On-disk entries are aligned on 4 byte boundaries */
400 struct ad_xattr_entry {
401         uint32_t adx_offset;    /* file offset to data */
402         uint32_t adx_length;    /* size of attribute data */
403         uint16_t adx_flags;
404         uint8_t  adx_namelen;   /* included the NULL terminator */
405         char    *adx_name;      /* NULL-terminated UTF-8 name */
406 };
407
408 struct ad_entry {
409         size_t ade_off;
410         size_t ade_len;
411 };
412
413 struct adouble {
414         vfs_handle_struct        *ad_handle;
415         int                       ad_fd;
416         bool                      ad_opened;
417         adouble_type_t            ad_type;
418         uint32_t                  ad_magic;
419         uint32_t                  ad_version;
420         uint8_t                   ad_filler[ADEDLEN_FILLER];
421         struct ad_entry           ad_eid[ADEID_MAX];
422         char                     *ad_data;
423         struct ad_xattr_header    adx_header;
424         struct ad_xattr_entry    *adx_entries;
425 };
426
427 struct ad_entry_order {
428         uint32_t id, offset, len;
429 };
430
431 /* Netatalk AppleDouble metadata xattr */
432 static const
433 struct ad_entry_order entry_order_meta_xattr[ADEID_NUM_XATTR + 1] = {
434         {ADEID_FINDERI,    ADEDOFF_FINDERI_XATTR,    ADEDLEN_FINDERI},
435         {ADEID_COMMENT,    ADEDOFF_COMMENT_XATTR,    0},
436         {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_XATTR, ADEDLEN_FILEDATESI},
437         {ADEID_AFPFILEI,   ADEDOFF_AFPFILEI_XATTR,   ADEDLEN_AFPFILEI},
438         {ADEID_PRIVDEV,    ADEDOFF_PRIVDEV_XATTR,    0},
439         {ADEID_PRIVINO,    ADEDOFF_PRIVINO_XATTR,    0},
440         {ADEID_PRIVSYN,    ADEDOFF_PRIVSYN_XATTR,    0},
441         {ADEID_PRIVID,     ADEDOFF_PRIVID_XATTR,     0},
442         {0, 0, 0}
443 };
444
445 /* AppleDouble resource fork file (the ones prefixed by "._") */
446 static const
447 struct ad_entry_order entry_order_dot_und[ADEID_NUM_DOT_UND + 1] = {
448         {ADEID_FINDERI,    ADEDOFF_FINDERI_DOT_UND,  ADEDLEN_FINDERI},
449         {ADEID_RFORK,      ADEDOFF_RFORK_DOT_UND,    0},
450         {0, 0, 0}
451 };
452
453 /*
454  * Fake AppleDouble entry oder for resource fork xattr.  The xattr
455  * isn't an AppleDouble file, it simply contains the resource data,
456  * but in order to be able to use some API calls like ad_getentryoff()
457  * we build a fake/helper struct adouble with this entry order struct.
458  */
459 static const
460 struct ad_entry_order entry_order_rsrc_xattr[ADEID_NUM_RSRC_XATTR + 1] = {
461         {ADEID_RFORK, 0, 0},
462         {0, 0, 0}
463 };
464
465 /* Conversion from enumerated id to on-disk AppleDouble id */
466 #define AD_EID_DISK(a) (set_eid[a])
467 static const uint32_t set_eid[] = {
468         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
469         AD_DEV, AD_INO, AD_SYN, AD_ID
470 };
471
472 static char empty_resourcefork[] = {
473         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
474         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
475         0x54, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73,
476         0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x66, 0x6F,
477         0x72, 0x6B, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E,
478         0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x6C, 0x79,
479         0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x62, 0x6C,
480         0x61, 0x6E, 0x6B, 0x20, 0x20, 0x20, 0x00, 0x00,
481         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
496         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
497         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
501         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
506         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
507         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508         0x00, 0x1C, 0x00, 0x1E, 0xFF, 0xFF
509 };
510
511 struct fio {
512         /* tcon config handle */
513         struct fruit_config_data *config;
514
515         /* Denote stream type, meta or rsrc */
516         adouble_type_t type;
517
518         /* Whether the create created the stream */
519         bool created;
520
521         /*
522          * AFP_AfpInfo stream created, but not written yet, thus still a fake
523          * pipe fd. This is set to true in fruit_open_meta if there was no
524          * exisiting stream but the caller requested O_CREAT. It is later set to
525          * false when we get a write on the stream that then does open and
526          * create the stream.
527          */
528         bool fake_fd;
529         int flags;
530         int mode;
531 };
532
533 /*
534  * Forward declarations
535  */
536 static struct adouble *ad_init(TALLOC_CTX *ctx, vfs_handle_struct *handle,
537                                adouble_type_t type);
538 static int ad_set(struct adouble *ad, const struct smb_filename *smb_fname);
539 static int ad_fset(struct adouble *ad, files_struct *fsp);
540 static int adouble_path(TALLOC_CTX *ctx,
541                         const struct smb_filename *smb_fname__in,
542                         struct smb_filename **ppsmb_fname_out);
543 static AfpInfo *afpinfo_new(TALLOC_CTX *ctx);
544 static ssize_t afpinfo_pack(const AfpInfo *ai, char *buf);
545 static AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data);
546
547
548 /**
549  * Return a pointer to an AppleDouble entry
550  *
551  * Returns NULL if the entry is not present
552  **/
553 static char *ad_get_entry(const struct adouble *ad, int eid)
554 {
555         off_t off = ad_getentryoff(ad, eid);
556         size_t len = ad_getentrylen(ad, eid);
557
558         if (off == 0 || len == 0) {
559                 return NULL;
560         }
561
562         return ad->ad_data + off;
563 }
564
565 /**
566  * Get a date
567  **/
568 static int ad_getdate(const struct adouble *ad,
569                       unsigned int dateoff,
570                       uint32_t *date)
571 {
572         bool xlate = (dateoff & AD_DATE_UNIX);
573         char *p = NULL;
574
575         dateoff &= AD_DATE_MASK;
576         p = ad_get_entry(ad, ADEID_FILEDATESI);
577         if (p == NULL) {
578                 return -1;
579         }
580
581         if (dateoff > AD_DATE_ACCESS) {
582             return -1;
583         }
584
585         memcpy(date, p + dateoff, sizeof(uint32_t));
586
587         if (xlate) {
588                 *date = AD_DATE_TO_UNIX(*date);
589         }
590         return 0;
591 }
592
593 /**
594  * Set a date
595  **/
596 static int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
597 {
598         bool xlate = (dateoff & AD_DATE_UNIX);
599         char *p = NULL;
600
601         p = ad_get_entry(ad, ADEID_FILEDATESI);
602         if (p == NULL) {
603                 return -1;
604         }
605
606         dateoff &= AD_DATE_MASK;
607         if (xlate) {
608                 date = AD_DATE_FROM_UNIX(date);
609         }
610
611         if (dateoff > AD_DATE_ACCESS) {
612                 return -1;
613         }
614
615         memcpy(p + dateoff, &date, sizeof(date));
616
617         return 0;
618 }
619
620
621 /**
622  * Map on-disk AppleDouble id to enumerated id
623  **/
624 static uint32_t get_eid(uint32_t eid)
625 {
626         if (eid <= 15) {
627                 return eid;
628         }
629
630         switch (eid) {
631         case AD_DEV:
632                 return ADEID_PRIVDEV;
633         case AD_INO:
634                 return ADEID_PRIVINO;
635         case AD_SYN:
636                 return ADEID_PRIVSYN;
637         case AD_ID:
638                 return ADEID_PRIVID;
639         default:
640                 break;
641         }
642
643         return 0;
644 }
645
646 /**
647  * Pack AppleDouble structure into data buffer
648  **/
649 static bool ad_pack(struct adouble *ad)
650 {
651         uint32_t       eid;
652         uint16_t       nent;
653         uint32_t       bufsize;
654         uint32_t       offset = 0;
655
656         bufsize = talloc_get_size(ad->ad_data);
657         if (bufsize < AD_DATASZ_DOT_UND) {
658                 DBG_ERR("bad buffer size [0x%" PRIx32 "]\n", bufsize);
659                 return false;
660         }
661
662         if (offset + ADEDLEN_MAGIC < offset ||
663                         offset + ADEDLEN_MAGIC >= bufsize) {
664                 return false;
665         }
666         RSIVAL(ad->ad_data, offset, ad->ad_magic);
667         offset += ADEDLEN_MAGIC;
668
669         if (offset + ADEDLEN_VERSION < offset ||
670                         offset + ADEDLEN_VERSION >= bufsize) {
671                 return false;
672         }
673         RSIVAL(ad->ad_data, offset, ad->ad_version);
674         offset += ADEDLEN_VERSION;
675
676         if (offset + ADEDLEN_FILLER < offset ||
677                         offset + ADEDLEN_FILLER >= bufsize) {
678                 return false;
679         }
680         if (ad->ad_type == ADOUBLE_RSRC) {
681                 memcpy(ad->ad_data + offset, AD_FILLER_TAG, ADEDLEN_FILLER);
682         }
683         offset += ADEDLEN_FILLER;
684
685         if (offset + ADEDLEN_NENTRIES < offset ||
686                         offset + ADEDLEN_NENTRIES >= bufsize) {
687                 return false;
688         }
689         offset += ADEDLEN_NENTRIES;
690
691         for (eid = 0, nent = 0; eid < ADEID_MAX; eid++) {
692                 if (ad->ad_eid[eid].ade_off == 0) {
693                         /*
694                          * ade_off is also used as indicator whether a
695                          * specific entry is used or not
696                          */
697                         continue;
698                 }
699
700                 if (offset + AD_ENTRY_LEN_EID < offset ||
701                                 offset + AD_ENTRY_LEN_EID >= bufsize) {
702                         return false;
703                 }
704                 RSIVAL(ad->ad_data, offset, AD_EID_DISK(eid));
705                 offset += AD_ENTRY_LEN_EID;
706
707                 if (offset + AD_ENTRY_LEN_OFF < offset ||
708                                 offset + AD_ENTRY_LEN_OFF >= bufsize) {
709                         return false;
710                 }
711                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_off);
712                 offset += AD_ENTRY_LEN_OFF;
713
714                 if (offset + AD_ENTRY_LEN_LEN < offset ||
715                                 offset + AD_ENTRY_LEN_LEN >= bufsize) {
716                         return false;
717                 }
718                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_len);
719                 offset += AD_ENTRY_LEN_LEN;
720
721                 nent++;
722         }
723
724         if (ADEDOFF_NENTRIES + 2 >= bufsize) {
725                 return false;
726         }
727         RSSVAL(ad->ad_data, ADEDOFF_NENTRIES, nent);
728
729         return true;
730 }
731
732 static bool ad_unpack_xattrs(struct adouble *ad)
733 {
734         struct ad_xattr_header *h = &ad->adx_header;
735         const char *p = ad->ad_data;
736         uint32_t hoff;
737         uint32_t i;
738
739         if (ad_getentrylen(ad, ADEID_FINDERI) <= ADEDLEN_FINDERI) {
740                 return true;
741         }
742
743         /* 2 bytes padding */
744         hoff = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI + 2;
745
746         h->adx_magic       = RIVAL(p, hoff + 0);
747         h->adx_debug_tag   = RIVAL(p, hoff + 4); /* Not used -> not checked */
748         h->adx_total_size  = RIVAL(p, hoff + 8);
749         h->adx_data_start  = RIVAL(p, hoff + 12);
750         h->adx_data_length = RIVAL(p, hoff + 16);
751         h->adx_flags       = RSVAL(p, hoff + 32); /* Not used -> not checked */
752         h->adx_num_attrs   = RSVAL(p, hoff + 34);
753
754         if (h->adx_magic != AD_XATTR_HDR_MAGIC) {
755                 DBG_ERR("Bad magic: 0x%" PRIx32 "\n", h->adx_magic);
756                 return false;
757         }
758
759         if (h->adx_total_size > ad_getentryoff(ad, ADEID_RFORK)) {
760                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
761                 return false;
762         }
763         if (h->adx_total_size > AD_XATTR_MAX_HDR_SIZE) {
764                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
765                 return false;
766         }
767
768         if (h->adx_data_start < (hoff + AD_XATTR_HDR_SIZE)) {
769                 DBG_ERR("Bad start: 0x%" PRIx32 "\n", h->adx_data_start);
770                 return false;
771         }
772
773         if ((h->adx_data_start + h->adx_data_length) < h->adx_data_start) {
774                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
775                 return false;
776         }
777         if ((h->adx_data_start + h->adx_data_length) >
778             ad->adx_header.adx_total_size)
779         {
780                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
781                 return false;
782         }
783
784         if (h->adx_num_attrs > AD_XATTR_MAX_ENTRIES) {
785                 DBG_ERR("Bad num xattrs: %" PRIu16 "\n", h->adx_num_attrs);
786                 return false;
787         }
788
789         if (h->adx_num_attrs == 0) {
790                 return true;
791         }
792
793         ad->adx_entries = talloc_zero_array(
794                 ad, struct ad_xattr_entry, h->adx_num_attrs);
795         if (ad->adx_entries == NULL) {
796                 return false;
797         }
798
799         hoff += AD_XATTR_HDR_SIZE;
800
801         for (i = 0; i < h->adx_num_attrs; i++) {
802                 struct ad_xattr_entry *e = &ad->adx_entries[i];
803
804                 hoff = (hoff + 3) & ~3;
805
806                 e->adx_offset  = RIVAL(p, hoff + 0);
807                 e->adx_length  = RIVAL(p, hoff + 4);
808                 e->adx_flags   = RSVAL(p, hoff + 8);
809                 e->adx_namelen = *(p + hoff + 10);
810
811                 if (e->adx_offset >= ad->adx_header.adx_total_size) {
812                         DBG_ERR("Bad adx_offset: %" PRIx32 "\n",
813                                 e->adx_offset);
814                         return false;
815                 }
816
817                 if ((e->adx_offset + e->adx_length) < e->adx_offset) {
818                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
819                                 e->adx_length);
820                         return false;
821                 }
822
823                 if ((e->adx_offset + e->adx_length) >
824                     ad->adx_header.adx_total_size)
825                 {
826                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
827                                 e->adx_length);
828                         return false;
829                 }
830
831                 if (e->adx_namelen == 0) {
832                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
833                                 e->adx_namelen);
834                         return false;
835                 }
836                 if ((hoff + 11 + e->adx_namelen) < hoff + 11) {
837                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
838                                 e->adx_namelen);
839                         return false;
840                 }
841                 if ((hoff + 11 + e->adx_namelen) >
842                     ad->adx_header.adx_data_start)
843                 {
844                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
845                                 e->adx_namelen);
846                         return false;
847                 }
848
849                 e->adx_name = talloc_strndup(ad->adx_entries,
850                                              p + hoff + 11,
851                                              e->adx_namelen);
852                 if (e->adx_name == NULL) {
853                         return false;
854                 }
855
856                 DBG_DEBUG("xattr [%s] offset [0x%x] size [0x%x]\n",
857                           e->adx_name, e->adx_offset, e->adx_length);
858                 dump_data(10, (uint8_t *)(ad->ad_data + e->adx_offset),
859                           e->adx_length);
860
861                 hoff += 11 + e->adx_namelen;
862         }
863
864         return true;
865 }
866
867 /**
868  * Unpack an AppleDouble blob into a struct adoble
869  **/
870 static bool ad_unpack(struct adouble *ad, const size_t nentries,
871                       size_t filesize)
872 {
873         size_t bufsize = talloc_get_size(ad->ad_data);
874         size_t adentries, i;
875         uint32_t eid, len, off;
876         bool ok;
877
878         /*
879          * The size of the buffer ad->ad_data is checked when read, so
880          * we wouldn't have to check our own offsets, a few extra
881          * checks won't hurt though. We have to check the offsets we
882          * read from the buffer anyway.
883          */
884
885         if (bufsize < (AD_HEADER_LEN + (AD_ENTRY_LEN * nentries))) {
886                 DEBUG(1, ("bad size\n"));
887                 return false;
888         }
889
890         ad->ad_magic = RIVAL(ad->ad_data, 0);
891         ad->ad_version = RIVAL(ad->ad_data, ADEDOFF_VERSION);
892         if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION)) {
893                 DEBUG(1, ("wrong magic or version\n"));
894                 return false;
895         }
896
897         memcpy(ad->ad_filler, ad->ad_data + ADEDOFF_FILLER, ADEDLEN_FILLER);
898
899         adentries = RSVAL(ad->ad_data, ADEDOFF_NENTRIES);
900         if (adentries != nentries) {
901                 DEBUG(1, ("invalid number of entries: %zu\n",
902                           adentries));
903                 return false;
904         }
905
906         /* now, read in the entry bits */
907         for (i = 0; i < adentries; i++) {
908                 eid = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN));
909                 eid = get_eid(eid);
910                 off = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 4);
911                 len = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 8);
912
913                 if (!eid || eid >= ADEID_MAX) {
914                         DEBUG(1, ("bogus eid %d\n", eid));
915                         return false;
916                 }
917
918                 /*
919                  * All entries other than the resource fork are
920                  * expected to be read into the ad_data buffer, so
921                  * ensure the specified offset is within that bound
922                  */
923                 if ((off > bufsize) && (eid != ADEID_RFORK)) {
924                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
925                                   eid, off, len));
926                         return false;
927                 }
928
929                 /*
930                  * All entries besides FinderInfo and resource fork
931                  * must fit into the buffer. FinderInfo is special as
932                  * it may be larger then the default 32 bytes (if it
933                  * contains marshalled xattrs), but we will fixup that
934                  * in ad_convert(). And the resource fork is never
935                  * accessed directly by the ad_data buf (also see
936                  * comment above) anyway.
937                  */
938                 if ((eid != ADEID_RFORK) &&
939                     (eid != ADEID_FINDERI) &&
940                     ((off + len) > bufsize)) {
941                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
942                                   eid, off, len));
943                         return false;
944                 }
945
946                 /*
947                  * That would be obviously broken
948                  */
949                 if (off > filesize) {
950                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
951                                   eid, off, len));
952                         return false;
953                 }
954
955                 /*
956                  * Check for any entry that has its end beyond the
957                  * filesize.
958                  */
959                 if (off + len < off) {
960                         DEBUG(1, ("offset wrap in eid %d: off: %" PRIu32
961                                   ", len: %" PRIu32 "\n",
962                                   eid, off, len));
963                         return false;
964
965                 }
966                 if (off + len > filesize) {
967                         /*
968                          * If this is the resource fork entry, we fix
969                          * up the length, for any other entry we bail
970                          * out.
971                          */
972                         if (eid != ADEID_RFORK) {
973                                 DEBUG(1, ("bogus eid %d: off: %" PRIu32
974                                           ", len: %" PRIu32 "\n",
975                                           eid, off, len));
976                                 return false;
977                         }
978
979                         /*
980                          * Fixup the resource fork entry by limiting
981                          * the size to entryoffset - filesize.
982                          */
983                         len = filesize - off;
984                         DEBUG(1, ("Limiting ADEID_RFORK: off: %" PRIu32
985                                   ", len: %" PRIu32 "\n", off, len));
986                 }
987
988                 ad->ad_eid[eid].ade_off = off;
989                 ad->ad_eid[eid].ade_len = len;
990         }
991
992         ok = ad_unpack_xattrs(ad);
993         if (!ok) {
994                 return false;
995         }
996
997         return true;
998 }
999
1000 static bool ad_convert_move_reso(struct adouble *ad,
1001                                  const struct smb_filename *smb_fname)
1002 {
1003         char *map = MAP_FAILED;
1004         size_t maplen;
1005         ssize_t len;
1006         int rc;
1007         bool ok;
1008
1009         if (ad_getentrylen(ad, ADEID_RFORK) == 0) {
1010                 return true;
1011         }
1012
1013         maplen = ad_getentryoff(ad, ADEID_RFORK) +
1014                 ad_getentrylen(ad, ADEID_RFORK);
1015
1016         /* FIXME: direct use of mmap(), vfs_aio_fork does it too */
1017         map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED,
1018                    ad->ad_fd, 0);
1019         if (map == MAP_FAILED) {
1020                 DBG_ERR("mmap AppleDouble: %s\n", strerror(errno));
1021                 return false;
1022         }
1023
1024
1025         memmove(map + ADEDOFF_RFORK_DOT_UND,
1026                 map + ad_getentryoff(ad, ADEID_RFORK),
1027                 ad_getentrylen(ad, ADEID_RFORK));
1028
1029         rc = munmap(map, maplen);
1030         if (rc != 0) {
1031                 DBG_ERR("munmap failed: %s\n", strerror(errno));
1032                 return false;
1033         }
1034
1035         ad_setentryoff(ad, ADEID_RFORK, ADEDOFF_RFORK_DOT_UND);
1036
1037         ok = ad_pack(ad);
1038         if (!ok) {
1039                 DBG_WARNING("ad_pack [%s] failed\n", smb_fname->base_name);
1040                 return false;
1041         }
1042
1043         len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
1044         if (len != AD_DATASZ_DOT_UND) {
1045                 DBG_ERR("%s: bad size: %zd\n", smb_fname->base_name, len);
1046                 return false;
1047         }
1048
1049         return true;
1050 }
1051
1052 static bool ad_convert_xattr(struct adouble *ad,
1053                              const struct smb_filename *smb_fname,
1054                              bool *converted_xattr)
1055 {
1056         static struct char_mappings **string_replace_cmaps = NULL;
1057         char *map = MAP_FAILED;
1058         size_t maplen;
1059         uint16_t i;
1060         ssize_t len;
1061         int saved_errno = 0;
1062         NTSTATUS status;
1063         int rc;
1064         bool ok;
1065
1066         *converted_xattr = false;
1067
1068         if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) {
1069                 return true;
1070         }
1071
1072         if (string_replace_cmaps == NULL) {
1073                 const char **mappings = NULL;
1074
1075                 mappings = str_list_make_v3_const(
1076                         talloc_tos(), fruit_catia_maps, NULL);
1077                 if (mappings == NULL) {
1078                         return false;
1079                 }
1080                 string_replace_cmaps = string_replace_init_map(mappings);
1081                 TALLOC_FREE(mappings);
1082         }
1083
1084         maplen = ad_getentryoff(ad, ADEID_RFORK) +
1085                 ad_getentrylen(ad, ADEID_RFORK);
1086
1087         /* FIXME: direct use of mmap(), vfs_aio_fork does it too */
1088         map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED,
1089                    ad->ad_fd, 0);
1090         if (map == MAP_FAILED) {
1091                 DBG_ERR("mmap AppleDouble: %s\n", strerror(errno));
1092                 return false;
1093         }
1094
1095         for (i = 0; i < ad->adx_header.adx_num_attrs; i++) {
1096                 struct ad_xattr_entry *e = &ad->adx_entries[i];
1097                 char *mapped_name = NULL;
1098                 char *tmp = NULL;
1099                 struct smb_filename *stream_name = NULL;
1100                 files_struct *fsp = NULL;
1101                 ssize_t nwritten;
1102
1103                 status = string_replace_allocate(ad->ad_handle->conn,
1104                                                  e->adx_name,
1105                                                  string_replace_cmaps,
1106                                                  talloc_tos(),
1107                                                  &mapped_name,
1108                                                  vfs_translate_to_windows);
1109                 if (!NT_STATUS_IS_OK(status) &&
1110                     !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
1111                 {
1112                         DBG_ERR("string_replace_allocate failed\n");
1113                         ok = false;
1114                         goto fail;
1115                 }
1116
1117                 tmp = mapped_name;
1118                 mapped_name = talloc_asprintf(talloc_tos(), ":%s", tmp);
1119                 TALLOC_FREE(tmp);
1120                 if (mapped_name == NULL) {
1121                         ok = false;
1122                         goto fail;
1123                 }
1124
1125                 stream_name = synthetic_smb_fname(talloc_tos(),
1126                                                   smb_fname->base_name,
1127                                                   mapped_name,
1128                                                   NULL,
1129                                                   smb_fname->flags);
1130                 TALLOC_FREE(mapped_name);
1131                 if (stream_name == NULL) {
1132                         DBG_ERR("synthetic_smb_fname failed\n");
1133                         ok = false;
1134                         goto fail;
1135                 }
1136
1137                 DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
1138
1139                 status = SMB_VFS_CREATE_FILE(
1140                         ad->ad_handle->conn,            /* conn */
1141                         NULL,                           /* req */
1142                         0,                              /* root_dir_fid */
1143                         stream_name,                    /* fname */
1144                         FILE_GENERIC_WRITE,             /* access_mask */
1145                         FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1146                         FILE_OPEN_IF,                   /* create_disposition */
1147                         0,                              /* create_options */
1148                         0,                              /* file_attributes */
1149                         INTERNAL_OPEN_ONLY,             /* oplock_request */
1150                         NULL,                           /* lease */
1151                         0,                              /* allocation_size */
1152                         0,                              /* private_flags */
1153                         NULL,                           /* sd */
1154                         NULL,                           /* ea_list */
1155                         &fsp,                           /* result */
1156                         NULL,                           /* psbuf */
1157                         NULL, NULL);                    /* create context */
1158                 TALLOC_FREE(stream_name);
1159                 if (!NT_STATUS_IS_OK(status)) {
1160                         DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
1161                         ok = false;
1162                         goto fail;
1163                 }
1164
1165                 nwritten = SMB_VFS_PWRITE(fsp,
1166                                           map + e->adx_offset,
1167                                           e->adx_length,
1168                                           0);
1169                 if (nwritten == -1) {
1170                         DBG_ERR("SMB_VFS_PWRITE failed\n");
1171                         saved_errno = errno;
1172                         close_file(NULL, fsp, ERROR_CLOSE);
1173                         errno = saved_errno;
1174                         ok = false;
1175                         goto fail;
1176                 }
1177
1178                 status = close_file(NULL, fsp, NORMAL_CLOSE);
1179                 if (!NT_STATUS_IS_OK(status)) {
1180                         ok = false;
1181                         goto fail;
1182                 }
1183                 fsp = NULL;
1184         }
1185
1186         ad_setentrylen(ad, ADEID_FINDERI, ADEDLEN_FINDERI);
1187
1188         ok = ad_pack(ad);
1189         if (!ok) {
1190                 DBG_WARNING("ad_pack [%s] failed\n", smb_fname->base_name);
1191                 goto fail;
1192         }
1193
1194         len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
1195         if (len != AD_DATASZ_DOT_UND) {
1196                 DBG_ERR("%s: bad size: %zd\n", smb_fname->base_name, len);
1197                 ok = false;
1198                 goto fail;
1199         }
1200
1201         ok = ad_convert_move_reso(ad, smb_fname);
1202         if (!ok) {
1203                 goto fail;
1204         }
1205
1206         *converted_xattr = true;
1207         ok = true;
1208
1209 fail:
1210         rc = munmap(map, maplen);
1211         if (rc != 0) {
1212                 DBG_ERR("munmap failed: %s\n", strerror(errno));
1213                 return false;
1214         }
1215
1216         return ok;
1217 }
1218
1219 static bool ad_convert_finderinfo(struct adouble *ad,
1220                                   const struct smb_filename *smb_fname)
1221 {
1222         char *p_ad = NULL;
1223         AfpInfo *ai = NULL;
1224         DATA_BLOB aiblob;
1225         struct smb_filename *stream_name = NULL;
1226         files_struct *fsp = NULL;
1227         size_t size;
1228         ssize_t nwritten;
1229         NTSTATUS status;
1230         int saved_errno = 0;
1231         int cmp;
1232
1233         cmp = memcmp(ad->ad_filler, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
1234         if (cmp != 0) {
1235                 return true;
1236         }
1237
1238         p_ad = ad_get_entry(ad, ADEID_FINDERI);
1239         if (p_ad == NULL) {
1240                 return false;
1241         }
1242
1243         ai = afpinfo_new(talloc_tos());
1244         if (ai == NULL) {
1245                 return false;
1246         }
1247
1248         memcpy(ai->afpi_FinderInfo, p_ad, ADEDLEN_FINDERI);
1249
1250         aiblob = data_blob_talloc(talloc_tos(), NULL, AFP_INFO_SIZE);
1251         if (aiblob.data == NULL) {
1252                 TALLOC_FREE(ai);
1253                 return false;
1254         }
1255
1256         size = afpinfo_pack(ai, (char *)aiblob.data);
1257         TALLOC_FREE(ai);
1258         if (size != AFP_INFO_SIZE) {
1259                 return false;
1260         }
1261
1262         stream_name = synthetic_smb_fname(talloc_tos(),
1263                                           smb_fname->base_name,
1264                                           AFPINFO_STREAM,
1265                                           NULL,
1266                                           smb_fname->flags);
1267         if (stream_name == NULL) {
1268                 data_blob_free(&aiblob);
1269                 DBG_ERR("synthetic_smb_fname failed\n");
1270                 return false;
1271         }
1272
1273         DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
1274
1275         status = SMB_VFS_CREATE_FILE(
1276                 ad->ad_handle->conn,            /* conn */
1277                 NULL,                           /* req */
1278                 0,                              /* root_dir_fid */
1279                 stream_name,                    /* fname */
1280                 FILE_GENERIC_WRITE,             /* access_mask */
1281                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1282                 FILE_OPEN_IF,                   /* create_disposition */
1283                 0,                              /* create_options */
1284                 0,                              /* file_attributes */
1285                 INTERNAL_OPEN_ONLY,             /* oplock_request */
1286                 NULL,                           /* lease */
1287                 0,                              /* allocation_size */
1288                 0,                              /* private_flags */
1289                 NULL,                           /* sd */
1290                 NULL,                           /* ea_list */
1291                 &fsp,                           /* result */
1292                 NULL,                           /* psbuf */
1293                 NULL, NULL);                    /* create context */
1294         TALLOC_FREE(stream_name);
1295         if (!NT_STATUS_IS_OK(status)) {
1296                 DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
1297                 return false;
1298         }
1299
1300         nwritten = SMB_VFS_PWRITE(fsp,
1301                                   aiblob.data,
1302                                   aiblob.length,
1303                                   0);
1304         if (nwritten == -1) {
1305                 DBG_ERR("SMB_VFS_PWRITE failed\n");
1306                 saved_errno = errno;
1307                 close_file(NULL, fsp, ERROR_CLOSE);
1308                 errno = saved_errno;
1309                 return false;
1310         }
1311
1312         status = close_file(NULL, fsp, NORMAL_CLOSE);
1313         if (!NT_STATUS_IS_OK(status)) {
1314                 return false;
1315         }
1316         fsp = NULL;
1317
1318         return true;
1319 }
1320
1321 static bool ad_convert_truncate(struct adouble *ad,
1322                                 const struct smb_filename *smb_fname)
1323 {
1324         int rc;
1325
1326         /*
1327          * FIXME: direct ftruncate(), but we don't have a fsp for the
1328          * VFS call
1329          */
1330         rc = ftruncate(ad->ad_fd, ADEDOFF_RFORK_DOT_UND +
1331                        ad_getentrylen(ad, ADEID_RFORK));
1332         if (rc != 0) {
1333                 return false;
1334         }
1335
1336         return true;
1337 }
1338
1339 static bool ad_convert_blank_rfork(struct adouble *ad,
1340                                    bool *blank)
1341 {
1342         struct fruit_config_data *config = NULL;
1343         uint8_t *map = MAP_FAILED;
1344         size_t maplen;
1345         int cmp;
1346         ssize_t len;
1347         int rc;
1348         bool ok;
1349
1350         *blank = false;
1351
1352         SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config,
1353                                 struct fruit_config_data, return false);
1354
1355         if (!config->wipe_intentionally_left_blank_rfork) {
1356                 return true;
1357         }
1358
1359         if (ad_getentrylen(ad, ADEID_RFORK) != sizeof(empty_resourcefork)) {
1360                 return true;
1361         }
1362
1363         maplen = ad_getentryoff(ad, ADEID_RFORK) +
1364                 ad_getentrylen(ad, ADEID_RFORK);
1365
1366         /* FIXME: direct use of mmap(), vfs_aio_fork does it too */
1367         map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED,
1368                    ad->ad_fd, 0);
1369         if (map == MAP_FAILED) {
1370                 DBG_ERR("mmap AppleDouble: %s\n", strerror(errno));
1371                 return false;
1372         }
1373
1374         cmp = memcmp(map + ADEDOFF_RFORK_DOT_UND,
1375                      empty_resourcefork,
1376                      sizeof(empty_resourcefork));
1377         rc = munmap(map, maplen);
1378         if (rc != 0) {
1379                 DBG_ERR("munmap failed: %s\n", strerror(errno));
1380                 return false;
1381         }
1382
1383         if (cmp != 0) {
1384                 return true;
1385         }
1386
1387         ad_setentrylen(ad, ADEID_RFORK, 0);
1388
1389         ok = ad_pack(ad);
1390         if (!ok) {
1391                 return false;
1392         }
1393
1394         len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
1395         if (len != AD_DATASZ_DOT_UND) {
1396                 return false;
1397         }
1398
1399         *blank = true;
1400         return true;
1401 }
1402
1403 static bool ad_convert_delete_adfile(struct adouble *ad,
1404                                      const struct smb_filename *smb_fname)
1405 {
1406         struct fruit_config_data *config = NULL;
1407         struct smb_filename *ad_name = NULL;
1408         int rc;
1409
1410         if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
1411                 return true;
1412         }
1413
1414         SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config,
1415                                 struct fruit_config_data, return false);
1416
1417         if (!config->delete_empty_adfiles) {
1418                 return true;
1419         }
1420
1421         rc = adouble_path(talloc_tos(), smb_fname, &ad_name);
1422         if (rc != 0) {
1423                 return false;
1424         }
1425
1426         rc = SMB_VFS_NEXT_UNLINK(ad->ad_handle, ad_name);
1427         if (rc != 0) {
1428                 DBG_ERR("Unlinking [%s] failed: %s\n",
1429                         smb_fname_str_dbg(ad_name), strerror(errno));
1430                 TALLOC_FREE(ad_name);
1431                 return false;
1432         }
1433
1434         DBG_WARNING("Unlinked [%s] after conversion\n", smb_fname_str_dbg(ad_name));
1435         TALLOC_FREE(ad_name);
1436
1437         return true;
1438 }
1439
1440 /**
1441  * Convert from Apple's ._ file to Netatalk
1442  *
1443  * Apple's AppleDouble may contain a FinderInfo entry longer then 32
1444  * bytes containing packed xattrs.
1445  *
1446  * @return -1 in case an error occurred, 0 if no conversion was done, 1
1447  * otherwise
1448  **/
1449 static int ad_convert(struct adouble *ad,
1450                       const struct smb_filename *smb_fname)
1451 {
1452         bool ok;
1453         bool converted_xattr = false;
1454         bool blank;
1455
1456         ok = ad_convert_xattr(ad, smb_fname, &converted_xattr);
1457         if (!ok) {
1458                 return -1;
1459         }
1460
1461         ok = ad_convert_blank_rfork(ad, &blank);
1462         if (!ok) {
1463                 return -1;
1464         }
1465
1466         if (converted_xattr || blank) {
1467                 ok = ad_convert_truncate(ad, smb_fname);
1468                 if (!ok) {
1469                         return -1;
1470                 }
1471         }
1472
1473         ok = ad_convert_finderinfo(ad, smb_fname);
1474         if (!ok) {
1475                 DBG_ERR("Failed to convert [%s]\n",
1476                         smb_fname_str_dbg(smb_fname));
1477                 return -1;
1478         }
1479
1480         ok = ad_convert_delete_adfile(ad, smb_fname);
1481         if (!ok) {
1482                 return -1;
1483         }
1484
1485         return 0;
1486 }
1487
1488 /**
1489  * Read and parse Netatalk AppleDouble metadata xattr
1490  **/
1491 static ssize_t ad_read_meta(struct adouble *ad,
1492                                 const struct smb_filename *smb_fname)
1493 {
1494         int      rc = 0;
1495         ssize_t  ealen;
1496         bool     ok;
1497
1498         DEBUG(10, ("reading meta xattr for %s\n", smb_fname->base_name));
1499
1500         ealen = SMB_VFS_GETXATTR(ad->ad_handle->conn, smb_fname,
1501                                  AFPINFO_EA_NETATALK, ad->ad_data,
1502                                  AD_DATASZ_XATTR);
1503         if (ealen == -1) {
1504                 switch (errno) {
1505                 case ENOATTR:
1506                 case ENOENT:
1507                         if (errno == ENOATTR) {
1508                                 errno = ENOENT;
1509                         }
1510                         rc = -1;
1511                         goto exit;
1512                 default:
1513                         DEBUG(2, ("error reading meta xattr: %s\n",
1514                                   strerror(errno)));
1515                         rc = -1;
1516                         goto exit;
1517                 }
1518         }
1519         if (ealen != AD_DATASZ_XATTR) {
1520                 DEBUG(2, ("bad size %zd\n", ealen));
1521                 errno = EINVAL;
1522                 rc = -1;
1523                 goto exit;
1524         }
1525
1526         /* Now parse entries */
1527         ok = ad_unpack(ad, ADEID_NUM_XATTR, AD_DATASZ_XATTR);
1528         if (!ok) {
1529                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
1530                 errno = EINVAL;
1531                 rc = -1;
1532                 goto exit;
1533         }
1534
1535         if (!ad_getentryoff(ad, ADEID_FINDERI)
1536             || !ad_getentryoff(ad, ADEID_COMMENT)
1537             || !ad_getentryoff(ad, ADEID_FILEDATESI)
1538             || !ad_getentryoff(ad, ADEID_AFPFILEI)
1539             || !ad_getentryoff(ad, ADEID_PRIVDEV)
1540             || !ad_getentryoff(ad, ADEID_PRIVINO)
1541             || !ad_getentryoff(ad, ADEID_PRIVSYN)
1542             || !ad_getentryoff(ad, ADEID_PRIVID)) {
1543                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
1544                 errno = EINVAL;
1545                 rc = -1;
1546                 goto exit;
1547         }
1548
1549 exit:
1550         DEBUG(10, ("reading meta xattr for %s, rc: %d\n",
1551                 smb_fname->base_name, rc));
1552
1553         if (rc != 0) {
1554                 ealen = -1;
1555                 if (errno == EINVAL) {
1556                         become_root();
1557                         removexattr(smb_fname->base_name, AFPINFO_EA_NETATALK);
1558                         unbecome_root();
1559                         errno = ENOENT;
1560                 }
1561         }
1562         return ealen;
1563 }
1564
1565 static int ad_open_rsrc_xattr(const struct smb_filename *smb_fname,
1566                                 int flags,
1567                                 mode_t mode)
1568 {
1569 #ifdef HAVE_ATTROPEN
1570         /* FIXME: direct Solaris xattr syscall */
1571         return attropen(smb_fname->base_name,
1572                         AFPRESOURCE_EA_NETATALK, flags, mode);
1573 #else
1574         errno = ENOSYS;
1575         return -1;
1576 #endif
1577 }
1578
1579 static int ad_open_rsrc_adouble(const struct smb_filename *smb_fname,
1580                                 int flags,
1581                                 mode_t mode)
1582 {
1583         int ret;
1584         int fd;
1585         struct smb_filename *adp_smb_fname = NULL;
1586
1587         ret = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
1588         if (ret != 0) {
1589                 return -1;
1590         }
1591
1592         fd = open(adp_smb_fname->base_name, flags, mode);
1593         TALLOC_FREE(adp_smb_fname);
1594
1595         return fd;
1596 }
1597
1598 static int ad_open_rsrc(vfs_handle_struct *handle,
1599                         const struct smb_filename *smb_fname,
1600                         int flags,
1601                         mode_t mode)
1602 {
1603         struct fruit_config_data *config = NULL;
1604         int fd;
1605
1606         SMB_VFS_HANDLE_GET_DATA(handle, config,
1607                                 struct fruit_config_data, return -1);
1608
1609         if (config->rsrc == FRUIT_RSRC_XATTR) {
1610                 fd = ad_open_rsrc_xattr(smb_fname, flags, mode);
1611         } else {
1612                 fd = ad_open_rsrc_adouble(smb_fname, flags, mode);
1613         }
1614
1615         return fd;
1616 }
1617
1618 /*
1619  * Here's the deal: for ADOUBLE_META we can do without an fd as we can issue
1620  * path based xattr calls. For ADOUBLE_RSRC however we need a full-fledged fd
1621  * for file IO on the ._ file.
1622  */
1623 static int ad_open(vfs_handle_struct *handle,
1624                    struct adouble *ad,
1625                    files_struct *fsp,
1626                    const struct smb_filename *smb_fname,
1627                    int flags,
1628                    mode_t mode)
1629 {
1630         int fd;
1631
1632         DBG_DEBUG("Path [%s] type [%s]\n", smb_fname->base_name,
1633                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
1634
1635         if (ad->ad_type == ADOUBLE_META) {
1636                 return 0;
1637         }
1638
1639         if ((fsp != NULL) && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
1640                 ad->ad_fd = fsp->fh->fd;
1641                 ad->ad_opened = false;
1642                 return 0;
1643         }
1644
1645         fd = ad_open_rsrc(handle, smb_fname, flags, mode);
1646         if (fd == -1) {
1647                 return -1;
1648         }
1649         ad->ad_opened = true;
1650         ad->ad_fd = fd;
1651
1652         DBG_DEBUG("Path [%s] type [%s] fd [%d]\n",
1653                   smb_fname->base_name,
1654                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc", fd);
1655
1656         return 0;
1657 }
1658
1659 static ssize_t ad_read_rsrc_xattr(struct adouble *ad)
1660 {
1661         int ret;
1662         SMB_STRUCT_STAT st;
1663
1664         /* FIXME: direct sys_fstat(), don't have an fsp */
1665         ret = sys_fstat(ad->ad_fd, &st,
1666                         lp_fake_directory_create_times(
1667                                 SNUM(ad->ad_handle->conn)));
1668         if (ret != 0) {
1669                 return -1;
1670         }
1671
1672         ad_setentrylen(ad, ADEID_RFORK, st.st_ex_size);
1673         return st.st_ex_size;
1674 }
1675
1676 static ssize_t ad_read_rsrc_adouble(struct adouble *ad,
1677                                 const struct smb_filename *smb_fname)
1678 {
1679         SMB_STRUCT_STAT sbuf;
1680         char *p_ad = NULL;
1681         size_t size;
1682         ssize_t len;
1683         int ret;
1684         bool ok;
1685
1686         ret = sys_fstat(ad->ad_fd, &sbuf, lp_fake_directory_create_times(
1687                                 SNUM(ad->ad_handle->conn)));
1688         if (ret != 0) {
1689                 return -1;
1690         }
1691
1692         /*
1693          * AppleDouble file header content and size, two cases:
1694          *
1695          * - without xattrs it is exactly AD_DATASZ_DOT_UND (82) bytes large
1696          * - with embedded xattrs it can be larger, up to AD_XATTR_MAX_HDR_SIZE
1697          *
1698          * Read as much as we can up to AD_XATTR_MAX_HDR_SIZE.
1699          */
1700         size = sbuf.st_ex_size;
1701         if (size > talloc_array_length(ad->ad_data)) {
1702                 if (size > AD_XATTR_MAX_HDR_SIZE) {
1703                         size = AD_XATTR_MAX_HDR_SIZE;
1704                 }
1705                 p_ad = talloc_realloc(ad, ad->ad_data, char, size);
1706                 if (p_ad == NULL) {
1707                         return -1;
1708                 }
1709                 ad->ad_data = p_ad;
1710         }
1711
1712         len = sys_pread(ad->ad_fd, ad->ad_data,
1713                         talloc_array_length(ad->ad_data), 0);
1714         if (len != talloc_array_length(ad->ad_data)) {
1715                 DBG_NOTICE("%s %s: bad size: %zd\n",
1716                            smb_fname->base_name, strerror(errno), len);
1717                 return -1;
1718         }
1719
1720         /* Now parse entries */
1721         ok = ad_unpack(ad, ADEID_NUM_DOT_UND, sbuf.st_ex_size);
1722         if (!ok) {
1723                 DBG_ERR("invalid AppleDouble resource %s\n",
1724                         smb_fname->base_name);
1725                 errno = EINVAL;
1726                 return -1;
1727         }
1728
1729         if ((ad_getentryoff(ad, ADEID_FINDERI) != ADEDOFF_FINDERI_DOT_UND)
1730             || (ad_getentrylen(ad, ADEID_FINDERI) < ADEDLEN_FINDERI)
1731             || (ad_getentryoff(ad, ADEID_RFORK) < ADEDOFF_RFORK_DOT_UND)) {
1732                 DBG_ERR("invalid AppleDouble resource %s\n",
1733                         smb_fname->base_name);
1734                 errno = EINVAL;
1735                 return -1;
1736         }
1737
1738         /*
1739          * Try to fixup AppleDouble files created by OS X with xattrs
1740          * appended to the ADEID_FINDERI entry.
1741          */
1742
1743         ret = ad_convert(ad, smb_fname);
1744         if (ret != 0) {
1745                 DBG_WARNING("Failed to convert [%s]\n", smb_fname->base_name);
1746                 return len;
1747         }
1748
1749         return len;
1750 }
1751
1752 /**
1753  * Read and parse resource fork, either ._ AppleDouble file or xattr
1754  **/
1755 static ssize_t ad_read_rsrc(struct adouble *ad,
1756                         const struct smb_filename *smb_fname)
1757 {
1758         struct fruit_config_data *config = NULL;
1759         ssize_t len;
1760
1761         SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config,
1762                                 struct fruit_config_data, return -1);
1763
1764         if (config->rsrc == FRUIT_RSRC_XATTR) {
1765                 len = ad_read_rsrc_xattr(ad);
1766         } else {
1767                 len = ad_read_rsrc_adouble(ad, smb_fname);
1768         }
1769
1770         return len;
1771 }
1772
1773 /**
1774  * Read and unpack an AppleDouble metadata xattr or resource
1775  **/
1776 static ssize_t ad_read(struct adouble *ad, const struct smb_filename *smb_fname)
1777 {
1778         switch (ad->ad_type) {
1779         case ADOUBLE_META:
1780                 return ad_read_meta(ad, smb_fname);
1781         case ADOUBLE_RSRC:
1782                 return ad_read_rsrc(ad, smb_fname);
1783         default:
1784                 return -1;
1785         }
1786 }
1787
1788 static int adouble_destructor(struct adouble *ad)
1789 {
1790         if ((ad->ad_fd != -1) && ad->ad_opened) {
1791                 close(ad->ad_fd);
1792                 ad->ad_fd = -1;
1793         }
1794         return 0;
1795 }
1796
1797 /**
1798  * Allocate a struct adouble without initialiing it
1799  *
1800  * The struct is either hang of the fsp extension context or if fsp is
1801  * NULL from ctx.
1802  *
1803  * @param[in] ctx        talloc context
1804  * @param[in] handle     vfs handle
1805  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
1806  *
1807  * @return               adouble handle
1808  **/
1809 static struct adouble *ad_alloc(TALLOC_CTX *ctx, vfs_handle_struct *handle,
1810                                 adouble_type_t type)
1811 {
1812         int rc = 0;
1813         size_t adsize = 0;
1814         struct adouble *ad;
1815         struct fruit_config_data *config;
1816
1817         SMB_VFS_HANDLE_GET_DATA(handle, config,
1818                                 struct fruit_config_data, return NULL);
1819
1820         switch (type) {
1821         case ADOUBLE_META:
1822                 adsize = AD_DATASZ_XATTR;
1823                 break;
1824         case ADOUBLE_RSRC:
1825                 if (config->rsrc == FRUIT_RSRC_ADFILE) {
1826                         adsize = AD_DATASZ_DOT_UND;
1827                 }
1828                 break;
1829         default:
1830                 return NULL;
1831         }
1832
1833         ad = talloc_zero(ctx, struct adouble);
1834         if (ad == NULL) {
1835                 rc = -1;
1836                 goto exit;
1837         }
1838
1839         if (adsize) {
1840                 ad->ad_data = talloc_zero_array(ad, char, adsize);
1841                 if (ad->ad_data == NULL) {
1842                         rc = -1;
1843                         goto exit;
1844                 }
1845         }
1846
1847         ad->ad_handle = handle;
1848         ad->ad_type = type;
1849         ad->ad_magic = AD_MAGIC;
1850         ad->ad_version = AD_VERSION;
1851         ad->ad_fd = -1;
1852
1853         talloc_set_destructor(ad, adouble_destructor);
1854
1855 exit:
1856         if (rc != 0) {
1857                 TALLOC_FREE(ad);
1858         }
1859         return ad;
1860 }
1861
1862 /**
1863  * Allocate and initialize a new struct adouble
1864  *
1865  * @param[in] ctx        talloc context
1866  * @param[in] handle     vfs handle
1867  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
1868  *
1869  * @return               adouble handle, initialized
1870  **/
1871 static struct adouble *ad_init(TALLOC_CTX *ctx, vfs_handle_struct *handle,
1872                                adouble_type_t type)
1873 {
1874         int rc = 0;
1875         const struct ad_entry_order  *eid;
1876         struct adouble *ad = NULL;
1877         struct fruit_config_data *config;
1878         time_t t = time(NULL);
1879
1880         SMB_VFS_HANDLE_GET_DATA(handle, config,
1881                                 struct fruit_config_data, return NULL);
1882
1883         switch (type) {
1884         case ADOUBLE_META:
1885                 eid = entry_order_meta_xattr;
1886                 break;
1887         case ADOUBLE_RSRC:
1888                 if (config->rsrc == FRUIT_RSRC_ADFILE) {
1889                         eid = entry_order_dot_und;
1890                 } else {
1891                         eid = entry_order_rsrc_xattr;
1892                 }
1893                 break;
1894         default:
1895                 return NULL;
1896         }
1897
1898         ad = ad_alloc(ctx, handle, type);
1899         if (ad == NULL) {
1900                 return NULL;
1901         }
1902
1903         while (eid->id) {
1904                 ad->ad_eid[eid->id].ade_off = eid->offset;
1905                 ad->ad_eid[eid->id].ade_len = eid->len;
1906                 eid++;
1907         }
1908
1909         /* put something sane in the date fields */
1910         ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, t);
1911         ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, t);
1912         ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, t);
1913         ad_setdate(ad, AD_DATE_BACKUP, htonl(AD_DATE_START));
1914
1915         if (rc != 0) {
1916                 TALLOC_FREE(ad);
1917         }
1918         return ad;
1919 }
1920
1921 static struct adouble *ad_get_internal(TALLOC_CTX *ctx,
1922                                        vfs_handle_struct *handle,
1923                                        files_struct *fsp,
1924                                        const struct smb_filename *smb_fname,
1925                                        adouble_type_t type)
1926 {
1927         int rc = 0;
1928         ssize_t len;
1929         struct adouble *ad = NULL;
1930         int mode;
1931
1932         if (fsp != NULL) {
1933                 smb_fname = fsp->base_fsp->fsp_name;
1934         }
1935
1936         DEBUG(10, ("ad_get(%s) called for %s\n",
1937                    type == ADOUBLE_META ? "meta" : "rsrc",
1938                    smb_fname->base_name));
1939
1940         ad = ad_alloc(ctx, handle, type);
1941         if (ad == NULL) {
1942                 rc = -1;
1943                 goto exit;
1944         }
1945
1946         /* Try rw first so we can use the fd in ad_convert() */
1947         mode = O_RDWR;
1948
1949         rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
1950         if (rc == -1 && ((errno == EROFS) || (errno == EACCES))) {
1951                 mode = O_RDONLY;
1952                 rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
1953         }
1954         if (rc == -1) {
1955                 DBG_DEBUG("ad_open [%s] error [%s]\n",
1956                           smb_fname->base_name, strerror(errno));
1957                 goto exit;
1958
1959         }
1960
1961         len = ad_read(ad, smb_fname);
1962         if (len == -1) {
1963                 DEBUG(10, ("error reading AppleDouble for %s\n",
1964                         smb_fname->base_name));
1965                 rc = -1;
1966                 goto exit;
1967         }
1968
1969 exit:
1970         DEBUG(10, ("ad_get(%s) for %s returning %d\n",
1971                   type == ADOUBLE_META ? "meta" : "rsrc",
1972                   smb_fname->base_name, rc));
1973
1974         if (rc != 0) {
1975                 TALLOC_FREE(ad);
1976         }
1977         return ad;
1978 }
1979
1980 /**
1981  * Return AppleDouble data for a file
1982  *
1983  * @param[in] ctx      talloc context
1984  * @param[in] handle   vfs handle
1985  * @param[in] smb_fname pathname to file or directory
1986  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
1987  *
1988  * @return             talloced struct adouble or NULL on error
1989  **/
1990 static struct adouble *ad_get(TALLOC_CTX *ctx,
1991                               vfs_handle_struct *handle,
1992                               const struct smb_filename *smb_fname,
1993                               adouble_type_t type)
1994 {
1995         return ad_get_internal(ctx, handle, NULL, smb_fname, type);
1996 }
1997
1998 /**
1999  * Return AppleDouble data for a file
2000  *
2001  * @param[in] ctx      talloc context
2002  * @param[in] handle   vfs handle
2003  * @param[in] fsp      fsp to use for IO
2004  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
2005  *
2006  * @return             talloced struct adouble or NULL on error
2007  **/
2008 static struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle,
2009                                files_struct *fsp, adouble_type_t type)
2010 {
2011         return ad_get_internal(ctx, handle, fsp, NULL, type);
2012 }
2013
2014 /**
2015  * Set AppleDouble metadata on a file or directory
2016  *
2017  * @param[in] ad      adouble handle
2018  *
2019  * @param[in] smb_fname    pathname to file or directory
2020  *
2021  * @return            status code, 0 means success
2022  **/
2023 static int ad_set(struct adouble *ad, const struct smb_filename *smb_fname)
2024 {
2025         bool ok;
2026         int ret;
2027
2028         DBG_DEBUG("Path [%s]\n", smb_fname->base_name);
2029
2030         if (ad->ad_type != ADOUBLE_META) {
2031                 DBG_ERR("ad_set on [%s] used with ADOUBLE_RSRC\n",
2032                         smb_fname->base_name);
2033                 return -1;
2034         }
2035
2036         ok = ad_pack(ad);
2037         if (!ok) {
2038                 return -1;
2039         }
2040
2041         ret = SMB_VFS_SETXATTR(ad->ad_handle->conn,
2042                                smb_fname,
2043                                AFPINFO_EA_NETATALK,
2044                                ad->ad_data,
2045                                AD_DATASZ_XATTR, 0);
2046
2047         DBG_DEBUG("Path [%s] ret [%d]\n", smb_fname->base_name, ret);
2048
2049         return ret;
2050 }
2051
2052 /**
2053  * Set AppleDouble metadata on a file or directory
2054  *
2055  * @param[in] ad      adouble handle
2056  * @param[in] fsp     file handle
2057  *
2058  * @return            status code, 0 means success
2059  **/
2060 static int ad_fset(struct adouble *ad, files_struct *fsp)
2061 {
2062         int rc = -1;
2063         ssize_t len;
2064         bool ok;
2065
2066         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
2067
2068         if ((fsp == NULL)
2069             || (fsp->fh == NULL)
2070             || (fsp->fh->fd == -1))
2071         {
2072                 smb_panic("bad fsp");
2073         }
2074
2075         ok = ad_pack(ad);
2076         if (!ok) {
2077                 return -1;
2078         }
2079
2080         switch (ad->ad_type) {
2081         case ADOUBLE_META:
2082                 rc = SMB_VFS_NEXT_SETXATTR(ad->ad_handle,
2083                                            fsp->fsp_name,
2084                                            AFPINFO_EA_NETATALK,
2085                                            ad->ad_data,
2086                                            AD_DATASZ_XATTR, 0);
2087                 break;
2088
2089         case ADOUBLE_RSRC:
2090                 len = SMB_VFS_NEXT_PWRITE(ad->ad_handle,
2091                                           fsp,
2092                                           ad->ad_data,
2093                                           AD_DATASZ_DOT_UND,
2094                                           0);
2095                 if (len != AD_DATASZ_DOT_UND) {
2096                         DBG_ERR("short write on %s: %zd", fsp_str_dbg(fsp), len);
2097                         return -1;
2098                 }
2099                 rc = 0;
2100                 break;
2101
2102         default:
2103                 return -1;
2104         }
2105
2106         DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc);
2107
2108         return rc;
2109 }
2110
2111 /*****************************************************************************
2112  * Helper functions
2113  *****************************************************************************/
2114
2115 static bool is_afpinfo_stream(const struct smb_filename *smb_fname)
2116 {
2117         if (strncasecmp_m(smb_fname->stream_name,
2118                           AFPINFO_STREAM_NAME,
2119                           strlen(AFPINFO_STREAM_NAME)) == 0) {
2120                 return true;
2121         }
2122         return false;
2123 }
2124
2125 static bool is_afpresource_stream(const struct smb_filename *smb_fname)
2126 {
2127         if (strncasecmp_m(smb_fname->stream_name,
2128                           AFPRESOURCE_STREAM_NAME,
2129                           strlen(AFPRESOURCE_STREAM_NAME)) == 0) {
2130                 return true;
2131         }
2132         return false;
2133 }
2134
2135 /**
2136  * Test whether stream is an Apple stream, not used atm
2137  **/
2138 #if 0
2139 static bool is_apple_stream(const struct smb_filename *smb_fname)
2140 {
2141         if (is_afpinfo_stream(smb_fname)) {
2142                 return true;
2143         }
2144         if (is_afpresource_stream(smb_fname)) {
2145                 return true;
2146         }
2147         return false;
2148 }
2149 #endif
2150
2151 /**
2152  * Initialize config struct from our smb.conf config parameters
2153  **/
2154 static int init_fruit_config(vfs_handle_struct *handle)
2155 {
2156         struct fruit_config_data *config;
2157         int enumval;
2158         const char *tm_size_str = NULL;
2159
2160         config = talloc_zero(handle->conn, struct fruit_config_data);
2161         if (!config) {
2162                 DEBUG(1, ("talloc_zero() failed\n"));
2163                 errno = ENOMEM;
2164                 return -1;
2165         }
2166
2167         /*
2168          * Versions up to Samba 4.5.x had a spelling bug in the
2169          * fruit:resource option calling lp_parm_enum with
2170          * "res*s*ource" (ie two s).
2171          *
2172          * In Samba 4.6 we accept both the wrong and the correct
2173          * spelling, in Samba 4.7 the bad spelling will be removed.
2174          */
2175         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2176                                "ressource", fruit_rsrc, FRUIT_RSRC_ADFILE);
2177         if (enumval == -1) {
2178                 DEBUG(1, ("value for %s: resource type unknown\n",
2179                           FRUIT_PARAM_TYPE_NAME));
2180                 return -1;
2181         }
2182         config->rsrc = (enum fruit_rsrc)enumval;
2183
2184         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2185                                "resource", fruit_rsrc, enumval);
2186         if (enumval == -1) {
2187                 DEBUG(1, ("value for %s: resource type unknown\n",
2188                           FRUIT_PARAM_TYPE_NAME));
2189                 return -1;
2190         }
2191         config->rsrc = (enum fruit_rsrc)enumval;
2192
2193         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2194                                "metadata", fruit_meta, FRUIT_META_NETATALK);
2195         if (enumval == -1) {
2196                 DEBUG(1, ("value for %s: metadata type unknown\n",
2197                           FRUIT_PARAM_TYPE_NAME));
2198                 return -1;
2199         }
2200         config->meta = (enum fruit_meta)enumval;
2201
2202         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2203                                "locking", fruit_locking, FRUIT_LOCKING_NONE);
2204         if (enumval == -1) {
2205                 DEBUG(1, ("value for %s: locking type unknown\n",
2206                           FRUIT_PARAM_TYPE_NAME));
2207                 return -1;
2208         }
2209         config->locking = (enum fruit_locking)enumval;
2210
2211         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2212                                "encoding", fruit_encoding, FRUIT_ENC_PRIVATE);
2213         if (enumval == -1) {
2214                 DEBUG(1, ("value for %s: encoding type unknown\n",
2215                           FRUIT_PARAM_TYPE_NAME));
2216                 return -1;
2217         }
2218         config->encoding = (enum fruit_encoding)enumval;
2219
2220         if (config->rsrc == FRUIT_RSRC_ADFILE) {
2221                 config->veto_appledouble = lp_parm_bool(SNUM(handle->conn),
2222                                                         FRUIT_PARAM_TYPE_NAME,
2223                                                         "veto_appledouble",
2224                                                         true);
2225         }
2226
2227         config->use_aapl = lp_parm_bool(
2228                 -1, FRUIT_PARAM_TYPE_NAME, "aapl", true);
2229
2230         config->time_machine = lp_parm_bool(
2231                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "time machine", false);
2232
2233         config->unix_info_enabled = lp_parm_bool(
2234                 -1, FRUIT_PARAM_TYPE_NAME, "nfs_aces", true);
2235
2236         config->use_copyfile = lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME,
2237                                            "copyfile", false);
2238
2239         config->posix_rename = lp_parm_bool(
2240                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "posix_rename", true);
2241
2242         config->aapl_zero_file_id =
2243             lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME, "zero_file_id", true);
2244
2245         config->readdir_attr_rsize = lp_parm_bool(
2246                 SNUM(handle->conn), "readdir_attr", "aapl_rsize", true);
2247
2248         config->readdir_attr_finder_info = lp_parm_bool(
2249                 SNUM(handle->conn), "readdir_attr", "aapl_finder_info", true);
2250
2251         config->readdir_attr_max_access = lp_parm_bool(
2252                 SNUM(handle->conn), "readdir_attr", "aapl_max_access", true);
2253
2254         config->model = lp_parm_const_string(
2255                 -1, FRUIT_PARAM_TYPE_NAME, "model", "MacSamba");
2256
2257         tm_size_str = lp_parm_const_string(
2258                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2259                 "time machine max size", NULL);
2260         if (tm_size_str != NULL) {
2261                 config->time_machine_max_size = conv_str_size(tm_size_str);
2262         }
2263
2264         config->wipe_intentionally_left_blank_rfork = lp_parm_bool(
2265                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2266                 "wipe_intentionally_left_blank_rfork", false);
2267
2268         config->delete_empty_adfiles = lp_parm_bool(
2269                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
2270                 "delete_empty_adfiles", false);
2271
2272         SMB_VFS_HANDLE_SET_DATA(handle, config,
2273                                 NULL, struct fruit_config_data,
2274                                 return -1);
2275
2276         return 0;
2277 }
2278
2279 /**
2280  * Prepend "._" to a basename
2281  * Return a new struct smb_filename with stream_name == NULL.
2282  **/
2283 static int adouble_path(TALLOC_CTX *ctx,
2284                         const struct smb_filename *smb_fname_in,
2285                         struct smb_filename **pp_smb_fname_out)
2286 {
2287         char *parent;
2288         const char *base;
2289         struct smb_filename *smb_fname = cp_smb_filename(ctx,
2290                                                 smb_fname_in);
2291
2292         if (smb_fname == NULL) {
2293                 return -1;
2294         }
2295
2296         /* We need streamname to be NULL */
2297         TALLOC_FREE(smb_fname->stream_name);
2298
2299         /* And we're replacing base_name. */
2300         TALLOC_FREE(smb_fname->base_name);
2301
2302         if (!parent_dirname(smb_fname, smb_fname_in->base_name,
2303                                 &parent, &base)) {
2304                 TALLOC_FREE(smb_fname);
2305                 return -1;
2306         }
2307
2308         smb_fname->base_name = talloc_asprintf(smb_fname,
2309                                         "%s/._%s", parent, base);
2310         if (smb_fname->base_name == NULL) {
2311                 TALLOC_FREE(smb_fname);
2312                 return -1;
2313         }
2314
2315         *pp_smb_fname_out = smb_fname;
2316
2317         return 0;
2318 }
2319
2320 /**
2321  * Allocate and initialize an AfpInfo struct
2322  **/
2323 static AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
2324 {
2325         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
2326         if (ai == NULL) {
2327                 return NULL;
2328         }
2329         ai->afpi_Signature = AFP_Signature;
2330         ai->afpi_Version = AFP_Version;
2331         ai->afpi_BackupTime = AD_DATE_START;
2332         return ai;
2333 }
2334
2335 /**
2336  * Pack an AfpInfo struct into a buffer
2337  *
2338  * Buffer size must be at least AFP_INFO_SIZE
2339  * Returns size of packed buffer
2340  **/
2341 static ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
2342 {
2343         memset(buf, 0, AFP_INFO_SIZE);
2344
2345         RSIVAL(buf, 0, ai->afpi_Signature);
2346         RSIVAL(buf, 4, ai->afpi_Version);
2347         RSIVAL(buf, 12, ai->afpi_BackupTime);
2348         memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
2349
2350         return AFP_INFO_SIZE;
2351 }
2352
2353 /**
2354  * Unpack a buffer into a AfpInfo structure
2355  *
2356  * Buffer size must be at least AFP_INFO_SIZE
2357  * Returns allocated AfpInfo struct
2358  **/
2359 static AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data)
2360 {
2361         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
2362         if (ai == NULL) {
2363                 return NULL;
2364         }
2365
2366         ai->afpi_Signature = RIVAL(data, 0);
2367         ai->afpi_Version = RIVAL(data, 4);
2368         ai->afpi_BackupTime = RIVAL(data, 12);
2369         memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
2370                sizeof(ai->afpi_FinderInfo));
2371
2372         if (ai->afpi_Signature != AFP_Signature
2373             || ai->afpi_Version != AFP_Version) {
2374                 DEBUG(1, ("Bad AfpInfo signature or version\n"));
2375                 TALLOC_FREE(ai);
2376         }
2377
2378         return ai;
2379 }
2380
2381 /**
2382  * Fake an inode number from the md5 hash of the (xattr) name
2383  **/
2384 static SMB_INO_T fruit_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
2385 {
2386         MD5_CTX ctx;
2387         unsigned char hash[16];
2388         SMB_INO_T result;
2389         char *upper_sname;
2390
2391         DBG_DEBUG("fruit_inode called for %ju/%ju [%s]\n",
2392                   (uintmax_t)sbuf->st_ex_dev,
2393                   (uintmax_t)sbuf->st_ex_ino, sname);
2394
2395         upper_sname = talloc_strdup_upper(talloc_tos(), sname);
2396         SMB_ASSERT(upper_sname != NULL);
2397
2398         MD5Init(&ctx);
2399         MD5Update(&ctx, (const unsigned char *)&(sbuf->st_ex_dev),
2400                   sizeof(sbuf->st_ex_dev));
2401         MD5Update(&ctx, (const unsigned char *)&(sbuf->st_ex_ino),
2402                   sizeof(sbuf->st_ex_ino));
2403         MD5Update(&ctx, (unsigned char *)upper_sname,
2404                   talloc_get_size(upper_sname)-1);
2405         MD5Final(hash, &ctx);
2406
2407         TALLOC_FREE(upper_sname);
2408
2409         /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
2410         memcpy(&result, hash, sizeof(result));
2411
2412         DBG_DEBUG("fruit_inode \"%s\": ino=%ju\n",
2413                   sname, (uintmax_t)result);
2414
2415         return result;
2416 }
2417
2418 static bool add_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
2419                              struct stream_struct **streams,
2420                              const char *name, off_t size,
2421                              off_t alloc_size)
2422 {
2423         struct stream_struct *tmp;
2424
2425         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
2426                              (*num_streams)+1);
2427         if (tmp == NULL) {
2428                 return false;
2429         }
2430
2431         tmp[*num_streams].name = talloc_asprintf(tmp, "%s:$DATA", name);
2432         if (tmp[*num_streams].name == NULL) {
2433                 return false;
2434         }
2435
2436         tmp[*num_streams].size = size;
2437         tmp[*num_streams].alloc_size = alloc_size;
2438
2439         *streams = tmp;
2440         *num_streams += 1;
2441         return true;
2442 }
2443
2444 static bool filter_empty_rsrc_stream(unsigned int *num_streams,
2445                                      struct stream_struct **streams)
2446 {
2447         struct stream_struct *tmp = *streams;
2448         unsigned int i;
2449
2450         if (*num_streams == 0) {
2451                 return true;
2452         }
2453
2454         for (i = 0; i < *num_streams; i++) {
2455                 if (strequal_m(tmp[i].name, AFPRESOURCE_STREAM)) {
2456                         break;
2457                 }
2458         }
2459
2460         if (i == *num_streams) {
2461                 return true;
2462         }
2463
2464         if (tmp[i].size > 0) {
2465                 return true;
2466         }
2467
2468         TALLOC_FREE(tmp[i].name);
2469         if (*num_streams - 1 > i) {
2470                 memmove(&tmp[i], &tmp[i+1],
2471                         (*num_streams - i - 1) * sizeof(struct stream_struct));
2472         }
2473
2474         *num_streams -= 1;
2475         return true;
2476 }
2477
2478 static bool del_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
2479                              struct stream_struct **streams,
2480                              const char *name)
2481 {
2482         struct stream_struct *tmp = *streams;
2483         unsigned int i;
2484
2485         if (*num_streams == 0) {
2486                 return true;
2487         }
2488
2489         for (i = 0; i < *num_streams; i++) {
2490                 if (strequal_m(tmp[i].name, name)) {
2491                         break;
2492                 }
2493         }
2494
2495         if (i == *num_streams) {
2496                 return true;
2497         }
2498
2499         TALLOC_FREE(tmp[i].name);
2500         if (*num_streams - 1 > i) {
2501                 memmove(&tmp[i], &tmp[i+1],
2502                         (*num_streams - i - 1) * sizeof(struct stream_struct));
2503         }
2504
2505         *num_streams -= 1;
2506         return true;
2507 }
2508
2509 static bool ad_empty_finderinfo(const struct adouble *ad)
2510 {
2511         int cmp;
2512         char emptybuf[ADEDLEN_FINDERI] = {0};
2513         char *fi = NULL;
2514
2515         fi = ad_get_entry(ad, ADEID_FINDERI);
2516         if (fi == NULL) {
2517                 DBG_ERR("Missing FinderInfo in struct adouble [%p]\n", ad);
2518                 return false;
2519         }
2520
2521         cmp = memcmp(emptybuf, fi, ADEDLEN_FINDERI);
2522         return (cmp == 0);
2523 }
2524
2525 static bool ai_empty_finderinfo(const AfpInfo *ai)
2526 {
2527         int cmp;
2528         char emptybuf[ADEDLEN_FINDERI] = {0};
2529
2530         cmp = memcmp(emptybuf, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI);
2531         return (cmp == 0);
2532 }
2533
2534 /**
2535  * Update btime with btime from Netatalk
2536  **/
2537 static void update_btime(vfs_handle_struct *handle,
2538                          struct smb_filename *smb_fname)
2539 {
2540         uint32_t t;
2541         struct timespec creation_time = {0};
2542         struct adouble *ad;
2543         struct fruit_config_data *config = NULL;
2544
2545         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
2546                                 return);
2547
2548         switch (config->meta) {
2549         case FRUIT_META_STREAM:
2550                 return;
2551         case FRUIT_META_NETATALK:
2552                 /* Handled below */
2553                 break;
2554         default:
2555                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
2556                 return;
2557         }
2558
2559         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
2560         if (ad == NULL) {
2561                 return;
2562         }
2563         if (ad_getdate(ad, AD_DATE_UNIX | AD_DATE_CREATE, &t) != 0) {
2564                 TALLOC_FREE(ad);
2565                 return;
2566         }
2567         TALLOC_FREE(ad);
2568
2569         creation_time.tv_sec = convert_uint32_t_to_time_t(t);
2570         update_stat_ex_create_time(&smb_fname->st, creation_time);
2571
2572         return;
2573 }
2574
2575 /**
2576  * Map an access mask to a Netatalk single byte byte range lock
2577  **/
2578 static off_t access_to_netatalk_brl(enum apple_fork fork_type,
2579                                     uint32_t access_mask)
2580 {
2581         off_t offset;
2582
2583         switch (access_mask) {
2584         case FILE_READ_DATA:
2585                 offset = AD_FILELOCK_OPEN_RD;
2586                 break;
2587
2588         case FILE_WRITE_DATA:
2589         case FILE_APPEND_DATA:
2590                 offset = AD_FILELOCK_OPEN_WR;
2591                 break;
2592
2593         default:
2594                 offset = AD_FILELOCK_OPEN_NONE;
2595                 break;
2596         }
2597
2598         if (fork_type == APPLE_FORK_RSRC) {
2599                 if (offset == AD_FILELOCK_OPEN_NONE) {
2600                         offset = AD_FILELOCK_RSRC_OPEN_NONE;
2601                 } else {
2602                         offset += 2;
2603                 }
2604         }
2605
2606         return offset;
2607 }
2608
2609 /**
2610  * Map a deny mode to a Netatalk brl
2611  **/
2612 static off_t denymode_to_netatalk_brl(enum apple_fork fork_type,
2613                                       uint32_t deny_mode)
2614 {
2615         off_t offset = 0;
2616
2617         switch (deny_mode) {
2618         case DENY_READ:
2619                 offset = AD_FILELOCK_DENY_RD;
2620                 break;
2621
2622         case DENY_WRITE:
2623                 offset = AD_FILELOCK_DENY_WR;
2624                 break;
2625
2626         default:
2627                 smb_panic("denymode_to_netatalk_brl: bad deny mode\n");
2628         }
2629
2630         if (fork_type == APPLE_FORK_RSRC) {
2631                 offset += 2;
2632         }
2633
2634         return offset;
2635 }
2636
2637 /**
2638  * Call fcntl() with an exclusive F_GETLK request in order to
2639  * determine if there's an exisiting shared lock
2640  *
2641  * @return true if the requested lock was found or any error occurred
2642  *         false if the lock was not found
2643  **/
2644 static bool test_netatalk_lock(files_struct *fsp, off_t in_offset)
2645 {
2646         bool result;
2647         off_t offset = in_offset;
2648         off_t len = 1;
2649         int type = F_WRLCK;
2650         pid_t pid = 0;
2651
2652         result = SMB_VFS_GETLOCK(fsp, &offset, &len, &type, &pid);
2653         if (result == false) {
2654                 return true;
2655         }
2656
2657         if (type != F_UNLCK) {
2658                 return true;
2659         }
2660
2661         return false;
2662 }
2663
2664 static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
2665                                    files_struct *fsp,
2666                                    uint32_t access_mask,
2667                                    uint32_t share_mode)
2668 {
2669         NTSTATUS status = NT_STATUS_OK;
2670         off_t off;
2671         bool share_for_read = (share_mode & FILE_SHARE_READ);
2672         bool share_for_write = (share_mode & FILE_SHARE_WRITE);
2673         bool netatalk_already_open_for_reading = false;
2674         bool netatalk_already_open_for_writing = false;
2675         bool netatalk_already_open_with_deny_read = false;
2676         bool netatalk_already_open_with_deny_write = false;
2677
2678         /* FIXME: hardcoded data fork, add resource fork */
2679         enum apple_fork fork_type = APPLE_FORK_DATA;
2680
2681         DBG_DEBUG("fruit_check_access: %s, am: %s/%s, sm: 0x%x\n",
2682                   fsp_str_dbg(fsp),
2683                   access_mask & FILE_READ_DATA ? "READ" :"-",
2684                   access_mask & FILE_WRITE_DATA ? "WRITE" : "-",
2685                   share_mode);
2686
2687         if (fsp->fh->fd == -1) {
2688                 return NT_STATUS_OK;
2689         }
2690
2691         /* Read NetATalk opens and deny modes on the file. */
2692         netatalk_already_open_for_reading = test_netatalk_lock(fsp,
2693                                 access_to_netatalk_brl(fork_type,
2694                                         FILE_READ_DATA));
2695
2696         netatalk_already_open_with_deny_read = test_netatalk_lock(fsp,
2697                                 denymode_to_netatalk_brl(fork_type,
2698                                         DENY_READ));
2699
2700         netatalk_already_open_for_writing = test_netatalk_lock(fsp,
2701                                 access_to_netatalk_brl(fork_type,
2702                                         FILE_WRITE_DATA));
2703
2704         netatalk_already_open_with_deny_write = test_netatalk_lock(fsp,
2705                                 denymode_to_netatalk_brl(fork_type,
2706                                         DENY_WRITE));
2707
2708         /* If there are any conflicts - sharing violation. */
2709         if ((access_mask & FILE_READ_DATA) &&
2710                         netatalk_already_open_with_deny_read) {
2711                 return NT_STATUS_SHARING_VIOLATION;
2712         }
2713
2714         if (!share_for_read &&
2715                         netatalk_already_open_for_reading) {
2716                 return NT_STATUS_SHARING_VIOLATION;
2717         }
2718
2719         if ((access_mask & FILE_WRITE_DATA) &&
2720                         netatalk_already_open_with_deny_write) {
2721                 return NT_STATUS_SHARING_VIOLATION;
2722         }
2723
2724         if (!share_for_write &&
2725                         netatalk_already_open_for_writing) {
2726                 return NT_STATUS_SHARING_VIOLATION;
2727         }
2728
2729         if (!(access_mask & FILE_READ_DATA)) {
2730                 /*
2731                  * Nothing we can do here, we need read access
2732                  * to set locks.
2733                  */
2734                 return NT_STATUS_OK;
2735         }
2736
2737         /* Set NetAtalk locks matching our access */
2738         if (access_mask & FILE_READ_DATA) {
2739                 struct byte_range_lock *br_lck = NULL;
2740
2741                 off = access_to_netatalk_brl(fork_type, FILE_READ_DATA);
2742                 br_lck = do_lock(
2743                         handle->conn->sconn->msg_ctx, fsp,
2744                         fsp->op->global->open_persistent_id, 1, off,
2745                         READ_LOCK, POSIX_LOCK, false,
2746                         &status, NULL);
2747
2748                 TALLOC_FREE(br_lck);
2749
2750                 if (!NT_STATUS_IS_OK(status))  {
2751                         return status;
2752                 }
2753         }
2754
2755         if (!share_for_read) {
2756                 struct byte_range_lock *br_lck = NULL;
2757
2758                 off = denymode_to_netatalk_brl(fork_type, DENY_READ);
2759                 br_lck = do_lock(
2760                         handle->conn->sconn->msg_ctx, fsp,
2761                         fsp->op->global->open_persistent_id, 1, off,
2762                         READ_LOCK, POSIX_LOCK, false,
2763                         &status, NULL);
2764
2765                 TALLOC_FREE(br_lck);
2766
2767                 if (!NT_STATUS_IS_OK(status)) {
2768                         return status;
2769                 }
2770         }
2771
2772         if (access_mask & FILE_WRITE_DATA) {
2773                 struct byte_range_lock *br_lck = NULL;
2774
2775                 off = access_to_netatalk_brl(fork_type, FILE_WRITE_DATA);
2776                 br_lck = do_lock(
2777                         handle->conn->sconn->msg_ctx, fsp,
2778                         fsp->op->global->open_persistent_id, 1, off,
2779                         READ_LOCK, POSIX_LOCK, false,
2780                         &status, NULL);
2781
2782                 TALLOC_FREE(br_lck);
2783
2784                 if (!NT_STATUS_IS_OK(status)) {
2785                         return status;
2786                 }
2787         }
2788
2789         if (!share_for_write) {
2790                 struct byte_range_lock *br_lck = NULL;
2791
2792                 off = denymode_to_netatalk_brl(fork_type, DENY_WRITE);
2793                 br_lck = do_lock(
2794                         handle->conn->sconn->msg_ctx, fsp,
2795                         fsp->op->global->open_persistent_id, 1, off,
2796                         READ_LOCK, POSIX_LOCK, false,
2797                         &status, NULL);
2798
2799                 TALLOC_FREE(br_lck);
2800
2801                 if (!NT_STATUS_IS_OK(status)) {
2802                         return status;
2803                 }
2804         }
2805
2806         return NT_STATUS_OK;
2807 }
2808
2809 static NTSTATUS check_aapl(vfs_handle_struct *handle,
2810                            struct smb_request *req,
2811                            const struct smb2_create_blobs *in_context_blobs,
2812                            struct smb2_create_blobs *out_context_blobs)
2813 {
2814         struct fruit_config_data *config;
2815         NTSTATUS status;
2816         struct smb2_create_blob *aapl = NULL;
2817         uint32_t cmd;
2818         bool ok;
2819         uint8_t p[16];
2820         DATA_BLOB blob = data_blob_talloc(req, NULL, 0);
2821         uint64_t req_bitmap, client_caps;
2822         uint64_t server_caps = SMB2_CRTCTX_AAPL_UNIX_BASED;
2823         smb_ucs2_t *model;
2824         size_t modellen;
2825
2826         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
2827                                 return NT_STATUS_UNSUCCESSFUL);
2828
2829         if (!config->use_aapl
2830             || in_context_blobs == NULL
2831             || out_context_blobs == NULL) {
2832                 return NT_STATUS_OK;
2833         }
2834
2835         aapl = smb2_create_blob_find(in_context_blobs,
2836                                      SMB2_CREATE_TAG_AAPL);
2837         if (aapl == NULL) {
2838                 return NT_STATUS_OK;
2839         }
2840
2841         if (aapl->data.length != 24) {
2842                 DEBUG(1, ("unexpected AAPL ctxt length: %ju\n",
2843                           (uintmax_t)aapl->data.length));
2844                 return NT_STATUS_INVALID_PARAMETER;
2845         }
2846
2847         cmd = IVAL(aapl->data.data, 0);
2848         if (cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) {
2849                 DEBUG(1, ("unsupported AAPL cmd: %d\n", cmd));
2850                 return NT_STATUS_INVALID_PARAMETER;
2851         }
2852
2853         req_bitmap = BVAL(aapl->data.data, 8);
2854         client_caps = BVAL(aapl->data.data, 16);
2855
2856         SIVAL(p, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
2857         SIVAL(p, 4, 0);
2858         SBVAL(p, 8, req_bitmap);
2859         ok = data_blob_append(req, &blob, p, 16);
2860         if (!ok) {
2861                 return NT_STATUS_UNSUCCESSFUL;
2862         }
2863
2864         if (req_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS) {
2865                 if ((client_caps & SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR) &&
2866                     (handle->conn->tcon->compat->fs_capabilities & FILE_NAMED_STREAMS)) {
2867                         server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR;
2868                         config->readdir_attr_enabled = true;
2869                 }
2870
2871                 if (config->use_copyfile) {
2872                         server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE;
2873                         config->copyfile_enabled = true;
2874                 }
2875
2876                 /*
2877                  * The client doesn't set the flag, so we can't check
2878                  * for it and just set it unconditionally
2879                  */
2880                 if (config->unix_info_enabled) {
2881                         server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE;
2882                 }
2883
2884                 SBVAL(p, 0, server_caps);
2885                 ok = data_blob_append(req, &blob, p, 8);
2886                 if (!ok) {
2887                         return NT_STATUS_UNSUCCESSFUL;
2888                 }
2889         }
2890
2891         if (req_bitmap & SMB2_CRTCTX_AAPL_VOLUME_CAPS) {
2892                 int val = lp_case_sensitive(SNUM(handle->conn->tcon->compat));
2893                 uint64_t caps = 0;
2894
2895                 switch (val) {
2896                 case Auto:
2897                         break;
2898
2899                 case True:
2900                         caps |= SMB2_CRTCTX_AAPL_CASE_SENSITIVE;
2901                         break;
2902
2903                 default:
2904                         break;
2905                 }
2906
2907                 if (config->time_machine) {
2908                         caps |= SMB2_CRTCTX_AAPL_FULL_SYNC;
2909                 }
2910
2911                 SBVAL(p, 0, caps);
2912
2913                 ok = data_blob_append(req, &blob, p, 8);
2914                 if (!ok) {
2915                         return NT_STATUS_UNSUCCESSFUL;
2916                 }
2917         }
2918
2919         if (req_bitmap & SMB2_CRTCTX_AAPL_MODEL_INFO) {
2920                 ok = convert_string_talloc(req,
2921                                            CH_UNIX, CH_UTF16LE,
2922                                            config->model, strlen(config->model),
2923                                            &model, &modellen);
2924                 if (!ok) {
2925                         return NT_STATUS_UNSUCCESSFUL;
2926                 }
2927
2928                 SIVAL(p, 0, 0);
2929                 SIVAL(p + 4, 0, modellen);
2930                 ok = data_blob_append(req, &blob, p, 8);
2931                 if (!ok) {
2932                         talloc_free(model);
2933                         return NT_STATUS_UNSUCCESSFUL;
2934                 }
2935
2936                 ok = data_blob_append(req, &blob, model, modellen);
2937                 talloc_free(model);
2938                 if (!ok) {
2939                         return NT_STATUS_UNSUCCESSFUL;
2940                 }
2941         }
2942
2943         status = smb2_create_blob_add(out_context_blobs,
2944                                       out_context_blobs,
2945                                       SMB2_CREATE_TAG_AAPL,
2946                                       blob);
2947         if (NT_STATUS_IS_OK(status)) {
2948                 global_fruit_config.nego_aapl = true;
2949                 if (config->aapl_zero_file_id) {
2950                         aapl_force_zero_file_id(handle->conn->sconn);
2951                 }
2952         }
2953
2954         return status;
2955 }
2956
2957 static bool readdir_attr_meta_finderi_stream(
2958         struct vfs_handle_struct *handle,
2959         const struct smb_filename *smb_fname,
2960         AfpInfo *ai)
2961 {
2962         struct smb_filename *stream_name = NULL;
2963         files_struct *fsp = NULL;
2964         ssize_t nread;
2965         NTSTATUS status;
2966         int ret;
2967         bool ok;
2968         uint8_t buf[AFP_INFO_SIZE];
2969
2970         stream_name = synthetic_smb_fname(talloc_tos(),
2971                                           smb_fname->base_name,
2972                                           AFPINFO_STREAM_NAME,
2973                                           NULL, smb_fname->flags);
2974         if (stream_name == NULL) {
2975                 return false;
2976         }
2977
2978         ret = SMB_VFS_STAT(handle->conn, stream_name);
2979         if (ret != 0) {
2980                 return false;
2981         }
2982
2983         status = SMB_VFS_CREATE_FILE(
2984                 handle->conn,                           /* conn */
2985                 NULL,                                   /* req */
2986                 0,                                      /* root_dir_fid */
2987                 stream_name,                            /* fname */
2988                 FILE_READ_DATA,                         /* access_mask */
2989                 (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
2990                         FILE_SHARE_DELETE),
2991                 FILE_OPEN,                              /* create_disposition*/
2992                 0,                                      /* create_options */
2993                 0,                                      /* file_attributes */
2994                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
2995                 NULL,                                   /* lease */
2996                 0,                                      /* allocation_size */
2997                 0,                                      /* private_flags */
2998                 NULL,                                   /* sd */
2999                 NULL,                                   /* ea_list */
3000                 &fsp,                                   /* result */
3001                 NULL,                                   /* pinfo */
3002                 NULL, NULL);                            /* create context */
3003
3004         TALLOC_FREE(stream_name);
3005
3006         if (!NT_STATUS_IS_OK(status)) {
3007                 return false;
3008         }
3009
3010         nread = SMB_VFS_PREAD(fsp, &buf[0], AFP_INFO_SIZE, 0);
3011         if (nread != AFP_INFO_SIZE) {
3012                 DBG_ERR("short read [%s] [%zd/%d]\n",
3013                         smb_fname_str_dbg(stream_name), nread, AFP_INFO_SIZE);
3014                 ok = false;
3015                 goto fail;
3016         }
3017
3018         memcpy(&ai->afpi_FinderInfo[0], &buf[AFP_OFF_FinderInfo],
3019                AFP_FinderSize);
3020
3021         ok = true;
3022
3023 fail:
3024         if (fsp != NULL) {
3025                 close_file(NULL, fsp, NORMAL_CLOSE);
3026         }
3027
3028         return ok;
3029 }
3030
3031 static bool readdir_attr_meta_finderi_netatalk(
3032         struct vfs_handle_struct *handle,
3033         const struct smb_filename *smb_fname,
3034         AfpInfo *ai)
3035 {
3036         struct adouble *ad = NULL;
3037         char *p = NULL;
3038
3039         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
3040         if (ad == NULL) {
3041                 return false;
3042         }
3043
3044         p = ad_get_entry(ad, ADEID_FINDERI);
3045         if (p == NULL) {
3046                 DBG_ERR("No ADEID_FINDERI for [%s]\n", smb_fname->base_name);
3047                 TALLOC_FREE(ad);
3048                 return false;
3049         }
3050
3051         memcpy(&ai->afpi_FinderInfo[0], p, AFP_FinderSize);
3052         TALLOC_FREE(ad);
3053         return true;
3054 }
3055
3056 static bool readdir_attr_meta_finderi(struct vfs_handle_struct *handle,
3057                                       const struct smb_filename *smb_fname,
3058                                       struct readdir_attr_data *attr_data)
3059 {
3060         struct fruit_config_data *config = NULL;
3061         uint32_t date_added;
3062         AfpInfo ai = {0};
3063         bool ok;
3064
3065         SMB_VFS_HANDLE_GET_DATA(handle, config,
3066                                 struct fruit_config_data,
3067                                 return false);
3068
3069         switch (config->meta) {
3070         case FRUIT_META_NETATALK:
3071                 ok = readdir_attr_meta_finderi_netatalk(
3072                         handle, smb_fname, &ai);
3073                 break;
3074
3075         case FRUIT_META_STREAM:
3076                 ok = readdir_attr_meta_finderi_stream(
3077                         handle, smb_fname, &ai);
3078                 break;
3079
3080         default:
3081                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
3082                 return false;
3083         }
3084
3085         if (!ok) {
3086                 /* Don't bother with errors, it's likely ENOENT */
3087                 return true;
3088         }
3089
3090         if (S_ISREG(smb_fname->st.st_ex_mode)) {
3091                 /* finder_type */
3092                 memcpy(&attr_data->attr_data.aapl.finder_info[0],
3093                        &ai.afpi_FinderInfo[0], 4);
3094
3095                 /* finder_creator */
3096                 memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4,
3097                        &ai.afpi_FinderInfo[4], 4);
3098         }
3099
3100         /* finder_flags */
3101         memcpy(&attr_data->attr_data.aapl.finder_info[0] + 8,
3102                &ai.afpi_FinderInfo[8], 2);
3103
3104         /* finder_ext_flags */
3105         memcpy(&attr_data->attr_data.aapl.finder_info[0] + 10,
3106                &ai.afpi_FinderInfo[24], 2);
3107
3108         /* creation date */
3109         date_added = convert_time_t_to_uint32_t(
3110                 smb_fname->st.st_ex_btime.tv_sec - AD_DATE_DELTA);
3111
3112         RSIVAL(&attr_data->attr_data.aapl.finder_info[0], 12, date_added);
3113
3114         return true;
3115 }
3116
3117 static uint64_t readdir_attr_rfork_size_adouble(
3118         struct vfs_handle_struct *handle,
3119         const struct smb_filename *smb_fname)
3120 {
3121         struct adouble *ad = NULL;
3122         uint64_t rfork_size;
3123
3124         ad = ad_get(talloc_tos(), handle, smb_fname,
3125                     ADOUBLE_RSRC);
3126         if (ad == NULL) {
3127                 return 0;
3128         }
3129
3130         rfork_size = ad_getentrylen(ad, ADEID_RFORK);
3131         TALLOC_FREE(ad);
3132
3133         return rfork_size;
3134 }
3135
3136 static uint64_t readdir_attr_rfork_size_stream(
3137         struct vfs_handle_struct *handle,
3138         const struct smb_filename *smb_fname)
3139 {
3140         struct smb_filename *stream_name = NULL;
3141         int ret;
3142         uint64_t rfork_size;
3143
3144         stream_name = synthetic_smb_fname(talloc_tos(),
3145                                           smb_fname->base_name,
3146                                           AFPRESOURCE_STREAM_NAME,
3147                                           NULL, 0);
3148         if (stream_name == NULL) {
3149                 return 0;
3150         }
3151
3152         ret = SMB_VFS_STAT(handle->conn, stream_name);
3153         if (ret != 0) {
3154                 TALLOC_FREE(stream_name);
3155                 return 0;
3156         }
3157
3158         rfork_size = stream_name->st.st_ex_size;
3159         TALLOC_FREE(stream_name);
3160
3161         return rfork_size;
3162 }
3163
3164 static uint64_t readdir_attr_rfork_size(struct vfs_handle_struct *handle,
3165                                         const struct smb_filename *smb_fname)
3166 {
3167         struct fruit_config_data *config = NULL;
3168         uint64_t rfork_size;
3169
3170         SMB_VFS_HANDLE_GET_DATA(handle, config,
3171                                 struct fruit_config_data,
3172                                 return 0);
3173
3174         switch (config->rsrc) {
3175         case FRUIT_RSRC_ADFILE:
3176         case FRUIT_RSRC_XATTR:
3177                 rfork_size = readdir_attr_rfork_size_adouble(handle,
3178                                                              smb_fname);
3179                 break;
3180
3181         case FRUIT_META_STREAM:
3182                 rfork_size = readdir_attr_rfork_size_stream(handle,
3183                                                             smb_fname);
3184                 break;
3185
3186         default:
3187                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
3188                 rfork_size = 0;
3189                 break;
3190         }
3191
3192         return rfork_size;
3193 }
3194
3195 static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle,
3196                                      const struct smb_filename *smb_fname,
3197                                      struct readdir_attr_data *attr_data)
3198 {
3199         NTSTATUS status = NT_STATUS_OK;
3200         struct fruit_config_data *config = NULL;
3201         bool ok;
3202
3203         SMB_VFS_HANDLE_GET_DATA(handle, config,
3204                                 struct fruit_config_data,
3205                                 return NT_STATUS_UNSUCCESSFUL);
3206
3207
3208         /* Ensure we return a default value in the creation_date field */
3209         RSIVAL(&attr_data->attr_data.aapl.finder_info, 12, AD_DATE_START);
3210
3211         /*
3212          * Resource fork length
3213          */
3214
3215         if (config->readdir_attr_rsize) {
3216                 uint64_t rfork_size;
3217
3218                 rfork_size = readdir_attr_rfork_size(handle, smb_fname);
3219                 attr_data->attr_data.aapl.rfork_size = rfork_size;
3220         }
3221
3222         /*
3223          * FinderInfo
3224          */
3225
3226         if (config->readdir_attr_finder_info) {
3227                 ok = readdir_attr_meta_finderi(handle, smb_fname, attr_data);
3228                 if (!ok) {
3229                         status = NT_STATUS_INTERNAL_ERROR;
3230                 }
3231         }
3232
3233         return status;
3234 }
3235
3236 static NTSTATUS remove_virtual_nfs_aces(struct security_descriptor *psd)
3237 {
3238         NTSTATUS status;
3239         uint32_t i;
3240
3241         if (psd->dacl == NULL) {
3242                 return NT_STATUS_OK;
3243         }
3244
3245         for (i = 0; i < psd->dacl->num_aces; i++) {
3246                 /* MS NFS style mode/uid/gid */
3247                 int cmp = dom_sid_compare_domain(
3248                                 &global_sid_Unix_NFS,
3249                                 &psd->dacl->aces[i].trustee);
3250                 if (cmp != 0) {
3251                         /* Normal ACE entry. */
3252                         continue;
3253                 }
3254
3255                 /*
3256                  * security_descriptor_dacl_del()
3257                  * *must* return NT_STATUS_OK as we know
3258                  * we have something to remove.
3259                  */
3260
3261                 status = security_descriptor_dacl_del(psd,
3262                                 &psd->dacl->aces[i].trustee);
3263                 if (!NT_STATUS_IS_OK(status)) {
3264                         DBG_WARNING("failed to remove MS NFS style ACE: %s\n",
3265                                 nt_errstr(status));
3266                         return status;
3267                 }
3268
3269                 /*
3270                  * security_descriptor_dacl_del() may delete more
3271                  * then one entry subsequent to this one if the
3272                  * SID matches, but we only need to ensure that
3273                  * we stay looking at the same element in the array.
3274                  */
3275                 i--;
3276         }
3277         return NT_STATUS_OK;
3278 }
3279
3280 /* Search MS NFS style ACE with UNIX mode */
3281 static NTSTATUS check_ms_nfs(vfs_handle_struct *handle,
3282                              files_struct *fsp,
3283                              struct security_descriptor *psd,
3284                              mode_t *pmode,
3285                              bool *pdo_chmod)
3286 {
3287         uint32_t i;
3288         struct fruit_config_data *config = NULL;
3289
3290         *pdo_chmod = false;
3291
3292         SMB_VFS_HANDLE_GET_DATA(handle, config,
3293                                 struct fruit_config_data,
3294                                 return NT_STATUS_UNSUCCESSFUL);
3295
3296         if (!global_fruit_config.nego_aapl) {
3297                 return NT_STATUS_OK;
3298         }
3299         if (psd->dacl == NULL || !config->unix_info_enabled) {
3300                 return NT_STATUS_OK;
3301         }
3302
3303         for (i = 0; i < psd->dacl->num_aces; i++) {
3304                 if (dom_sid_compare_domain(
3305                             &global_sid_Unix_NFS_Mode,
3306                             &psd->dacl->aces[i].trustee) == 0) {
3307                         *pmode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
3308                         *pmode &= (S_IRWXU | S_IRWXG | S_IRWXO);
3309                         *pdo_chmod = true;
3310
3311                         DEBUG(10, ("MS NFS chmod request %s, %04o\n",
3312                                    fsp_str_dbg(fsp), (unsigned)(*pmode)));
3313                         break;
3314                 }
3315         }
3316
3317         /*
3318          * Remove any incoming virtual ACE entries generated by
3319          * fruit_fget_nt_acl().
3320          */
3321
3322         return remove_virtual_nfs_aces(psd);
3323 }
3324
3325 /****************************************************************************
3326  * VFS ops
3327  ****************************************************************************/
3328
3329 static int fruit_connect(vfs_handle_struct *handle,
3330                          const char *service,
3331                          const char *user)
3332 {
3333         int rc;
3334         char *list = NULL, *newlist = NULL;
3335         struct fruit_config_data *config;
3336
3337         DEBUG(10, ("fruit_connect\n"));
3338
3339         rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
3340         if (rc < 0) {
3341                 return rc;
3342         }
3343
3344         rc = init_fruit_config(handle);
3345         if (rc != 0) {
3346                 return rc;
3347         }
3348
3349         SMB_VFS_HANDLE_GET_DATA(handle, config,
3350                                 struct fruit_config_data, return -1);
3351
3352         if (config->veto_appledouble) {
3353                 list = lp_veto_files(talloc_tos(), SNUM(handle->conn));
3354
3355                 if (list) {
3356                         if (strstr(list, "/" ADOUBLE_NAME_PREFIX "*/") == NULL) {
3357                                 newlist = talloc_asprintf(
3358                                         list,
3359                                         "%s/" ADOUBLE_NAME_PREFIX "*/",
3360                                         list);
3361                                 lp_do_parameter(SNUM(handle->conn),
3362                                                 "veto files",
3363                                                 newlist);
3364                         }
3365                 } else {
3366                         lp_do_parameter(SNUM(handle->conn),
3367                                         "veto files",
3368                                         "/" ADOUBLE_NAME_PREFIX "*/");
3369                 }
3370
3371                 TALLOC_FREE(list);
3372         }
3373
3374         if (config->encoding == FRUIT_ENC_NATIVE) {
3375                 lp_do_parameter(SNUM(handle->conn),
3376                                 "catia:mappings",
3377                                 fruit_catia_maps);
3378         }
3379
3380         if (config->time_machine) {
3381                 DBG_NOTICE("Enabling durable handles for Time Machine "
3382                            "support on [%s]\n", service);
3383                 lp_do_parameter(SNUM(handle->conn), "durable handles", "yes");
3384                 lp_do_parameter(SNUM(handle->conn), "kernel oplocks", "no");
3385                 lp_do_parameter(SNUM(handle->conn), "kernel share modes", "no");
3386                 if (!lp_strict_sync(SNUM(handle->conn))) {
3387                         DBG_WARNING("Time Machine without strict sync is not "
3388                                     "recommended!\n");
3389                 }
3390                 lp_do_parameter(SNUM(handle->conn), "posix locking", "no");
3391         }
3392
3393         return rc;
3394 }
3395
3396 static int fruit_fake_fd(void)
3397 {
3398         int pipe_fds[2];
3399         int fd;
3400         int ret;
3401
3402         /*
3403          * Return a valid fd, but ensure any attempt to use it returns
3404          * an error (EPIPE). Once we get a write on the handle, we open
3405          * the real fd.
3406          */
3407         ret = pipe(pipe_fds);
3408         if (ret != 0) {
3409                 return -1;
3410         }
3411         fd = pipe_fds[0];
3412         close(pipe_fds[1]);
3413
3414         return fd;
3415 }
3416
3417 static int fruit_open_meta_stream(vfs_handle_struct *handle,
3418                                   struct smb_filename *smb_fname,
3419                                   files_struct *fsp,
3420                                   int flags,
3421                                   mode_t mode)
3422 {
3423         struct fruit_config_data *config = NULL;
3424         struct fio *fio = NULL;
3425         int open_flags = flags & ~O_CREAT;
3426         int fd;
3427
3428         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
3429
3430         SMB_VFS_HANDLE_GET_DATA(handle, config,
3431                                 struct fruit_config_data, return -1);
3432
3433         fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
3434         fio->type = ADOUBLE_META;
3435         fio->config = config;
3436
3437         fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, open_flags, mode);
3438         if (fd != -1) {
3439                 return fd;
3440         }
3441
3442         if (!(flags & O_CREAT)) {
3443                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
3444                 return -1;
3445         }
3446
3447         fd = fruit_fake_fd();
3448         if (fd == -1) {
3449                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
3450                 return -1;
3451         }
3452
3453         fio->fake_fd = true;
3454         fio->flags = flags;
3455         fio->mode = mode;
3456
3457         return fd;
3458 }
3459
3460 static int fruit_open_meta_netatalk(vfs_handle_struct *handle,
3461                                     struct smb_filename *smb_fname,
3462                                     files_struct *fsp,
3463                                     int flags,
3464                                     mode_t mode)
3465 {
3466         struct fruit_config_data *config = NULL;
3467         struct fio *fio = NULL;
3468         struct adouble *ad = NULL;
3469         bool meta_exists = false;
3470         int fd;
3471
3472         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
3473
3474         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
3475         if (ad != NULL) {
3476                 meta_exists = true;
3477         }
3478
3479         TALLOC_FREE(ad);
3480
3481         if (!meta_exists && !(flags & O_CREAT)) {
3482                 errno = ENOENT;
3483                 return -1;
3484         }
3485
3486         fd = fruit_fake_fd();
3487         if (fd == -1) {
3488                 return -1;
3489         }
3490
3491         SMB_VFS_HANDLE_GET_DATA(handle, config,
3492                                 struct fruit_config_data, return -1);
3493
3494         fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
3495         fio->type = ADOUBLE_META;
3496         fio->config = config;
3497         fio->fake_fd = true;
3498         fio->flags = flags;
3499         fio->mode = mode;
3500
3501         return fd;
3502 }
3503
3504 static int fruit_open_meta(vfs_handle_struct *handle,
3505                            struct smb_filename *smb_fname,
3506                            files_struct *fsp, int flags, mode_t mode)
3507 {
3508         int fd;
3509         struct fruit_config_data *config = NULL;
3510
3511         DBG_DEBUG("path [%s]\n", smb_fname_str_dbg(smb_fname));
3512
3513         SMB_VFS_HANDLE_GET_DATA(handle, config,
3514                                 struct fruit_config_data, return -1);
3515
3516         switch (config->meta) {
3517         case FRUIT_META_STREAM:
3518                 fd = fruit_open_meta_stream(handle, smb_fname,
3519                                             fsp, flags, mode);
3520                 break;
3521
3522         case FRUIT_META_NETATALK:
3523                 fd = fruit_open_meta_netatalk(handle, smb_fname,
3524                                               fsp, flags, mode);
3525                 break;
3526
3527         default:
3528                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
3529                 return -1;
3530         }
3531
3532         DBG_DEBUG("path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
3533
3534         return fd;
3535 }
3536
3537 static int fruit_open_rsrc_adouble(vfs_handle_struct *handle,
3538                                    struct smb_filename *smb_fname,
3539                                    files_struct *fsp,
3540                                    int flags,
3541                                    mode_t mode)
3542 {
3543         int rc = 0;
3544         struct adouble *ad = NULL;
3545         struct smb_filename *smb_fname_base = NULL;
3546         struct fruit_config_data *config = NULL;
3547         int hostfd = -1;
3548
3549         SMB_VFS_HANDLE_GET_DATA(handle, config,
3550                                 struct fruit_config_data, return -1);
3551
3552         if ((!(flags & O_CREAT)) &&
3553             S_ISDIR(fsp->base_fsp->fsp_name->st.st_ex_mode))
3554         {
3555                 /* sorry, but directories don't habe a resource fork */
3556                 rc = -1;
3557                 goto exit;
3558         }
3559
3560         rc = adouble_path(talloc_tos(), smb_fname, &smb_fname_base);
3561         if (rc != 0) {
3562                 goto exit;
3563         }
3564
3565         /* We always need read/write access for the metadata header too */
3566         flags &= ~(O_RDONLY | O_WRONLY);
3567         flags |= O_RDWR;
3568
3569         hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp,
3570                                    flags, mode);
3571         if (hostfd == -1) {
3572                 rc = -1;
3573                 goto exit;
3574         }
3575
3576         if (flags & (O_CREAT | O_TRUNC)) {
3577                 ad = ad_init(fsp, handle, ADOUBLE_RSRC);
3578                 if (ad == NULL) {
3579                         rc = -1;
3580                         goto exit;
3581                 }
3582
3583                 fsp->fh->fd = hostfd;
3584
3585                 rc = ad_fset(ad, fsp);
3586                 fsp->fh->fd = -1;
3587                 if (rc != 0) {
3588                         rc = -1;
3589                         goto exit;
3590                 }
3591                 TALLOC_FREE(ad);
3592         }
3593
3594 exit:
3595
3596         TALLOC_FREE(smb_fname_base);
3597
3598         DEBUG(10, ("fruit_open resource fork: rc=%d, fd=%d\n", rc, hostfd));
3599         if (rc != 0) {
3600                 int saved_errno = errno;
3601                 if (hostfd >= 0) {
3602                         /*
3603                          * BUGBUGBUG -- we would need to call
3604                          * fd_close_posix here, but we don't have a
3605                          * full fsp yet
3606                          */
3607                         fsp->fh->fd = hostfd;
3608                         SMB_VFS_CLOSE(fsp);
3609                 }
3610                 hostfd = -1;
3611                 errno = saved_errno;
3612         }
3613         return hostfd;
3614 }
3615
3616 static int fruit_open_rsrc_xattr(vfs_handle_struct *handle,
3617                                  struct smb_filename *smb_fname,
3618                                  files_struct *fsp,
3619                                  int flags,
3620                                  mode_t mode)
3621 {
3622 #ifdef HAVE_ATTROPEN
3623         int fd = -1;
3624
3625         fd = attropen(smb_fname->base_name,
3626                       AFPRESOURCE_EA_NETATALK,
3627                       flags,
3628                       mode);
3629         if (fd == -1) {
3630                 return -1;
3631         }
3632
3633         return fd;
3634
3635 #else
3636         errno = ENOSYS;
3637         return -1;
3638 #endif
3639 }
3640
3641 static int fruit_open_rsrc(vfs_handle_struct *handle,
3642                            struct smb_filename *smb_fname,
3643                            files_struct *fsp, int flags, mode_t mode)
3644 {
3645         int fd;
3646         struct fruit_config_data *config = NULL;
3647         struct fio *fio = NULL;
3648
3649         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
3650
3651         SMB_VFS_HANDLE_GET_DATA(handle, config,
3652                                 struct fruit_config_data, return -1);
3653
3654         switch (config->rsrc) {
3655         case FRUIT_RSRC_STREAM:
3656                 fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
3657                 break;
3658
3659         case FRUIT_RSRC_ADFILE:
3660                 fd = fruit_open_rsrc_adouble(handle, smb_fname,
3661                                              fsp, flags, mode);
3662                 break;
3663
3664         case FRUIT_RSRC_XATTR:
3665                 fd = fruit_open_rsrc_xattr(handle, smb_fname,
3666                                            fsp, flags, mode);
3667                 break;
3668
3669         default:
3670                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
3671                 return -1;
3672         }
3673
3674         DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
3675
3676         if (fd == -1) {
3677                 return -1;
3678         }
3679
3680         fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
3681         fio->type = ADOUBLE_RSRC;
3682         fio->config = config;
3683
3684         return fd;
3685 }
3686
3687 static int fruit_open(vfs_handle_struct *handle,
3688                       struct smb_filename *smb_fname,
3689                       files_struct *fsp, int flags, mode_t mode)
3690 {
3691         int fd;
3692
3693         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
3694
3695         if (!is_ntfs_stream_smb_fname(smb_fname)) {
3696                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
3697         }
3698
3699         if (is_afpinfo_stream(smb_fname)) {
3700                 fd = fruit_open_meta(handle, smb_fname, fsp, flags, mode);
3701         } else if (is_afpresource_stream(smb_fname)) {
3702                 fd = fruit_open_rsrc(handle, smb_fname, fsp, flags, mode);
3703         } else {
3704                 fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
3705         }
3706
3707         DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
3708
3709         return fd;
3710 }
3711
3712 static int fruit_close_meta(vfs_handle_struct *handle,
3713                             files_struct *fsp)
3714 {
3715         int ret;
3716         struct fruit_config_data *config = NULL;
3717
3718         SMB_VFS_HANDLE_GET_DATA(handle, config,
3719                                 struct fruit_config_data, return -1);
3720
3721         switch (config->meta) {
3722         case FRUIT_META_STREAM:
3723                 ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
3724                 break;
3725
3726         case FRUIT_META_NETATALK:
3727                 ret = close(fsp->fh->fd);
3728                 fsp->fh->fd = -1;
3729                 break;
3730
3731         default:
3732                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
3733                 return -1;
3734         }
3735
3736         return ret;
3737 }
3738
3739
3740 static int fruit_close_rsrc(vfs_handle_struct *handle,
3741                             files_struct *fsp)
3742 {
3743         int ret;
3744         struct fruit_config_data *config = NULL;
3745
3746         SMB_VFS_HANDLE_GET_DATA(handle, config,
3747                                 struct fruit_config_data, return -1);
3748
3749         switch (config->rsrc) {
3750         case FRUIT_RSRC_STREAM:
3751         case FRUIT_RSRC_ADFILE:
3752                 ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
3753                 break;
3754
3755         case FRUIT_RSRC_XATTR:
3756                 ret = close(fsp->fh->fd);
3757                 fsp->fh->fd = -1;
3758                 break;
3759
3760         default:
3761                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
3762                 return -1;
3763         }
3764
3765         return ret;
3766 }
3767
3768 static int fruit_close(vfs_handle_struct *handle,
3769                        files_struct *fsp)
3770 {
3771         int ret;
3772         int fd;
3773
3774         fd = fsp->fh->fd;
3775
3776         DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(fsp->fsp_name), fd);
3777
3778         if (!is_ntfs_stream_smb_fname(fsp->fsp_name)) {
3779                 return SMB_VFS_NEXT_CLOSE(handle, fsp);
3780         }
3781
3782         if (is_afpinfo_stream(fsp->fsp_name)) {
3783                 ret = fruit_close_meta(handle, fsp);
3784         } else if (is_afpresource_stream(fsp->fsp_name)) {
3785                 ret = fruit_close_rsrc(handle, fsp);
3786         } else {
3787                 ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
3788         }
3789
3790         return ret;
3791 }
3792
3793 static int fruit_rename(struct vfs_handle_struct *handle,
3794                         const struct smb_filename *smb_fname_src,
3795                         const struct smb_filename *smb_fname_dst)
3796 {
3797         int rc = -1;
3798         struct fruit_config_data *config = NULL;
3799         struct smb_filename *src_adp_smb_fname = NULL;
3800         struct smb_filename *dst_adp_smb_fname = NULL;
3801
3802         SMB_VFS_HANDLE_GET_DATA(handle, config,
3803                                 struct fruit_config_data, return -1);
3804
3805         if (!VALID_STAT(smb_fname_src->st)) {
3806                 DBG_ERR("Need valid stat for [%s]\n",
3807                         smb_fname_str_dbg(smb_fname_src));
3808                 return -1;
3809         }
3810
3811         rc = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
3812         if (rc != 0) {
3813                 return -1;
3814         }
3815
3816         if ((config->rsrc != FRUIT_RSRC_ADFILE) ||
3817             (!S_ISREG(smb_fname_src->st.st_ex_mode)))
3818         {
3819                 return 0;
3820         }
3821
3822         rc = adouble_path(talloc_tos(), smb_fname_src, &src_adp_smb_fname);
3823         if (rc != 0) {
3824                 goto done;
3825         }
3826
3827         rc = adouble_path(talloc_tos(), smb_fname_dst, &dst_adp_smb_fname);
3828         if (rc != 0) {
3829                 goto done;
3830         }
3831
3832         DBG_DEBUG("%s -> %s\n",
3833                   smb_fname_str_dbg(src_adp_smb_fname),
3834                   smb_fname_str_dbg(dst_adp_smb_fname));
3835
3836         rc = SMB_VFS_NEXT_RENAME(handle, src_adp_smb_fname, dst_adp_smb_fname);
3837         if (errno == ENOENT) {
3838                 rc = 0;
3839         }
3840
3841 done:
3842         TALLOC_FREE(src_adp_smb_fname);
3843         TALLOC_FREE(dst_adp_smb_fname);
3844         return rc;
3845 }
3846
3847 static int fruit_unlink_meta_stream(vfs_handle_struct *handle,
3848                                     const struct smb_filename *smb_fname)
3849 {
3850         return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
3851 }
3852
3853 static int fruit_unlink_meta_netatalk(vfs_handle_struct *handle,
3854                                       const struct smb_filename *smb_fname)
3855 {
3856         return SMB_VFS_REMOVEXATTR(handle->conn,
3857                                    smb_fname,
3858                                    AFPINFO_EA_NETATALK);
3859 }
3860
3861 static int fruit_unlink_meta(vfs_handle_struct *handle,
3862                              const struct smb_filename *smb_fname)
3863 {
3864         struct fruit_config_data *config = NULL;
3865         int rc;
3866
3867         SMB_VFS_HANDLE_GET_DATA(handle, config,
3868                                 struct fruit_config_data, return -1);
3869
3870         switch (config->meta) {
3871         case FRUIT_META_STREAM:
3872                 rc = fruit_unlink_meta_stream(handle, smb_fname);
3873                 break;
3874
3875         case FRUIT_META_NETATALK:
3876                 rc = fruit_unlink_meta_netatalk(handle, smb_fname);
3877                 break;
3878
3879         default:
3880                 DBG_ERR("Unsupported meta config [%d]\n", config->meta);
3881                 return -1;
3882         }
3883
3884         return rc;
3885 }
3886
3887 static int fruit_unlink_rsrc_stream(vfs_handle_struct *handle,
3888                                     const struct smb_filename *smb_fname,
3889                                     bool force_unlink)
3890 {
3891         int ret;
3892
3893         if (!force_unlink) {
3894                 struct smb_filename *smb_fname_cp = NULL;
3895                 off_t size;
3896
3897                 smb_fname_cp = cp_smb_filename(talloc_tos(), smb_fname);
3898                 if (smb_fname_cp == NULL) {
3899                         return -1;
3900                 }
3901
3902                 /*
3903                  * 0 byte resource fork streams are not listed by
3904                  * vfs_streaminfo, as a result stream cleanup/deletion of file
3905                  * deletion doesn't remove the resourcefork stream.
3906                  */
3907
3908                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_cp);
3909                 if (ret != 0) {
3910                         TALLOC_FREE(smb_fname_cp);
3911                         DBG_ERR("stat [%s] failed [%s]\n",
3912                                 smb_fname_str_dbg(smb_fname_cp), strerror(errno));
3913                         return -1;
3914                 }
3915
3916                 size = smb_fname_cp->st.st_ex_size;
3917                 TALLOC_FREE(smb_fname_cp);
3918
3919                 if (size > 0) {
3920                         /* OS X ignores resource fork stream delete requests */
3921                         return 0;
3922                 }
3923         }
3924
3925         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
3926         if ((ret != 0) && (errno == ENOENT) && force_unlink) {
3927                 ret = 0;
3928         }
3929
3930         return ret;
3931 }
3932
3933 static int fruit_unlink_rsrc_adouble(vfs_handle_struct *handle,
3934                                      const struct smb_filename *smb_fname,
3935                                      bool force_unlink)
3936 {
3937         int rc;
3938         struct adouble *ad = NULL;
3939         struct smb_filename *adp_smb_fname = NULL;
3940
3941         if (!force_unlink) {
3942                 ad = ad_get(talloc_tos(), handle, smb_fname,
3943                             ADOUBLE_RSRC);
3944                 if (ad == NULL) {
3945                         errno = ENOENT;
3946                         return -1;
3947                 }
3948
3949
3950                 /*
3951                  * 0 byte resource fork streams are not listed by
3952                  * vfs_streaminfo, as a result stream cleanup/deletion of file
3953                  * deletion doesn't remove the resourcefork stream.
3954                  */
3955
3956                 if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
3957                         /* OS X ignores resource fork stream delete requests */
3958                         TALLOC_FREE(ad);
3959                         return 0;
3960                 }
3961
3962                 TALLOC_FREE(ad);
3963         }
3964
3965         rc = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
3966         if (rc != 0) {
3967                 return -1;
3968         }
3969
3970         rc = SMB_VFS_NEXT_UNLINK(handle, adp_smb_fname);
3971         TALLOC_FREE(adp_smb_fname);
3972         if ((rc != 0) && (errno == ENOENT) && force_unlink) {
3973                 rc = 0;
3974         }
3975
3976         return rc;
3977 }
3978
3979 static int fruit_unlink_rsrc_xattr(vfs_handle_struct *handle,
3980                                    const struct smb_filename *smb_fname,
3981                                    bool force_unlink)
3982 {
3983         /*
3984          * OS X ignores resource fork stream delete requests, so nothing to do
3985          * here. Removing the file will remove the xattr anyway, so we don't
3986          * have to take care of removing 0 byte resource forks that could be
3987          * left behind.
3988          */
3989         return 0;
3990 }
3991
3992 static int fruit_unlink_rsrc(vfs_handle_struct *handle,
3993                              const struct smb_filename *smb_fname,
3994                              bool force_unlink)
3995 {
3996         struct fruit_config_data *config = NULL;
3997         int rc;
3998
3999         SMB_VFS_HANDLE_GET_DATA(handle, config,
4000                                 struct fruit_config_data, return -1);
4001
4002         switch (config->rsrc) {
4003         case FRUIT_RSRC_STREAM:
4004                 rc = fruit_unlink_rsrc_stream(handle, smb_fname, force_unlink);
4005                 break;
4006
4007         case FRUIT_RSRC_ADFILE:
4008                 rc = fruit_unlink_rsrc_adouble(handle, smb_fname, force_unlink);
4009                 break;
4010
4011         case FRUIT_RSRC_XATTR:
4012                 rc = fruit_unlink_rsrc_xattr(handle, smb_fname, force_unlink);
4013                 break;
4014
4015         default:
4016                 DBG_ERR("Unsupported rsrc config [%d]\n", config->rsrc);
4017                 return -1;
4018         }
4019
4020         return rc;
4021 }
4022
4023 static int fruit_unlink(vfs_handle_struct *handle,
4024                         const struct smb_filename *smb_fname)
4025 {
4026         int rc;
4027         struct fruit_config_data *config = NULL;
4028         struct smb_filename *rsrc_smb_fname = NULL;
4029
4030         SMB_VFS_HANDLE_GET_DATA(handle, config,
4031                                 struct fruit_config_data, return -1);
4032
4033         if (is_afpinfo_stream(smb_fname)) {
4034                 return fruit_unlink_meta(handle, smb_fname);
4035         } else if (is_afpresource_stream(smb_fname)) {
4036                 return fruit_unlink_rsrc(handle, smb_fname, false);
4037         } if (is_ntfs_stream_smb_fname(smb_fname)) {
4038                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
4039         }
4040
4041         /*
4042          * A request to delete the base file. Because 0 byte resource
4043          * fork streams are not listed by fruit_streaminfo,
4044          * delete_all_streams() can't remove 0 byte resource fork
4045          * streams, so we have to cleanup this here.
4046          */
4047         rsrc_smb_fname = synthetic_smb_fname(talloc_tos(),
4048                                              smb_fname->base_name,
4049                                              AFPRESOURCE_STREAM_NAME,
4050                                              NULL,
4051                                              smb_fname->flags);
4052         if (rsrc_smb_fname == NULL) {
4053                 return -1;
4054         }
4055
4056         rc = fruit_unlink_rsrc(handle, rsrc_smb_fname, true);
4057         if ((rc != 0) && (errno != ENOENT)) {
4058                 DBG_ERR("Forced unlink of [%s] failed [%s]\n",
4059                         smb_fname_str_dbg(rsrc_smb_fname), strerror(errno));
4060                 TALLOC_FREE(rsrc_smb_fname);
4061                 return -1;
4062         }
4063         TALLOC_FREE(rsrc_smb_fname);
4064
4065         return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
4066 }
4067
4068 static int fruit_chmod(vfs_handle_struct *handle,
4069                        const struct smb_filename *smb_fname,
4070                        mode_t mode)
4071 {
4072         int rc = -1;
4073         struct fruit_config_data *config = NULL;
4074         struct smb_filename *smb_fname_adp = NULL;
4075
4076         rc = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
4077         if (rc != 0) {
4078                 return rc;
4079         }
4080
4081         SMB_VFS_HANDLE_GET_DATA(handle, config,
4082                                 struct fruit_config_data, return -1);
4083
4084         if (config->rsrc != FRUIT_RSRC_ADFILE) {
4085                 return 0;
4086         }
4087
4088         if (!VALID_STAT(smb_fname->st)) {
4089                 return 0;
4090         }
4091
4092         if (!S_ISREG(smb_fname->st.st_ex_mode)) {
4093                 return 0;
4094         }
4095
4096         rc = adouble_path(talloc_tos(), smb_fname, &smb_fname_adp);
4097         if (rc != 0) {
4098                 return -1;
4099         }
4100
4101         DEBUG(10, ("fruit_chmod: %s\n", smb_fname_adp->base_name));
4102
4103         rc = SMB_VFS_NEXT_CHMOD(handle, smb_fname_adp, mode);
4104         if (errno == ENOENT) {
4105                 rc = 0;
4106         }
4107
4108         TALLOC_FREE(smb_fname_adp);
4109         return rc;
4110 }
4111
4112 static int fruit_chown(vfs_handle_struct *handle,
4113                        const struct smb_filename *smb_fname,
4114                        uid_t uid,
4115                        gid_t gid)
4116 {
4117         int rc = -1;
4118         struct fruit_config_data *config = NULL;
4119         struct smb_filename *adp_smb_fname = NULL;
4120
4121         rc = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
4122         if (rc != 0) {
4123                 return rc;
4124         }
4125
4126         SMB_VFS_HANDLE_GET_DATA(handle, config,
4127                                 struct fruit_config_data, return -1);
4128
4129         if (config->rsrc != FRUIT_RSRC_ADFILE) {
4130                 return 0;
4131         }
4132
4133         if (!VALID_STAT(smb_fname->st)) {
4134                 return 0;
4135         }
4136
4137         if (!S_ISREG(smb_fname->st.st_ex_mode)) {
4138                 return 0;
4139         }
4140
4141         rc = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
4142         if (rc != 0) {
4143                 goto done;
4144         }
4145
4146         DEBUG(10, ("fruit_chown: %s\n", adp_smb_fname->base_name));
4147
4148         rc = SMB_VFS_NEXT_CHOWN(handle, adp_smb_fname, uid, gid);
4149         if (errno == ENOENT) {
4150                 rc = 0;
4151         }
4152
4153  done:
4154         TALLOC_FREE(adp_smb_fname);
4155         return rc;
4156 }
4157
4158 static int fruit_rmdir(struct vfs_handle_struct *handle,
4159                         const struct smb_filename *smb_fname)
4160 {
4161         DIR *dh = NULL;
4162         struct dirent *de;
4163         struct fruit_config_data *config;
4164
4165         SMB_VFS_HANDLE_GET_DATA(handle, config,
4166                                 struct fruit_config_data, return -1);
4167
4168         if (config->rsrc != FRUIT_RSRC_ADFILE) {
4169                 goto exit_rmdir;
4170         }
4171
4172         /*
4173          * Due to there is no way to change bDeleteVetoFiles variable
4174          * from this module, need to clean up ourselves
4175          */
4176
4177         dh = SMB_VFS_OPENDIR(handle->conn, smb_fname, NULL, 0);
4178         if (dh == NULL) {
4179                 goto exit_rmdir;
4180         }
4181
4182         while ((de = SMB_VFS_READDIR(handle->conn, dh, NULL)) != NULL) {
4183                 int match;
4184                 struct adouble *ad = NULL;
4185                 char *p = NULL;
4186                 struct smb_filename *ad_smb_fname = NULL;
4187                 int ret;
4188
4189                 match = strncmp(de->d_name,
4190                                 ADOUBLE_NAME_PREFIX,
4191                                 strlen(ADOUBLE_NAME_PREFIX));
4192                 if (match != 0) {
4193                         continue;
4194                 }
4195
4196                 p = talloc_asprintf(talloc_tos(), "%s/%s",
4197                                     smb_fname->base_name, de->d_name);
4198                 if (p == NULL) {
4199                         DBG_ERR("talloc_asprintf failed\n");
4200                         return -1;
4201                 }
4202
4203                 ad_smb_fname = synthetic_smb_fname(talloc_tos(), p,
4204                                                     NULL, NULL,
4205                                                     smb_fname->flags);
4206                 TALLOC_FREE(p);
4207                 if (ad_smb_fname == NULL) {
4208                         DBG_ERR("synthetic_smb_fname failed\n");
4209                         return -1;
4210                 }
4211
4212                 /*
4213                  * Check whether it's a valid AppleDouble file, if
4214                  * yes, delete it, ignore it otherwise.
4215                  */
4216                 ad = ad_get(talloc_tos(), handle, ad_smb_fname, ADOUBLE_RSRC);
4217                 if (ad == NULL) {
4218                         TALLOC_FREE(ad_smb_fname);
4219                         TALLOC_FREE(p);
4220                         continue;
4221                 }
4222                 TALLOC_FREE(ad);
4223
4224                 ret = SMB_VFS_NEXT_UNLINK(handle, ad_smb_fname);
4225                 if (ret != 0) {
4226                         DBG_ERR("Deleting [%s] failed\n",
4227                                 smb_fname_str_dbg(ad_smb_fname));
4228                 }
4229                 TALLOC_FREE(ad_smb_fname);
4230         }
4231
4232 exit_rmdir:
4233         if (dh) {
4234                 SMB_VFS_CLOSEDIR(handle->conn, dh);
4235         }
4236         return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
4237 }
4238
4239 static ssize_t fruit_pread_meta_stream(vfs_handle_struct *handle,
4240                                        files_struct *fsp, void *data,
4241                                        size_t n, off_t offset)
4242 {
4243         ssize_t nread;
4244         int ret;
4245
4246         nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
4247         if (nread == -1 || nread == n) {
4248                 return nread;
4249         }
4250
4251         DBG_ERR("Removing [%s] after short read [%zd]\n",
4252                 fsp_str_dbg(fsp), nread);
4253
4254         ret = SMB_VFS_NEXT_UNLINK(handle, fsp->fsp_name);
4255         if (ret != 0) {
4256                 DBG_ERR("Removing [%s] failed\n", fsp_str_dbg(fsp));
4257                 return -1;
4258         }
4259
4260         errno = EINVAL;
4261         return -1;
4262 }
4263
4264 static ssize_t fruit_pread_meta_adouble(vfs_handle_struct *handle,
4265                                         files_struct *fsp, void *data,
4266                                         size_t n, off_t offset)
4267 {
4268         AfpInfo *ai = NULL;
4269         struct adouble *ad = NULL;
4270         char afpinfo_buf[AFP_INFO_SIZE];
4271         char *p = NULL;
4272         ssize_t nread;
4273
4274         ai = afpinfo_new(talloc_tos());
4275         if (ai == NULL) {
4276                 return -1;
4277         }
4278
4279         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
4280         if (ad == NULL) {
4281                 nread = -1;
4282                 goto fail;
4283         }
4284
4285         p = ad_get_entry(ad, ADEID_FINDERI);
4286         if (p == NULL) {
4287                 DBG_ERR("No ADEID_FINDERI for [%s]\n", fsp_str_dbg(fsp));
4288                 nread = -1;
4289                 goto fail;
4290         }
4291
4292         memcpy(&ai->afpi_FinderInfo[0], p, ADEDLEN_FINDERI);
4293
4294         nread = afpinfo_pack(ai, afpinfo_buf);
4295         if (nread != AFP_INFO_SIZE) {
4296                 nread = -1;
4297                 goto fail;
4298         }
4299
4300         memcpy(data, afpinfo_buf, n);
4301         nread = n;
4302
4303 fail:
4304         TALLOC_FREE(ai);
4305         return nread;
4306 }
4307
4308 static ssize_t fruit_pread_meta(vfs_handle_struct *handle,
4309                                 files_struct *fsp, void *data,
4310                                 size_t n, off_t offset)
4311 {
4312         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4313         ssize_t nread;
4314         ssize_t to_return;
4315
4316         /*
4317          * OS X has a off-by-1 error in the offset calculation, so we're
4318          * bug compatible here. It won't hurt, as any relevant real
4319          * world read requests from the AFP_AfpInfo stream will be
4320          * offset=0 n=60. offset is ignored anyway, see below.
4321          */
4322         if ((offset < 0) || (offset >= AFP_INFO_SIZE + 1)) {
4323                 return 0;
4324         }
4325
4326         if (fio == NULL) {
4327                 DBG_ERR("Failed to fetch fsp extension");
4328                 return -1;
4329         }
4330
4331         /* Yes, macOS always reads from offset 0 */
4332         offset = 0;
4333         to_return = MIN(n, AFP_INFO_SIZE);
4334
4335         switch (fio->config->meta) {
4336         case FRUIT_META_STREAM:
4337                 nread = fruit_pread_meta_stream(handle, fsp, data,
4338                                                 to_return, offset);
4339                 break;
4340
4341         case FRUIT_META_NETATALK:
4342                 nread = fruit_pread_meta_adouble(handle, fsp, data,
4343                                                  to_return, offset);
4344                 break;
4345
4346         default:
4347                 DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
4348                 return -1;
4349         }
4350
4351         if (nread == -1 && fio->created) {
4352                 AfpInfo *ai = NULL;
4353                 char afpinfo_buf[AFP_INFO_SIZE];
4354
4355                 ai = afpinfo_new(talloc_tos());
4356                 if (ai == NULL) {
4357                         return -1;
4358                 }
4359
4360                 nread = afpinfo_pack(ai, afpinfo_buf);
4361                 TALLOC_FREE(ai);
4362                 if (nread != AFP_INFO_SIZE) {
4363                         return -1;
4364                 }
4365
4366                 memcpy(data, afpinfo_buf, to_return);
4367                 return to_return;
4368         }
4369
4370         return nread;
4371 }
4372
4373 static ssize_t fruit_pread_rsrc_stream(vfs_handle_struct *handle,
4374                                        files_struct *fsp, void *data,
4375                                        size_t n, off_t offset)
4376 {
4377         return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
4378 }
4379
4380 static ssize_t fruit_pread_rsrc_xattr(vfs_handle_struct *handle,
4381                                       files_struct *fsp, void *data,
4382                                       size_t n, off_t offset)
4383 {
4384         return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
4385 }
4386
4387 static ssize_t fruit_pread_rsrc_adouble(vfs_handle_struct *handle,
4388                                         files_struct *fsp, void *data,
4389                                         size_t n, off_t offset)
4390 {
4391         struct adouble *ad = NULL;
4392         ssize_t nread;
4393
4394         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
4395         if (ad == NULL) {
4396                 return -1;
4397         }
4398
4399         nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n,
4400                                    offset + ad_getentryoff(ad, ADEID_RFORK));
4401
4402         TALLOC_FREE(ad);
4403         return nread;
4404 }
4405
4406 static ssize_t fruit_pread_rsrc(vfs_handle_struct *handle,
4407                                 files_struct *fsp, void *data,
4408                                 size_t n, off_t offset)
4409 {
4410         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4411         ssize_t nread;
4412
4413         if (fio == NULL) {
4414                 errno = EINVAL;
4415                 return -1;
4416         }
4417
4418         switch (fio->config->rsrc) {
4419         case FRUIT_RSRC_STREAM:
4420                 nread = fruit_pread_rsrc_stream(handle, fsp, data, n, offset);
4421                 break;
4422
4423         case FRUIT_RSRC_ADFILE:
4424                 nread = fruit_pread_rsrc_adouble(handle, fsp, data, n, offset);
4425                 break;
4426
4427         case FRUIT_RSRC_XATTR:
4428                 nread = fruit_pread_rsrc_xattr(handle, fsp, data, n, offset);
4429                 break;
4430
4431         default:
4432                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
4433                 return -1;
4434         }
4435
4436         return nread;
4437 }
4438
4439 static ssize_t fruit_pread(vfs_handle_struct *handle,
4440                            files_struct *fsp, void *data,
4441                            size_t n, off_t offset)
4442 {
4443         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4444         ssize_t nread;
4445
4446         DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
4447                   fsp_str_dbg(fsp), (intmax_t)offset, n);
4448
4449         if (fio == NULL) {
4450                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
4451         }
4452
4453         if (fio->type == ADOUBLE_META) {
4454                 nread = fruit_pread_meta(handle, fsp, data, n, offset);
4455         } else {
4456                 nread = fruit_pread_rsrc(handle, fsp, data, n, offset);
4457         }
4458
4459         DBG_DEBUG("Path [%s] nread [%zd]\n", fsp_str_dbg(fsp), nread);
4460         return nread;
4461 }
4462
4463 static bool fruit_must_handle_aio_stream(struct fio *fio)
4464 {
4465         if (fio == NULL) {
4466                 return false;
4467         };
4468
4469         if (fio->type == ADOUBLE_META) {
4470                 return true;
4471         }
4472
4473         if ((fio->type == ADOUBLE_RSRC) &&
4474             (fio->config->rsrc == FRUIT_RSRC_ADFILE))
4475         {
4476                 return true;
4477         }
4478
4479         return false;
4480 }
4481
4482 struct fruit_pread_state {
4483         ssize_t nread;
4484         struct vfs_aio_state vfs_aio_state;
4485 };
4486
4487 static void fruit_pread_done(struct tevent_req *subreq);
4488
4489 static struct tevent_req *fruit_pread_send(
4490         struct vfs_handle_struct *handle,
4491         TALLOC_CTX *mem_ctx,
4492         struct tevent_context *ev,
4493         struct files_struct *fsp,
4494         void *data,
4495         size_t n, off_t offset)
4496 {
4497         struct tevent_req *req = NULL;
4498         struct tevent_req *subreq = NULL;
4499         struct fruit_pread_state *state = NULL;
4500         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4501
4502         req = tevent_req_create(mem_ctx, &state,
4503                                 struct fruit_pread_state);
4504         if (req == NULL) {
4505                 return NULL;
4506         }
4507
4508         if (fruit_must_handle_aio_stream(fio)) {
4509                 state->nread = SMB_VFS_PREAD(fsp, data, n, offset);
4510                 if (state->nread != n) {
4511                         if (state->nread != -1) {
4512                                 errno = EIO;
4513                         }
4514                         tevent_req_error(req, errno);
4515                         return tevent_req_post(req, ev);
4516                 }
4517                 tevent_req_done(req);
4518                 return tevent_req_post(req, ev);
4519         }
4520
4521         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp,
4522                                          data, n, offset);
4523         if (tevent_req_nomem(req, subreq)) {
4524                 return tevent_req_post(req, ev);
4525         }
4526         tevent_req_set_callback(subreq, fruit_pread_done, req);
4527         return req;
4528 }
4529
4530 static void fruit_pread_done(struct tevent_req *subreq)
4531 {
4532         struct tevent_req *req = tevent_req_callback_data(
4533                 subreq, struct tevent_req);
4534         struct fruit_pread_state *state = tevent_req_data(
4535                 req, struct fruit_pread_state);
4536
4537         state->nread = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
4538         TALLOC_FREE(subreq);
4539
4540         if (tevent_req_error(req, state->vfs_aio_state.error)) {
4541                 return;
4542         }
4543         tevent_req_done(req);
4544 }
4545
4546 static ssize_t fruit_pread_recv(struct tevent_req *req,
4547                                         struct vfs_aio_state *vfs_aio_state)
4548 {
4549         struct fruit_pread_state *state = tevent_req_data(
4550                 req, struct fruit_pread_state);
4551
4552         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
4553                 return -1;
4554         }
4555
4556         *vfs_aio_state = state->vfs_aio_state;
4557         return state->nread;
4558 }
4559
4560 static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle,
4561                                         files_struct *fsp, const void *data,
4562                                         size_t n, off_t offset)
4563 {
4564         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4565         AfpInfo *ai = NULL;
4566         size_t nwritten;
4567         int ret;
4568         bool ok;
4569
4570         DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
4571                   fsp_str_dbg(fsp), (intmax_t)offset, n);
4572
4573         if (fio == NULL) {
4574                 return -1;
4575         }
4576
4577         if (fio->fake_fd) {
4578                 int fd;
4579
4580                 ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
4581                 if (ret != 0) {
4582                         DBG_ERR("Close [%s] failed: %s\n",
4583                                 fsp_str_dbg(fsp), strerror(errno));
4584                         fsp->fh->fd = -1;
4585                         return -1;
4586                 }
4587
4588                 fd = SMB_VFS_NEXT_OPEN(handle,
4589                                        fsp->fsp_name,
4590                                        fsp,
4591                                        fio->flags,
4592                                        fio->mode);
4593                 if (fd == -1) {
4594                         DBG_ERR("On-demand create [%s] in write failed: %s\n",
4595                                 fsp_str_dbg(fsp), strerror(errno));
4596                         return -1;
4597                 }
4598                 fsp->fh->fd = fd;
4599                 fio->fake_fd = false;
4600         }
4601
4602         ai = afpinfo_unpack(talloc_tos(), data);
4603         if (ai == NULL) {
4604                 return -1;
4605         }
4606
4607         if (ai_empty_finderinfo(ai)) {
4608                 /*
4609                  * Writing an all 0 blob to the metadata stream results in the
4610                  * stream being removed on a macOS server. This ensures we
4611                  * behave the same and it verified by the "delete AFP_AfpInfo by
4612                  * writing all 0" test.
4613                  */
4614                 ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, 0);
4615                 if (ret != 0) {
4616                         DBG_ERR("SMB_VFS_NEXT_FTRUNCATE on [%s] failed\n",
4617                                 fsp_str_dbg(fsp));
4618                         return -1;
4619                 }
4620
4621                 ok = set_delete_on_close(
4622                         fsp,
4623                         true,
4624                         handle->conn->session_info->security_token,
4625                         handle->conn->session_info->unix_token);
4626                 if (!ok) {
4627                         DBG_ERR("set_delete_on_close on [%s] failed\n",
4628                                 fsp_str_dbg(fsp));
4629                         return -1;
4630                 }
4631                 return n;
4632         }
4633
4634         nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
4635         if (nwritten != n) {
4636                 return -1;
4637         }
4638
4639         return n;
4640 }
4641
4642 static ssize_t fruit_pwrite_meta_netatalk(vfs_handle_struct *handle,
4643                                           files_struct *fsp, const void *data,
4644                                           size_t n, off_t offset)
4645 {
4646         struct adouble *ad = NULL;
4647         AfpInfo *ai = NULL;
4648         char *p = NULL;
4649         int ret;
4650         bool ok;
4651
4652         ai = afpinfo_unpack(talloc_tos(), data);
4653         if (ai == NULL) {
4654                 return -1;
4655         }
4656
4657         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
4658         if (ad == NULL) {
4659                 ad = ad_init(talloc_tos(), handle, ADOUBLE_META);
4660                 if (ad == NULL) {
4661                         return -1;
4662                 }
4663         }
4664         p = ad_get_entry(ad, ADEID_FINDERI);
4665         if (p == NULL) {
4666                 DBG_ERR("No ADEID_FINDERI for [%s]\n", fsp_str_dbg(fsp));
4667                 TALLOC_FREE(ad);
4668                 return -1;
4669         }
4670
4671         memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI);
4672
4673         ret = ad_fset(ad, fsp);
4674         if (ret != 0) {
4675                 DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp));
4676                 TALLOC_FREE(ad);
4677                 return -1;
4678         }
4679
4680         TALLOC_FREE(ad);
4681
4682         if (!ai_empty_finderinfo(ai)) {
4683                 return n;
4684         }
4685
4686         /*
4687          * Writing an all 0 blob to the metadata stream results in the stream
4688          * being removed on a macOS server. This ensures we behave the same and
4689          * it verified by the "delete AFP_AfpInfo by writing all 0" test.
4690          */
4691
4692         ok = set_delete_on_close(
4693                 fsp,
4694                 true,
4695                 handle->conn->session_info->security_token,
4696                 handle->conn->session_info->unix_token);
4697         if (!ok) {
4698                 DBG_ERR("set_delete_on_close on [%s] failed\n",
4699                         fsp_str_dbg(fsp));
4700                 return -1;
4701         }
4702
4703         return n;
4704 }
4705
4706 static ssize_t fruit_pwrite_meta(vfs_handle_struct *handle,
4707                                  files_struct *fsp, const void *data,
4708                                  size_t n, off_t offset)
4709 {
4710         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4711         ssize_t nwritten;
4712         uint8_t buf[AFP_INFO_SIZE];
4713         size_t to_write;
4714         size_t to_copy;
4715         int cmp;
4716
4717         if (fio == NULL) {
4718                 DBG_ERR("Failed to fetch fsp extension");
4719                 return -1;
4720         }
4721
4722         if (n < 3) {
4723                 errno = EINVAL;
4724                 return -1;
4725         }
4726
4727         if (offset != 0 && n < 60) {
4728                 errno = EINVAL;
4729                 return -1;
4730         }
4731
4732         cmp = memcmp(data, "AFP", 3);
4733         if (cmp != 0) {
4734                 errno = EINVAL;
4735                 return -1;
4736         }
4737
4738         if (n <= AFP_OFF_FinderInfo) {
4739                 /*
4740                  * Nothing to do here really, just return
4741                  */
4742                 return n;
4743         }
4744
4745         offset = 0;
4746
4747         to_copy = n;
4748         if (to_copy > AFP_INFO_SIZE) {
4749                 to_copy = AFP_INFO_SIZE;
4750         }
4751         memcpy(buf, data, to_copy);
4752
4753         to_write = n;
4754         if (to_write != AFP_INFO_SIZE) {
4755                 to_write = AFP_INFO_SIZE;
4756         }
4757
4758         switch (fio->config->meta) {
4759         case FRUIT_META_STREAM:
4760                 nwritten = fruit_pwrite_meta_stream(handle,
4761                                                     fsp,
4762                                                     buf,
4763                                                     to_write,
4764                                                     offset);
4765                 break;
4766
4767         case FRUIT_META_NETATALK:
4768                 nwritten = fruit_pwrite_meta_netatalk(handle,
4769                                                       fsp,
4770                                                       buf,
4771                                                       to_write,
4772                                                       offset);
4773                 break;
4774
4775         default:
4776                 DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
4777                 return -1;
4778         }
4779
4780         if (nwritten != to_write) {
4781                 return -1;
4782         }
4783
4784         /*
4785          * Return the requested amount, verified against macOS SMB server
4786          */
4787         return n;
4788 }
4789
4790 static ssize_t fruit_pwrite_rsrc_stream(vfs_handle_struct *handle,
4791                                         files_struct *fsp, const void *data,
4792                                         size_t n, off_t offset)
4793 {
4794         return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
4795 }
4796
4797 static ssize_t fruit_pwrite_rsrc_xattr(vfs_handle_struct *handle,
4798                                        files_struct *fsp, const void *data,
4799                                        size_t n, off_t offset)
4800 {
4801         return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
4802 }
4803
4804 static ssize_t fruit_pwrite_rsrc_adouble(vfs_handle_struct *handle,
4805                                          files_struct *fsp, const void *data,
4806                                          size_t n, off_t offset)
4807 {
4808         struct adouble *ad = NULL;
4809         ssize_t nwritten;
4810         int ret;
4811
4812         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
4813         if (ad == NULL) {
4814                 DBG_ERR("ad_get [%s] failed\n", fsp_str_dbg(fsp));
4815                 return -1;
4816         }
4817
4818         nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n,
4819                                        offset + ad_getentryoff(ad, ADEID_RFORK));
4820         if (nwritten != n) {
4821                 DBG_ERR("Short write on [%s] [%zd/%zd]\n",
4822                         fsp_str_dbg(fsp), nwritten, n);
4823                 TALLOC_FREE(ad);
4824                 return -1;
4825         }
4826
4827         if ((n + offset) > ad_getentrylen(ad, ADEID_RFORK)) {
4828                 ad_setentrylen(ad, ADEID_RFORK, n + offset);
4829                 ret = ad_fset(ad, fsp);
4830                 if (ret != 0) {
4831                         DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp));
4832                         TALLOC_FREE(ad);
4833                         return -1;
4834                 }
4835         }
4836
4837         TALLOC_FREE(ad);
4838         return n;
4839 }
4840
4841 static ssize_t fruit_pwrite_rsrc(vfs_handle_struct *handle,
4842                                  files_struct *fsp, const void *data,
4843                                  size_t n, off_t offset)
4844 {
4845         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4846         ssize_t nwritten;
4847
4848         if (fio == NULL) {
4849                 DBG_ERR("Failed to fetch fsp extension");
4850                 return -1;
4851         }
4852
4853         switch (fio->config->rsrc) {
4854         case FRUIT_RSRC_STREAM:
4855                 nwritten = fruit_pwrite_rsrc_stream(handle, fsp, data, n, offset);
4856                 break;
4857
4858         case FRUIT_RSRC_ADFILE:
4859                 nwritten = fruit_pwrite_rsrc_adouble(handle, fsp, data, n, offset);
4860                 break;
4861
4862         case FRUIT_RSRC_XATTR:
4863                 nwritten = fruit_pwrite_rsrc_xattr(handle, fsp, data, n, offset);
4864                 break;
4865
4866         default:
4867                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
4868                 return -1;
4869         }
4870
4871         return nwritten;
4872 }
4873
4874 static ssize_t fruit_pwrite(vfs_handle_struct *handle,
4875                             files_struct *fsp, const void *data,
4876                             size_t n, off_t offset)
4877 {
4878         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4879         ssize_t nwritten;
4880
4881         DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
4882                   fsp_str_dbg(fsp), (intmax_t)offset, n);
4883
4884         if (fio == NULL) {
4885                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
4886         }
4887
4888         if (fio->type == ADOUBLE_META) {
4889                 nwritten = fruit_pwrite_meta(handle, fsp, data, n, offset);
4890         } else {
4891                 nwritten = fruit_pwrite_rsrc(handle, fsp, data, n, offset);
4892         }
4893
4894         DBG_DEBUG("Path [%s] nwritten=%zd\n", fsp_str_dbg(fsp), nwritten);
4895         return nwritten;
4896 }
4897
4898 struct fruit_pwrite_state {
4899         ssize_t nwritten;
4900         struct vfs_aio_state vfs_aio_state;
4901 };
4902
4903 static void fruit_pwrite_done(struct tevent_req *subreq);
4904
4905 static struct tevent_req *fruit_pwrite_send(
4906         struct vfs_handle_struct *handle,
4907         TALLOC_CTX *mem_ctx,
4908         struct tevent_context *ev,
4909         struct files_struct *fsp,
4910         const void *data,
4911         size_t n, off_t offset)
4912 {
4913         struct tevent_req *req = NULL;
4914         struct tevent_req *subreq = NULL;
4915         struct fruit_pwrite_state *state = NULL;
4916         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
4917
4918         req = tevent_req_create(mem_ctx, &state,
4919                                 struct fruit_pwrite_state);
4920         if (req == NULL) {
4921                 return NULL;
4922         }
4923
4924         if (fruit_must_handle_aio_stream(fio)) {
4925                 state->nwritten = SMB_VFS_PWRITE(fsp, data, n, offset);
4926                 if (state->nwritten != n) {
4927                         if (state->nwritten != -1) {
4928                                 errno = EIO;
4929                         }
4930                         tevent_req_error(req, errno);
4931                         return tevent_req_post(req, ev);
4932                 }
4933                 tevent_req_done(req);
4934                 return tevent_req_post(req, ev);
4935         }
4936
4937         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp,
4938                                           data, n, offset);
4939         if (tevent_req_nomem(req, subreq)) {
4940                 return tevent_req_post(req, ev);
4941         }
4942         tevent_req_set_callback(subreq, fruit_pwrite_done, req);
4943         return req;
4944 }
4945
4946 static void fruit_pwrite_done(struct tevent_req *subreq)
4947 {
4948         struct tevent_req *req = tevent_req_callback_data(
4949                 subreq, struct tevent_req);
4950         struct fruit_pwrite_state *state = tevent_req_data(
4951                 req, struct fruit_pwrite_state);
4952
4953         state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
4954         TALLOC_FREE(subreq);
4955
4956         if (tevent_req_error(req, state->vfs_aio_state.error)) {
4957                 return;
4958         }
4959         tevent_req_done(req);
4960 }
4961
4962 static ssize_t fruit_pwrite_recv(struct tevent_req *req,
4963                                          struct vfs_aio_state *vfs_aio_state)
4964 {
4965         struct fruit_pwrite_state *state = tevent_req_data(
4966                 req, struct fruit_pwrite_state);
4967
4968         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
4969                 return -1;
4970         }
4971
4972         *vfs_aio_state = state->vfs_aio_state;
4973         return state->nwritten;
4974 }
4975
4976 /**
4977  * Helper to stat/lstat the base file of an smb_fname.
4978  */
4979 static int fruit_stat_base(vfs_handle_struct *handle,
4980                            struct smb_filename *smb_fname,
4981                            bool follow_links)
4982 {
4983         char *tmp_stream_name;
4984         int rc;
4985
4986         tmp_stream_name = smb_fname->stream_name;
4987         smb_fname->stream_name = NULL;
4988         if (follow_links) {
4989                 rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
4990         } else {
4991                 rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
4992         }
4993         smb_fname->stream_name = tmp_stream_name;
4994
4995         DBG_DEBUG("fruit_stat_base [%s] dev [%ju] ino [%ju]\n",
4996                   smb_fname->base_name,
4997                   (uintmax_t)smb_fname->st.st_ex_dev,
4998                   (uintmax_t)smb_fname->st.st_ex_ino);
4999         return rc;
5000 }
5001
5002 static int fruit_stat_meta_stream(vfs_handle_struct *handle,
5003                                   struct smb_filename *smb_fname,
5004                                   bool follow_links)
5005 {
5006         int ret;
5007         ino_t ino;
5008
5009         ret = fruit_stat_base(handle, smb_fname, false);
5010         if (ret != 0) {
5011                 return -1;
5012         }
5013
5014         ino = fruit_inode(&smb_fname->st, smb_fname->stream_name);
5015
5016         if (follow_links) {
5017                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
5018         } else {
5019                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
5020         }
5021
5022         smb_fname->st.st_ex_ino = ino;
5023
5024         return ret;
5025 }
5026
5027 static int fruit_stat_meta_netatalk(vfs_handle_struct *handle,
5028                                     struct smb_filename *smb_fname,
5029                                     bool follow_links)
5030 {
5031         struct adouble *ad = NULL;
5032
5033         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
5034         if (ad == NULL) {
5035                 DBG_INFO("fruit_stat_meta %s: %s\n",
5036                          smb_fname_str_dbg(smb_fname), strerror(errno));
5037                 errno = ENOENT;
5038                 return -1;
5039         }
5040         TALLOC_FREE(ad);
5041
5042         /* Populate the stat struct with info from the base file. */
5043         if (fruit_stat_base(handle, smb_fname, follow_links) == -1) {
5044                 return -1;
5045         }
5046         smb_fname->st.st_ex_size = AFP_INFO_SIZE;
5047         smb_fname->st.st_ex_ino = fruit_inode(&smb_fname->st,
5048                                               smb_fname->stream_name);
5049         return 0;
5050 }
5051
5052 static int fruit_stat_meta(vfs_handle_struct *handle,
5053                            struct smb_filename *smb_fname,
5054                            bool follow_links)
5055 {
5056         struct fruit_config_data *config = NULL;
5057         int ret;
5058
5059         SMB_VFS_HANDLE_GET_DATA(handle, config,
5060                                 struct fruit_config_data, return -1);
5061
5062         switch (config->meta) {
5063         case FRUIT_META_STREAM:
5064                 ret = fruit_stat_meta_stream(handle, smb_fname, follow_links);
5065                 break;
5066
5067         case FRUIT_META_NETATALK:
5068                 ret = fruit_stat_meta_netatalk(handle, smb_fname, follow_links);
5069                 break;
5070
5071         default:
5072                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
5073                 return -1;
5074         }
5075
5076         return ret;
5077 }
5078
5079 static int fruit_stat_rsrc_netatalk(vfs_handle_struct *handle,
5080                                     struct smb_filename *smb_fname,
5081                                     bool follow_links)
5082 {
5083         struct adouble *ad = NULL;
5084         int ret;
5085
5086         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
5087         if (ad == NULL) {
5088                 errno = ENOENT;
5089                 return -1;
5090         }
5091
5092         /* Populate the stat struct with info from the base file. */
5093         ret = fruit_stat_base(handle, smb_fname, follow_links);
5094         if (ret != 0) {
5095                 TALLOC_FREE(ad);
5096                 return -1;
5097         }
5098
5099         smb_fname->st.st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
5100         smb_fname->st.st_ex_ino = fruit_inode(&smb_fname->st,
5101                                               smb_fname->stream_name);
5102         TALLOC_FREE(ad);
5103         return 0;
5104 }
5105
5106 static int fruit_stat_rsrc_stream(vfs_handle_struct *handle,
5107                                   struct smb_filename *smb_fname,
5108                                   bool follow_links)
5109 {
5110         int ret;
5111
5112         if (follow_links) {
5113                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
5114         } else {
5115                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
5116         }
5117
5118         return ret;
5119 }
5120
5121 static int fruit_stat_rsrc_xattr(vfs_handle_struct *handle,
5122                                  struct smb_filename *smb_fname,
5123                                  bool follow_links)
5124 {
5125 #ifdef HAVE_ATTROPEN
5126         int ret;
5127         int fd = -1;
5128
5129         /* Populate the stat struct with info from the base file. */
5130         ret = fruit_stat_base(handle, smb_fname, follow_links);
5131         if (ret != 0) {
5132                 return -1;
5133         }
5134
5135         fd = attropen(smb_fname->base_name,
5136                       AFPRESOURCE_EA_NETATALK,
5137                       O_RDONLY);
5138         if (fd == -1) {
5139                 return 0;
5140         }
5141
5142         ret = sys_fstat(fd, &smb_fname->st, false);
5143         if (ret != 0) {
5144                 close(fd);
5145                 DBG_ERR("fstat [%s:%s] failed\n", smb_fname->base_name,
5146                         AFPRESOURCE_EA_NETATALK);
5147                 return -1;
5148         }
5149         close(fd);
5150         fd = -1;
5151
5152         smb_fname->st.st_ex_ino = fruit_inode(&smb_fname->st,
5153                                               smb_fname->stream_name);
5154
5155         return ret;
5156
5157 #else
5158         errno = ENOSYS;
5159         return -1;
5160 #endif
5161 }
5162
5163 static int fruit_stat_rsrc(vfs_handle_struct *handle,
5164                            struct smb_filename *smb_fname,
5165                            bool follow_links)
5166 {
5167         struct fruit_config_data *config = NULL;
5168         int ret;
5169
5170         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
5171
5172         SMB_VFS_HANDLE_GET_DATA(handle, config,
5173                                 struct fruit_config_data, return -1);
5174
5175         switch (config->rsrc) {
5176         case FRUIT_RSRC_STREAM:
5177                 ret = fruit_stat_rsrc_stream(handle, smb_fname, follow_links);
5178                 break;
5179
5180         case FRUIT_RSRC_XATTR:
5181                 ret = fruit_stat_rsrc_xattr(handle, smb_fname, follow_links);
5182                 break;
5183
5184         case FRUIT_RSRC_ADFILE:
5185                 ret = fruit_stat_rsrc_netatalk(handle, smb_fname, follow_links);
5186                 break;
5187
5188         default:
5189                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
5190                 return -1;
5191         }
5192
5193         return ret;
5194 }
5195
5196 static int fruit_stat(vfs_handle_struct *handle,
5197                       struct smb_filename *smb_fname)
5198 {
5199         int rc = -1;
5200
5201         DEBUG(10, ("fruit_stat called for %s\n",
5202                    smb_fname_str_dbg(smb_fname)));
5203
5204         if (!is_ntfs_stream_smb_fname(smb_fname)
5205             || is_ntfs_default_stream_smb_fname(smb_fname)) {
5206                 rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
5207                 if (rc == 0) {
5208                         update_btime(handle, smb_fname);
5209                 }
5210                 return rc;
5211         }
5212
5213         /*
5214          * Note if lp_posix_paths() is true, we can never
5215          * get here as is_ntfs_stream_smb_fname() is
5216          * always false. So we never need worry about
5217          * not following links here.
5218          */
5219
5220         if (is_afpinfo_stream(smb_fname)) {
5221                 rc = fruit_stat_meta(handle, smb_fname, true);
5222         } else if (is_afpresource_stream(smb_fname)) {
5223                 rc = fruit_stat_rsrc(handle, smb_fname, true);
5224         } else {
5225                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
5226         }
5227
5228         if (rc == 0) {
5229                 update_btime(handle, smb_fname);
5230                 smb_fname->st.st_ex_mode &= ~S_IFMT;
5231                 smb_fname->st.st_ex_mode |= S_IFREG;
5232                 smb_fname->st.st_ex_blocks =
5233                         smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
5234         }
5235         return rc;
5236 }
5237
5238 static int fruit_lstat(vfs_handle_struct *handle,
5239                        struct smb_filename *smb_fname)
5240 {
5241         int rc = -1;
5242
5243         DEBUG(10, ("fruit_lstat called for %s\n",
5244                    smb_fname_str_dbg(smb_fname)));
5245
5246         if (!is_ntfs_stream_smb_fname(smb_fname)
5247             || is_ntfs_default_stream_smb_fname(smb_fname)) {
5248                 rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
5249                 if (rc == 0) {
5250                         update_btime(handle, smb_fname);
5251                 }
5252                 return rc;
5253         }
5254
5255         if (is_afpinfo_stream(smb_fname)) {
5256                 rc = fruit_stat_meta(handle, smb_fname, false);
5257         } else if (is_afpresource_stream(smb_fname)) {
5258                 rc = fruit_stat_rsrc(handle, smb_fname, false);
5259         } else {
5260                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
5261         }
5262
5263         if (rc == 0) {
5264                 update_btime(handle, smb_fname);
5265                 smb_fname->st.st_ex_mode &= ~S_IFMT;
5266                 smb_fname->st.st_ex_mode |= S_IFREG;
5267                 smb_fname->st.st_ex_blocks =
5268                         smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
5269         }
5270         return rc;
5271 }
5272
5273 static int fruit_fstat_meta_stream(vfs_handle_struct *handle,
5274                                    files_struct *fsp,
5275                                    SMB_STRUCT_STAT *sbuf)
5276 {
5277         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
5278         struct smb_filename smb_fname;
5279         ino_t ino;
5280         int ret;
5281
5282         if (fio == NULL) {
5283                 return -1;
5284         }
5285
5286         if (fio->fake_fd) {
5287                 ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
5288                 if (ret != 0) {
5289                         return -1;
5290                 }
5291
5292                 *sbuf = fsp->base_fsp->fsp_name->st;
5293                 sbuf->st_ex_size = AFP_INFO_SIZE;
5294                 sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
5295                 return 0;
5296         }
5297
5298         smb_fname = (struct smb_filename) {
5299                 .base_name = fsp->fsp_name->base_name,
5300         };
5301
5302         ret = fruit_stat_base(handle, &smb_fname, false);
5303         if (ret != 0) {
5304                 return -1;
5305         }
5306         *sbuf = smb_fname.st;
5307
5308         ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
5309
5310         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
5311         if (ret != 0) {
5312                 return -1;
5313         }
5314
5315         sbuf->st_ex_ino = ino;
5316         return 0;
5317 }
5318
5319 static int fruit_fstat_meta_netatalk(vfs_handle_struct *handle,
5320                                      files_struct *fsp,
5321                                      SMB_STRUCT_STAT *sbuf)
5322 {
5323         int ret;
5324
5325         ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
5326         if (ret != 0) {
5327                 return -1;
5328         }
5329
5330         *sbuf = fsp->base_fsp->fsp_name->st;
5331         sbuf->st_ex_size = AFP_INFO_SIZE;
5332         sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
5333
5334         return 0;
5335 }
5336
5337 static int fruit_fstat_meta(vfs_handle_struct *handle,
5338                             files_struct *fsp,
5339                             SMB_STRUCT_STAT *sbuf,
5340                             struct fio *fio)
5341 {
5342         int ret;
5343
5344         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
5345
5346         switch (fio->config->meta) {
5347         case FRUIT_META_STREAM:
5348                 ret = fruit_fstat_meta_stream(handle, fsp, sbuf);
5349                 break;
5350
5351         case FRUIT_META_NETATALK:
5352                 ret = fruit_fstat_meta_netatalk(handle, fsp, sbuf);
5353                 break;
5354
5355         default:
5356                 DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
5357                 return -1;
5358         }
5359
5360         DBG_DEBUG("Path [%s] ret [%d]\n", fsp_str_dbg(fsp), ret);
5361         return ret;
5362 }
5363
5364 static int fruit_fstat_rsrc_xattr(vfs_handle_struct *handle,
5365                                   files_struct *fsp,
5366                                   SMB_STRUCT_STAT *sbuf)
5367 {
5368         return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
5369 }
5370
5371 static int fruit_fstat_rsrc_stream(vfs_handle_struct *handle,
5372                                    files_struct *fsp,
5373                                    SMB_STRUCT_STAT *sbuf)
5374 {
5375         return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
5376 }
5377
5378 static int fruit_fstat_rsrc_adouble(vfs_handle_struct *handle,
5379                                     files_struct *fsp,
5380                                     SMB_STRUCT_STAT *sbuf)
5381 {
5382         struct adouble *ad = NULL;
5383         int ret;
5384
5385         /* Populate the stat struct with info from the base file. */
5386         ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
5387         if (ret == -1) {
5388                 return -1;
5389         }
5390
5391         ad = ad_get(talloc_tos(), handle,
5392                     fsp->base_fsp->fsp_name,
5393                     ADOUBLE_RSRC);
5394         if (ad == NULL) {
5395                 DBG_ERR("ad_get [%s] failed [%s]\n",
5396                         fsp_str_dbg(fsp), strerror(errno));
5397                 return -1;
5398         }
5399
5400         *sbuf = fsp->base_fsp->fsp_name->st;
5401         sbuf->st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
5402         sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
5403
5404         TALLOC_FREE(ad);
5405         return 0;
5406 }
5407
5408 static int fruit_fstat_rsrc(vfs_handle_struct *handle, files_struct *fsp,
5409                             SMB_STRUCT_STAT *sbuf, struct fio *fio)
5410 {
5411         int ret;
5412
5413         switch (fio->config->rsrc) {
5414         case FRUIT_RSRC_STREAM:
5415                 ret = fruit_fstat_rsrc_stream(handle, fsp, sbuf);
5416                 break;
5417
5418         case FRUIT_RSRC_ADFILE:
5419                 ret = fruit_fstat_rsrc_adouble(handle, fsp, sbuf);
5420                 break;
5421
5422         case FRUIT_RSRC_XATTR:
5423                 ret = fruit_fstat_rsrc_xattr(handle, fsp, sbuf);
5424                 break;
5425
5426         default:
5427                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
5428                 return -1;
5429         }
5430
5431         return ret;
5432 }
5433
5434 static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp,
5435                        SMB_STRUCT_STAT *sbuf)
5436 {
5437         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
5438         int rc;
5439
5440         if (fio == NULL) {
5441                 return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
5442         }
5443
5444         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
5445
5446         if (fio->type == ADOUBLE_META) {
5447                 rc = fruit_fstat_meta(handle, fsp, sbuf, fio);
5448         } else {
5449                 rc = fruit_fstat_rsrc(handle, fsp, sbuf, fio);
5450         }
5451
5452         if (rc == 0) {
5453                 sbuf->st_ex_mode &= ~S_IFMT;
5454                 sbuf->st_ex_mode |= S_IFREG;
5455                 sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
5456         }
5457
5458         DBG_DEBUG("Path [%s] rc [%d] size [%"PRIdMAX"]\n",
5459                   fsp_str_dbg(fsp), rc, (intmax_t)sbuf->st_ex_size);
5460         return rc;
5461 }
5462
5463 static NTSTATUS delete_invalid_meta_stream(
5464         vfs_handle_struct *handle,
5465         const struct smb_filename *smb_fname,
5466         TALLOC_CTX *mem_ctx,
5467         unsigned int *pnum_streams,
5468         struct stream_struct **pstreams,
5469         off_t size)
5470 {
5471         struct smb_filename *sname = NULL;
5472         int ret;
5473         bool ok;
5474
5475         ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams, AFPINFO_STREAM);
5476         if (!ok) {
5477                 return NT_STATUS_INTERNAL_ERROR;
5478         }
5479
5480         if (size == 0) {
5481                 return NT_STATUS_OK;
5482         }
5483
5484         sname = synthetic_smb_fname(talloc_tos(),
5485                                     smb_fname->base_name,
5486                                     AFPINFO_STREAM_NAME,
5487                                     NULL, 0);
5488         if (sname == NULL) {
5489                 return NT_STATUS_NO_MEMORY;
5490         }
5491
5492         ret = SMB_VFS_NEXT_UNLINK(handle, sname);
5493         TALLOC_FREE(sname);
5494         if (ret != 0) {
5495                 DBG_ERR("Removing [%s] failed\n", smb_fname_str_dbg(sname));
5496                 return map_nt_error_from_unix(errno);
5497         }
5498
5499         return NT_STATUS_OK;
5500 }
5501
5502 static NTSTATUS fruit_streaminfo_meta_stream(
5503         vfs_handle_struct *handle,
5504         struct files_struct *fsp,
5505         const struct smb_filename *smb_fname,
5506         TALLOC_CTX *mem_ctx,
5507         unsigned int *pnum_streams,
5508         struct stream_struct **pstreams)
5509 {
5510         struct stream_struct *stream = *pstreams;
5511         unsigned int num_streams = *pnum_streams;
5512         int i;
5513
5514         for (i = 0; i < num_streams; i++) {
5515                 if (strequal_m(stream[i].name, AFPINFO_STREAM)) {
5516                         break;
5517                 }
5518         }
5519
5520         if (i == num_streams) {
5521                 return NT_STATUS_OK;
5522         }
5523
5524         if (stream[i].size != AFP_INFO_SIZE) {
5525                 DBG_ERR("Removing invalid AFPINFO_STREAM size [%jd] from [%s]\n",
5526                         (intmax_t)stream[i].size, smb_fname_str_dbg(smb_fname));
5527
5528                 return delete_invalid_meta_stream(handle,
5529                                                   smb_fname,
5530                                                   mem_ctx,
5531                                                   pnum_streams,
5532                                                   pstreams,
5533                                                   stream[i].size);
5534         }
5535
5536
5537         return NT_STATUS_OK;
5538 }
5539
5540 static NTSTATUS fruit_streaminfo_meta_netatalk(
5541         vfs_handle_struct *handle,
5542         struct files_struct *fsp,
5543         const struct smb_filename *smb_fname,
5544         TALLOC_CTX *mem_ctx,
5545         unsigned int *pnum_streams,
5546         struct stream_struct **pstreams)
5547 {
5548         struct stream_struct *stream = *pstreams;
5549         unsigned int num_streams = *pnum_streams;
5550         struct adouble *ad = NULL;
5551         bool is_fi_empty;
5552         int i;
5553         bool ok;
5554
5555         /* Remove the Netatalk xattr from the list */
5556         ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
5557                               ":" NETATALK_META_XATTR ":$DATA");
5558         if (!ok) {
5559                 return NT_STATUS_NO_MEMORY;
5560         }
5561
5562         /*
5563          * Check if there's a AFPINFO_STREAM from the VFS streams
5564          * backend and if yes, remove it from the list
5565          */
5566         for (i = 0; i < num_streams; i++) {
5567                 if (strequal_m(stream[i].name, AFPINFO_STREAM)) {
5568                         break;
5569                 }
5570         }
5571
5572         if (i < num_streams) {
5573                 DBG_WARNING("Unexpected AFPINFO_STREAM on [%s]\n",
5574                             smb_fname_str_dbg(smb_fname));
5575
5576                 ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
5577                                       AFPINFO_STREAM);
5578                 if (!ok) {
5579                         return NT_STATUS_INTERNAL_ERROR;
5580                 }
5581         }
5582
5583         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
5584         if (ad == NULL) {
5585                 return NT_STATUS_OK;
5586         }
5587
5588         is_fi_empty = ad_empty_finderinfo(ad);
5589         TALLOC_FREE(ad);
5590
5591         if (is_fi_empty) {
5592                 return NT_STATUS_OK;
5593         }
5594
5595         ok = add_fruit_stream(mem_ctx, pnum_streams, pstreams,
5596                               AFPINFO_STREAM_NAME, AFP_INFO_SIZE,
5597                               smb_roundup(handle->conn, AFP_INFO_SIZE));
5598         if (!ok) {
5599                 return NT_STATUS_NO_MEMORY;
5600         }
5601
5602         return NT_STATUS_OK;
5603 }
5604
5605 static NTSTATUS fruit_streaminfo_meta(vfs_handle_struct *handle,
5606                                       struct files_struct *fsp,
5607                                       const struct smb_filename *smb_fname,
5608                                       TALLOC_CTX *mem_ctx,
5609                                       unsigned int *pnum_streams,
5610                                       struct stream_struct **pstreams)
5611 {
5612         struct fruit_config_data *config = NULL;
5613         NTSTATUS status;
5614
5615         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
5616                                 return NT_STATUS_INTERNAL_ERROR);
5617
5618         switch (config->meta) {
5619         case FRUIT_META_NETATALK:
5620                 status = fruit_streaminfo_meta_netatalk(handle, fsp, smb_fname,
5621                                                         mem_ctx, pnum_streams,
5622                                                         pstreams);
5623                 break;
5624
5625         case FRUIT_META_STREAM:
5626                 status = fruit_streaminfo_meta_stream(handle, fsp, smb_fname,
5627                                                       mem_ctx, pnum_streams,
5628                                                       pstreams);
5629                 break;
5630
5631         default:
5632                 return NT_STATUS_INTERNAL_ERROR;
5633         }
5634
5635         return status;
5636 }
5637
5638 static NTSTATUS fruit_streaminfo_rsrc_stream(
5639         vfs_handle_struct *handle,
5640         struct files_struct *fsp,
5641         const struct smb_filename *smb_fname,
5642         TALLOC_CTX *mem_ctx,
5643         unsigned int *pnum_streams,
5644         struct stream_struct **pstreams)
5645 {
5646         bool ok;
5647
5648         ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
5649         if (!ok) {
5650                 DBG_ERR("Filtering resource stream failed\n");
5651                 return NT_STATUS_INTERNAL_ERROR;
5652         }
5653         return NT_STATUS_OK;
5654 }
5655
5656 static NTSTATUS fruit_streaminfo_rsrc_xattr(
5657         vfs_handle_struct *handle,
5658         struct files_struct *fsp,
5659         const struct smb_filename *smb_fname,
5660         TALLOC_CTX *mem_ctx,
5661         unsigned int *pnum_streams,
5662         struct stream_struct **pstreams)
5663 {
5664         bool ok;
5665
5666         ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
5667         if (!ok) {
5668                 DBG_ERR("Filtering resource stream failed\n");
5669                 return NT_STATUS_INTERNAL_ERROR;
5670         }
5671         return NT_STATUS_OK;
5672 }
5673
5674 static NTSTATUS fruit_streaminfo_rsrc_adouble(
5675         vfs_handle_struct *handle,
5676         struct files_struct *fsp,
5677         const struct smb_filename *smb_fname,
5678         TALLOC_CTX *mem_ctx,
5679         unsigned int *pnum_streams,
5680         struct stream_struct **pstreams)
5681 {
5682         struct stream_struct *stream = *pstreams;
5683         unsigned int num_streams = *pnum_streams;
5684         struct adouble *ad = NULL;
5685         bool ok;
5686         size_t rlen;
5687         int i;
5688
5689         /*
5690          * Check if there's a AFPRESOURCE_STREAM from the VFS streams backend
5691          * and if yes, remove it from the list
5692          */
5693         for (i = 0; i < num_streams; i++) {
5694                 if (strequal_m(stream[i].name, AFPRESOURCE_STREAM)) {
5695                         break;
5696                 }
5697         }
5698
5699         if (i < num_streams) {
5700                 DBG_WARNING("Unexpected AFPRESOURCE_STREAM on [%s]\n",
5701                             smb_fname_str_dbg(smb_fname));
5702
5703                 ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
5704                                       AFPRESOURCE_STREAM);
5705                 if (!ok) {
5706                         return NT_STATUS_INTERNAL_ERROR;
5707                 }
5708         }
5709
5710         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
5711         if (ad == NULL) {
5712                 return NT_STATUS_OK;
5713         }
5714
5715         rlen = ad_getentrylen(ad, ADEID_RFORK);
5716         TALLOC_FREE(ad);
5717
5718         if (rlen == 0) {
5719                 return NT_STATUS_OK;
5720         }
5721
5722         ok = add_fruit_stream(mem_ctx, pnum_streams, pstreams,
5723                               AFPRESOURCE_STREAM_NAME, rlen,
5724                               smb_roundup(handle->conn, rlen));
5725         if (!ok) {
5726                 return NT_STATUS_NO_MEMORY;
5727         }
5728
5729         return NT_STATUS_OK;
5730 }
5731
5732 static NTSTATUS fruit_streaminfo_rsrc(vfs_handle_struct *handle,
5733                                       struct files_struct *fsp,
5734                                       const struct smb_filename *smb_fname,
5735                                       TALLOC_CTX *mem_ctx,
5736                                       unsigned int *pnum_streams,
5737                                       struct stream_struct **pstreams)
5738 {
5739         struct fruit_config_data *config = NULL;
5740         NTSTATUS status;
5741
5742         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
5743                                 return NT_STATUS_INTERNAL_ERROR);
5744
5745         switch (config->rsrc) {
5746         case FRUIT_RSRC_STREAM:
5747                 status = fruit_streaminfo_rsrc_stream(handle, fsp, smb_fname,
5748                                                       mem_ctx, pnum_streams,
5749                                                       pstreams);
5750                 break;
5751
5752         case FRUIT_RSRC_XATTR:
5753                 status = fruit_streaminfo_rsrc_xattr(handle, fsp, smb_fname,
5754                                                      mem_ctx, pnum_streams,
5755                                                      pstreams);
5756                 break;
5757
5758         case FRUIT_RSRC_ADFILE:
5759                 status = fruit_streaminfo_rsrc_adouble(handle, fsp, smb_fname,
5760                                                        mem_ctx, pnum_streams,
5761                                                        pstreams);
5762                 break;
5763
5764         default:
5765                 return NT_STATUS_INTERNAL_ERROR;
5766         }
5767
5768         return status;
5769 }
5770
5771 static void fruit_filter_empty_streams(unsigned int *pnum_streams,
5772                                        struct stream_struct **pstreams)
5773 {
5774         unsigned num_streams = *pnum_streams;
5775         struct stream_struct *streams = *pstreams;
5776         unsigned i = 0;
5777
5778         if (!global_fruit_config.nego_aapl) {
5779                 return;
5780         }
5781
5782         while (i < num_streams) {
5783                 struct smb_filename smb_fname = (struct smb_filename) {
5784                         .stream_name = streams[i].name,
5785                 };
5786
5787                 if (is_ntfs_default_stream_smb_fname(&smb_fname)
5788                     || streams[i].size > 0)
5789                 {
5790                         i++;
5791                         continue;
5792                 }
5793
5794                 streams[i] = streams[num_streams - 1];
5795                 num_streams--;
5796         }
5797
5798         *pnum_streams = num_streams;
5799 }
5800
5801 static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
5802                                  struct files_struct *fsp,
5803                                  const struct smb_filename *smb_fname,
5804                                  TALLOC_CTX *mem_ctx,
5805                                  unsigned int *pnum_streams,
5806                                  struct stream_struct **pstreams)
5807 {
5808         struct fruit_config_data *config = NULL;
5809         NTSTATUS status;
5810
5811         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
5812                                 return NT_STATUS_UNSUCCESSFUL);
5813
5814         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
5815
5816         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname, mem_ctx,
5817                                          pnum_streams, pstreams);
5818         if (!NT_STATUS_IS_OK(status)) {
5819                 return status;
5820         }
5821
5822         fruit_filter_empty_streams(pnum_streams, pstreams);
5823
5824         status = fruit_streaminfo_meta(handle, fsp, smb_fname,
5825                                        mem_ctx, pnum_streams, pstreams);
5826         if (!NT_STATUS_IS_OK(status)) {
5827                 return status;
5828         }
5829
5830         status = fruit_streaminfo_rsrc(handle, fsp, smb_fname,
5831                                        mem_ctx, pnum_streams, pstreams);
5832         if (!NT_STATUS_IS_OK(status)) {
5833                 return status;
5834         }
5835
5836         return NT_STATUS_OK;
5837 }
5838
5839 static int fruit_ntimes(vfs_handle_struct *handle,
5840                         const struct smb_filename *smb_fname,
5841                         struct smb_file_time *ft)
5842 {
5843         int rc = 0;
5844         struct adouble *ad = NULL;
5845         struct fruit_config_data *config = NULL;
5846
5847         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
5848                                 return -1);
5849
5850         if ((config->meta != FRUIT_META_NETATALK) ||
5851             null_timespec(ft->create_time))
5852         {
5853                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
5854         }
5855
5856         DEBUG(10,("set btime for %s to %s\n", smb_fname_str_dbg(smb_fname),
5857                  time_to_asc(convert_timespec_to_time_t(ft->create_time))));
5858
5859         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
5860         if (ad == NULL) {
5861                 goto exit;
5862         }
5863
5864         ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX,
5865                    convert_time_t_to_uint32_t(ft->create_time.tv_sec));
5866
5867         rc = ad_set(ad, smb_fname);
5868
5869 exit:
5870
5871         TALLOC_FREE(ad);
5872         if (rc != 0) {
5873                 DEBUG(1, ("fruit_ntimes: %s\n", smb_fname_str_dbg(smb_fname)));
5874                 return -1;
5875         }
5876         return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
5877 }
5878
5879 static int fruit_fallocate(struct vfs_handle_struct *handle,
5880                            struct files_struct *fsp,
5881                            uint32_t mode,
5882                            off_t offset,
5883                            off_t len)
5884 {
5885         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
5886
5887         if (fio == NULL) {
5888                 return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
5889         }
5890
5891         /* Let the pwrite code path handle it. */
5892         errno = ENOSYS;
5893         return -1;
5894 }
5895
5896 static int fruit_ftruncate_rsrc_xattr(struct vfs_handle_struct *handle,
5897                                       struct files_struct *fsp,
5898                                       off_t offset)
5899 {
5900 #ifdef HAVE_ATTROPEN
5901         return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
5902 #endif
5903         return 0;
5904 }
5905
5906 static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle,
5907                                         struct files_struct *fsp,
5908                                         off_t offset)
5909 {
5910         int rc;
5911         struct adouble *ad = NULL;
5912         off_t ad_off;
5913
5914         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
5915         if (ad == NULL) {
5916                 DBG_DEBUG("ad_get [%s] failed [%s]\n",
5917                           fsp_str_dbg(fsp), strerror(errno));
5918                 return -1;
5919         }
5920
5921         ad_off = ad_getentryoff(ad, ADEID_RFORK);
5922
5923         rc = ftruncate(fsp->fh->fd, offset + ad_off);
5924         if (rc != 0) {
5925                 TALLOC_FREE(ad);
5926                 return -1;
5927         }
5928
5929         ad_setentrylen(ad, ADEID_RFORK, offset);
5930
5931         rc = ad_fset(ad, fsp);
5932         if (rc != 0) {
5933                 DBG_ERR("ad_fset [%s] failed [%s]\n",
5934                         fsp_str_dbg(fsp), strerror(errno));
5935                 TALLOC_FREE(ad);
5936                 return -1;
5937         }
5938
5939         TALLOC_FREE(ad);
5940         return 0;
5941 }
5942
5943 static int fruit_ftruncate_rsrc_stream(struct vfs_handle_struct *handle,
5944                                        struct files_struct *fsp,
5945                                        off_t offset)
5946 {
5947         return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
5948 }
5949
5950 static int fruit_ftruncate_rsrc(struct vfs_handle_struct *handle,
5951                                 struct files_struct *fsp,
5952                                 off_t offset)
5953 {
5954         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
5955         int ret;
5956
5957         if (fio == NULL) {
5958                 DBG_ERR("Failed to fetch fsp extension");
5959                 return -1;
5960         }
5961
5962         switch (fio->config->rsrc) {
5963         case FRUIT_RSRC_XATTR:
5964                 ret = fruit_ftruncate_rsrc_xattr(handle, fsp, offset);
5965                 break;
5966
5967         case FRUIT_RSRC_ADFILE:
5968                 ret = fruit_ftruncate_rsrc_adouble(handle, fsp, offset);
5969                 break;
5970
5971         case FRUIT_RSRC_STREAM:
5972                 ret = fruit_ftruncate_rsrc_stream(handle, fsp, offset);
5973                 break;
5974
5975         default:
5976                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
5977                 return -1;
5978         }
5979
5980
5981         return ret;
5982 }
5983
5984 static int fruit_ftruncate_meta(struct vfs_handle_struct *handle,
5985                                 struct files_struct *fsp,
5986                                 off_t offset)
5987 {
5988         if (offset > 60) {
5989                 DBG_WARNING("ftruncate %s to %jd",
5990                             fsp_str_dbg(fsp), (intmax_t)offset);
5991                 /* OS X returns NT_STATUS_ALLOTTED_SPACE_EXCEEDED  */
5992                 errno = EOVERFLOW;
5993                 return -1;
5994         }
5995
5996         /* OS X returns success but does nothing  */
5997         DBG_INFO("ignoring ftruncate %s to %jd\n",
5998                  fsp_str_dbg(fsp), (intmax_t)offset);
5999         return 0;
6000 }
6001
6002 static int fruit_ftruncate(struct vfs_handle_struct *handle,
6003                            struct files_struct *fsp,
6004                            off_t offset)
6005 {
6006         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
6007         int ret;
6008
6009         DBG_DEBUG("Path [%s] offset [%"PRIdMAX"]\n", fsp_str_dbg(fsp),
6010                   (intmax_t)offset);
6011
6012         if (fio == NULL) {
6013                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
6014         }
6015
6016         if (fio->type == ADOUBLE_META) {
6017                 ret = fruit_ftruncate_meta(handle, fsp, offset);
6018         } else {
6019                 ret = fruit_ftruncate_rsrc(handle, fsp, offset);
6020         }
6021
6022         DBG_DEBUG("Path [%s] result [%d]\n", fsp_str_dbg(fsp), ret);
6023         return ret;
6024 }
6025
6026 static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
6027                                   struct smb_request *req,
6028                                   uint16_t root_dir_fid,
6029                                   struct smb_filename *smb_fname,
6030                                   uint32_t access_mask,
6031                                   uint32_t share_access,
6032                                   uint32_t create_disposition,
6033                                   uint32_t create_options,
6034                                   uint32_t file_attributes,
6035                                   uint32_t oplock_request,
6036                                   struct smb2_lease *lease,
6037                                   uint64_t allocation_size,
6038                                   uint32_t private_flags,
6039                                   struct security_descriptor *sd,
6040                                   struct ea_list *ea_list,
6041                                   files_struct **result,
6042                                   int *pinfo,
6043                                   const struct smb2_create_blobs *in_context_blobs,
6044                                   struct smb2_create_blobs *out_context_blobs)
6045 {
6046         NTSTATUS status;
6047         struct fruit_config_data *config = NULL;
6048         files_struct *fsp = NULL;
6049         struct fio *fio = NULL;
6050
6051         status = check_aapl(handle, req, in_context_blobs, out_context_blobs);
6052         if (!NT_STATUS_IS_OK(status)) {
6053                 goto fail;
6054         }
6055
6056         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
6057                                 return NT_STATUS_UNSUCCESSFUL);
6058
6059         status = SMB_VFS_NEXT_CREATE_FILE(
6060                 handle, req, root_dir_fid, smb_fname,
6061                 access_mask, share_access,
6062                 create_disposition, create_options,
6063                 file_attributes, oplock_request,
6064                 lease,
6065                 allocation_size, private_flags,
6066                 sd, ea_list, result,
6067                 pinfo, in_context_blobs, out_context_blobs);
6068         if (!NT_STATUS_IS_OK(status)) {
6069                 return status;
6070         }
6071
6072         fsp = *result;
6073
6074         if (global_fruit_config.nego_aapl) {
6075                 if (config->posix_rename && fsp->is_directory) {
6076                         /*
6077                          * Enable POSIX directory rename behaviour
6078                          */
6079                         fsp->posix_flags |= FSP_POSIX_FLAGS_RENAME;
6080                 }
6081         }
6082
6083         /*
6084          * If this is a plain open for existing files, opening an 0
6085          * byte size resource fork MUST fail with
6086          * NT_STATUS_OBJECT_NAME_NOT_FOUND.
6087          *
6088          * Cf the vfs_fruit torture tests in test_rfork_create().
6089          */
6090         if (global_fruit_config.nego_aapl &&
6091             create_disposition == FILE_OPEN &&
6092             smb_fname->st.st_ex_size == 0 &&
6093             is_ntfs_stream_smb_fname(smb_fname) &&
6094             !(is_ntfs_default_stream_smb_fname(smb_fname)))
6095         {
6096                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6097                 goto fail;
6098         }
6099
6100         fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
6101         if (fio != NULL && pinfo != NULL && *pinfo == FILE_WAS_CREATED) {
6102                 fio->created = true;
6103         }
6104
6105         if (is_ntfs_stream_smb_fname(smb_fname)
6106             || fsp->is_directory) {
6107                 return status;
6108         }
6109
6110         if (config->locking == FRUIT_LOCKING_NETATALK) {
6111                 status = fruit_check_access(
6112                         handle, *result,
6113                         access_mask,
6114                         share_access);
6115                 if (!NT_STATUS_IS_OK(status)) {
6116                         goto fail;
6117                 }
6118         }
6119
6120         return status;
6121
6122 fail:
6123         DEBUG(10, ("fruit_create_file: %s\n", nt_errstr(status)));
6124
6125         if (fsp) {
6126                 close_file(req, fsp, ERROR_CLOSE);
6127                 *result = fsp = NULL;
6128         }
6129
6130         return status;
6131 }
6132
6133 static NTSTATUS fruit_readdir_attr(struct vfs_handle_struct *handle,
6134                                    const struct smb_filename *fname,
6135                                    TALLOC_CTX *mem_ctx,
6136                                    struct readdir_attr_data **pattr_data)
6137 {
6138         struct fruit_config_data *config = NULL;
6139         struct readdir_attr_data *attr_data;
6140         NTSTATUS status;
6141
6142         SMB_VFS_HANDLE_GET_DATA(handle, config,
6143                                 struct fruit_config_data,
6144                                 return NT_STATUS_UNSUCCESSFUL);
6145
6146         if (!global_fruit_config.nego_aapl) {
6147                 return SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
6148         }
6149
6150         DEBUG(10, ("fruit_readdir_attr %s\n", fname->base_name));
6151
6152         *pattr_data = talloc_zero(mem_ctx, struct readdir_attr_data);
6153         if (*pattr_data == NULL) {
6154                 return NT_STATUS_UNSUCCESSFUL;
6155         }
6156         attr_data = *pattr_data;
6157         attr_data->type = RDATTR_AAPL;
6158
6159         /*
6160          * Mac metadata: compressed FinderInfo, resource fork length
6161          * and creation date
6162          */
6163         status = readdir_attr_macmeta(handle, fname, attr_data);
6164         if (!NT_STATUS_IS_OK(status)) {
6165                 /*
6166                  * Error handling is tricky: if we return failure from
6167                  * this function, the corresponding directory entry
6168                  * will to be passed to the client, so we really just
6169                  * want to error out on fatal errors.
6170                  */
6171                 if  (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
6172                         goto fail;
6173                 }
6174         }
6175
6176         /*
6177          * UNIX mode
6178          */
6179         if (config->unix_info_enabled) {
6180                 attr_data->attr_data.aapl.unix_mode = fname->st.st_ex_mode;
6181         }
6182
6183         /*
6184          * max_access
6185          */
6186         if (!config->readdir_attr_max_access) {
6187                 attr_data->attr_data.aapl.max_access = FILE_GENERIC_ALL;
6188         } else {
6189                 status = smbd_calculate_access_mask(
6190                         handle->conn,
6191                         fname,
6192                         false,
6193                         SEC_FLAG_MAXIMUM_ALLOWED,
6194                         &attr_data->attr_data.aapl.max_access);
6195                 if (!NT_STATUS_IS_OK(status)) {
6196                         goto fail;
6197                 }
6198         }
6199
6200         return NT_STATUS_OK;
6201
6202 fail:
6203         DEBUG(1, ("fruit_readdir_attr %s, error: %s\n",
6204                   fname->base_name, nt_errstr(status)));
6205         TALLOC_FREE(*pattr_data);
6206         return status;
6207 }
6208
6209 static NTSTATUS fruit_fget_nt_acl(vfs_handle_struct *handle,
6210                                   files_struct *fsp,
6211                                   uint32_t security_info,
6212                                   TALLOC_CTX *mem_ctx,
6213                                   struct security_descriptor **ppdesc)
6214 {
6215         NTSTATUS status;
6216         struct security_ace ace;
6217         struct dom_sid sid;
6218         struct fruit_config_data *config;
6219
6220         SMB_VFS_HANDLE_GET_DATA(handle, config,
6221                                 struct fruit_config_data,
6222                                 return NT_STATUS_UNSUCCESSFUL);
6223
6224         status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
6225                                           mem_ctx, ppdesc);
6226         if (!NT_STATUS_IS_OK(status)) {
6227                 return status;
6228         }
6229
6230         /*
6231          * Add MS NFS style ACEs with uid, gid and mode
6232          */
6233         if (!global_fruit_config.nego_aapl) {
6234                 return NT_STATUS_OK;
6235         }
6236         if (!config->unix_info_enabled) {
6237                 return NT_STATUS_OK;
6238         }
6239
6240         /* First remove any existing ACE's with NFS style mode/uid/gid SIDs. */
6241         status = remove_virtual_nfs_aces(*ppdesc);
6242         if (!NT_STATUS_IS_OK(status)) {
6243                 DBG_WARNING("failed to remove MS NFS style ACEs\n");
6244                 return status;
6245         }
6246
6247         /* MS NFS style mode */
6248         sid_compose(&sid, &global_sid_Unix_NFS_Mode, fsp->fsp_name->st.st_ex_mode);
6249         init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
6250         status = security_descriptor_dacl_add(*ppdesc, &ace);
6251         if (!NT_STATUS_IS_OK(status)) {
6252                 DEBUG(1,("failed to add MS NFS style ACE\n"));
6253                 return status;
6254         }
6255
6256         /* MS NFS style uid */
6257         sid_compose(&sid, &global_sid_Unix_NFS_Users, fsp->fsp_name->st.st_ex_uid);
6258         init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
6259         status = security_descriptor_dacl_add(*ppdesc, &ace);
6260         if (!NT_STATUS_IS_OK(status)) {
6261                 DEBUG(1,("failed to add MS NFS style ACE\n"));
6262                 return status;
6263         }
6264
6265         /* MS NFS style gid */
6266         sid_compose(&sid, &global_sid_Unix_NFS_Groups, fsp->fsp_name->st.st_ex_gid);
6267         init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
6268         status = security_descriptor_dacl_add(*ppdesc, &ace);
6269         if (!NT_STATUS_IS_OK(status)) {
6270                 DEBUG(1,("failed to add MS NFS style ACE\n"));
6271                 return status;
6272         }
6273
6274         return NT_STATUS_OK;
6275 }
6276
6277 static NTSTATUS fruit_fset_nt_acl(vfs_handle_struct *handle,
6278                                   files_struct *fsp,
6279                                   uint32_t security_info_sent,
6280                                   const struct security_descriptor *orig_psd)
6281 {
6282         NTSTATUS status;
6283         bool do_chmod;
6284         mode_t ms_nfs_mode = 0;
6285         int result;
6286         struct security_descriptor *psd = NULL;
6287         uint32_t orig_num_aces = 0;
6288
6289         if (orig_psd->dacl != NULL) {
6290                 orig_num_aces = orig_psd->dacl->num_aces;
6291         }
6292
6293         psd = security_descriptor_copy(talloc_tos(), orig_psd);
6294         if (psd == NULL) {
6295                 return NT_STATUS_NO_MEMORY;
6296         }
6297
6298         DBG_DEBUG("fruit_fset_nt_acl: %s\n", fsp_str_dbg(fsp));
6299
6300         status = check_ms_nfs(handle, fsp, psd, &ms_nfs_mode, &do_chmod);
6301         if (!NT_STATUS_IS_OK(status)) {
6302                 DEBUG(1, ("fruit_fset_nt_acl: check_ms_nfs failed%s\n", fsp_str_dbg(fsp)));
6303                 TALLOC_FREE(psd);
6304                 return status;
6305         }
6306
6307         /*
6308          * If only ms_nfs ACE entries were sent, ensure we set the DACL
6309          * sent/present flags correctly now we've removed them.
6310          */
6311
6312         if (orig_num_aces != 0) {
6313                 /*
6314                  * Are there any ACE's left ?
6315                  */
6316                 if (psd->dacl->num_aces == 0) {
6317                         /* No - clear the DACL sent/present flags. */
6318                         security_info_sent &= ~SECINFO_DACL;
6319                         psd->type &= ~SEC_DESC_DACL_PRESENT;
6320                 }
6321         }
6322
6323         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
6324         if (!NT_STATUS_IS_OK(status)) {
6325                 DEBUG(1, ("fruit_fset_nt_acl: SMB_VFS_NEXT_FSET_NT_ACL failed%s\n", fsp_str_dbg(fsp)));
6326                 TALLOC_FREE(psd);
6327                 return status;
6328         }
6329
6330         if (do_chmod) {
6331                 if (fsp->fh->fd != -1) {
6332                         result = SMB_VFS_FCHMOD(fsp, ms_nfs_mode);
6333                 } else {
6334                         result = SMB_VFS_CHMOD(fsp->conn,
6335                                                fsp->fsp_name,
6336                                                ms_nfs_mode);
6337                 }
6338
6339                 if (result != 0) {
6340                         DEBUG(1, ("chmod: %s, result: %d, %04o error %s\n", fsp_str_dbg(fsp),
6341                                   result, (unsigned)ms_nfs_mode,
6342                                   strerror(errno)));
6343                         status = map_nt_error_from_unix(errno);
6344                         TALLOC_FREE(psd);
6345                         return status;
6346                 }
6347         }
6348
6349         TALLOC_FREE(psd);
6350         return NT_STATUS_OK;
6351 }
6352
6353 static struct vfs_offload_ctx *fruit_offload_ctx;
6354
6355 struct fruit_offload_read_state {
6356         struct vfs_handle_struct *handle;
6357         struct tevent_context *ev;
6358         files_struct *fsp;
6359         uint32_t fsctl;
6360         DATA_BLOB token;
6361 };
6362
6363 static void fruit_offload_read_done(struct tevent_req *subreq);
6364
6365 static struct tevent_req *fruit_offload_read_send(
6366         TALLOC_CTX *mem_ctx,
6367         struct tevent_context *ev,
6368         struct vfs_handle_struct *handle,
6369         files_struct *fsp,
6370         uint32_t fsctl,
6371         uint32_t ttl,
6372         off_t offset,
6373         size_t to_copy)
6374 {
6375         struct tevent_req *req = NULL;
6376         struct tevent_req *subreq = NULL;
6377         struct fruit_offload_read_state *state = NULL;
6378
6379         req = tevent_req_create(mem_ctx, &state,
6380                                 struct fruit_offload_read_state);
6381         if (req == NULL) {
6382                 return NULL;
6383         }
6384         *state = (struct fruit_offload_read_state) {
6385                 .handle = handle,
6386                 .ev = ev,
6387                 .fsp = fsp,
6388                 .fsctl = fsctl,
6389         };
6390
6391         subreq = SMB_VFS_NEXT_OFFLOAD_READ_SEND(mem_ctx, ev, handle, fsp,
6392                                                 fsctl, ttl, offset, to_copy);
6393         if (tevent_req_nomem(subreq, req)) {
6394                 return tevent_req_post(req, ev);
6395         }
6396         tevent_req_set_callback(subreq, fruit_offload_read_done, req);
6397         return req;
6398 }
6399
6400 static void fruit_offload_read_done(struct tevent_req *subreq)
6401 {
6402         struct tevent_req *req = tevent_req_callback_data(
6403                 subreq, struct tevent_req);
6404         struct fruit_offload_read_state *state = tevent_req_data(
6405                 req, struct fruit_offload_read_state);
6406         NTSTATUS status;
6407
6408         status = SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq,
6409                                                 state->handle,
6410                                                 state,
6411                                                 &state->token);
6412         TALLOC_FREE(subreq);
6413         if (tevent_req_nterror(req, status)) {
6414                 return;
6415         }
6416
6417         if (state->fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
6418                 tevent_req_done(req);
6419                 return;
6420         }
6421
6422         status = vfs_offload_token_ctx_init(state->fsp->conn->sconn->client,
6423                                             &fruit_offload_ctx);
6424         if (tevent_req_nterror(req, status)) {
6425                 return;
6426         }
6427
6428         status = vfs_offload_token_db_store_fsp(fruit_offload_ctx,
6429                                                 state->fsp,
6430                                                 &state->token);
6431         if (tevent_req_nterror(req, status)) {
6432                 return;
6433         }
6434
6435         tevent_req_done(req);
6436         return;
6437 }
6438
6439 static NTSTATUS fruit_offload_read_recv(struct tevent_req *req,
6440                                         struct vfs_handle_struct *handle,
6441                                         TALLOC_CTX *mem_ctx,
6442                                         DATA_BLOB *token)
6443 {
6444         struct fruit_offload_read_state *state = tevent_req_data(
6445                 req, struct fruit_offload_read_state);
6446         NTSTATUS status;
6447
6448         if (tevent_req_is_nterror(req, &status)) {
6449                 tevent_req_received(req);
6450                 return status;
6451         }
6452
6453         token->length = state->token.length;
6454         token->data = talloc_move(mem_ctx, &state->token.data);
6455
6456         tevent_req_received(req);
6457         return NT_STATUS_OK;
6458 }
6459
6460 struct fruit_offload_write_state {
6461         struct vfs_handle_struct *handle;
6462         off_t copied;
6463         struct files_struct *src_fsp;
6464         struct files_struct *dst_fsp;
6465         bool is_copyfile;
6466 };
6467
6468 static void fruit_offload_write_done(struct tevent_req *subreq);
6469 static struct tevent_req *fruit_offload_write_send(struct vfs_handle_struct *handle,
6470                                                 TALLOC_CTX *mem_ctx,
6471                                                 struct tevent_context *ev,
6472                                                 uint32_t fsctl,
6473                                                 DATA_BLOB *token,
6474                                                 off_t transfer_offset,
6475                                                 struct files_struct *dest_fsp,
6476                                                 off_t dest_off,
6477                                                 off_t num)
6478 {
6479         struct tevent_req *req, *subreq;
6480         struct fruit_offload_write_state *state;
6481         NTSTATUS status;
6482         struct fruit_config_data *config;
6483         off_t src_off = transfer_offset;
6484         files_struct *src_fsp = NULL;
6485         off_t to_copy = num;
6486         bool copyfile_enabled = false;
6487
6488         DEBUG(10,("soff: %ju, doff: %ju, len: %ju\n",
6489                   (uintmax_t)src_off, (uintmax_t)dest_off, (uintmax_t)num));
6490
6491         SMB_VFS_HANDLE_GET_DATA(handle, config,
6492                                 struct fruit_config_data,
6493                                 return NULL);
6494
6495         req = tevent_req_create(mem_ctx, &state,
6496                                 struct fruit_offload_write_state);
6497         if (req == NULL) {
6498                 return NULL;
6499         }
6500         state->handle = handle;
6501         state->dst_fsp = dest_fsp;
6502
6503         switch (fsctl) {
6504         case FSCTL_SRV_COPYCHUNK:
6505         case FSCTL_SRV_COPYCHUNK_WRITE:
6506                 copyfile_enabled = config->copyfile_enabled;
6507                 break;
6508         default:
6509                 break;
6510         }
6511
6512         /*
6513          * Check if this a OS X copyfile style copychunk request with
6514          * a requested chunk count of 0 that was translated to a
6515          * offload_write_send VFS call overloading the parameters src_off
6516          * = dest_off = num = 0.
6517          */
6518         if (copyfile_enabled && num == 0 && src_off == 0 && dest_off == 0) {
6519                 status = vfs_offload_token_db_fetch_fsp(
6520                         fruit_offload_ctx, token, &src_fsp);
6521                 if (tevent_req_nterror(req, status)) {
6522                         return tevent_req_post(req, ev);
6523                 }
6524                 state->src_fsp = src_fsp;
6525
6526                 status = vfs_stat_fsp(src_fsp);
6527                 if (tevent_req_nterror(req, status)) {
6528                         return tevent_req_post(req, ev);
6529                 }
6530
6531                 to_copy = src_fsp->fsp_name->st.st_ex_size;
6532                 state->is_copyfile = true;
6533         }
6534
6535         subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle,
6536                                               mem_ctx,
6537                                               ev,
6538                                               fsctl,
6539                                               token,
6540                                               transfer_offset,
6541                                               dest_fsp,
6542                                               dest_off,
6543                                               to_copy);
6544         if (tevent_req_nomem(subreq, req)) {
6545                 return tevent_req_post(req, ev);
6546         }
6547
6548         tevent_req_set_callback(subreq, fruit_offload_write_done, req);
6549         return req;
6550 }
6551
6552 static void fruit_offload_write_done(struct tevent_req *subreq)
6553 {
6554         struct tevent_req *req = tevent_req_callback_data(
6555                 subreq, struct tevent_req);
6556         struct fruit_offload_write_state *state = tevent_req_data(
6557                 req, struct fruit_offload_write_state);
6558         NTSTATUS status;
6559         unsigned int num_streams = 0;
6560         struct stream_struct *streams = NULL;
6561         unsigned int i;
6562         struct smb_filename *src_fname_tmp = NULL;
6563         struct smb_filename *dst_fname_tmp = NULL;
6564
6565         status = SMB_VFS_NEXT_OFFLOAD_WRITE_RECV(state->handle,
6566                                               subreq,
6567                                               &state->copied);
6568         TALLOC_FREE(subreq);
6569         if (tevent_req_nterror(req, status)) {
6570                 return;
6571         }
6572
6573         if (!state->is_copyfile) {
6574                 tevent_req_done(req);
6575                 return;
6576         }
6577
6578         /*
6579          * Now copy all remaining streams. We know the share supports
6580          * streams, because we're in vfs_fruit. We don't do this async
6581          * because streams are few and small.
6582          */
6583         status = vfs_streaminfo(state->handle->conn, state->src_fsp,
6584                                 state->src_fsp->fsp_name,
6585                                 req, &num_streams, &streams);
6586         if (tevent_req_nterror(req, status)) {
6587                 return;
6588         }
6589
6590         if (num_streams == 1) {
6591                 /* There is always one stream, ::$DATA. */
6592                 tevent_req_done(req);
6593                 return;
6594         }
6595
6596         for (i = 0; i < num_streams; i++) {
6597                 DEBUG(10, ("%s: stream: '%s'/%zu\n",
6598                           __func__, streams[i].name, (size_t)streams[i].size));
6599
6600                 src_fname_tmp = synthetic_smb_fname(
6601                         req,
6602                         state->src_fsp->fsp_name->base_name,
6603                         streams[i].name,
6604                         NULL,
6605                         state->src_fsp->fsp_name->flags);
6606                 if (tevent_req_nomem(src_fname_tmp, req)) {
6607                         return;
6608                 }
6609
6610                 if (is_ntfs_default_stream_smb_fname(src_fname_tmp)) {
6611                         TALLOC_FREE(src_fname_tmp);
6612                         continue;
6613                 }
6614
6615                 dst_fname_tmp = synthetic_smb_fname(
6616                         req,
6617                         state->dst_fsp->fsp_name->base_name,
6618                         streams[i].name,
6619                         NULL,
6620                         state->dst_fsp->fsp_name->flags);
6621                 if (tevent_req_nomem(dst_fname_tmp, req)) {
6622                         TALLOC_FREE(src_fname_tmp);
6623                         return;
6624                 }
6625
6626                 status = copy_file(req,
6627                                    state->handle->conn,
6628                                    src_fname_tmp,
6629                                    dst_fname_tmp,
6630                                    OPENX_FILE_CREATE_IF_NOT_EXIST,
6631                                    0, false);
6632                 if (!NT_STATUS_IS_OK(status)) {
6633                         DEBUG(1, ("%s: copy %s to %s failed: %s\n", __func__,
6634                                   smb_fname_str_dbg(src_fname_tmp),
6635                                   smb_fname_str_dbg(dst_fname_tmp),
6636                                   nt_errstr(status)));
6637                         TALLOC_FREE(src_fname_tmp);
6638                         TALLOC_FREE(dst_fname_tmp);
6639                         tevent_req_nterror(req, status);
6640                         return;
6641                 }
6642
6643                 TALLOC_FREE(src_fname_tmp);
6644                 TALLOC_FREE(dst_fname_tmp);
6645         }
6646
6647         TALLOC_FREE(streams);
6648         TALLOC_FREE(src_fname_tmp);
6649         TALLOC_FREE(dst_fname_tmp);
6650         tevent_req_done(req);
6651 }
6652
6653 static NTSTATUS fruit_offload_write_recv(struct vfs_handle_struct *handle,
6654                                       struct tevent_req *req,
6655                                       off_t *copied)
6656 {
6657         struct fruit_offload_write_state *state = tevent_req_data(
6658                 req, struct fruit_offload_write_state);
6659         NTSTATUS status;
6660
6661         if (tevent_req_is_nterror(req, &status)) {
6662                 DEBUG(1, ("server side copy chunk failed: %s\n",
6663                           nt_errstr(status)));
6664                 *copied = 0;
6665                 tevent_req_received(req);
6666                 return status;
6667         }
6668
6669         *copied = state->copied;
6670         tevent_req_received(req);
6671
6672         return NT_STATUS_OK;
6673 }
6674
6675 static char *fruit_get_bandsize_line(char **lines, int numlines)
6676 {
6677         static regex_t re;
6678         static bool re_initialized = false;
6679         int i;
6680         int ret;
6681
6682         if (!re_initialized) {
6683                 ret = regcomp(&re, "^[[:blank:]]*<key>band-size</key>$", 0);
6684                 if (ret != 0) {
6685                         return NULL;
6686                 }
6687                 re_initialized = true;
6688         }
6689
6690         for (i = 0; i < numlines; i++) {
6691                 regmatch_t matches[1];
6692
6693                 ret = regexec(&re, lines[i], 1, matches, 0);
6694                 if (ret == 0) {
6695                         /*
6696                          * Check if the match was on the last line, sa we want
6697                          * the subsequent line.
6698                          */
6699                         if (i + 1 == numlines) {
6700                                 return NULL;
6701                         }
6702                         return lines[i + 1];
6703                 }
6704                 if (ret != REG_NOMATCH) {
6705                         return NULL;
6706                 }
6707         }
6708
6709         return NULL;
6710 }
6711
6712 static bool fruit_get_bandsize_from_line(char *line, size_t *_band_size)
6713 {
6714         static regex_t re;
6715         static bool re_initialized = false;
6716         regmatch_t matches[2];
6717         uint64_t band_size;
6718         int ret;
6719         bool ok;
6720
6721         if (!re_initialized) {
6722                 ret = regcomp(&re,
6723                               "^[[:blank:]]*"
6724                               "<integer>\\([[:digit:]]*\\)</integer>$",
6725                               0);
6726                 if (ret != 0) {
6727                         return false;
6728                 }
6729                 re_initialized = true;
6730         }
6731
6732         ret = regexec(&re, line, 2, matches, 0);
6733         if (ret != 0) {
6734                 DBG_ERR("regex failed [%s]\n", line);
6735                 return false;
6736         }
6737
6738         line[matches[1].rm_eo] = '\0';
6739
6740         ok = conv_str_u64(&line[matches[1].rm_so], &band_size);
6741         if (!ok) {
6742                 return false;
6743         }
6744         *_band_size = (size_t)band_size;
6745         return true;
6746 }
6747
6748 /*
6749  * This reads and parses an Info.plist from a TM sparsebundle looking for the
6750  * "band-size" key and value.
6751  */
6752 static bool fruit_get_bandsize(vfs_handle_struct *handle,
6753                                const char *dir,
6754                                size_t *band_size)
6755 {
6756 #define INFO_PLIST_MAX_SIZE 64*1024
6757         char *plist = NULL;
6758         struct smb_filename *smb_fname = NULL;
6759         files_struct *fsp = NULL;
6760         uint8_t *file_data = NULL;
6761         char **lines = NULL;
6762         char *band_size_line = NULL;
6763         size_t plist_file_size;
6764         ssize_t nread;
6765         int numlines;
6766         int ret;
6767         bool ok = false;
6768         NTSTATUS status;
6769
6770         plist = talloc_asprintf(talloc_tos(),
6771                                 "%s/%s/Info.plist",
6772                                 handle->conn->connectpath,
6773                                 dir);
6774         if (plist == NULL) {
6775                 ok = false;
6776                 goto out;
6777         }
6778
6779         smb_fname = synthetic_smb_fname(talloc_tos(), plist, NULL, NULL, 0);
6780         if (smb_fname == NULL) {
6781                 ok = false;
6782                 goto out;
6783         }
6784
6785         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
6786         if (ret != 0) {
6787                 DBG_INFO("Ignoring Sparsebundle without Info.plist [%s]\n", dir);
6788                 ok = true;
6789                 goto out;
6790         }
6791
6792         plist_file_size = smb_fname->st.st_ex_size;
6793
6794         if (plist_file_size > INFO_PLIST_MAX_SIZE) {
6795                 DBG_INFO("%s is too large, ignoring\n", plist);
6796                 ok = true;
6797                 goto out;
6798         }
6799
6800         status = SMB_VFS_NEXT_CREATE_FILE(
6801                 handle,                         /* conn */
6802                 NULL,                           /* req */
6803                 0,                              /* root_dir_fid */
6804                 smb_fname,                      /* fname */
6805                 FILE_GENERIC_READ,              /* access_mask */
6806                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6807                 FILE_OPEN,                      /* create_disposition */
6808                 0,                              /* create_options */
6809                 0,                              /* file_attributes */
6810                 INTERNAL_OPEN_ONLY,             /* oplock_request */
6811                 NULL,                           /* lease */
6812                 0,                              /* allocation_size */
6813                 0,                              /* private_flags */
6814                 NULL,                           /* sd */
6815                 NULL,                           /* ea_list */
6816                 &fsp,                           /* result */
6817                 NULL,                           /* psbuf */
6818                 NULL, NULL);                    /* create context */
6819         if (!NT_STATUS_IS_OK(status)) {
6820                 DBG_INFO("Opening [%s] failed [%s]\n",
6821                          smb_fname_str_dbg(smb_fname), nt_errstr(status));
6822                 ok = false;
6823                 goto out;
6824         }
6825
6826         file_data = talloc_array(talloc_tos(), uint8_t, plist_file_size);
6827         if (file_data == NULL) {
6828                 ok = false;
6829                 goto out;
6830         }
6831
6832         nread = SMB_VFS_NEXT_PREAD(handle, fsp, file_data, plist_file_size, 0);
6833         if (nread != plist_file_size) {
6834                 DBG_ERR("Short read on [%s]: %zu/%zd\n",
6835                         fsp_str_dbg(fsp), nread, plist_file_size);
6836                 ok = false;
6837                 goto out;
6838
6839         }
6840
6841         status = close_file(NULL, fsp, NORMAL_CLOSE);
6842         fsp = NULL;
6843         if (!NT_STATUS_IS_OK(status)) {
6844                 DBG_ERR("close_file failed: %s\n", nt_errstr(status));
6845                 ok = false;
6846                 goto out;
6847         }
6848
6849         lines = file_lines_parse((char *)file_data,
6850                                  plist_file_size,
6851                                  &numlines,
6852                                  talloc_tos());
6853         if (lines == NULL) {
6854                 ok = false;
6855                 goto out;
6856         }
6857
6858         band_size_line = fruit_get_bandsize_line(lines, numlines);
6859         if (band_size_line == NULL) {
6860                 DBG_ERR("Didn't find band-size key in [%s]\n",
6861                         smb_fname_str_dbg(smb_fname));
6862                 ok = false;
6863                 goto out;
6864         }
6865
6866         ok = fruit_get_bandsize_from_line(band_size_line, band_size);
6867         if (!ok) {
6868                 DBG_ERR("fruit_get_bandsize_from_line failed\n");
6869                 goto out;
6870         }
6871
6872         DBG_DEBUG("Parsed band-size [%zu] for [%s]\n", *band_size, plist);
6873
6874 out:
6875         if (fsp != NULL) {
6876                 status = close_file(NULL, fsp, NORMAL_CLOSE);
6877                 if (!NT_STATUS_IS_OK(status)) {
6878                         DBG_ERR("close_file failed: %s\n", nt_errstr(status));
6879                 }
6880                 fsp = NULL;
6881         }
6882         TALLOC_FREE(plist);
6883         TALLOC_FREE(smb_fname);
6884         TALLOC_FREE(file_data);
6885         TALLOC_FREE(lines);
6886         return ok;
6887 }
6888
6889 struct fruit_disk_free_state {
6890         off_t total_size;
6891 };
6892
6893 static bool fruit_get_num_bands(vfs_handle_struct *handle,
6894                                 char *bundle,
6895                                 size_t *_nbands)
6896 {
6897         char *path = NULL;
6898         struct smb_filename *bands_dir = NULL;
6899         DIR *d = NULL;
6900         struct dirent *e = NULL;
6901         size_t nbands;
6902         int ret;
6903
6904         path = talloc_asprintf(talloc_tos(),
6905                                "%s/%s/bands",
6906                                handle->conn->connectpath,
6907                                bundle);
6908         if (path == NULL) {
6909                 return false;
6910         }
6911
6912         bands_dir = synthetic_smb_fname(talloc_tos(),
6913                                         path,
6914                                         NULL,
6915                                         NULL,
6916                                         0);
6917         TALLOC_FREE(path);
6918         if (bands_dir == NULL) {
6919                 return false;
6920         }
6921
6922         d = SMB_VFS_NEXT_OPENDIR(handle, bands_dir, NULL, 0);
6923         if (d == NULL) {
6924                 TALLOC_FREE(bands_dir);
6925                 return false;
6926         }
6927
6928         nbands = 0;
6929
6930         for (e = SMB_VFS_NEXT_READDIR(handle, d, NULL);
6931              e != NULL;
6932              e = SMB_VFS_NEXT_READDIR(handle, d, NULL))
6933         {
6934                 if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) {
6935                         continue;
6936                 }
6937                 nbands++;
6938         }
6939
6940         ret = SMB_VFS_NEXT_CLOSEDIR(handle, d);
6941         if (ret != 0) {
6942                 TALLOC_FREE(bands_dir);
6943                 return false;
6944         }
6945
6946         DBG_DEBUG("%zu bands in [%s]\n", nbands, smb_fname_str_dbg(bands_dir));
6947
6948         TALLOC_FREE(bands_dir);
6949
6950         *_nbands = nbands;
6951         return true;
6952 }
6953
6954 static bool fruit_tmsize_do_dirent(vfs_handle_struct *handle,
6955                                    struct fruit_disk_free_state *state,
6956                                    struct dirent *e)
6957 {
6958         bool ok;
6959         char *p = NULL;
6960         size_t sparsebundle_strlen = strlen("sparsebundle");
6961         size_t bandsize = 0;
6962         size_t nbands;
6963         off_t tm_size;
6964
6965         p = strstr(e->d_name, "sparsebundle");
6966         if (p == NULL) {
6967                 return true;
6968         }
6969
6970         if (p[sparsebundle_strlen] != '\0') {
6971                 return true;
6972         }
6973
6974         DBG_DEBUG("Processing sparsebundle [%s]\n", e->d_name);
6975
6976         ok = fruit_get_bandsize(handle, e->d_name, &bandsize);
6977         if (!ok) {
6978                 /*
6979                  * Beware of race conditions: this may be an uninitialized
6980                  * Info.plist that a client is just creating. We don't want let
6981                  * this to trigger complete failure.
6982                  */
6983                 DBG_ERR("Processing sparsebundle [%s] failed\n", e->d_name);
6984                 return true;
6985         }
6986
6987         ok = fruit_get_num_bands(handle, e->d_name, &nbands);
6988         if (!ok) {
6989                 /*
6990                  * Beware of race conditions: this may be a backup sparsebundle
6991                  * in an early stage lacking a bands subdirectory. We don't want
6992                  * let this to trigger complete failure.
6993                  */
6994                 DBG_ERR("Processing sparsebundle [%s] failed\n", e->d_name);
6995                 return true;
6996         }
6997
6998         if (bandsize > SIZE_MAX/nbands) {
6999                 DBG_ERR("tmsize overflow: bandsize [%zu] nbands [%zu]\n",
7000                         bandsize, nbands);
7001                 return false;
7002         }
7003         tm_size = bandsize * nbands;
7004
7005         if (state->total_size + tm_size < state->total_size) {
7006                 DBG_ERR("tmsize overflow: bandsize [%zu] nbands [%zu]\n",
7007                         bandsize, nbands);
7008                 return false;
7009         }
7010
7011         state->total_size += tm_size;
7012
7013         DBG_DEBUG("[%s] tm_size [%jd] total_size [%jd]\n",
7014                   e->d_name, (intmax_t)tm_size, (intmax_t)state->total_size);
7015
7016         return true;
7017 }
7018
7019 /**
7020  * Calculate used size of a TimeMachine volume
7021  *
7022  * This assumes that the volume is used only for TimeMachine.
7023  *
7024  * - readdir(basedir of share), then
7025  * - for every element that matches regex "^\(.*\)\.sparsebundle$" :
7026  * - parse "\1.sparsebundle/Info.plist" and read the band-size XML key
7027  * - count band files in "\1.sparsebundle/bands/"
7028  * - calculate used size of all bands: band_count * band_size
7029  **/
7030 static uint64_t fruit_disk_free(vfs_handle_struct *handle,
7031                                 const struct smb_filename *smb_fname,
7032                                 uint64_t *_bsize,
7033                                 uint64_t *_dfree,
7034                                 uint64_t *_dsize)
7035 {
7036         struct fruit_config_data *config = NULL;
7037         struct fruit_disk_free_state state = {0};
7038         DIR *d = NULL;
7039         struct dirent *e = NULL;
7040         uint64_t dfree;
7041         uint64_t dsize;
7042         int ret;
7043         bool ok;
7044
7045         SMB_VFS_HANDLE_GET_DATA(handle, config,
7046                                 struct fruit_config_data,
7047                                 return UINT64_MAX);
7048
7049         if (!config->time_machine ||
7050             config->time_machine_max_size == 0)
7051         {
7052                 return SMB_VFS_NEXT_DISK_FREE(handle,
7053                                               smb_fname,
7054                                               _bsize,
7055                                               _dfree,
7056                                               _dsize);
7057         }
7058
7059         d = SMB_VFS_NEXT_OPENDIR(handle, smb_fname, NULL, 0);
7060         if (d == NULL) {
7061                 return UINT64_MAX;
7062         }
7063
7064         for (e = SMB_VFS_NEXT_READDIR(handle, d, NULL);
7065              e != NULL;
7066              e = SMB_VFS_NEXT_READDIR(handle, d, NULL))
7067         {
7068                 ok = fruit_tmsize_do_dirent(handle, &state, e);
7069                 if (!ok) {
7070                         SMB_VFS_NEXT_CLOSEDIR(handle, d);
7071                         return UINT64_MAX;
7072                 }
7073         }
7074
7075         ret = SMB_VFS_NEXT_CLOSEDIR(handle, d);
7076         if (ret != 0) {
7077                 return UINT64_MAX;
7078         }
7079
7080         dsize = config->time_machine_max_size / 512;
7081         dfree = dsize - (state.total_size / 512);
7082         if (dfree > dsize) {
7083                 dfree = 0;
7084         }
7085
7086         *_bsize = 512;
7087         *_dsize = dsize;
7088         *_dfree = dfree;
7089         return dfree / 2;
7090 }
7091
7092 static struct vfs_fn_pointers vfs_fruit_fns = {
7093         .connect_fn = fruit_connect,
7094         .disk_free_fn = fruit_disk_free,
7095
7096         /* File operations */
7097         .chmod_fn = fruit_chmod,
7098         .chown_fn = fruit_chown,
7099         .unlink_fn = fruit_unlink,
7100         .rename_fn = fruit_rename,
7101         .rmdir_fn = fruit_rmdir,
7102         .open_fn = fruit_open,
7103         .close_fn = fruit_close,
7104         .pread_fn = fruit_pread,
7105         .pwrite_fn = fruit_pwrite,
7106         .pread_send_fn = fruit_pread_send,
7107         .pread_recv_fn = fruit_pread_recv,
7108         .pwrite_send_fn = fruit_pwrite_send,
7109         .pwrite_recv_fn = fruit_pwrite_recv,
7110         .stat_fn = fruit_stat,
7111         .lstat_fn = fruit_lstat,
7112         .fstat_fn = fruit_fstat,
7113         .streaminfo_fn = fruit_streaminfo,
7114         .ntimes_fn = fruit_ntimes,
7115         .ftruncate_fn = fruit_ftruncate,
7116         .fallocate_fn = fruit_fallocate,
7117         .create_file_fn = fruit_create_file,
7118         .readdir_attr_fn = fruit_readdir_attr,
7119         .offload_read_send_fn = fruit_offload_read_send,
7120         .offload_read_recv_fn = fruit_offload_read_recv,
7121         .offload_write_send_fn = fruit_offload_write_send,
7122         .offload_write_recv_fn = fruit_offload_write_recv,
7123
7124         /* NT ACL operations */
7125         .fget_nt_acl_fn = fruit_fget_nt_acl,
7126         .fset_nt_acl_fn = fruit_fset_nt_acl,
7127 };
7128
7129 static_decl_vfs;
7130 NTSTATUS vfs_fruit_init(TALLOC_CTX *ctx)
7131 {
7132         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fruit",
7133                                         &vfs_fruit_fns);
7134         if (!NT_STATUS_IS_OK(ret)) {
7135                 return ret;
7136         }
7137
7138         vfs_fruit_debug_level = debug_add_class("fruit");
7139         if (vfs_fruit_debug_level == -1) {
7140                 vfs_fruit_debug_level = DBGC_VFS;
7141                 DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
7142                           "vfs_fruit_init"));
7143         } else {
7144                 DEBUG(10, ("%s: Debug class number of '%s': %d\n",
7145                            "vfs_fruit_init","fruit",vfs_fruit_debug_level));
7146         }
7147
7148         return ret;
7149 }