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