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