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