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