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