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