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