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