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