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