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