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