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