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