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