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