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