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