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