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