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