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