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