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