s3/modules: VFS: fruit: Remove SMB_VFS_STREAMINFO
[samba.git] / source3 / modules / vfs_fruit.c
1 /*
2  * OS X and Netatalk interoperability VFS module for Samba-3.x
3  *
4  * Copyright (C) Ralph Boehme, 2013, 2014
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "MacExtensions.h"
22 #include "smbd/smbd.h"
23 #include "system/filesys.h"
24 #include "lib/util/time.h"
25 #include "system/shmem.h"
26 #include "locking/proto.h"
27 #include "smbd/globals.h"
28 #include "messages.h"
29 #include "libcli/security/security.h"
30 #include "../libcli/smb/smb2_create_ctx.h"
31 #include "lib/util/tevent_ntstatus.h"
32 #include "lib/util/tevent_unix.h"
33 #include "offload_token.h"
34 #include "string_replace.h"
35 #include "hash_inode.h"
36 #include "lib/adouble.h"
37 #include "lib/util_macstreams.h"
38
39 /*
40  * Enhanced OS X and Netatalk compatibility
41  * ========================================
42  *
43  * This modules takes advantage of vfs_streams_xattr and
44  * vfs_catia. VFS modules vfs_fruit and vfs_streams_xattr must be
45  * loaded in the correct order:
46  *
47  *   vfs modules = catia fruit streams_xattr
48  *
49  * The module intercepts the OS X special streams "AFP_AfpInfo" and
50  * "AFP_Resource" and handles them in a special way. All other named
51  * streams are deferred to vfs_streams_xattr.
52  *
53  * The OS X client maps all NTFS illegal characters to the Unicode
54  * private range. This module optionally stores the characters using
55  * their native ASCII encoding using vfs_catia. If you're not enabling
56  * this feature, you can skip catia from vfs modules.
57  *
58  * Finally, open modes are optionally checked against Netatalk AFP
59  * share modes.
60  *
61  * The "AFP_AfpInfo" named stream is a binary blob containing OS X
62  * extended metadata for files and directories. This module optionally
63  * reads and stores this metadata in a way compatible with Netatalk 3
64  * which stores the metadata in an EA "org.netatalk.metadata". Cf
65  * source3/include/MacExtensions.h for a description of the binary
66  * blobs content.
67  *
68  * The "AFP_Resource" named stream may be arbitrarily large, thus it
69  * can't be stored in an xattr on most filesystem. ZFS on Solaris is
70  * the only available filesystem where xattrs can be of any size and
71  * the OS supports using the file APIs for xattrs.
72  *
73  * The AFP_Resource stream is stored in an AppleDouble file prepending
74  * "._" to the filename. On Solaris with ZFS the stream is optionally
75  * stored in an EA "org.netatalk.resource".
76  *
77  *
78  * Extended Attributes
79  * ===================
80  *
81  * The OS X SMB client sends xattrs as ADS too. For xattr interop with
82  * other protocols you may want to adjust the xattr names the VFS
83  * module vfs_streams_xattr uses for storing ADS's. This defaults to
84  * user.DosStream.ADS_NAME:$DATA and can be changed by specifying
85  * these module parameters:
86  *
87  *   streams_xattr:prefix = user.
88  *   streams_xattr:store_stream_type = false
89  *
90  *
91  * TODO
92  * ====
93  *
94  * - log diagnostic if any needed VFS module is not loaded
95  *   (eg with lp_vfs_objects())
96  * - add tests
97  */
98
99 static int vfs_fruit_debug_level = DBGC_VFS;
100
101 static struct global_fruit_config {
102         bool nego_aapl; /* client negotiated AAPL */
103
104 } global_fruit_config;
105
106 #undef DBGC_CLASS
107 #define DBGC_CLASS vfs_fruit_debug_level
108
109 #define FRUIT_PARAM_TYPE_NAME "fruit"
110
111 enum apple_fork {APPLE_FORK_DATA, APPLE_FORK_RSRC};
112
113 enum fruit_rsrc {FRUIT_RSRC_STREAM, FRUIT_RSRC_ADFILE, FRUIT_RSRC_XATTR};
114 enum fruit_meta {FRUIT_META_STREAM, FRUIT_META_NETATALK};
115 enum fruit_locking {FRUIT_LOCKING_NETATALK, FRUIT_LOCKING_NONE};
116 enum fruit_encoding {FRUIT_ENC_NATIVE, FRUIT_ENC_PRIVATE};
117
118 struct fruit_config_data {
119         enum fruit_rsrc rsrc;
120         enum fruit_meta meta;
121         enum fruit_locking locking;
122         enum fruit_encoding encoding;
123         bool use_aapl;          /* config from smb.conf */
124         bool use_copyfile;
125         bool readdir_attr_enabled;
126         bool unix_info_enabled;
127         bool copyfile_enabled;
128         bool veto_appledouble;
129         bool posix_rename;
130         bool aapl_zero_file_id;
131         const char *model;
132         bool time_machine;
133         off_t time_machine_max_size;
134         bool wipe_intentionally_left_blank_rfork;
135         bool delete_empty_adfiles;
136
137         /*
138          * Additional options, all enabled by default,
139          * possibly useful for analyzing performance. The associated
140          * operations with each of them may be expensive, so having
141          * the chance to disable them individually gives a chance
142          * tweaking the setup for the particular usecase.
143          */
144         bool readdir_attr_rsize;
145         bool readdir_attr_finder_info;
146         bool readdir_attr_max_access;
147 };
148
149 static const struct enum_list fruit_rsrc[] = {
150         {FRUIT_RSRC_STREAM, "stream"}, /* pass on to vfs_streams_xattr */
151         {FRUIT_RSRC_ADFILE, "file"}, /* ._ AppleDouble file */
152         {FRUIT_RSRC_XATTR, "xattr"}, /* Netatalk compatible xattr (ZFS only) */
153         { -1, NULL}
154 };
155
156 static const struct enum_list fruit_meta[] = {
157         {FRUIT_META_STREAM, "stream"}, /* pass on to vfs_streams_xattr */
158         {FRUIT_META_NETATALK, "netatalk"}, /* Netatalk compatible xattr */
159         { -1, NULL}
160 };
161
162 static const struct enum_list fruit_locking[] = {
163         {FRUIT_LOCKING_NETATALK, "netatalk"}, /* synchronize locks with Netatalk */
164         {FRUIT_LOCKING_NONE, "none"},
165         { -1, NULL}
166 };
167
168 static const struct enum_list fruit_encoding[] = {
169         {FRUIT_ENC_NATIVE, "native"}, /* map unicode private chars to ASCII */
170         {FRUIT_ENC_PRIVATE, "private"}, /* keep unicode private chars */
171         { -1, NULL}
172 };
173
174 struct fio {
175         vfs_handle_struct *handle;
176         files_struct *fsp; /* backlink to itself */
177
178         /* tcon config handle */
179         struct fruit_config_data *config;
180
181         /* Backend fsp for AppleDouble file, can be NULL */
182         files_struct *ad_fsp;
183         /* link from adouble_open_from_base_fsp() to fio */
184         struct fio *real_fio;
185
186         /* Denote stream type, meta or rsrc */
187         adouble_type_t type;
188
189         /*
190          * AFP_AfpInfo stream created, but not written yet, thus still a fake
191          * pipe fd. This is set to true in fruit_open_meta if there was no
192          * existing stream but the caller requested O_CREAT. It is later set to
193          * false when we get a write on the stream that then does open and
194          * create the stream.
195          */
196         bool fake_fd;
197         int flags;
198         int mode;
199 };
200
201 /*****************************************************************************
202  * Helper functions
203  *****************************************************************************/
204
205 static struct fio *fruit_get_complete_fio(vfs_handle_struct *handle,
206                                           files_struct *fsp)
207 {
208         struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
209
210         if (fio == NULL) {
211                 return NULL;
212         }
213
214         if (fio->real_fio != NULL) {
215                 /*
216                  * This is an fsp from adouble_open_from_base_fsp()
217                  * we should just pass this to the next
218                  * module.
219                  */
220                 return NULL;
221         }
222
223         return fio;
224 }
225
226 /**
227  * Initialize config struct from our smb.conf config parameters
228  **/
229 static int init_fruit_config(vfs_handle_struct *handle)
230 {
231         struct fruit_config_data *config;
232         int enumval;
233         const char *tm_size_str = NULL;
234
235         config = talloc_zero(handle->conn, struct fruit_config_data);
236         if (!config) {
237                 DEBUG(1, ("talloc_zero() failed\n"));
238                 errno = ENOMEM;
239                 return -1;
240         }
241
242         /*
243          * Versions up to Samba 4.5.x had a spelling bug in the
244          * fruit:resource option calling lp_parm_enum with
245          * "res*s*ource" (ie two s).
246          *
247          * In Samba 4.6 we accept both the wrong and the correct
248          * spelling, in Samba 4.7 the bad spelling will be removed.
249          */
250         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
251                                "ressource", fruit_rsrc, FRUIT_RSRC_ADFILE);
252         if (enumval == -1) {
253                 DEBUG(1, ("value for %s: resource type unknown\n",
254                           FRUIT_PARAM_TYPE_NAME));
255                 return -1;
256         }
257         config->rsrc = (enum fruit_rsrc)enumval;
258
259         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
260                                "resource", fruit_rsrc, enumval);
261         if (enumval == -1) {
262                 DEBUG(1, ("value for %s: resource type unknown\n",
263                           FRUIT_PARAM_TYPE_NAME));
264                 return -1;
265         }
266         config->rsrc = (enum fruit_rsrc)enumval;
267
268         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
269                                "metadata", fruit_meta, FRUIT_META_NETATALK);
270         if (enumval == -1) {
271                 DEBUG(1, ("value for %s: metadata type unknown\n",
272                           FRUIT_PARAM_TYPE_NAME));
273                 return -1;
274         }
275         config->meta = (enum fruit_meta)enumval;
276
277         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
278                                "locking", fruit_locking, FRUIT_LOCKING_NONE);
279         if (enumval == -1) {
280                 DEBUG(1, ("value for %s: locking type unknown\n",
281                           FRUIT_PARAM_TYPE_NAME));
282                 return -1;
283         }
284         config->locking = (enum fruit_locking)enumval;
285
286         enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
287                                "encoding", fruit_encoding, FRUIT_ENC_PRIVATE);
288         if (enumval == -1) {
289                 DEBUG(1, ("value for %s: encoding type unknown\n",
290                           FRUIT_PARAM_TYPE_NAME));
291                 return -1;
292         }
293         config->encoding = (enum fruit_encoding)enumval;
294
295         if (config->rsrc == FRUIT_RSRC_ADFILE) {
296                 config->veto_appledouble = lp_parm_bool(SNUM(handle->conn),
297                                                         FRUIT_PARAM_TYPE_NAME,
298                                                         "veto_appledouble",
299                                                         true);
300         }
301
302         config->use_aapl = lp_parm_bool(
303                 -1, FRUIT_PARAM_TYPE_NAME, "aapl", true);
304
305         config->time_machine = lp_parm_bool(
306                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "time machine", false);
307
308         config->unix_info_enabled = lp_parm_bool(
309                 -1, FRUIT_PARAM_TYPE_NAME, "nfs_aces", true);
310
311         config->use_copyfile = lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME,
312                                            "copyfile", false);
313
314         config->posix_rename = lp_parm_bool(
315                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "posix_rename", true);
316
317         config->aapl_zero_file_id =
318             lp_parm_bool(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
319                          "zero_file_id", false);
320
321         config->readdir_attr_rsize = lp_parm_bool(
322                 SNUM(handle->conn), "readdir_attr", "aapl_rsize", true);
323
324         config->readdir_attr_finder_info = lp_parm_bool(
325                 SNUM(handle->conn), "readdir_attr", "aapl_finder_info", true);
326
327         config->readdir_attr_max_access = lp_parm_bool(
328                 SNUM(handle->conn), "readdir_attr", "aapl_max_access", true);
329
330         config->model = lp_parm_const_string(
331                 -1, FRUIT_PARAM_TYPE_NAME, "model", "MacSamba");
332
333         tm_size_str = lp_parm_const_string(
334                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
335                 "time machine max size", NULL);
336         if (tm_size_str != NULL) {
337                 config->time_machine_max_size = conv_str_size(tm_size_str);
338         }
339
340         config->wipe_intentionally_left_blank_rfork = lp_parm_bool(
341                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
342                 "wipe_intentionally_left_blank_rfork", false);
343
344         config->delete_empty_adfiles = lp_parm_bool(
345                 SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
346                 "delete_empty_adfiles", false);
347
348         SMB_VFS_HANDLE_SET_DATA(handle, config,
349                                 NULL, struct fruit_config_data,
350                                 return -1);
351
352         return 0;
353 }
354
355 static bool add_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
356                              struct stream_struct **streams,
357                              const char *name, off_t size,
358                              off_t alloc_size)
359 {
360         struct stream_struct *tmp;
361
362         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
363                              (*num_streams)+1);
364         if (tmp == NULL) {
365                 return false;
366         }
367
368         tmp[*num_streams].name = talloc_asprintf(tmp, "%s:$DATA", name);
369         if (tmp[*num_streams].name == NULL) {
370                 return false;
371         }
372
373         tmp[*num_streams].size = size;
374         tmp[*num_streams].alloc_size = alloc_size;
375
376         *streams = tmp;
377         *num_streams += 1;
378         return true;
379 }
380
381 static bool filter_empty_rsrc_stream(unsigned int *num_streams,
382                                      struct stream_struct **streams)
383 {
384         struct stream_struct *tmp = *streams;
385         unsigned int i;
386
387         if (*num_streams == 0) {
388                 return true;
389         }
390
391         for (i = 0; i < *num_streams; i++) {
392                 if (strequal_m(tmp[i].name, AFPRESOURCE_STREAM)) {
393                         break;
394                 }
395         }
396
397         if (i == *num_streams) {
398                 return true;
399         }
400
401         if (tmp[i].size > 0) {
402                 return true;
403         }
404
405         TALLOC_FREE(tmp[i].name);
406         ARRAY_DEL_ELEMENT(tmp, i, *num_streams);
407         *num_streams -= 1;
408         return true;
409 }
410
411 static bool del_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
412                              struct stream_struct **streams,
413                              const char *name)
414 {
415         struct stream_struct *tmp = *streams;
416         unsigned int i;
417
418         if (*num_streams == 0) {
419                 return true;
420         }
421
422         for (i = 0; i < *num_streams; i++) {
423                 if (strequal_m(tmp[i].name, name)) {
424                         break;
425                 }
426         }
427
428         if (i == *num_streams) {
429                 return true;
430         }
431
432         TALLOC_FREE(tmp[i].name);
433         ARRAY_DEL_ELEMENT(tmp, i, *num_streams);
434         *num_streams -= 1;
435         return true;
436 }
437
438 static bool ad_empty_finderinfo(const struct adouble *ad)
439 {
440         int cmp;
441         char emptybuf[ADEDLEN_FINDERI] = {0};
442         char *fi = NULL;
443
444         fi = ad_get_entry(ad, ADEID_FINDERI);
445         if (fi == NULL) {
446                 DBG_ERR("Missing FinderInfo in struct adouble [%p]\n", ad);
447                 return false;
448         }
449
450         cmp = memcmp(emptybuf, fi, ADEDLEN_FINDERI);
451         return (cmp == 0);
452 }
453
454 static bool ai_empty_finderinfo(const AfpInfo *ai)
455 {
456         int cmp;
457         char emptybuf[ADEDLEN_FINDERI] = {0};
458
459         cmp = memcmp(emptybuf, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI);
460         return (cmp == 0);
461 }
462
463 /**
464  * Update btime with btime from Netatalk
465  **/
466 static void update_btime(vfs_handle_struct *handle,
467                          struct smb_filename *smb_fname)
468 {
469         uint32_t t;
470         struct timespec creation_time = {0};
471         struct adouble *ad;
472         struct fruit_config_data *config = NULL;
473
474         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
475                                 return);
476
477         switch (config->meta) {
478         case FRUIT_META_STREAM:
479                 return;
480         case FRUIT_META_NETATALK:
481                 /* Handled below */
482                 break;
483         default:
484                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
485                 return;
486         }
487
488         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
489         if (ad == NULL) {
490                 return;
491         }
492         if (ad_getdate(ad, AD_DATE_UNIX | AD_DATE_CREATE, &t) != 0) {
493                 TALLOC_FREE(ad);
494                 return;
495         }
496         TALLOC_FREE(ad);
497
498         creation_time.tv_sec = convert_uint32_t_to_time_t(t);
499         update_stat_ex_create_time(&smb_fname->st, creation_time);
500
501         return;
502 }
503
504 /**
505  * Map an access mask to a Netatalk single byte byte range lock
506  **/
507 static off_t access_to_netatalk_brl(enum apple_fork fork_type,
508                                     uint32_t access_mask)
509 {
510         off_t offset;
511
512         switch (access_mask) {
513         case FILE_READ_DATA:
514                 offset = AD_FILELOCK_OPEN_RD;
515                 break;
516
517         case FILE_WRITE_DATA:
518         case FILE_APPEND_DATA:
519                 offset = AD_FILELOCK_OPEN_WR;
520                 break;
521
522         default:
523                 offset = AD_FILELOCK_OPEN_NONE;
524                 break;
525         }
526
527         if (fork_type == APPLE_FORK_RSRC) {
528                 if (offset == AD_FILELOCK_OPEN_NONE) {
529                         offset = AD_FILELOCK_RSRC_OPEN_NONE;
530                 } else {
531                         offset += 2;
532                 }
533         }
534
535         return offset;
536 }
537
538 /**
539  * Map a deny mode to a Netatalk brl
540  **/
541 static off_t denymode_to_netatalk_brl(enum apple_fork fork_type,
542                                       uint32_t deny_mode)
543 {
544         off_t offset = 0;
545
546         switch (deny_mode) {
547         case DENY_READ:
548                 offset = AD_FILELOCK_DENY_RD;
549                 break;
550
551         case DENY_WRITE:
552                 offset = AD_FILELOCK_DENY_WR;
553                 break;
554
555         default:
556                 smb_panic("denymode_to_netatalk_brl: bad deny mode\n");
557         }
558
559         if (fork_type == APPLE_FORK_RSRC) {
560                 offset += 2;
561         }
562
563         return offset;
564 }
565
566 /**
567  * Call fcntl() with an exclusive F_GETLK request in order to
568  * determine if there's an existing shared lock
569  *
570  * @return true if the requested lock was found or any error occurred
571  *         false if the lock was not found
572  **/
573 static bool test_netatalk_lock(files_struct *fsp, off_t in_offset)
574 {
575         bool result;
576         off_t offset = in_offset;
577         off_t len = 1;
578         int type = F_WRLCK;
579         pid_t pid = 0;
580
581         result = SMB_VFS_GETLOCK(fsp, &offset, &len, &type, &pid);
582         if (result == false) {
583                 return true;
584         }
585
586         if (type != F_UNLCK) {
587                 return true;
588         }
589
590         return false;
591 }
592
593 static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
594                                    files_struct *fsp,
595                                    uint32_t access_mask,
596                                    uint32_t share_mode)
597 {
598         NTSTATUS status = NT_STATUS_OK;
599         off_t off;
600         bool share_for_read = (share_mode & FILE_SHARE_READ);
601         bool share_for_write = (share_mode & FILE_SHARE_WRITE);
602         bool netatalk_already_open_for_reading = false;
603         bool netatalk_already_open_for_writing = false;
604         bool netatalk_already_open_with_deny_read = false;
605         bool netatalk_already_open_with_deny_write = false;
606         struct GUID req_guid = GUID_random();
607
608         /* FIXME: hardcoded data fork, add resource fork */
609         enum apple_fork fork_type = APPLE_FORK_DATA;
610
611         DBG_DEBUG("fruit_check_access: %s, am: %s/%s, sm: 0x%x\n",
612                   fsp_str_dbg(fsp),
613                   access_mask & FILE_READ_DATA ? "READ" :"-",
614                   access_mask & FILE_WRITE_DATA ? "WRITE" : "-",
615                   share_mode);
616
617         if (fsp_get_io_fd(fsp) == -1) {
618                 return NT_STATUS_OK;
619         }
620
621         /* Read NetATalk opens and deny modes on the file. */
622         netatalk_already_open_for_reading = test_netatalk_lock(fsp,
623                                 access_to_netatalk_brl(fork_type,
624                                         FILE_READ_DATA));
625
626         netatalk_already_open_with_deny_read = test_netatalk_lock(fsp,
627                                 denymode_to_netatalk_brl(fork_type,
628                                         DENY_READ));
629
630         netatalk_already_open_for_writing = test_netatalk_lock(fsp,
631                                 access_to_netatalk_brl(fork_type,
632                                         FILE_WRITE_DATA));
633
634         netatalk_already_open_with_deny_write = test_netatalk_lock(fsp,
635                                 denymode_to_netatalk_brl(fork_type,
636                                         DENY_WRITE));
637
638         /* If there are any conflicts - sharing violation. */
639         if ((access_mask & FILE_READ_DATA) &&
640                         netatalk_already_open_with_deny_read) {
641                 return NT_STATUS_SHARING_VIOLATION;
642         }
643
644         if (!share_for_read &&
645                         netatalk_already_open_for_reading) {
646                 return NT_STATUS_SHARING_VIOLATION;
647         }
648
649         if ((access_mask & FILE_WRITE_DATA) &&
650                         netatalk_already_open_with_deny_write) {
651                 return NT_STATUS_SHARING_VIOLATION;
652         }
653
654         if (!share_for_write &&
655                         netatalk_already_open_for_writing) {
656                 return NT_STATUS_SHARING_VIOLATION;
657         }
658
659         if (!(access_mask & FILE_READ_DATA)) {
660                 /*
661                  * Nothing we can do here, we need read access
662                  * to set locks.
663                  */
664                 return NT_STATUS_OK;
665         }
666
667         /* Set NetAtalk locks matching our access */
668         if (access_mask & FILE_READ_DATA) {
669                 off = access_to_netatalk_brl(fork_type, FILE_READ_DATA);
670                 req_guid.time_hi_and_version = __LINE__;
671                 status = do_lock(
672                         fsp,
673                         talloc_tos(),
674                         &req_guid,
675                         fsp->op->global->open_persistent_id,
676                         1,
677                         off,
678                         READ_LOCK,
679                         POSIX_LOCK,
680                         NULL,
681                         NULL);
682
683                 if (!NT_STATUS_IS_OK(status))  {
684                         return status;
685                 }
686         }
687
688         if (!share_for_read) {
689                 off = denymode_to_netatalk_brl(fork_type, DENY_READ);
690                 req_guid.time_hi_and_version = __LINE__;
691                 status = do_lock(
692                         fsp,
693                         talloc_tos(),
694                         &req_guid,
695                         fsp->op->global->open_persistent_id,
696                         1,
697                         off,
698                         READ_LOCK,
699                         POSIX_LOCK,
700                         NULL,
701                         NULL);
702
703                 if (!NT_STATUS_IS_OK(status)) {
704                         return status;
705                 }
706         }
707
708         if (access_mask & FILE_WRITE_DATA) {
709                 off = access_to_netatalk_brl(fork_type, FILE_WRITE_DATA);
710                 req_guid.time_hi_and_version = __LINE__;
711                 status = do_lock(
712                         fsp,
713                         talloc_tos(),
714                         &req_guid,
715                         fsp->op->global->open_persistent_id,
716                         1,
717                         off,
718                         READ_LOCK,
719                         POSIX_LOCK,
720                         NULL,
721                         NULL);
722
723                 if (!NT_STATUS_IS_OK(status)) {
724                         return status;
725                 }
726         }
727
728         if (!share_for_write) {
729                 off = denymode_to_netatalk_brl(fork_type, DENY_WRITE);
730                 req_guid.time_hi_and_version = __LINE__;
731                 status = do_lock(
732                         fsp,
733                         talloc_tos(),
734                         &req_guid,
735                         fsp->op->global->open_persistent_id,
736                         1,
737                         off,
738                         READ_LOCK,
739                         POSIX_LOCK,
740                         NULL,
741                         NULL);
742
743                 if (!NT_STATUS_IS_OK(status)) {
744                         return status;
745                 }
746         }
747
748         return NT_STATUS_OK;
749 }
750
751 static NTSTATUS check_aapl(vfs_handle_struct *handle,
752                            struct smb_request *req,
753                            const struct smb2_create_blobs *in_context_blobs,
754                            struct smb2_create_blobs *out_context_blobs)
755 {
756         struct fruit_config_data *config;
757         NTSTATUS status;
758         struct smb2_create_blob *aapl = NULL;
759         uint32_t cmd;
760         bool ok;
761         uint8_t p[16];
762         DATA_BLOB blob = data_blob_talloc(req, NULL, 0);
763         uint64_t req_bitmap, client_caps;
764         uint64_t server_caps = SMB2_CRTCTX_AAPL_UNIX_BASED;
765         smb_ucs2_t *model;
766         size_t modellen;
767
768         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
769                                 return NT_STATUS_UNSUCCESSFUL);
770
771         if (!config->use_aapl
772             || in_context_blobs == NULL
773             || out_context_blobs == NULL) {
774                 return NT_STATUS_OK;
775         }
776
777         aapl = smb2_create_blob_find(in_context_blobs,
778                                      SMB2_CREATE_TAG_AAPL);
779         if (aapl == NULL) {
780                 return NT_STATUS_OK;
781         }
782
783         if (aapl->data.length != 24) {
784                 DEBUG(1, ("unexpected AAPL ctxt length: %ju\n",
785                           (uintmax_t)aapl->data.length));
786                 return NT_STATUS_INVALID_PARAMETER;
787         }
788
789         cmd = IVAL(aapl->data.data, 0);
790         if (cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) {
791                 DEBUG(1, ("unsupported AAPL cmd: %d\n", cmd));
792                 return NT_STATUS_INVALID_PARAMETER;
793         }
794
795         req_bitmap = BVAL(aapl->data.data, 8);
796         client_caps = BVAL(aapl->data.data, 16);
797
798         SIVAL(p, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
799         SIVAL(p, 4, 0);
800         SBVAL(p, 8, req_bitmap);
801         ok = data_blob_append(req, &blob, p, 16);
802         if (!ok) {
803                 return NT_STATUS_UNSUCCESSFUL;
804         }
805
806         if (req_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS) {
807                 if ((client_caps & SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR) &&
808                     (handle->conn->tcon->compat->fs_capabilities & FILE_NAMED_STREAMS)) {
809                         server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR;
810                         config->readdir_attr_enabled = true;
811                 }
812
813                 if (config->use_copyfile) {
814                         server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE;
815                         config->copyfile_enabled = true;
816                 }
817
818                 /*
819                  * The client doesn't set the flag, so we can't check
820                  * for it and just set it unconditionally
821                  */
822                 if (config->unix_info_enabled) {
823                         server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE;
824                 }
825
826                 SBVAL(p, 0, server_caps);
827                 ok = data_blob_append(req, &blob, p, 8);
828                 if (!ok) {
829                         return NT_STATUS_UNSUCCESSFUL;
830                 }
831         }
832
833         if (req_bitmap & SMB2_CRTCTX_AAPL_VOLUME_CAPS) {
834                 int val = lp_case_sensitive(SNUM(handle->conn->tcon->compat));
835                 uint64_t caps = 0;
836
837                 switch (val) {
838                 case Auto:
839                         break;
840
841                 case True:
842                         caps |= SMB2_CRTCTX_AAPL_CASE_SENSITIVE;
843                         break;
844
845                 default:
846                         break;
847                 }
848
849                 if (config->time_machine) {
850                         caps |= SMB2_CRTCTX_AAPL_FULL_SYNC;
851                 }
852
853                 SBVAL(p, 0, caps);
854
855                 ok = data_blob_append(req, &blob, p, 8);
856                 if (!ok) {
857                         return NT_STATUS_UNSUCCESSFUL;
858                 }
859         }
860
861         if (req_bitmap & SMB2_CRTCTX_AAPL_MODEL_INFO) {
862                 ok = convert_string_talloc(req,
863                                            CH_UNIX, CH_UTF16LE,
864                                            config->model, strlen(config->model),
865                                            &model, &modellen);
866                 if (!ok) {
867                         return NT_STATUS_UNSUCCESSFUL;
868                 }
869
870                 SIVAL(p, 0, 0);
871                 SIVAL(p + 4, 0, modellen);
872                 ok = data_blob_append(req, &blob, p, 8);
873                 if (!ok) {
874                         talloc_free(model);
875                         return NT_STATUS_UNSUCCESSFUL;
876                 }
877
878                 ok = data_blob_append(req, &blob, model, modellen);
879                 talloc_free(model);
880                 if (!ok) {
881                         return NT_STATUS_UNSUCCESSFUL;
882                 }
883         }
884
885         status = smb2_create_blob_add(out_context_blobs,
886                                       out_context_blobs,
887                                       SMB2_CREATE_TAG_AAPL,
888                                       blob);
889         if (NT_STATUS_IS_OK(status)) {
890                 global_fruit_config.nego_aapl = true;
891         }
892
893         return status;
894 }
895
896 static bool readdir_attr_meta_finderi_stream(
897         struct vfs_handle_struct *handle,
898         const struct smb_filename *smb_fname,
899         AfpInfo *ai)
900 {
901         struct smb_filename *stream_name = NULL;
902         files_struct *fsp = NULL;
903         ssize_t nread;
904         NTSTATUS status;
905         bool ok;
906         uint8_t buf[AFP_INFO_SIZE];
907
908         status = synthetic_pathref(talloc_tos(),
909                                    handle->conn->cwd_fsp,
910                                    smb_fname->base_name,
911                                    AFPINFO_STREAM_NAME,
912                                    NULL,
913                                    smb_fname->twrp,
914                                    smb_fname->flags,
915                                    &stream_name);
916         if (!NT_STATUS_IS_OK(status)) {
917                 return false;
918         }
919
920         status = SMB_VFS_CREATE_FILE(
921                 handle->conn,                           /* conn */
922                 NULL,                                   /* req */
923                 stream_name,                            /* fname */
924                 FILE_READ_DATA,                         /* access_mask */
925                 (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
926                         FILE_SHARE_DELETE),
927                 FILE_OPEN,                              /* create_disposition*/
928                 0,                                      /* create_options */
929                 0,                                      /* file_attributes */
930                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
931                 NULL,                                   /* lease */
932                 0,                                      /* allocation_size */
933                 0,                                      /* private_flags */
934                 NULL,                                   /* sd */
935                 NULL,                                   /* ea_list */
936                 &fsp,                                   /* result */
937                 NULL,                                   /* pinfo */
938                 NULL, NULL);                            /* create context */
939
940         TALLOC_FREE(stream_name);
941
942         if (!NT_STATUS_IS_OK(status)) {
943                 return false;
944         }
945
946         nread = SMB_VFS_PREAD(fsp, &buf[0], AFP_INFO_SIZE, 0);
947         if (nread != AFP_INFO_SIZE) {
948                 DBG_ERR("short read [%s] [%zd/%d]\n",
949                         smb_fname_str_dbg(stream_name), nread, AFP_INFO_SIZE);
950                 ok = false;
951                 goto fail;
952         }
953
954         memcpy(&ai->afpi_FinderInfo[0], &buf[AFP_OFF_FinderInfo],
955                AFP_FinderSize);
956
957         ok = true;
958
959 fail:
960         if (fsp != NULL) {
961                 close_file(NULL, fsp, NORMAL_CLOSE);
962         }
963
964         return ok;
965 }
966
967 static bool readdir_attr_meta_finderi_netatalk(
968         struct vfs_handle_struct *handle,
969         const struct smb_filename *smb_fname,
970         AfpInfo *ai)
971 {
972         struct adouble *ad = NULL;
973         char *p = NULL;
974
975         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
976         if (ad == NULL) {
977                 return false;
978         }
979
980         p = ad_get_entry(ad, ADEID_FINDERI);
981         if (p == NULL) {
982                 DBG_ERR("No ADEID_FINDERI for [%s]\n", smb_fname->base_name);
983                 TALLOC_FREE(ad);
984                 return false;
985         }
986
987         memcpy(&ai->afpi_FinderInfo[0], p, AFP_FinderSize);
988         TALLOC_FREE(ad);
989         return true;
990 }
991
992 static bool readdir_attr_meta_finderi(struct vfs_handle_struct *handle,
993                                       const struct smb_filename *smb_fname,
994                                       struct readdir_attr_data *attr_data)
995 {
996         struct fruit_config_data *config = NULL;
997         uint32_t date_added;
998         AfpInfo ai = {0};
999         bool ok;
1000
1001         SMB_VFS_HANDLE_GET_DATA(handle, config,
1002                                 struct fruit_config_data,
1003                                 return false);
1004
1005         switch (config->meta) {
1006         case FRUIT_META_NETATALK:
1007                 ok = readdir_attr_meta_finderi_netatalk(
1008                         handle, smb_fname, &ai);
1009                 break;
1010
1011         case FRUIT_META_STREAM:
1012                 ok = readdir_attr_meta_finderi_stream(
1013                         handle, smb_fname, &ai);
1014                 break;
1015
1016         default:
1017                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
1018                 return false;
1019         }
1020
1021         if (!ok) {
1022                 /* Don't bother with errors, it's likely ENOENT */
1023                 return true;
1024         }
1025
1026         if (S_ISREG(smb_fname->st.st_ex_mode)) {
1027                 /* finder_type */
1028                 memcpy(&attr_data->attr_data.aapl.finder_info[0],
1029                        &ai.afpi_FinderInfo[0], 4);
1030
1031                 /* finder_creator */
1032                 memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4,
1033                        &ai.afpi_FinderInfo[4], 4);
1034         }
1035
1036         /* finder_flags */
1037         memcpy(&attr_data->attr_data.aapl.finder_info[0] + 8,
1038                &ai.afpi_FinderInfo[8], 2);
1039
1040         /* finder_ext_flags */
1041         memcpy(&attr_data->attr_data.aapl.finder_info[0] + 10,
1042                &ai.afpi_FinderInfo[24], 2);
1043
1044         /* creation date */
1045         date_added = convert_time_t_to_uint32_t(
1046                 smb_fname->st.st_ex_btime.tv_sec - AD_DATE_DELTA);
1047
1048         RSIVAL(&attr_data->attr_data.aapl.finder_info[0], 12, date_added);
1049
1050         return true;
1051 }
1052
1053 static uint64_t readdir_attr_rfork_size_adouble(
1054         struct vfs_handle_struct *handle,
1055         const struct smb_filename *smb_fname)
1056 {
1057         struct adouble *ad = NULL;
1058         uint64_t rfork_size;
1059
1060         ad = ad_get(talloc_tos(), handle, smb_fname,
1061                     ADOUBLE_RSRC);
1062         if (ad == NULL) {
1063                 return 0;
1064         }
1065
1066         rfork_size = ad_getentrylen(ad, ADEID_RFORK);
1067         TALLOC_FREE(ad);
1068
1069         return rfork_size;
1070 }
1071
1072 static uint64_t readdir_attr_rfork_size_stream(
1073         struct vfs_handle_struct *handle,
1074         const struct smb_filename *smb_fname)
1075 {
1076         struct smb_filename *stream_name = NULL;
1077         int ret;
1078         uint64_t rfork_size;
1079
1080         stream_name = synthetic_smb_fname(talloc_tos(),
1081                                           smb_fname->base_name,
1082                                           AFPRESOURCE_STREAM_NAME,
1083                                           NULL,
1084                                           smb_fname->twrp,
1085                                           0);
1086         if (stream_name == NULL) {
1087                 return 0;
1088         }
1089
1090         ret = SMB_VFS_STAT(handle->conn, stream_name);
1091         if (ret != 0) {
1092                 TALLOC_FREE(stream_name);
1093                 return 0;
1094         }
1095
1096         rfork_size = stream_name->st.st_ex_size;
1097         TALLOC_FREE(stream_name);
1098
1099         return rfork_size;
1100 }
1101
1102 static uint64_t readdir_attr_rfork_size(struct vfs_handle_struct *handle,
1103                                         const struct smb_filename *smb_fname)
1104 {
1105         struct fruit_config_data *config = NULL;
1106         uint64_t rfork_size;
1107
1108         SMB_VFS_HANDLE_GET_DATA(handle, config,
1109                                 struct fruit_config_data,
1110                                 return 0);
1111
1112         switch (config->rsrc) {
1113         case FRUIT_RSRC_ADFILE:
1114                 rfork_size = readdir_attr_rfork_size_adouble(handle,
1115                                                              smb_fname);
1116                 break;
1117
1118         case FRUIT_RSRC_XATTR:
1119         case FRUIT_RSRC_STREAM:
1120                 rfork_size = readdir_attr_rfork_size_stream(handle,
1121                                                             smb_fname);
1122                 break;
1123
1124         default:
1125                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
1126                 rfork_size = 0;
1127                 break;
1128         }
1129
1130         return rfork_size;
1131 }
1132
1133 static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle,
1134                                      const struct smb_filename *smb_fname,
1135                                      struct readdir_attr_data *attr_data)
1136 {
1137         NTSTATUS status = NT_STATUS_OK;
1138         struct fruit_config_data *config = NULL;
1139         bool ok;
1140
1141         SMB_VFS_HANDLE_GET_DATA(handle, config,
1142                                 struct fruit_config_data,
1143                                 return NT_STATUS_UNSUCCESSFUL);
1144
1145
1146         /* Ensure we return a default value in the creation_date field */
1147         RSIVAL(&attr_data->attr_data.aapl.finder_info, 12, AD_DATE_START);
1148
1149         /*
1150          * Resource fork length
1151          */
1152
1153         if (config->readdir_attr_rsize) {
1154                 uint64_t rfork_size;
1155
1156                 rfork_size = readdir_attr_rfork_size(handle, smb_fname);
1157                 attr_data->attr_data.aapl.rfork_size = rfork_size;
1158         }
1159
1160         /*
1161          * FinderInfo
1162          */
1163
1164         if (config->readdir_attr_finder_info) {
1165                 ok = readdir_attr_meta_finderi(handle, smb_fname, attr_data);
1166                 if (!ok) {
1167                         status = NT_STATUS_INTERNAL_ERROR;
1168                 }
1169         }
1170
1171         return status;
1172 }
1173
1174 static NTSTATUS remove_virtual_nfs_aces(struct security_descriptor *psd)
1175 {
1176         NTSTATUS status;
1177         uint32_t i;
1178
1179         if (psd->dacl == NULL) {
1180                 return NT_STATUS_OK;
1181         }
1182
1183         for (i = 0; i < psd->dacl->num_aces; i++) {
1184                 /* MS NFS style mode/uid/gid */
1185                 int cmp = dom_sid_compare_domain(
1186                                 &global_sid_Unix_NFS,
1187                                 &psd->dacl->aces[i].trustee);
1188                 if (cmp != 0) {
1189                         /* Normal ACE entry. */
1190                         continue;
1191                 }
1192
1193                 /*
1194                  * security_descriptor_dacl_del()
1195                  * *must* return NT_STATUS_OK as we know
1196                  * we have something to remove.
1197                  */
1198
1199                 status = security_descriptor_dacl_del(psd,
1200                                 &psd->dacl->aces[i].trustee);
1201                 if (!NT_STATUS_IS_OK(status)) {
1202                         DBG_WARNING("failed to remove MS NFS style ACE: %s\n",
1203                                 nt_errstr(status));
1204                         return status;
1205                 }
1206
1207                 /*
1208                  * security_descriptor_dacl_del() may delete more
1209                  * then one entry subsequent to this one if the
1210                  * SID matches, but we only need to ensure that
1211                  * we stay looking at the same element in the array.
1212                  */
1213                 i--;
1214         }
1215         return NT_STATUS_OK;
1216 }
1217
1218 /* Search MS NFS style ACE with UNIX mode */
1219 static NTSTATUS check_ms_nfs(vfs_handle_struct *handle,
1220                              files_struct *fsp,
1221                              struct security_descriptor *psd,
1222                              mode_t *pmode,
1223                              bool *pdo_chmod)
1224 {
1225         uint32_t i;
1226         struct fruit_config_data *config = NULL;
1227
1228         *pdo_chmod = false;
1229
1230         SMB_VFS_HANDLE_GET_DATA(handle, config,
1231                                 struct fruit_config_data,
1232                                 return NT_STATUS_UNSUCCESSFUL);
1233
1234         if (!global_fruit_config.nego_aapl) {
1235                 return NT_STATUS_OK;
1236         }
1237         if (psd->dacl == NULL || !config->unix_info_enabled) {
1238                 return NT_STATUS_OK;
1239         }
1240
1241         for (i = 0; i < psd->dacl->num_aces; i++) {
1242                 if (dom_sid_compare_domain(
1243                             &global_sid_Unix_NFS_Mode,
1244                             &psd->dacl->aces[i].trustee) == 0) {
1245                         *pmode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
1246                         *pmode &= (S_IRWXU | S_IRWXG | S_IRWXO);
1247                         *pdo_chmod = true;
1248
1249                         DEBUG(10, ("MS NFS chmod request %s, %04o\n",
1250                                    fsp_str_dbg(fsp), (unsigned)(*pmode)));
1251                         break;
1252                 }
1253         }
1254
1255         /*
1256          * Remove any incoming virtual ACE entries generated by
1257          * fruit_fget_nt_acl().
1258          */
1259
1260         return remove_virtual_nfs_aces(psd);
1261 }
1262
1263 /****************************************************************************
1264  * VFS ops
1265  ****************************************************************************/
1266
1267 static int fruit_connect(vfs_handle_struct *handle,
1268                          const char *service,
1269                          const char *user)
1270 {
1271         int rc;
1272         char *list = NULL, *newlist = NULL;
1273         struct fruit_config_data *config;
1274         const struct loadparm_substitution *lp_sub =
1275                 loadparm_s3_global_substitution();
1276
1277         DEBUG(10, ("fruit_connect\n"));
1278
1279         rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1280         if (rc < 0) {
1281                 return rc;
1282         }
1283
1284         rc = init_fruit_config(handle);
1285         if (rc != 0) {
1286                 return rc;
1287         }
1288
1289         SMB_VFS_HANDLE_GET_DATA(handle, config,
1290                                 struct fruit_config_data, return -1);
1291
1292         if (config->veto_appledouble) {
1293                 list = lp_veto_files(talloc_tos(), lp_sub, SNUM(handle->conn));
1294
1295                 if (list) {
1296                         if (strstr(list, "/" ADOUBLE_NAME_PREFIX "*/") == NULL) {
1297                                 newlist = talloc_asprintf(
1298                                         list,
1299                                         "%s/" ADOUBLE_NAME_PREFIX "*/",
1300                                         list);
1301                                 lp_do_parameter(SNUM(handle->conn),
1302                                                 "veto files",
1303                                                 newlist);
1304                         }
1305                 } else {
1306                         lp_do_parameter(SNUM(handle->conn),
1307                                         "veto files",
1308                                         "/" ADOUBLE_NAME_PREFIX "*/");
1309                 }
1310
1311                 TALLOC_FREE(list);
1312         }
1313
1314         if (config->encoding == FRUIT_ENC_NATIVE) {
1315                 lp_do_parameter(SNUM(handle->conn),
1316                                 "catia:mappings",
1317                                 macos_string_replace_map);
1318         }
1319
1320         if (config->time_machine) {
1321                 DBG_NOTICE("Enabling durable handles for Time Machine "
1322                            "support on [%s]\n", service);
1323                 lp_do_parameter(SNUM(handle->conn), "durable handles", "yes");
1324                 lp_do_parameter(SNUM(handle->conn), "kernel oplocks", "no");
1325                 lp_do_parameter(SNUM(handle->conn), "kernel share modes", "no");
1326                 if (!lp_strict_sync(SNUM(handle->conn))) {
1327                         DBG_WARNING("Time Machine without strict sync is not "
1328                                     "recommended!\n");
1329                 }
1330                 lp_do_parameter(SNUM(handle->conn), "posix locking", "no");
1331         }
1332
1333         return rc;
1334 }
1335
1336 static void fio_ref_destroy_fn(void *p_data)
1337 {
1338         struct fio *ref_fio = (struct fio *)p_data;
1339         if (ref_fio->real_fio != NULL) {
1340                 SMB_ASSERT(ref_fio->real_fio->ad_fsp == ref_fio->fsp);
1341                 ref_fio->real_fio->ad_fsp = NULL;
1342                 ref_fio->real_fio = NULL;
1343         }
1344 }
1345
1346 static void fio_close_ad_fsp(struct fio *fio)
1347 {
1348         if (fio->ad_fsp != NULL) {
1349                 fd_close(fio->ad_fsp);
1350                 file_free(NULL, fio->ad_fsp);
1351                 /* fio_ref_destroy_fn() should have cleared this */
1352                 SMB_ASSERT(fio->ad_fsp == NULL);
1353         }
1354 }
1355
1356 static void fio_destroy_fn(void *p_data)
1357 {
1358         struct fio *fio = (struct fio *)p_data;
1359         fio_close_ad_fsp(fio);
1360 }
1361
1362 static int fruit_open_meta_stream(vfs_handle_struct *handle,
1363                                   const struct files_struct *dirfsp,
1364                                   const struct smb_filename *smb_fname,
1365                                   files_struct *fsp,
1366                                   int flags,
1367                                   mode_t mode)
1368 {
1369         struct fruit_config_data *config = NULL;
1370         struct fio *fio = NULL;
1371         int open_flags = flags & ~O_CREAT;
1372         int fd;
1373
1374         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
1375
1376         SMB_VFS_HANDLE_GET_DATA(handle, config,
1377                                 struct fruit_config_data, return -1);
1378
1379         fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
1380         fio->handle = handle;
1381         fio->fsp = fsp;
1382         fio->type = ADOUBLE_META;
1383         fio->config = config;
1384
1385         fd = SMB_VFS_NEXT_OPENAT(handle,
1386                                  dirfsp,
1387                                  smb_fname,
1388                                  fsp,
1389                                  open_flags,
1390                                  mode);
1391         if (fd != -1) {
1392                 return fd;
1393         }
1394
1395         if (!(flags & O_CREAT)) {
1396                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1397                 return -1;
1398         }
1399
1400         fd = vfs_fake_fd();
1401         if (fd == -1) {
1402                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1403                 return -1;
1404         }
1405
1406         fio->fake_fd = true;
1407         fio->flags = flags;
1408         fio->mode = mode;
1409
1410         return fd;
1411 }
1412
1413 static int fruit_open_meta_netatalk(vfs_handle_struct *handle,
1414                                     const struct files_struct *dirfsp,
1415                                     const struct smb_filename *smb_fname,
1416                                     files_struct *fsp,
1417                                     int flags,
1418                                     mode_t mode)
1419 {
1420         struct fruit_config_data *config = NULL;
1421         struct fio *fio = NULL;
1422         struct adouble *ad = NULL;
1423         bool meta_exists = false;
1424         int fd;
1425
1426         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
1427
1428         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
1429         if (ad != NULL) {
1430                 meta_exists = true;
1431         }
1432
1433         TALLOC_FREE(ad);
1434
1435         if (!meta_exists && !(flags & O_CREAT)) {
1436                 errno = ENOENT;
1437                 return -1;
1438         }
1439
1440         fd = vfs_fake_fd();
1441         if (fd == -1) {
1442                 return -1;
1443         }
1444
1445         SMB_VFS_HANDLE_GET_DATA(handle, config,
1446                                 struct fruit_config_data, return -1);
1447
1448         fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
1449         fio->handle = handle;
1450         fio->fsp = fsp;
1451         fio->type = ADOUBLE_META;
1452         fio->config = config;
1453         fio->fake_fd = true;
1454         fio->flags = flags;
1455         fio->mode = mode;
1456
1457         return fd;
1458 }
1459
1460 static int fruit_open_meta(vfs_handle_struct *handle,
1461                            const struct files_struct *dirfsp,
1462                            const struct smb_filename *smb_fname,
1463                            files_struct *fsp, int flags, mode_t mode)
1464 {
1465         int fd;
1466         struct fruit_config_data *config = NULL;
1467
1468         DBG_DEBUG("path [%s]\n", smb_fname_str_dbg(smb_fname));
1469
1470         SMB_VFS_HANDLE_GET_DATA(handle, config,
1471                                 struct fruit_config_data, return -1);
1472
1473         switch (config->meta) {
1474         case FRUIT_META_STREAM:
1475                 fd = fruit_open_meta_stream(handle, dirfsp, smb_fname,
1476                                             fsp, flags, mode);
1477                 break;
1478
1479         case FRUIT_META_NETATALK:
1480                 fd = fruit_open_meta_netatalk(handle, dirfsp, smb_fname,
1481                                               fsp, flags, mode);
1482                 break;
1483
1484         default:
1485                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
1486                 return -1;
1487         }
1488
1489         DBG_DEBUG("path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
1490
1491         return fd;
1492 }
1493
1494 static int fruit_open_rsrc_adouble(vfs_handle_struct *handle,
1495                                    const struct files_struct *dirfsp,
1496                                    const struct smb_filename *smb_fname,
1497                                    files_struct *fsp,
1498                                    int flags,
1499                                    mode_t mode)
1500 {
1501         int rc = 0;
1502         struct fruit_config_data *config = NULL;
1503         struct files_struct *ad_fsp = NULL;
1504         struct fio *fio = NULL;
1505         struct fio *ref_fio = NULL;
1506         NTSTATUS status;
1507         int fd = -1;
1508
1509         SMB_VFS_HANDLE_GET_DATA(handle, config,
1510                                 struct fruit_config_data, return -1);
1511
1512         if ((!(flags & O_CREAT)) &&
1513             S_ISDIR(fsp->base_fsp->fsp_name->st.st_ex_mode))
1514         {
1515                 /* sorry, but directories don't habe a resource fork */
1516                 errno = EISDIR;
1517                 rc = -1;
1518                 goto exit;
1519         }
1520
1521         /*
1522          * We return a fake_fd to the vfs modules above,
1523          * while we open an internal backend fsp for the
1524          * '._' file for the next vfs modules.
1525          *
1526          * Note that adouble_open_from_base_fsp() recurses
1527          * into fruit_openat(), but it'll just pass to
1528          * the next module as just opens a flat file on
1529          * disk.
1530          */
1531
1532         fd = vfs_fake_fd();
1533         if (fd == -1) {
1534                 rc = fd;
1535                 goto exit;
1536         }
1537
1538         status = adouble_open_from_base_fsp(dirfsp,
1539                                             fsp->base_fsp,
1540                                             ADOUBLE_RSRC,
1541                                             flags,
1542                                             mode,
1543                                             &ad_fsp);
1544         if (!NT_STATUS_IS_OK(status)) {
1545                 errno = map_errno_from_nt_status(status);
1546                 rc = -1;
1547                 goto exit;
1548         }
1549
1550         /*
1551          * Now we need to glue both handles together,
1552          * so that they automatically detach each other
1553          * on close.
1554          */
1555         fio = fruit_get_complete_fio(handle, fsp);
1556
1557         ref_fio = VFS_ADD_FSP_EXTENSION(handle, ad_fsp,
1558                                         struct fio,
1559                                         fio_ref_destroy_fn);
1560         if (ref_fio == NULL) {
1561                 int saved_errno = errno;
1562                 fd_close(ad_fsp);
1563                 file_free(NULL, ad_fsp);
1564                 ad_fsp = NULL;
1565                 errno = saved_errno;
1566                 rc = -1;
1567                 goto exit;
1568         }
1569
1570         SMB_ASSERT(ref_fio->fsp == NULL);
1571         ref_fio->handle = handle;
1572         ref_fio->fsp = ad_fsp;
1573         ref_fio->type = ADOUBLE_RSRC;
1574         ref_fio->config = config;
1575         ref_fio->real_fio = fio;
1576         SMB_ASSERT(fio->ad_fsp == NULL);
1577         fio->ad_fsp = ad_fsp;
1578         fio->fake_fd = true;
1579
1580 exit:
1581
1582         DEBUG(10, ("fruit_open resource fork: rc=%d\n", rc));
1583         if (rc != 0) {
1584                 int saved_errno = errno;
1585                 if (fd != -1) {
1586                         vfs_fake_fd_close(fd);
1587                 }
1588                 errno = saved_errno;
1589                 return rc;
1590         }
1591         return fd;
1592 }
1593
1594 static int fruit_open_rsrc_xattr(vfs_handle_struct *handle,
1595                                  const struct files_struct *dirfsp,
1596                                  const struct smb_filename *smb_fname,
1597                                  files_struct *fsp,
1598                                  int flags,
1599                                  mode_t mode)
1600 {
1601 #ifdef HAVE_ATTROPEN
1602         int fd = -1;
1603
1604         /*
1605          * As there's no attropenat() this is only going to work with AT_FDCWD.
1606          */
1607         SMB_ASSERT(fsp_get_pathref_fd(dirfsp) == AT_FDCWD);
1608
1609         fd = attropen(smb_fname->base_name,
1610                       AFPRESOURCE_EA_NETATALK,
1611                       flags,
1612                       mode);
1613         if (fd == -1) {
1614                 return -1;
1615         }
1616
1617         return fd;
1618
1619 #else
1620         errno = ENOSYS;
1621         return -1;
1622 #endif
1623 }
1624
1625 static int fruit_open_rsrc(vfs_handle_struct *handle,
1626                            const struct files_struct *dirfsp,
1627                            const struct smb_filename *smb_fname,
1628                            files_struct *fsp, int flags, mode_t mode)
1629 {
1630         int fd;
1631         struct fruit_config_data *config = NULL;
1632         struct fio *fio = NULL;
1633
1634         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
1635
1636         SMB_VFS_HANDLE_GET_DATA(handle, config,
1637                                 struct fruit_config_data, return -1);
1638
1639         fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
1640         fio->handle = handle;
1641         fio->fsp = fsp;
1642         fio->type = ADOUBLE_RSRC;
1643         fio->config = config;
1644
1645         switch (config->rsrc) {
1646         case FRUIT_RSRC_STREAM:
1647                 fd = SMB_VFS_NEXT_OPENAT(handle,
1648                                          dirfsp,
1649                                          smb_fname,
1650                                          fsp,
1651                                          flags,
1652                                          mode);
1653                 break;
1654
1655         case FRUIT_RSRC_ADFILE:
1656                 fd = fruit_open_rsrc_adouble(handle, dirfsp, smb_fname,
1657                                              fsp, flags, mode);
1658                 break;
1659
1660         case FRUIT_RSRC_XATTR:
1661                 fd = fruit_open_rsrc_xattr(handle, dirfsp, smb_fname,
1662                                            fsp, flags, mode);
1663                 break;
1664
1665         default:
1666                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
1667                 return -1;
1668         }
1669
1670         DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
1671
1672         if (fd == -1) {
1673                 return -1;
1674         }
1675
1676         return fd;
1677 }
1678
1679 static int fruit_openat(vfs_handle_struct *handle,
1680                         const struct files_struct *dirfsp,
1681                         const struct smb_filename *smb_fname,
1682                         files_struct *fsp,
1683                         int flags,
1684                         mode_t mode)
1685 {
1686         int fd;
1687
1688         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
1689
1690         if (!is_named_stream(smb_fname)) {
1691                 return SMB_VFS_NEXT_OPENAT(handle,
1692                                            dirfsp,
1693                                            smb_fname,
1694                                            fsp,
1695                                            flags,
1696                                            mode);
1697         }
1698
1699         if (is_afpinfo_stream(smb_fname->stream_name)) {
1700                 fd = fruit_open_meta(handle,
1701                                      dirfsp,
1702                                      smb_fname,
1703                                      fsp,
1704                                      flags,
1705                                      mode);
1706         } else if (is_afpresource_stream(smb_fname->stream_name)) {
1707                 fd = fruit_open_rsrc(handle,
1708                                      dirfsp,
1709                                      smb_fname,
1710                                      fsp,
1711                                      flags,
1712                                      mode);
1713         } else {
1714                 fd = SMB_VFS_NEXT_OPENAT(handle,
1715                                          dirfsp,
1716                                          smb_fname,
1717                                          fsp,
1718                                          flags,
1719                                          mode);
1720         }
1721
1722         DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
1723
1724         /* Prevent reopen optimisation */
1725         fsp->fsp_flags.have_proc_fds = false;
1726         return fd;
1727 }
1728
1729 static int fruit_close_meta(vfs_handle_struct *handle,
1730                             files_struct *fsp)
1731 {
1732         struct fio *fio = fruit_get_complete_fio(handle, fsp);
1733         int ret;
1734         struct fruit_config_data *config = NULL;
1735
1736         SMB_VFS_HANDLE_GET_DATA(handle, config,
1737                                 struct fruit_config_data, return -1);
1738
1739         if (fio == NULL) {
1740                 return -1;
1741         }
1742
1743         switch (config->meta) {
1744         case FRUIT_META_STREAM:
1745                 if (fio->fake_fd) {
1746                         ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
1747                         fsp_set_fd(fsp, -1);
1748                 } else {
1749                         ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
1750                 }
1751                 break;
1752
1753         case FRUIT_META_NETATALK:
1754                 ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
1755                 fsp_set_fd(fsp, -1);
1756                 break;
1757
1758         default:
1759                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
1760                 return -1;
1761         }
1762
1763         return ret;
1764 }
1765
1766
1767 static int fruit_close_rsrc(vfs_handle_struct *handle,
1768                             files_struct *fsp)
1769 {
1770         struct fio *fio = fruit_get_complete_fio(handle, fsp);
1771         int ret;
1772         struct fruit_config_data *config = NULL;
1773
1774         SMB_VFS_HANDLE_GET_DATA(handle, config,
1775                                 struct fruit_config_data, return -1);
1776
1777         switch (config->rsrc) {
1778         case FRUIT_RSRC_STREAM:
1779                 ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
1780                 break;
1781
1782         case FRUIT_RSRC_ADFILE:
1783                 fio_close_ad_fsp(fio);
1784                 ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
1785                 fsp_set_fd(fsp, -1);
1786                 break;
1787
1788         case FRUIT_RSRC_XATTR:
1789                 ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
1790                 fsp_set_fd(fsp, -1);
1791                 break;
1792
1793         default:
1794                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
1795                 return -1;
1796         }
1797
1798         return ret;
1799 }
1800
1801 static int fruit_close(vfs_handle_struct *handle,
1802                        files_struct *fsp)
1803 {
1804         int ret;
1805         int fd;
1806
1807         fd = fsp_get_pathref_fd(fsp);
1808
1809         DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(fsp->fsp_name), fd);
1810
1811         if (!is_named_stream(fsp->fsp_name)) {
1812                 return SMB_VFS_NEXT_CLOSE(handle, fsp);
1813         }
1814
1815         if (is_afpinfo_stream(fsp->fsp_name->stream_name)) {
1816                 ret = fruit_close_meta(handle, fsp);
1817         } else if (is_afpresource_stream(fsp->fsp_name->stream_name)) {
1818                 ret = fruit_close_rsrc(handle, fsp);
1819         } else {
1820                 ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
1821         }
1822
1823         return ret;
1824 }
1825
1826 static int fruit_renameat(struct vfs_handle_struct *handle,
1827                         files_struct *srcfsp,
1828                         const struct smb_filename *smb_fname_src,
1829                         files_struct *dstfsp,
1830                         const struct smb_filename *smb_fname_dst)
1831 {
1832         int rc = -1;
1833         struct fruit_config_data *config = NULL;
1834         struct smb_filename *src_adp_smb_fname = NULL;
1835         struct smb_filename *dst_adp_smb_fname = NULL;
1836
1837         SMB_VFS_HANDLE_GET_DATA(handle, config,
1838                                 struct fruit_config_data, return -1);
1839
1840         if (!VALID_STAT(smb_fname_src->st)) {
1841                 DBG_ERR("Need valid stat for [%s]\n",
1842                         smb_fname_str_dbg(smb_fname_src));
1843                 return -1;
1844         }
1845
1846         rc = SMB_VFS_NEXT_RENAMEAT(handle,
1847                                 srcfsp,
1848                                 smb_fname_src,
1849                                 dstfsp,
1850                                 smb_fname_dst);
1851         if (rc != 0) {
1852                 return -1;
1853         }
1854
1855         if ((config->rsrc != FRUIT_RSRC_ADFILE) ||
1856             (!S_ISREG(smb_fname_src->st.st_ex_mode)))
1857         {
1858                 return 0;
1859         }
1860
1861         rc = adouble_path(talloc_tos(), smb_fname_src, &src_adp_smb_fname);
1862         if (rc != 0) {
1863                 goto done;
1864         }
1865
1866         rc = adouble_path(talloc_tos(), smb_fname_dst, &dst_adp_smb_fname);
1867         if (rc != 0) {
1868                 goto done;
1869         }
1870
1871         DBG_DEBUG("%s -> %s\n",
1872                   smb_fname_str_dbg(src_adp_smb_fname),
1873                   smb_fname_str_dbg(dst_adp_smb_fname));
1874
1875         rc = SMB_VFS_NEXT_RENAMEAT(handle,
1876                         srcfsp,
1877                         src_adp_smb_fname,
1878                         dstfsp,
1879                         dst_adp_smb_fname);
1880         if (errno == ENOENT) {
1881                 rc = 0;
1882         }
1883
1884 done:
1885         TALLOC_FREE(src_adp_smb_fname);
1886         TALLOC_FREE(dst_adp_smb_fname);
1887         return rc;
1888 }
1889
1890 static int fruit_unlink_meta_stream(vfs_handle_struct *handle,
1891                                 struct files_struct *dirfsp,
1892                                 const struct smb_filename *smb_fname)
1893 {
1894         return SMB_VFS_NEXT_UNLINKAT(handle,
1895                                 dirfsp,
1896                                 smb_fname,
1897                                 0);
1898 }
1899
1900 static int fruit_unlink_meta_netatalk(vfs_handle_struct *handle,
1901                                       const struct smb_filename *smb_fname)
1902 {
1903         SMB_ASSERT(smb_fname->fsp != NULL);
1904         SMB_ASSERT(smb_fname->fsp->base_fsp != NULL);
1905         return SMB_VFS_FREMOVEXATTR(smb_fname->fsp->base_fsp,
1906                                    AFPINFO_EA_NETATALK);
1907 }
1908
1909 static int fruit_unlink_meta(vfs_handle_struct *handle,
1910                         struct files_struct *dirfsp,
1911                         const struct smb_filename *smb_fname)
1912 {
1913         struct fruit_config_data *config = NULL;
1914         int rc;
1915
1916         SMB_VFS_HANDLE_GET_DATA(handle, config,
1917                                 struct fruit_config_data, return -1);
1918
1919         switch (config->meta) {
1920         case FRUIT_META_STREAM:
1921                 rc = fruit_unlink_meta_stream(handle,
1922                                 dirfsp,
1923                                 smb_fname);
1924                 break;
1925
1926         case FRUIT_META_NETATALK:
1927                 rc = fruit_unlink_meta_netatalk(handle, smb_fname);
1928                 break;
1929
1930         default:
1931                 DBG_ERR("Unsupported meta config [%d]\n", config->meta);
1932                 return -1;
1933         }
1934
1935         return rc;
1936 }
1937
1938 static int fruit_unlink_rsrc_stream(vfs_handle_struct *handle,
1939                                 struct files_struct *dirfsp,
1940                                 const struct smb_filename *smb_fname,
1941                                 bool force_unlink)
1942 {
1943         int ret;
1944
1945         if (!force_unlink) {
1946                 struct smb_filename *full_fname = NULL;
1947                 off_t size;
1948
1949                 /*
1950                  * TODO: use SMB_VFS_STATX() once we have it.
1951                  */
1952
1953                 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1954                                                           dirfsp,
1955                                                           smb_fname);
1956                 if (full_fname == NULL) {
1957                         return -1;
1958                 }
1959
1960                 /*
1961                  * 0 byte resource fork streams are not listed by
1962                  * vfs_streaminfo, as a result stream cleanup/deletion of file
1963                  * deletion doesn't remove the resourcefork stream.
1964                  */
1965
1966                 ret = SMB_VFS_NEXT_STAT(handle, full_fname);
1967                 if (ret != 0) {
1968                         TALLOC_FREE(full_fname);
1969                         DBG_ERR("stat [%s] failed [%s]\n",
1970                                 smb_fname_str_dbg(full_fname), strerror(errno));
1971                         return -1;
1972                 }
1973
1974                 size = full_fname->st.st_ex_size;
1975                 TALLOC_FREE(full_fname);
1976
1977                 if (size > 0) {
1978                         /* OS X ignores resource fork stream delete requests */
1979                         return 0;
1980                 }
1981         }
1982
1983         ret = SMB_VFS_NEXT_UNLINKAT(handle,
1984                         dirfsp,
1985                         smb_fname,
1986                         0);
1987         if ((ret != 0) && (errno == ENOENT) && force_unlink) {
1988                 ret = 0;
1989         }
1990
1991         return ret;
1992 }
1993
1994 static int fruit_unlink_rsrc_adouble(vfs_handle_struct *handle,
1995                                 struct files_struct *dirfsp,
1996                                 const struct smb_filename *smb_fname,
1997                                 bool force_unlink)
1998 {
1999         int rc;
2000         struct adouble *ad = NULL;
2001         struct smb_filename *adp_smb_fname = NULL;
2002
2003         if (!force_unlink) {
2004                 struct smb_filename *full_fname = NULL;
2005
2006                 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2007                                                           dirfsp,
2008                                                           smb_fname);
2009                 if (full_fname == NULL) {
2010                         return -1;
2011                 }
2012
2013                 ad = ad_get(talloc_tos(), handle, full_fname,
2014                             ADOUBLE_RSRC);
2015                 TALLOC_FREE(full_fname);
2016                 if (ad == NULL) {
2017                         errno = ENOENT;
2018                         return -1;
2019                 }
2020
2021
2022                 /*
2023                  * 0 byte resource fork streams are not listed by
2024                  * vfs_streaminfo, as a result stream cleanup/deletion of file
2025                  * deletion doesn't remove the resourcefork stream.
2026                  */
2027
2028                 if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
2029                         /* OS X ignores resource fork stream delete requests */
2030                         TALLOC_FREE(ad);
2031                         return 0;
2032                 }
2033
2034                 TALLOC_FREE(ad);
2035         }
2036
2037         rc = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
2038         if (rc != 0) {
2039                 return -1;
2040         }
2041
2042         rc = SMB_VFS_NEXT_UNLINKAT(handle,
2043                         dirfsp,
2044                         adp_smb_fname,
2045                         0);
2046         TALLOC_FREE(adp_smb_fname);
2047         if ((rc != 0) && (errno == ENOENT) && force_unlink) {
2048                 rc = 0;
2049         }
2050
2051         return rc;
2052 }
2053
2054 static int fruit_unlink_rsrc_xattr(vfs_handle_struct *handle,
2055                                    const struct smb_filename *smb_fname,
2056                                    bool force_unlink)
2057 {
2058         /*
2059          * OS X ignores resource fork stream delete requests, so nothing to do
2060          * here. Removing the file will remove the xattr anyway, so we don't
2061          * have to take care of removing 0 byte resource forks that could be
2062          * left behind.
2063          */
2064         return 0;
2065 }
2066
2067 static int fruit_unlink_rsrc(vfs_handle_struct *handle,
2068                         struct files_struct *dirfsp,
2069                         const struct smb_filename *smb_fname,
2070                         bool force_unlink)
2071 {
2072         struct fruit_config_data *config = NULL;
2073         int rc;
2074
2075         SMB_VFS_HANDLE_GET_DATA(handle, config,
2076                                 struct fruit_config_data, return -1);
2077
2078         switch (config->rsrc) {
2079         case FRUIT_RSRC_STREAM:
2080                 rc = fruit_unlink_rsrc_stream(handle,
2081                                 dirfsp,
2082                                 smb_fname,
2083                                 force_unlink);
2084                 break;
2085
2086         case FRUIT_RSRC_ADFILE:
2087                 rc = fruit_unlink_rsrc_adouble(handle,
2088                                 dirfsp,
2089                                 smb_fname,
2090                                 force_unlink);
2091                 break;
2092
2093         case FRUIT_RSRC_XATTR:
2094                 rc = fruit_unlink_rsrc_xattr(handle, smb_fname, force_unlink);
2095                 break;
2096
2097         default:
2098                 DBG_ERR("Unsupported rsrc config [%d]\n", config->rsrc);
2099                 return -1;
2100         }
2101
2102         return rc;
2103 }
2104
2105 static int fruit_fchmod(vfs_handle_struct *handle,
2106                       struct files_struct *fsp,
2107                       mode_t mode)
2108 {
2109         int rc = -1;
2110         struct fruit_config_data *config = NULL;
2111         struct smb_filename *smb_fname_adp = NULL;
2112         const struct smb_filename *smb_fname = NULL;
2113         NTSTATUS status;
2114
2115         rc = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
2116         if (rc != 0) {
2117                 return rc;
2118         }
2119
2120         smb_fname = fsp->fsp_name;
2121         SMB_VFS_HANDLE_GET_DATA(handle, config,
2122                                 struct fruit_config_data, return -1);
2123
2124         if (config->rsrc != FRUIT_RSRC_ADFILE) {
2125                 return 0;
2126         }
2127
2128         if (!VALID_STAT(smb_fname->st)) {
2129                 return 0;
2130         }
2131
2132         if (!S_ISREG(smb_fname->st.st_ex_mode)) {
2133                 return 0;
2134         }
2135
2136         rc = adouble_path(talloc_tos(), smb_fname, &smb_fname_adp);
2137         if (rc != 0) {
2138                 return -1;
2139         }
2140
2141         status = openat_pathref_fsp(handle->conn->cwd_fsp,
2142                                     smb_fname_adp);
2143         if (!NT_STATUS_IS_OK(status)) {
2144                 /* detect ENOENT (mapped to OBJECT_NAME_NOT_FOUND) */
2145                 if (NT_STATUS_EQUAL(status,
2146                                     NT_STATUS_OBJECT_NAME_NOT_FOUND)){
2147                         rc = 0;
2148                         goto out;
2149                 }
2150                 rc = -1;
2151                 goto out;
2152         }
2153
2154         DBG_DEBUG("%s\n", smb_fname_adp->base_name);
2155
2156         rc = SMB_VFS_NEXT_FCHMOD(handle, smb_fname_adp->fsp, mode);
2157         if (errno == ENOENT) {
2158                 rc = 0;
2159         }
2160 out:
2161         TALLOC_FREE(smb_fname_adp);
2162         return rc;
2163 }
2164
2165 static int fruit_unlinkat(vfs_handle_struct *handle,
2166                         struct files_struct *dirfsp,
2167                         const struct smb_filename *smb_fname,
2168                         int flags)
2169 {
2170         struct fruit_config_data *config = NULL;
2171         struct smb_filename *rsrc_smb_fname = NULL;
2172         int ret;
2173
2174         if (flags & AT_REMOVEDIR) {
2175                 return SMB_VFS_NEXT_UNLINKAT(handle,
2176                                              dirfsp,
2177                                              smb_fname,
2178                                              AT_REMOVEDIR);
2179         }
2180
2181         SMB_VFS_HANDLE_GET_DATA(handle, config,
2182                                 struct fruit_config_data, return -1);
2183
2184         if (is_afpinfo_stream(smb_fname->stream_name)) {
2185                 return fruit_unlink_meta(handle,
2186                                 dirfsp,
2187                                 smb_fname);
2188         } else if (is_afpresource_stream(smb_fname->stream_name)) {
2189                 return fruit_unlink_rsrc(handle,
2190                                 dirfsp,
2191                                 smb_fname,
2192                                 false);
2193         } else if (is_named_stream(smb_fname)) {
2194                 return SMB_VFS_NEXT_UNLINKAT(handle,
2195                                 dirfsp,
2196                                 smb_fname,
2197                                 0);
2198         } else if (is_adouble_file(smb_fname->base_name)) {
2199                 return SMB_VFS_NEXT_UNLINKAT(handle,
2200                                 dirfsp,
2201                                 smb_fname,
2202                                 0);
2203         }
2204
2205         /*
2206          * A request to delete the base file. Because 0 byte resource
2207          * fork streams are not listed by fruit_streaminfo,
2208          * delete_all_streams() can't remove 0 byte resource fork
2209          * streams, so we have to cleanup this here.
2210          */
2211         rsrc_smb_fname = synthetic_smb_fname(talloc_tos(),
2212                                              smb_fname->base_name,
2213                                              AFPRESOURCE_STREAM_NAME,
2214                                              NULL,
2215                                              smb_fname->twrp,
2216                                              smb_fname->flags);
2217         if (rsrc_smb_fname == NULL) {
2218                 return -1;
2219         }
2220
2221         ret = fruit_unlink_rsrc(handle, dirfsp, rsrc_smb_fname, true);
2222         if ((ret != 0) && (errno != ENOENT)) {
2223                 DBG_ERR("Forced unlink of [%s] failed [%s]\n",
2224                         smb_fname_str_dbg(rsrc_smb_fname), strerror(errno));
2225                 TALLOC_FREE(rsrc_smb_fname);
2226                 return -1;
2227         }
2228         TALLOC_FREE(rsrc_smb_fname);
2229
2230         return SMB_VFS_NEXT_UNLINKAT(handle,
2231                         dirfsp,
2232                         smb_fname,
2233                         0);
2234 }
2235
2236 static ssize_t fruit_pread_meta_stream(vfs_handle_struct *handle,
2237                                        files_struct *fsp, void *data,
2238                                        size_t n, off_t offset)
2239 {
2240         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2241         ssize_t nread;
2242         int ret;
2243
2244         if ((fio == NULL) || fio->fake_fd) {
2245                 return -1;
2246         }
2247
2248         nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
2249         if (nread == -1 || nread == n) {
2250                 return nread;
2251         }
2252
2253         DBG_ERR("Removing [%s] after short read [%zd]\n",
2254                 fsp_str_dbg(fsp), nread);
2255
2256         ret = SMB_VFS_NEXT_UNLINKAT(handle,
2257                         fsp->conn->cwd_fsp,
2258                         fsp->fsp_name,
2259                         0);
2260         if (ret != 0) {
2261                 DBG_ERR("Removing [%s] failed\n", fsp_str_dbg(fsp));
2262                 return -1;
2263         }
2264
2265         errno = EINVAL;
2266         return -1;
2267 }
2268
2269 static ssize_t fruit_pread_meta_adouble(vfs_handle_struct *handle,
2270                                         files_struct *fsp, void *data,
2271                                         size_t n, off_t offset)
2272 {
2273         AfpInfo *ai = NULL;
2274         struct adouble *ad = NULL;
2275         char afpinfo_buf[AFP_INFO_SIZE];
2276         char *p = NULL;
2277         ssize_t nread;
2278
2279         ai = afpinfo_new(talloc_tos());
2280         if (ai == NULL) {
2281                 return -1;
2282         }
2283
2284         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
2285         if (ad == NULL) {
2286                 nread = -1;
2287                 goto fail;
2288         }
2289
2290         p = ad_get_entry(ad, ADEID_FINDERI);
2291         if (p == NULL) {
2292                 DBG_ERR("No ADEID_FINDERI for [%s]\n", fsp_str_dbg(fsp));
2293                 nread = -1;
2294                 goto fail;
2295         }
2296
2297         memcpy(&ai->afpi_FinderInfo[0], p, ADEDLEN_FINDERI);
2298
2299         nread = afpinfo_pack(ai, afpinfo_buf);
2300         if (nread != AFP_INFO_SIZE) {
2301                 nread = -1;
2302                 goto fail;
2303         }
2304
2305         memcpy(data, afpinfo_buf, n);
2306         nread = n;
2307
2308 fail:
2309         TALLOC_FREE(ai);
2310         return nread;
2311 }
2312
2313 static ssize_t fruit_pread_meta(vfs_handle_struct *handle,
2314                                 files_struct *fsp, void *data,
2315                                 size_t n, off_t offset)
2316 {
2317         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2318         ssize_t nread;
2319         ssize_t to_return;
2320
2321         /*
2322          * OS X has a off-by-1 error in the offset calculation, so we're
2323          * bug compatible here. It won't hurt, as any relevant real
2324          * world read requests from the AFP_AfpInfo stream will be
2325          * offset=0 n=60. offset is ignored anyway, see below.
2326          */
2327         if ((offset < 0) || (offset >= AFP_INFO_SIZE + 1)) {
2328                 return 0;
2329         }
2330
2331         if (fio == NULL) {
2332                 DBG_ERR("Failed to fetch fsp extension");
2333                 return -1;
2334         }
2335
2336         /* Yes, macOS always reads from offset 0 */
2337         offset = 0;
2338         to_return = MIN(n, AFP_INFO_SIZE);
2339
2340         switch (fio->config->meta) {
2341         case FRUIT_META_STREAM:
2342                 nread = fruit_pread_meta_stream(handle, fsp, data,
2343                                                 to_return, offset);
2344                 break;
2345
2346         case FRUIT_META_NETATALK:
2347                 nread = fruit_pread_meta_adouble(handle, fsp, data,
2348                                                  to_return, offset);
2349                 break;
2350
2351         default:
2352                 DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
2353                 return -1;
2354         }
2355
2356         if (nread == -1 && fio->fake_fd) {
2357                 AfpInfo *ai = NULL;
2358                 char afpinfo_buf[AFP_INFO_SIZE];
2359
2360                 ai = afpinfo_new(talloc_tos());
2361                 if (ai == NULL) {
2362                         return -1;
2363                 }
2364
2365                 nread = afpinfo_pack(ai, afpinfo_buf);
2366                 TALLOC_FREE(ai);
2367                 if (nread != AFP_INFO_SIZE) {
2368                         return -1;
2369                 }
2370
2371                 memcpy(data, afpinfo_buf, to_return);
2372                 return to_return;
2373         }
2374
2375         return nread;
2376 }
2377
2378 static ssize_t fruit_pread_rsrc_stream(vfs_handle_struct *handle,
2379                                        files_struct *fsp, void *data,
2380                                        size_t n, off_t offset)
2381 {
2382         return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
2383 }
2384
2385 static ssize_t fruit_pread_rsrc_xattr(vfs_handle_struct *handle,
2386                                       files_struct *fsp, void *data,
2387                                       size_t n, off_t offset)
2388 {
2389         return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
2390 }
2391
2392 static ssize_t fruit_pread_rsrc_adouble(vfs_handle_struct *handle,
2393                                         files_struct *fsp, void *data,
2394                                         size_t n, off_t offset)
2395 {
2396         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2397         struct adouble *ad = NULL;
2398         ssize_t nread;
2399
2400         if (fio->ad_fsp == NULL) {
2401                 DBG_ERR("ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
2402                 errno = EBADF;
2403                 return -1;
2404         }
2405
2406         ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
2407         if (ad == NULL) {
2408                 DBG_ERR("ad_fget [%s] failed [%s]\n",
2409                         fsp_str_dbg(fio->ad_fsp), strerror(errno));
2410                 return -1;
2411         }
2412
2413         nread = SMB_VFS_NEXT_PREAD(handle, fio->ad_fsp, data, n,
2414                                    offset + ad_getentryoff(ad, ADEID_RFORK));
2415
2416         TALLOC_FREE(ad);
2417         return nread;
2418 }
2419
2420 static ssize_t fruit_pread_rsrc(vfs_handle_struct *handle,
2421                                 files_struct *fsp, void *data,
2422                                 size_t n, off_t offset)
2423 {
2424         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2425         ssize_t nread;
2426
2427         if (fio == NULL) {
2428                 errno = EINVAL;
2429                 return -1;
2430         }
2431
2432         switch (fio->config->rsrc) {
2433         case FRUIT_RSRC_STREAM:
2434                 nread = fruit_pread_rsrc_stream(handle, fsp, data, n, offset);
2435                 break;
2436
2437         case FRUIT_RSRC_ADFILE:
2438                 nread = fruit_pread_rsrc_adouble(handle, fsp, data, n, offset);
2439                 break;
2440
2441         case FRUIT_RSRC_XATTR:
2442                 nread = fruit_pread_rsrc_xattr(handle, fsp, data, n, offset);
2443                 break;
2444
2445         default:
2446                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
2447                 return -1;
2448         }
2449
2450         return nread;
2451 }
2452
2453 static ssize_t fruit_pread(vfs_handle_struct *handle,
2454                            files_struct *fsp, void *data,
2455                            size_t n, off_t offset)
2456 {
2457         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2458         ssize_t nread;
2459
2460         DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
2461                   fsp_str_dbg(fsp), (intmax_t)offset, n);
2462
2463         if (fio == NULL) {
2464                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
2465         }
2466
2467         if (fio->type == ADOUBLE_META) {
2468                 nread = fruit_pread_meta(handle, fsp, data, n, offset);
2469         } else {
2470                 nread = fruit_pread_rsrc(handle, fsp, data, n, offset);
2471         }
2472
2473         DBG_DEBUG("Path [%s] nread [%zd]\n", fsp_str_dbg(fsp), nread);
2474         return nread;
2475 }
2476
2477 static bool fruit_must_handle_aio_stream(struct fio *fio)
2478 {
2479         if (fio == NULL) {
2480                 return false;
2481         };
2482
2483         if (fio->type == ADOUBLE_META) {
2484                 return true;
2485         }
2486
2487         if ((fio->type == ADOUBLE_RSRC) &&
2488             (fio->config->rsrc == FRUIT_RSRC_ADFILE))
2489         {
2490                 return true;
2491         }
2492
2493         return false;
2494 }
2495
2496 struct fruit_pread_state {
2497         ssize_t nread;
2498         struct vfs_aio_state vfs_aio_state;
2499 };
2500
2501 static void fruit_pread_done(struct tevent_req *subreq);
2502
2503 static struct tevent_req *fruit_pread_send(
2504         struct vfs_handle_struct *handle,
2505         TALLOC_CTX *mem_ctx,
2506         struct tevent_context *ev,
2507         struct files_struct *fsp,
2508         void *data,
2509         size_t n, off_t offset)
2510 {
2511         struct tevent_req *req = NULL;
2512         struct tevent_req *subreq = NULL;
2513         struct fruit_pread_state *state = NULL;
2514         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2515
2516         req = tevent_req_create(mem_ctx, &state,
2517                                 struct fruit_pread_state);
2518         if (req == NULL) {
2519                 return NULL;
2520         }
2521
2522         if (fruit_must_handle_aio_stream(fio)) {
2523                 state->nread = SMB_VFS_PREAD(fsp, data, n, offset);
2524                 if (state->nread != n) {
2525                         if (state->nread != -1) {
2526                                 errno = EIO;
2527                         }
2528                         tevent_req_error(req, errno);
2529                         return tevent_req_post(req, ev);
2530                 }
2531                 tevent_req_done(req);
2532                 return tevent_req_post(req, ev);
2533         }
2534
2535         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp,
2536                                          data, n, offset);
2537         if (tevent_req_nomem(req, subreq)) {
2538                 return tevent_req_post(req, ev);
2539         }
2540         tevent_req_set_callback(subreq, fruit_pread_done, req);
2541         return req;
2542 }
2543
2544 static void fruit_pread_done(struct tevent_req *subreq)
2545 {
2546         struct tevent_req *req = tevent_req_callback_data(
2547                 subreq, struct tevent_req);
2548         struct fruit_pread_state *state = tevent_req_data(
2549                 req, struct fruit_pread_state);
2550
2551         state->nread = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
2552         TALLOC_FREE(subreq);
2553
2554         if (tevent_req_error(req, state->vfs_aio_state.error)) {
2555                 return;
2556         }
2557         tevent_req_done(req);
2558 }
2559
2560 static ssize_t fruit_pread_recv(struct tevent_req *req,
2561                                         struct vfs_aio_state *vfs_aio_state)
2562 {
2563         struct fruit_pread_state *state = tevent_req_data(
2564                 req, struct fruit_pread_state);
2565
2566         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2567                 return -1;
2568         }
2569
2570         *vfs_aio_state = state->vfs_aio_state;
2571         return state->nread;
2572 }
2573
2574 static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle,
2575                                         files_struct *fsp, const void *data,
2576                                         size_t n, off_t offset)
2577 {
2578         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2579         AfpInfo *ai = NULL;
2580         size_t nwritten;
2581         int ret;
2582         bool ok;
2583
2584         DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
2585                   fsp_str_dbg(fsp), (intmax_t)offset, n);
2586
2587         if (fio == NULL) {
2588                 return -1;
2589         }
2590
2591         if (fio->fake_fd) {
2592                 int fd = fsp_get_pathref_fd(fsp);
2593
2594                 ret = vfs_fake_fd_close(fd);
2595                 fsp_set_fd(fsp, -1);
2596                 if (ret != 0) {
2597                         DBG_ERR("Close [%s] failed: %s\n",
2598                                 fsp_str_dbg(fsp), strerror(errno));
2599                         return -1;
2600                 }
2601
2602                 fd = SMB_VFS_NEXT_OPENAT(handle,
2603                                          fsp->conn->cwd_fsp,
2604                                          fsp->fsp_name,
2605                                          fsp,
2606                                          fio->flags,
2607                                          fio->mode);
2608                 if (fd == -1) {
2609                         DBG_ERR("On-demand create [%s] in write failed: %s\n",
2610                                 fsp_str_dbg(fsp), strerror(errno));
2611                         return -1;
2612                 }
2613                 fsp_set_fd(fsp, fd);
2614                 fio->fake_fd = false;
2615         }
2616
2617         ai = afpinfo_unpack(talloc_tos(), data);
2618         if (ai == NULL) {
2619                 return -1;
2620         }
2621
2622         if (ai_empty_finderinfo(ai)) {
2623                 /*
2624                  * Writing an all 0 blob to the metadata stream results in the
2625                  * stream being removed on a macOS server. This ensures we
2626                  * behave the same and it verified by the "delete AFP_AfpInfo by
2627                  * writing all 0" test.
2628                  */
2629                 ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, 0);
2630                 if (ret != 0) {
2631                         DBG_ERR("SMB_VFS_NEXT_FTRUNCATE on [%s] failed\n",
2632                                 fsp_str_dbg(fsp));
2633                         return -1;
2634                 }
2635
2636                 ok = set_delete_on_close(
2637                         fsp,
2638                         true,
2639                         handle->conn->session_info->security_token,
2640                         handle->conn->session_info->unix_token);
2641                 if (!ok) {
2642                         DBG_ERR("set_delete_on_close on [%s] failed\n",
2643                                 fsp_str_dbg(fsp));
2644                         return -1;
2645                 }
2646                 return n;
2647         }
2648
2649         nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2650         if (nwritten != n) {
2651                 return -1;
2652         }
2653
2654         return n;
2655 }
2656
2657 static ssize_t fruit_pwrite_meta_netatalk(vfs_handle_struct *handle,
2658                                           files_struct *fsp, const void *data,
2659                                           size_t n, off_t offset)
2660 {
2661         struct adouble *ad = NULL;
2662         AfpInfo *ai = NULL;
2663         char *p = NULL;
2664         int ret;
2665         bool ok;
2666
2667         ai = afpinfo_unpack(talloc_tos(), data);
2668         if (ai == NULL) {
2669                 return -1;
2670         }
2671
2672         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
2673         if (ad == NULL) {
2674                 ad = ad_init(talloc_tos(), ADOUBLE_META);
2675                 if (ad == NULL) {
2676                         return -1;
2677                 }
2678         }
2679         p = ad_get_entry(ad, ADEID_FINDERI);
2680         if (p == NULL) {
2681                 DBG_ERR("No ADEID_FINDERI for [%s]\n", fsp_str_dbg(fsp));
2682                 TALLOC_FREE(ad);
2683                 return -1;
2684         }
2685
2686         memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI);
2687
2688         ret = ad_fset(handle, ad, fsp);
2689         if (ret != 0) {
2690                 DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp));
2691                 TALLOC_FREE(ad);
2692                 return -1;
2693         }
2694
2695         TALLOC_FREE(ad);
2696
2697         if (!ai_empty_finderinfo(ai)) {
2698                 return n;
2699         }
2700
2701         /*
2702          * Writing an all 0 blob to the metadata stream results in the stream
2703          * being removed on a macOS server. This ensures we behave the same and
2704          * it verified by the "delete AFP_AfpInfo by writing all 0" test.
2705          */
2706
2707         ok = set_delete_on_close(
2708                 fsp,
2709                 true,
2710                 handle->conn->session_info->security_token,
2711                 handle->conn->session_info->unix_token);
2712         if (!ok) {
2713                 DBG_ERR("set_delete_on_close on [%s] failed\n",
2714                         fsp_str_dbg(fsp));
2715                 return -1;
2716         }
2717
2718         return n;
2719 }
2720
2721 static ssize_t fruit_pwrite_meta(vfs_handle_struct *handle,
2722                                  files_struct *fsp, const void *data,
2723                                  size_t n, off_t offset)
2724 {
2725         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2726         ssize_t nwritten;
2727         uint8_t buf[AFP_INFO_SIZE];
2728         size_t to_write;
2729         size_t to_copy;
2730         int cmp;
2731
2732         if (fio == NULL) {
2733                 DBG_ERR("Failed to fetch fsp extension");
2734                 return -1;
2735         }
2736
2737         if (n < 3) {
2738                 errno = EINVAL;
2739                 return -1;
2740         }
2741
2742         if (offset != 0 && n < 60) {
2743                 errno = EINVAL;
2744                 return -1;
2745         }
2746
2747         cmp = memcmp(data, "AFP", 3);
2748         if (cmp != 0) {
2749                 errno = EINVAL;
2750                 return -1;
2751         }
2752
2753         if (n <= AFP_OFF_FinderInfo) {
2754                 /*
2755                  * Nothing to do here really, just return
2756                  */
2757                 return n;
2758         }
2759
2760         offset = 0;
2761
2762         to_copy = n;
2763         if (to_copy > AFP_INFO_SIZE) {
2764                 to_copy = AFP_INFO_SIZE;
2765         }
2766         memcpy(buf, data, to_copy);
2767
2768         to_write = n;
2769         if (to_write != AFP_INFO_SIZE) {
2770                 to_write = AFP_INFO_SIZE;
2771         }
2772
2773         switch (fio->config->meta) {
2774         case FRUIT_META_STREAM:
2775                 nwritten = fruit_pwrite_meta_stream(handle,
2776                                                     fsp,
2777                                                     buf,
2778                                                     to_write,
2779                                                     offset);
2780                 break;
2781
2782         case FRUIT_META_NETATALK:
2783                 nwritten = fruit_pwrite_meta_netatalk(handle,
2784                                                       fsp,
2785                                                       buf,
2786                                                       to_write,
2787                                                       offset);
2788                 break;
2789
2790         default:
2791                 DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
2792                 return -1;
2793         }
2794
2795         if (nwritten != to_write) {
2796                 return -1;
2797         }
2798
2799         /*
2800          * Return the requested amount, verified against macOS SMB server
2801          */
2802         return n;
2803 }
2804
2805 static ssize_t fruit_pwrite_rsrc_stream(vfs_handle_struct *handle,
2806                                         files_struct *fsp, const void *data,
2807                                         size_t n, off_t offset)
2808 {
2809         return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2810 }
2811
2812 static ssize_t fruit_pwrite_rsrc_xattr(vfs_handle_struct *handle,
2813                                        files_struct *fsp, const void *data,
2814                                        size_t n, off_t offset)
2815 {
2816         return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2817 }
2818
2819 static ssize_t fruit_pwrite_rsrc_adouble(vfs_handle_struct *handle,
2820                                          files_struct *fsp, const void *data,
2821                                          size_t n, off_t offset)
2822 {
2823         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2824         struct adouble *ad = NULL;
2825         ssize_t nwritten;
2826         int ret;
2827
2828         if (fio->ad_fsp == NULL) {
2829                 DBG_ERR("ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
2830                 errno = EBADF;
2831                 return -1;
2832         }
2833
2834         ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
2835         if (ad == NULL) {
2836                 DBG_ERR("ad_fget [%s] failed [%s]\n",
2837                         fsp_str_dbg(fio->ad_fsp), strerror(errno));
2838                 return -1;
2839         }
2840
2841         nwritten = SMB_VFS_NEXT_PWRITE(handle, fio->ad_fsp, data, n,
2842                                        offset + ad_getentryoff(ad, ADEID_RFORK));
2843         if (nwritten != n) {
2844                 DBG_ERR("Short write on [%s] [%zd/%zd]\n",
2845                         fsp_str_dbg(fio->ad_fsp), nwritten, n);
2846                 TALLOC_FREE(ad);
2847                 return -1;
2848         }
2849
2850         if ((n + offset) > ad_getentrylen(ad, ADEID_RFORK)) {
2851                 ad_setentrylen(ad, ADEID_RFORK, n + offset);
2852                 ret = ad_fset(handle, ad, fio->ad_fsp);
2853                 if (ret != 0) {
2854                         DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fio->ad_fsp));
2855                         TALLOC_FREE(ad);
2856                         return -1;
2857                 }
2858         }
2859
2860         TALLOC_FREE(ad);
2861         return n;
2862 }
2863
2864 static ssize_t fruit_pwrite_rsrc(vfs_handle_struct *handle,
2865                                  files_struct *fsp, const void *data,
2866                                  size_t n, off_t offset)
2867 {
2868         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2869         ssize_t nwritten;
2870
2871         if (fio == NULL) {
2872                 DBG_ERR("Failed to fetch fsp extension");
2873                 return -1;
2874         }
2875
2876         switch (fio->config->rsrc) {
2877         case FRUIT_RSRC_STREAM:
2878                 nwritten = fruit_pwrite_rsrc_stream(handle, fsp, data, n, offset);
2879                 break;
2880
2881         case FRUIT_RSRC_ADFILE:
2882                 nwritten = fruit_pwrite_rsrc_adouble(handle, fsp, data, n, offset);
2883                 break;
2884
2885         case FRUIT_RSRC_XATTR:
2886                 nwritten = fruit_pwrite_rsrc_xattr(handle, fsp, data, n, offset);
2887                 break;
2888
2889         default:
2890                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
2891                 return -1;
2892         }
2893
2894         return nwritten;
2895 }
2896
2897 static ssize_t fruit_pwrite(vfs_handle_struct *handle,
2898                             files_struct *fsp, const void *data,
2899                             size_t n, off_t offset)
2900 {
2901         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2902         ssize_t nwritten;
2903
2904         DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
2905                   fsp_str_dbg(fsp), (intmax_t)offset, n);
2906
2907         if (fio == NULL) {
2908                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2909         }
2910
2911         if (fio->type == ADOUBLE_META) {
2912                 nwritten = fruit_pwrite_meta(handle, fsp, data, n, offset);
2913         } else {
2914                 nwritten = fruit_pwrite_rsrc(handle, fsp, data, n, offset);
2915         }
2916
2917         DBG_DEBUG("Path [%s] nwritten=%zd\n", fsp_str_dbg(fsp), nwritten);
2918         return nwritten;
2919 }
2920
2921 struct fruit_pwrite_state {
2922         ssize_t nwritten;
2923         struct vfs_aio_state vfs_aio_state;
2924 };
2925
2926 static void fruit_pwrite_done(struct tevent_req *subreq);
2927
2928 static struct tevent_req *fruit_pwrite_send(
2929         struct vfs_handle_struct *handle,
2930         TALLOC_CTX *mem_ctx,
2931         struct tevent_context *ev,
2932         struct files_struct *fsp,
2933         const void *data,
2934         size_t n, off_t offset)
2935 {
2936         struct tevent_req *req = NULL;
2937         struct tevent_req *subreq = NULL;
2938         struct fruit_pwrite_state *state = NULL;
2939         struct fio *fio = fruit_get_complete_fio(handle, fsp);
2940
2941         req = tevent_req_create(mem_ctx, &state,
2942                                 struct fruit_pwrite_state);
2943         if (req == NULL) {
2944                 return NULL;
2945         }
2946
2947         if (fruit_must_handle_aio_stream(fio)) {
2948                 state->nwritten = SMB_VFS_PWRITE(fsp, data, n, offset);
2949                 if (state->nwritten != n) {
2950                         if (state->nwritten != -1) {
2951                                 errno = EIO;
2952                         }
2953                         tevent_req_error(req, errno);
2954                         return tevent_req_post(req, ev);
2955                 }
2956                 tevent_req_done(req);
2957                 return tevent_req_post(req, ev);
2958         }
2959
2960         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp,
2961                                           data, n, offset);
2962         if (tevent_req_nomem(req, subreq)) {
2963                 return tevent_req_post(req, ev);
2964         }
2965         tevent_req_set_callback(subreq, fruit_pwrite_done, req);
2966         return req;
2967 }
2968
2969 static void fruit_pwrite_done(struct tevent_req *subreq)
2970 {
2971         struct tevent_req *req = tevent_req_callback_data(
2972                 subreq, struct tevent_req);
2973         struct fruit_pwrite_state *state = tevent_req_data(
2974                 req, struct fruit_pwrite_state);
2975
2976         state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
2977         TALLOC_FREE(subreq);
2978
2979         if (tevent_req_error(req, state->vfs_aio_state.error)) {
2980                 return;
2981         }
2982         tevent_req_done(req);
2983 }
2984
2985 static ssize_t fruit_pwrite_recv(struct tevent_req *req,
2986                                          struct vfs_aio_state *vfs_aio_state)
2987 {
2988         struct fruit_pwrite_state *state = tevent_req_data(
2989                 req, struct fruit_pwrite_state);
2990
2991         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2992                 return -1;
2993         }
2994
2995         *vfs_aio_state = state->vfs_aio_state;
2996         return state->nwritten;
2997 }
2998
2999 /**
3000  * Helper to stat/lstat the base file of an smb_fname.
3001  */
3002 static int fruit_stat_base(vfs_handle_struct *handle,
3003                            struct smb_filename *smb_fname,
3004                            bool follow_links)
3005 {
3006         char *tmp_stream_name;
3007         int rc;
3008
3009         tmp_stream_name = smb_fname->stream_name;
3010         smb_fname->stream_name = NULL;
3011         if (follow_links) {
3012                 rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
3013         } else {
3014                 rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
3015         }
3016         smb_fname->stream_name = tmp_stream_name;
3017
3018         DBG_DEBUG("fruit_stat_base [%s] dev [%ju] ino [%ju]\n",
3019                   smb_fname->base_name,
3020                   (uintmax_t)smb_fname->st.st_ex_dev,
3021                   (uintmax_t)smb_fname->st.st_ex_ino);
3022         return rc;
3023 }
3024
3025 static int fruit_stat_meta_stream(vfs_handle_struct *handle,
3026                                   struct smb_filename *smb_fname,
3027                                   bool follow_links)
3028 {
3029         int ret;
3030         ino_t ino;
3031
3032         ret = fruit_stat_base(handle, smb_fname, false);
3033         if (ret != 0) {
3034                 return -1;
3035         }
3036
3037         ino = hash_inode(&smb_fname->st, smb_fname->stream_name);
3038
3039         if (follow_links) {
3040                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
3041         } else {
3042                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
3043         }
3044
3045         smb_fname->st.st_ex_ino = ino;
3046
3047         return ret;
3048 }
3049
3050 static int fruit_stat_meta_netatalk(vfs_handle_struct *handle,
3051                                     struct smb_filename *smb_fname,
3052                                     bool follow_links)
3053 {
3054         struct adouble *ad = NULL;
3055
3056         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
3057         if (ad == NULL) {
3058                 DBG_INFO("fruit_stat_meta %s: %s\n",
3059                          smb_fname_str_dbg(smb_fname), strerror(errno));
3060                 errno = ENOENT;
3061                 return -1;
3062         }
3063         TALLOC_FREE(ad);
3064
3065         /* Populate the stat struct with info from the base file. */
3066         if (fruit_stat_base(handle, smb_fname, follow_links) == -1) {
3067                 return -1;
3068         }
3069         smb_fname->st.st_ex_size = AFP_INFO_SIZE;
3070         smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st,
3071                                               smb_fname->stream_name);
3072         return 0;
3073 }
3074
3075 static int fruit_stat_meta(vfs_handle_struct *handle,
3076                            struct smb_filename *smb_fname,
3077                            bool follow_links)
3078 {
3079         struct fruit_config_data *config = NULL;
3080         int ret;
3081
3082         SMB_VFS_HANDLE_GET_DATA(handle, config,
3083                                 struct fruit_config_data, return -1);
3084
3085         switch (config->meta) {
3086         case FRUIT_META_STREAM:
3087                 ret = fruit_stat_meta_stream(handle, smb_fname, follow_links);
3088                 break;
3089
3090         case FRUIT_META_NETATALK:
3091                 ret = fruit_stat_meta_netatalk(handle, smb_fname, follow_links);
3092                 break;
3093
3094         default:
3095                 DBG_ERR("Unexpected meta config [%d]\n", config->meta);
3096                 return -1;
3097         }
3098
3099         return ret;
3100 }
3101
3102 static int fruit_stat_rsrc_netatalk(vfs_handle_struct *handle,
3103                                     struct smb_filename *smb_fname,
3104                                     bool follow_links)
3105 {
3106         struct adouble *ad = NULL;
3107         int ret;
3108
3109         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
3110         if (ad == NULL) {
3111                 errno = ENOENT;
3112                 return -1;
3113         }
3114
3115         /* Populate the stat struct with info from the base file. */
3116         ret = fruit_stat_base(handle, smb_fname, follow_links);
3117         if (ret != 0) {
3118                 TALLOC_FREE(ad);
3119                 return -1;
3120         }
3121
3122         smb_fname->st.st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
3123         smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st,
3124                                               smb_fname->stream_name);
3125         TALLOC_FREE(ad);
3126         return 0;
3127 }
3128
3129 static int fruit_stat_rsrc_stream(vfs_handle_struct *handle,
3130                                   struct smb_filename *smb_fname,
3131                                   bool follow_links)
3132 {
3133         int ret;
3134
3135         if (follow_links) {
3136                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
3137         } else {
3138                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
3139         }
3140
3141         return ret;
3142 }
3143
3144 static int fruit_stat_rsrc_xattr(vfs_handle_struct *handle,
3145                                  struct smb_filename *smb_fname,
3146                                  bool follow_links)
3147 {
3148 #ifdef HAVE_ATTROPEN
3149         int ret;
3150         int fd = -1;
3151
3152         /* Populate the stat struct with info from the base file. */
3153         ret = fruit_stat_base(handle, smb_fname, follow_links);
3154         if (ret != 0) {
3155                 return -1;
3156         }
3157
3158         fd = attropen(smb_fname->base_name,
3159                       AFPRESOURCE_EA_NETATALK,
3160                       O_RDONLY);
3161         if (fd == -1) {
3162                 return 0;
3163         }
3164
3165         ret = sys_fstat(fd, &smb_fname->st, false);
3166         if (ret != 0) {
3167                 close(fd);
3168                 DBG_ERR("fstat [%s:%s] failed\n", smb_fname->base_name,
3169                         AFPRESOURCE_EA_NETATALK);
3170                 return -1;
3171         }
3172         close(fd);
3173         fd = -1;
3174
3175         smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st,
3176                                              smb_fname->stream_name);
3177
3178         return ret;
3179
3180 #else
3181         errno = ENOSYS;
3182         return -1;
3183 #endif
3184 }
3185
3186 static int fruit_stat_rsrc(vfs_handle_struct *handle,
3187                            struct smb_filename *smb_fname,
3188                            bool follow_links)
3189 {
3190         struct fruit_config_data *config = NULL;
3191         int ret;
3192
3193         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
3194
3195         SMB_VFS_HANDLE_GET_DATA(handle, config,
3196                                 struct fruit_config_data, return -1);
3197
3198         switch (config->rsrc) {
3199         case FRUIT_RSRC_STREAM:
3200                 ret = fruit_stat_rsrc_stream(handle, smb_fname, follow_links);
3201                 break;
3202
3203         case FRUIT_RSRC_XATTR:
3204                 ret = fruit_stat_rsrc_xattr(handle, smb_fname, follow_links);
3205                 break;
3206
3207         case FRUIT_RSRC_ADFILE:
3208                 ret = fruit_stat_rsrc_netatalk(handle, smb_fname, follow_links);
3209                 break;
3210
3211         default:
3212                 DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
3213                 return -1;
3214         }
3215
3216         return ret;
3217 }
3218
3219 static int fruit_stat(vfs_handle_struct *handle,
3220                       struct smb_filename *smb_fname)
3221 {
3222         int rc = -1;
3223
3224         DEBUG(10, ("fruit_stat called for %s\n",
3225                    smb_fname_str_dbg(smb_fname)));
3226
3227         if (!is_named_stream(smb_fname)) {
3228                 rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
3229                 if (rc == 0) {
3230                         update_btime(handle, smb_fname);
3231                 }
3232                 return rc;
3233         }
3234
3235         /*
3236          * Note if lp_posix_paths() is true, we can never
3237          * get here as is_ntfs_stream_smb_fname() is
3238          * always false. So we never need worry about
3239          * not following links here.
3240          */
3241
3242         if (is_afpinfo_stream(smb_fname->stream_name)) {
3243                 rc = fruit_stat_meta(handle, smb_fname, true);
3244         } else if (is_afpresource_stream(smb_fname->stream_name)) {
3245                 rc = fruit_stat_rsrc(handle, smb_fname, true);
3246         } else {
3247                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
3248         }
3249
3250         if (rc == 0) {
3251                 update_btime(handle, smb_fname);
3252                 smb_fname->st.st_ex_mode &= ~S_IFMT;
3253                 smb_fname->st.st_ex_mode |= S_IFREG;
3254                 smb_fname->st.st_ex_blocks =
3255                         smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
3256         }
3257         return rc;
3258 }
3259
3260 static int fruit_lstat(vfs_handle_struct *handle,
3261                        struct smb_filename *smb_fname)
3262 {
3263         int rc = -1;
3264
3265         DEBUG(10, ("fruit_lstat called for %s\n",
3266                    smb_fname_str_dbg(smb_fname)));
3267
3268         if (!is_named_stream(smb_fname)) {
3269                 rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
3270                 if (rc == 0) {
3271                         update_btime(handle, smb_fname);
3272                 }
3273                 return rc;
3274         }
3275
3276         if (is_afpinfo_stream(smb_fname->stream_name)) {
3277                 rc = fruit_stat_meta(handle, smb_fname, false);
3278         } else if (is_afpresource_stream(smb_fname->stream_name)) {
3279                 rc = fruit_stat_rsrc(handle, smb_fname, false);
3280         } else {
3281                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
3282         }
3283
3284         if (rc == 0) {
3285                 update_btime(handle, smb_fname);
3286                 smb_fname->st.st_ex_mode &= ~S_IFMT;
3287                 smb_fname->st.st_ex_mode |= S_IFREG;
3288                 smb_fname->st.st_ex_blocks =
3289                         smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
3290         }
3291         return rc;
3292 }
3293
3294 static int fruit_fstat_meta_stream(vfs_handle_struct *handle,
3295                                    files_struct *fsp,
3296                                    SMB_STRUCT_STAT *sbuf)
3297 {
3298         struct fio *fio = fruit_get_complete_fio(handle, fsp);
3299         struct smb_filename smb_fname;
3300         ino_t ino;
3301         int ret;
3302
3303         if (fio == NULL) {
3304                 return -1;
3305         }
3306
3307         if (fio->fake_fd) {
3308                 ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
3309                 if (ret != 0) {
3310                         return -1;
3311                 }
3312
3313                 *sbuf = fsp->base_fsp->fsp_name->st;
3314                 sbuf->st_ex_size = AFP_INFO_SIZE;
3315                 sbuf->st_ex_ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
3316                 return 0;
3317         }
3318
3319         smb_fname = (struct smb_filename) {
3320                 .base_name = fsp->fsp_name->base_name,
3321                 .twrp = fsp->fsp_name->twrp,
3322         };
3323
3324         ret = fruit_stat_base(handle, &smb_fname, false);
3325         if (ret != 0) {
3326                 return -1;
3327         }
3328         *sbuf = smb_fname.st;
3329
3330         ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
3331
3332         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
3333         if (ret != 0) {
3334                 return -1;
3335         }
3336
3337         sbuf->st_ex_ino = ino;
3338         return 0;
3339 }
3340
3341 static int fruit_fstat_meta_netatalk(vfs_handle_struct *handle,
3342                                      files_struct *fsp,
3343                                      SMB_STRUCT_STAT *sbuf)
3344 {
3345         int ret;
3346
3347         ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
3348         if (ret != 0) {
3349                 return -1;
3350         }
3351
3352         *sbuf = fsp->base_fsp->fsp_name->st;
3353         sbuf->st_ex_size = AFP_INFO_SIZE;
3354         sbuf->st_ex_ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
3355
3356         return 0;
3357 }
3358
3359 static int fruit_fstat_meta(vfs_handle_struct *handle,
3360                             files_struct *fsp,
3361                             SMB_STRUCT_STAT *sbuf,
3362                             struct fio *fio)
3363 {
3364         int ret;
3365
3366         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
3367
3368         switch (fio->config->meta) {
3369         case FRUIT_META_STREAM:
3370                 ret = fruit_fstat_meta_stream(handle, fsp, sbuf);
3371                 break;
3372
3373         case FRUIT_META_NETATALK:
3374                 ret = fruit_fstat_meta_netatalk(handle, fsp, sbuf);
3375                 break;
3376
3377         default:
3378                 DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
3379                 return -1;
3380         }
3381
3382         DBG_DEBUG("Path [%s] ret [%d]\n", fsp_str_dbg(fsp), ret);
3383         return ret;
3384 }
3385
3386 static int fruit_fstat_rsrc_xattr(vfs_handle_struct *handle,
3387                                   files_struct *fsp,
3388                                   SMB_STRUCT_STAT *sbuf)
3389 {
3390         return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
3391 }
3392
3393 static int fruit_fstat_rsrc_stream(vfs_handle_struct *handle,
3394                                    files_struct *fsp,
3395                                    SMB_STRUCT_STAT *sbuf)
3396 {
3397         return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
3398 }
3399
3400 static int fruit_fstat_rsrc_adouble(vfs_handle_struct *handle,
3401                                     files_struct *fsp,
3402                                     SMB_STRUCT_STAT *sbuf)
3403 {
3404         struct fio *fio = fruit_get_complete_fio(handle, fsp);
3405         struct adouble *ad = NULL;
3406         int ret;
3407
3408         if (fio->ad_fsp == NULL) {
3409                 DBG_ERR("ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
3410                 errno = EBADF;
3411                 return -1;
3412         }
3413
3414         /* Populate the stat struct with info from the base file. */
3415         ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
3416         if (ret == -1) {
3417                 return -1;
3418         }
3419
3420         ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
3421         if (ad == NULL) {
3422                 DBG_ERR("ad_fget [%s] failed [%s]\n",
3423                         fsp_str_dbg(fio->ad_fsp), strerror(errno));
3424                 return -1;
3425         }
3426
3427         *sbuf = fsp->base_fsp->fsp_name->st;
3428         sbuf->st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
3429         sbuf->st_ex_ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
3430
3431         TALLOC_FREE(ad);
3432         return 0;
3433 }
3434
3435 static int fruit_fstat_rsrc(vfs_handle_struct *handle, files_struct *fsp,
3436                             SMB_STRUCT_STAT *sbuf, struct fio *fio)
3437 {
3438         int ret;
3439
3440         switch (fio->config->rsrc) {
3441         case FRUIT_RSRC_STREAM:
3442                 ret = fruit_fstat_rsrc_stream(handle, fsp, sbuf);
3443                 break;
3444
3445         case FRUIT_RSRC_ADFILE:
3446                 ret = fruit_fstat_rsrc_adouble(handle, fsp, sbuf);
3447                 break;
3448
3449         case FRUIT_RSRC_XATTR:
3450                 ret = fruit_fstat_rsrc_xattr(handle, fsp, sbuf);
3451                 break;
3452
3453         default:
3454                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
3455                 return -1;
3456         }
3457
3458         return ret;
3459 }
3460
3461 static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp,
3462                        SMB_STRUCT_STAT *sbuf)
3463 {
3464         struct fio *fio = fruit_get_complete_fio(handle, fsp);
3465         int rc;
3466
3467         if (fio == NULL) {
3468                 return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
3469         }
3470
3471         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
3472
3473         if (fio->type == ADOUBLE_META) {
3474                 rc = fruit_fstat_meta(handle, fsp, sbuf, fio);
3475         } else {
3476                 rc = fruit_fstat_rsrc(handle, fsp, sbuf, fio);
3477         }
3478
3479         if (rc == 0) {
3480                 sbuf->st_ex_mode &= ~S_IFMT;
3481                 sbuf->st_ex_mode |= S_IFREG;
3482                 sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
3483         }
3484
3485         DBG_DEBUG("Path [%s] rc [%d] size [%"PRIdMAX"]\n",
3486                   fsp_str_dbg(fsp), rc, (intmax_t)sbuf->st_ex_size);
3487         return rc;
3488 }
3489
3490 static NTSTATUS delete_invalid_meta_stream(
3491         vfs_handle_struct *handle,
3492         const struct smb_filename *smb_fname,
3493         TALLOC_CTX *mem_ctx,
3494         unsigned int *pnum_streams,
3495         struct stream_struct **pstreams,
3496         off_t size)
3497 {
3498         struct smb_filename *sname = NULL;
3499         NTSTATUS status;
3500         int ret;
3501         bool ok;
3502
3503         ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams, AFPINFO_STREAM);
3504         if (!ok) {
3505                 return NT_STATUS_INTERNAL_ERROR;
3506         }
3507
3508         if (size == 0) {
3509                 return NT_STATUS_OK;
3510         }
3511
3512         status = synthetic_pathref(talloc_tos(),
3513                                    handle->conn->cwd_fsp,
3514                                    smb_fname->base_name,
3515                                    AFPINFO_STREAM_NAME,
3516                                    NULL,
3517                                    smb_fname->twrp,
3518                                    0,
3519                                    &sname);
3520         if (!NT_STATUS_IS_OK(status)) {
3521                 return NT_STATUS_NO_MEMORY;
3522         }
3523
3524         ret = SMB_VFS_NEXT_UNLINKAT(handle,
3525                         handle->conn->cwd_fsp,
3526                         sname,
3527                         0);
3528         if (ret != 0) {
3529                 DBG_ERR("Removing [%s] failed\n", smb_fname_str_dbg(sname));
3530                 TALLOC_FREE(sname);
3531                 return map_nt_error_from_unix(errno);
3532         }
3533
3534         TALLOC_FREE(sname);
3535         return NT_STATUS_OK;
3536 }
3537
3538 static NTSTATUS fruit_streaminfo_meta_stream(
3539         vfs_handle_struct *handle,
3540         struct files_struct *fsp,
3541         const struct smb_filename *smb_fname,
3542         TALLOC_CTX *mem_ctx,
3543         unsigned int *pnum_streams,
3544         struct stream_struct **pstreams)
3545 {
3546         struct stream_struct *stream = *pstreams;
3547         unsigned int num_streams = *pnum_streams;
3548         int i;
3549
3550         for (i = 0; i < num_streams; i++) {
3551                 if (strequal_m(stream[i].name, AFPINFO_STREAM)) {
3552                         break;
3553                 }
3554         }
3555
3556         if (i == num_streams) {
3557                 return NT_STATUS_OK;
3558         }
3559
3560         if (stream[i].size != AFP_INFO_SIZE) {
3561                 DBG_ERR("Removing invalid AFPINFO_STREAM size [%jd] from [%s]\n",
3562                         (intmax_t)stream[i].size, smb_fname_str_dbg(smb_fname));
3563
3564                 return delete_invalid_meta_stream(handle,
3565                                                   smb_fname,
3566                                                   mem_ctx,
3567                                                   pnum_streams,
3568                                                   pstreams,
3569                                                   stream[i].size);
3570         }
3571
3572
3573         return NT_STATUS_OK;
3574 }
3575
3576 static NTSTATUS fruit_streaminfo_meta_netatalk(
3577         vfs_handle_struct *handle,
3578         struct files_struct *fsp,
3579         const struct smb_filename *smb_fname,
3580         TALLOC_CTX *mem_ctx,
3581         unsigned int *pnum_streams,
3582         struct stream_struct **pstreams)
3583 {
3584         struct stream_struct *stream = *pstreams;
3585         unsigned int num_streams = *pnum_streams;
3586         struct adouble *ad = NULL;
3587         bool is_fi_empty;
3588         int i;
3589         bool ok;
3590
3591         /* Remove the Netatalk xattr from the list */
3592         ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
3593                               ":" NETATALK_META_XATTR ":$DATA");
3594         if (!ok) {
3595                 return NT_STATUS_NO_MEMORY;
3596         }
3597
3598         /*
3599          * Check if there's a AFPINFO_STREAM from the VFS streams
3600          * backend and if yes, remove it from the list
3601          */
3602         for (i = 0; i < num_streams; i++) {
3603                 if (strequal_m(stream[i].name, AFPINFO_STREAM)) {
3604                         break;
3605                 }
3606         }
3607
3608         if (i < num_streams) {
3609                 DBG_WARNING("Unexpected AFPINFO_STREAM on [%s]\n",
3610                             smb_fname_str_dbg(smb_fname));
3611
3612                 ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
3613                                       AFPINFO_STREAM);
3614                 if (!ok) {
3615                         return NT_STATUS_INTERNAL_ERROR;
3616                 }
3617         }
3618
3619         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
3620         if (ad == NULL) {
3621                 return NT_STATUS_OK;
3622         }
3623
3624         is_fi_empty = ad_empty_finderinfo(ad);
3625         TALLOC_FREE(ad);
3626
3627         if (is_fi_empty) {
3628                 return NT_STATUS_OK;
3629         }
3630
3631         ok = add_fruit_stream(mem_ctx, pnum_streams, pstreams,
3632                               AFPINFO_STREAM_NAME, AFP_INFO_SIZE,
3633                               smb_roundup(handle->conn, AFP_INFO_SIZE));
3634         if (!ok) {
3635                 return NT_STATUS_NO_MEMORY;
3636         }
3637
3638         return NT_STATUS_OK;
3639 }
3640
3641 static NTSTATUS fruit_streaminfo_meta(vfs_handle_struct *handle,
3642                                       struct files_struct *fsp,
3643                                       const struct smb_filename *smb_fname,
3644                                       TALLOC_CTX *mem_ctx,
3645                                       unsigned int *pnum_streams,
3646                                       struct stream_struct **pstreams)
3647 {
3648         struct fruit_config_data *config = NULL;
3649         NTSTATUS status;
3650
3651         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
3652                                 return NT_STATUS_INTERNAL_ERROR);
3653
3654         switch (config->meta) {
3655         case FRUIT_META_NETATALK:
3656                 status = fruit_streaminfo_meta_netatalk(handle, fsp, smb_fname,
3657                                                         mem_ctx, pnum_streams,
3658                                                         pstreams);
3659                 break;
3660
3661         case FRUIT_META_STREAM:
3662                 status = fruit_streaminfo_meta_stream(handle, fsp, smb_fname,
3663                                                       mem_ctx, pnum_streams,
3664                                                       pstreams);
3665                 break;
3666
3667         default:
3668                 return NT_STATUS_INTERNAL_ERROR;
3669         }
3670
3671         return status;
3672 }
3673
3674 static NTSTATUS fruit_streaminfo_rsrc_stream(
3675         vfs_handle_struct *handle,
3676         struct files_struct *fsp,
3677         const struct smb_filename *smb_fname,
3678         TALLOC_CTX *mem_ctx,
3679         unsigned int *pnum_streams,
3680         struct stream_struct **pstreams)
3681 {
3682         bool ok;
3683
3684         ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
3685         if (!ok) {
3686                 DBG_ERR("Filtering resource stream failed\n");
3687                 return NT_STATUS_INTERNAL_ERROR;
3688         }
3689         return NT_STATUS_OK;
3690 }
3691
3692 static NTSTATUS fruit_streaminfo_rsrc_xattr(
3693         vfs_handle_struct *handle,
3694         struct files_struct *fsp,
3695         const struct smb_filename *smb_fname,
3696         TALLOC_CTX *mem_ctx,
3697         unsigned int *pnum_streams,
3698         struct stream_struct **pstreams)
3699 {
3700         bool ok;
3701
3702         ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
3703         if (!ok) {
3704                 DBG_ERR("Filtering resource stream failed\n");
3705                 return NT_STATUS_INTERNAL_ERROR;
3706         }
3707         return NT_STATUS_OK;
3708 }
3709
3710 static NTSTATUS fruit_streaminfo_rsrc_adouble(
3711         vfs_handle_struct *handle,
3712         struct files_struct *fsp,
3713         const struct smb_filename *smb_fname,
3714         TALLOC_CTX *mem_ctx,
3715         unsigned int *pnum_streams,
3716         struct stream_struct **pstreams)
3717 {
3718         struct stream_struct *stream = *pstreams;
3719         unsigned int num_streams = *pnum_streams;
3720         struct adouble *ad = NULL;
3721         bool ok;
3722         size_t rlen;
3723         int i;
3724
3725         /*
3726          * Check if there's a AFPRESOURCE_STREAM from the VFS streams backend
3727          * and if yes, remove it from the list
3728          */
3729         for (i = 0; i < num_streams; i++) {
3730                 if (strequal_m(stream[i].name, AFPRESOURCE_STREAM)) {
3731                         break;
3732                 }
3733         }
3734
3735         if (i < num_streams) {
3736                 DBG_WARNING("Unexpected AFPRESOURCE_STREAM on [%s]\n",
3737                             smb_fname_str_dbg(smb_fname));
3738
3739                 ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
3740                                       AFPRESOURCE_STREAM);
3741                 if (!ok) {
3742                         return NT_STATUS_INTERNAL_ERROR;
3743                 }
3744         }
3745
3746         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
3747         if (ad == NULL) {
3748                 return NT_STATUS_OK;
3749         }
3750
3751         rlen = ad_getentrylen(ad, ADEID_RFORK);
3752         TALLOC_FREE(ad);
3753
3754         if (rlen == 0) {
3755                 return NT_STATUS_OK;
3756         }
3757
3758         ok = add_fruit_stream(mem_ctx, pnum_streams, pstreams,
3759                               AFPRESOURCE_STREAM_NAME, rlen,
3760                               smb_roundup(handle->conn, rlen));
3761         if (!ok) {
3762                 return NT_STATUS_NO_MEMORY;
3763         }
3764
3765         return NT_STATUS_OK;
3766 }
3767
3768 static NTSTATUS fruit_streaminfo_rsrc(vfs_handle_struct *handle,
3769                                       struct files_struct *fsp,
3770                                       const struct smb_filename *smb_fname,
3771                                       TALLOC_CTX *mem_ctx,
3772                                       unsigned int *pnum_streams,
3773                                       struct stream_struct **pstreams)
3774 {
3775         struct fruit_config_data *config = NULL;
3776         NTSTATUS status;
3777
3778         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
3779                                 return NT_STATUS_INTERNAL_ERROR);
3780
3781         switch (config->rsrc) {
3782         case FRUIT_RSRC_STREAM:
3783                 status = fruit_streaminfo_rsrc_stream(handle, fsp, smb_fname,
3784                                                       mem_ctx, pnum_streams,
3785                                                       pstreams);
3786                 break;
3787
3788         case FRUIT_RSRC_XATTR:
3789                 status = fruit_streaminfo_rsrc_xattr(handle, fsp, smb_fname,
3790                                                      mem_ctx, pnum_streams,
3791                                                      pstreams);
3792                 break;
3793
3794         case FRUIT_RSRC_ADFILE:
3795                 status = fruit_streaminfo_rsrc_adouble(handle, fsp, smb_fname,
3796                                                        mem_ctx, pnum_streams,
3797                                                        pstreams);
3798                 break;
3799
3800         default:
3801                 return NT_STATUS_INTERNAL_ERROR;
3802         }
3803
3804         return status;
3805 }
3806
3807 static void fruit_filter_empty_streams(unsigned int *pnum_streams,
3808                                        struct stream_struct **pstreams)
3809 {
3810         unsigned num_streams = *pnum_streams;
3811         struct stream_struct *streams = *pstreams;
3812         unsigned i = 0;
3813
3814         if (!global_fruit_config.nego_aapl) {
3815                 return;
3816         }
3817
3818         while (i < num_streams) {
3819                 struct smb_filename smb_fname = (struct smb_filename) {
3820                         .stream_name = streams[i].name,
3821                 };
3822
3823                 if (is_ntfs_default_stream_smb_fname(&smb_fname)
3824                     || streams[i].size > 0)
3825                 {
3826                         i++;
3827                         continue;
3828                 }
3829
3830                 streams[i] = streams[num_streams - 1];
3831                 num_streams--;
3832         }
3833
3834         *pnum_streams = num_streams;
3835 }
3836
3837 static NTSTATUS fruit_fstreaminfo(vfs_handle_struct *handle,
3838                                  struct files_struct *fsp,
3839                                  TALLOC_CTX *mem_ctx,
3840                                  unsigned int *pnum_streams,
3841                                  struct stream_struct **pstreams)
3842 {
3843         struct fruit_config_data *config = NULL;
3844         const struct smb_filename *smb_fname = NULL;
3845         NTSTATUS status;
3846
3847         smb_fname = fsp->fsp_name;
3848
3849         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
3850                                 return NT_STATUS_UNSUCCESSFUL);
3851
3852         DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
3853
3854         status = SMB_VFS_NEXT_FSTREAMINFO(handle, fsp, mem_ctx,
3855                                          pnum_streams, pstreams);
3856         if (!NT_STATUS_IS_OK(status)) {
3857                 return status;
3858         }
3859
3860         fruit_filter_empty_streams(pnum_streams, pstreams);
3861
3862         status = fruit_streaminfo_meta(handle, fsp, smb_fname,
3863                                        mem_ctx, pnum_streams, pstreams);
3864         if (!NT_STATUS_IS_OK(status)) {
3865                 return status;
3866         }
3867
3868         status = fruit_streaminfo_rsrc(handle, fsp, smb_fname,
3869                                        mem_ctx, pnum_streams, pstreams);
3870         if (!NT_STATUS_IS_OK(status)) {
3871                 return status;
3872         }
3873
3874         return NT_STATUS_OK;
3875 }
3876
3877 static int fruit_fntimes(vfs_handle_struct *handle,
3878                          files_struct *fsp,
3879                          struct smb_file_time *ft)
3880 {
3881         int rc = 0;
3882         struct adouble *ad = NULL;
3883         struct fruit_config_data *config = NULL;
3884
3885         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
3886                                 return -1);
3887
3888         if ((config->meta != FRUIT_META_NETATALK) ||
3889             is_omit_timespec(&ft->create_time))
3890         {
3891                 return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
3892         }
3893
3894         DBG_DEBUG("set btime for %s to %s\n", fsp_str_dbg(fsp),
3895                   time_to_asc(convert_timespec_to_time_t(ft->create_time)));
3896
3897         ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
3898         if (ad == NULL) {
3899                 goto exit;
3900         }
3901
3902         ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX,
3903                    convert_time_t_to_uint32_t(ft->create_time.tv_sec));
3904
3905         rc = ad_fset(handle, ad, fsp);
3906
3907 exit:
3908
3909         TALLOC_FREE(ad);
3910         if (rc != 0) {
3911                 DBG_WARNING("%s\n", fsp_str_dbg(fsp));
3912                 return -1;
3913         }
3914         return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
3915 }
3916
3917 static int fruit_fallocate(struct vfs_handle_struct *handle,
3918                            struct files_struct *fsp,
3919                            uint32_t mode,
3920                            off_t offset,
3921                            off_t len)
3922 {
3923         struct fio *fio = fruit_get_complete_fio(handle, fsp);
3924
3925         if (fio == NULL) {
3926                 return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
3927         }
3928
3929         /* Let the pwrite code path handle it. */
3930         errno = ENOSYS;
3931         return -1;
3932 }
3933
3934 static int fruit_ftruncate_rsrc_xattr(struct vfs_handle_struct *handle,
3935                                       struct files_struct *fsp,
3936                                       off_t offset)
3937 {
3938 #ifdef HAVE_ATTROPEN
3939         return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
3940 #endif
3941         return 0;
3942 }
3943
3944 static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle,
3945                                         struct files_struct *fsp,
3946                                         off_t offset)
3947 {
3948         struct fio *fio = fruit_get_complete_fio(handle, fsp);
3949         int rc;
3950         struct adouble *ad = NULL;
3951         off_t ad_off;
3952
3953         if (fio->ad_fsp == NULL) {
3954                 DBG_ERR("ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
3955                 errno = EBADF;
3956                 return -1;
3957         }
3958
3959         ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
3960         if (ad == NULL) {
3961                 DBG_ERR("ad_fget [%s] failed [%s]\n",
3962                         fsp_str_dbg(fio->ad_fsp), strerror(errno));
3963                 return -1;
3964         }
3965
3966         ad_off = ad_getentryoff(ad, ADEID_RFORK);
3967
3968         rc = SMB_VFS_NEXT_FTRUNCATE(handle, fio->ad_fsp, offset + ad_off);
3969         if (rc != 0) {
3970                 TALLOC_FREE(ad);
3971                 return -1;
3972         }
3973
3974         ad_setentrylen(ad, ADEID_RFORK, offset);
3975
3976         rc = ad_fset(handle, ad, fio->ad_fsp);
3977         if (rc != 0) {
3978                 DBG_ERR("ad_fset [%s] failed [%s]\n",
3979                         fsp_str_dbg(fio->ad_fsp), strerror(errno));
3980                 TALLOC_FREE(ad);
3981                 return -1;
3982         }
3983
3984         TALLOC_FREE(ad);
3985         return 0;
3986 }
3987
3988 static int fruit_ftruncate_rsrc_stream(struct vfs_handle_struct *handle,
3989                                        struct files_struct *fsp,
3990                                        off_t offset)
3991 {
3992         return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
3993 }
3994
3995 static int fruit_ftruncate_rsrc(struct vfs_handle_struct *handle,
3996                                 struct files_struct *fsp,
3997                                 off_t offset)
3998 {
3999         struct fio *fio = fruit_get_complete_fio(handle, fsp);
4000         int ret;
4001
4002         if (fio == NULL) {
4003                 DBG_ERR("Failed to fetch fsp extension");
4004                 return -1;
4005         }
4006
4007         switch (fio->config->rsrc) {
4008         case FRUIT_RSRC_XATTR:
4009                 ret = fruit_ftruncate_rsrc_xattr(handle, fsp, offset);
4010                 break;
4011
4012         case FRUIT_RSRC_ADFILE:
4013                 ret = fruit_ftruncate_rsrc_adouble(handle, fsp, offset);
4014                 break;
4015
4016         case FRUIT_RSRC_STREAM:
4017                 ret = fruit_ftruncate_rsrc_stream(handle, fsp, offset);
4018                 break;
4019
4020         default:
4021                 DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
4022                 return -1;
4023         }
4024
4025
4026         return ret;
4027 }
4028
4029 static int fruit_ftruncate_meta(struct vfs_handle_struct *handle,
4030                                 struct files_struct *fsp,
4031                                 off_t offset)
4032 {
4033         if (offset > 60) {
4034                 DBG_WARNING("ftruncate %s to %jd",
4035                             fsp_str_dbg(fsp), (intmax_t)offset);
4036                 /* OS X returns NT_STATUS_ALLOTTED_SPACE_EXCEEDED  */
4037                 errno = EOVERFLOW;
4038                 return -1;
4039         }
4040
4041         /* OS X returns success but does nothing  */
4042         DBG_INFO("ignoring ftruncate %s to %jd\n",
4043                  fsp_str_dbg(fsp), (intmax_t)offset);
4044         return 0;
4045 }
4046
4047 static int fruit_ftruncate(struct vfs_handle_struct *handle,
4048                            struct files_struct *fsp,
4049                            off_t offset)
4050 {
4051         struct fio *fio = fruit_get_complete_fio(handle, fsp);
4052         int ret;
4053
4054         DBG_DEBUG("Path [%s] offset [%"PRIdMAX"]\n", fsp_str_dbg(fsp),
4055                   (intmax_t)offset);
4056
4057         if (fio == NULL) {
4058                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
4059         }
4060
4061         if (fio->type == ADOUBLE_META) {
4062                 ret = fruit_ftruncate_meta(handle, fsp, offset);
4063         } else {
4064                 ret = fruit_ftruncate_rsrc(handle, fsp, offset);
4065         }
4066
4067         DBG_DEBUG("Path [%s] result [%d]\n", fsp_str_dbg(fsp), ret);
4068         return ret;
4069 }
4070
4071 static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
4072                                   struct smb_request *req,
4073                                   struct smb_filename *smb_fname,
4074                                   uint32_t access_mask,
4075                                   uint32_t share_access,
4076                                   uint32_t create_disposition,
4077                                   uint32_t create_options,
4078                                   uint32_t file_attributes,
4079                                   uint32_t oplock_request,
4080                                   const struct smb2_lease *lease,
4081                                   uint64_t allocation_size,
4082                                   uint32_t private_flags,
4083                                   struct security_descriptor *sd,
4084                                   struct ea_list *ea_list,
4085                                   files_struct **result,
4086                                   int *pinfo,
4087                                   const struct smb2_create_blobs *in_context_blobs,
4088                                   struct smb2_create_blobs *out_context_blobs)
4089 {
4090         NTSTATUS status;
4091         struct fruit_config_data *config = NULL;
4092         files_struct *fsp = NULL;
4093         bool internal_open = (oplock_request & INTERNAL_OPEN_ONLY);
4094         int ret;
4095
4096         status = check_aapl(handle, req, in_context_blobs, out_context_blobs);
4097         if (!NT_STATUS_IS_OK(status)) {
4098                 goto fail;
4099         }
4100
4101         SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
4102                                 return NT_STATUS_UNSUCCESSFUL);
4103
4104         if (is_apple_stream(smb_fname->stream_name) && !internal_open) {
4105                 uint32_t conv_flags  = 0;
4106
4107                 if (config->wipe_intentionally_left_blank_rfork) {
4108                         conv_flags |= AD_CONV_WIPE_BLANK;
4109                 }
4110                 if (config->delete_empty_adfiles) {
4111                         conv_flags |= AD_CONV_DELETE;
4112                 }
4113
4114                 ret = ad_convert(handle,
4115                                  smb_fname,
4116                                  macos_string_replace_map,
4117                                  conv_flags);
4118                 if (ret != 0) {
4119                         DBG_ERR("ad_convert() failed\n");
4120                         return NT_STATUS_UNSUCCESSFUL;
4121                 }
4122         }
4123
4124         status = SMB_VFS_NEXT_CREATE_FILE(
4125                 handle, req, smb_fname,
4126                 access_mask, share_access,
4127                 create_disposition, create_options,
4128                 file_attributes, oplock_request,
4129                 lease,
4130                 allocation_size, private_flags,
4131                 sd, ea_list, result,
4132                 pinfo, in_context_blobs, out_context_blobs);
4133         if (!NT_STATUS_IS_OK(status)) {
4134                 return status;
4135         }
4136
4137         fsp = *result;
4138
4139         if (global_fruit_config.nego_aapl) {
4140                 if (config->posix_rename && fsp->fsp_flags.is_directory) {
4141                         /*
4142                          * Enable POSIX directory rename behaviour
4143                          */
4144                         fsp->posix_flags |= FSP_POSIX_FLAGS_RENAME;
4145                 }
4146         }
4147
4148         /*
4149          * If this is a plain open for existing files, opening an 0
4150          * byte size resource fork MUST fail with
4151          * NT_STATUS_OBJECT_NAME_NOT_FOUND.
4152          *
4153          * Cf the vfs_fruit torture tests in test_rfork_create().
4154          */
4155         if (global_fruit_config.nego_aapl &&
4156             create_disposition == FILE_OPEN &&
4157             smb_fname->st.st_ex_size == 0 &&
4158             is_named_stream(smb_fname))
4159         {
4160                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
4161                 goto fail;
4162         }
4163
4164         if (is_named_stream(smb_fname) || fsp->fsp_flags.is_directory) {
4165                 return status;
4166         }
4167
4168         if ((config->locking == FRUIT_LOCKING_NETATALK) &&
4169             (fsp->op != NULL) &&
4170             !fsp->fsp_flags.is_pathref)
4171         {
4172                 status = fruit_check_access(
4173                         handle, *result,
4174                         access_mask,
4175                         share_access);
4176                 if (!NT_STATUS_IS_OK(status)) {
4177                         goto fail;
4178                 }
4179         }
4180
4181         return status;
4182
4183 fail:
4184         DEBUG(10, ("fruit_create_file: %s\n", nt_errstr(status)));
4185
4186         if (fsp) {
4187                 close_file(req, fsp, ERROR_CLOSE);
4188                 *result = fsp = NULL;
4189         }
4190
4191         return status;
4192 }
4193
4194 static NTSTATUS fruit_readdir_attr(struct vfs_handle_struct *handle,
4195                                    const struct smb_filename *fname,
4196                                    TALLOC_CTX *mem_ctx,
4197                                    struct readdir_attr_data **pattr_data)
4198 {
4199         struct fruit_config_data *config = NULL;
4200         struct readdir_attr_data *attr_data;
4201         uint32_t conv_flags  = 0;
4202         NTSTATUS status;
4203         int ret;
4204
4205         SMB_VFS_HANDLE_GET_DATA(handle, config,
4206                                 struct fruit_config_data,
4207                                 return NT_STATUS_UNSUCCESSFUL);
4208
4209         if (!global_fruit_config.nego_aapl) {
4210                 return SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
4211         }
4212
4213         DEBUG(10, ("fruit_readdir_attr %s\n", fname->base_name));
4214
4215         if (config->wipe_intentionally_left_blank_rfork) {
4216                 conv_flags |= AD_CONV_WIPE_BLANK;
4217         }
4218         if (config->delete_empty_adfiles) {
4219                 conv_flags |= AD_CONV_DELETE;
4220         }
4221
4222         ret = ad_convert(handle,
4223                         fname,
4224                         macos_string_replace_map,
4225                         conv_flags);
4226         if (ret != 0) {
4227                 DBG_ERR("ad_convert() failed\n");
4228                 return NT_STATUS_UNSUCCESSFUL;
4229         }
4230
4231         *pattr_data = talloc_zero(mem_ctx, struct readdir_attr_data);
4232         if (*pattr_data == NULL) {
4233                 return NT_STATUS_UNSUCCESSFUL;
4234         }
4235         attr_data = *pattr_data;
4236         attr_data->type = RDATTR_AAPL;
4237
4238         /*
4239          * Mac metadata: compressed FinderInfo, resource fork length
4240          * and creation date
4241          */
4242         status = readdir_attr_macmeta(handle, fname, attr_data);
4243         if (!NT_STATUS_IS_OK(status)) {
4244                 /*
4245                  * Error handling is tricky: if we return failure from
4246                  * this function, the corresponding directory entry
4247                  * will to be passed to the client, so we really just
4248                  * want to error out on fatal errors.
4249                  */
4250                 if  (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
4251                         goto fail;
4252                 }
4253         }
4254
4255         /*
4256          * UNIX mode
4257          */
4258         if (config->unix_info_enabled) {
4259                 attr_data->attr_data.aapl.unix_mode = fname->st.st_ex_mode;
4260         }
4261
4262         /*
4263          * max_access
4264          */
4265         if (!config->readdir_attr_max_access) {
4266                 attr_data->attr_data.aapl.max_access = FILE_GENERIC_ALL;
4267         } else {
4268                 status = smbd_calculate_access_mask(
4269                         handle->conn,
4270                         handle->conn->cwd_fsp,
4271                         fname,
4272                         false,
4273                         SEC_FLAG_MAXIMUM_ALLOWED,
4274                         &attr_data->attr_data.aapl.max_access);
4275                 if (!NT_STATUS_IS_OK(status)) {
4276                         goto fail;
4277                 }
4278         }
4279
4280         return NT_STATUS_OK;
4281
4282 fail:
4283         DEBUG(1, ("fruit_readdir_attr %s, error: %s\n",
4284                   fname->base_name, nt_errstr(status)));
4285         TALLOC_FREE(*pattr_data);
4286         return status;
4287 }
4288
4289 static NTSTATUS fruit_fget_nt_acl(vfs_handle_struct *handle,
4290                                   files_struct *fsp,
4291                                   uint32_t security_info,
4292                                   TALLOC_CTX *mem_ctx,
4293                                   struct security_descriptor **ppdesc)
4294 {
4295         NTSTATUS status;
4296         struct security_ace ace;
4297         struct dom_sid sid;
4298         struct fruit_config_data *config;
4299
4300         SMB_VFS_HANDLE_GET_DATA(handle, config,
4301                                 struct fruit_config_data,
4302                                 return NT_STATUS_UNSUCCESSFUL);
4303
4304         status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
4305                                           mem_ctx, ppdesc);
4306         if (!NT_STATUS_IS_OK(status)) {
4307                 return status;
4308         }
4309
4310         /*
4311          * Add MS NFS style ACEs with uid, gid and mode
4312          */
4313         if (!global_fruit_config.nego_aapl) {
4314                 return NT_STATUS_OK;
4315         }
4316         if (!config->unix_info_enabled) {
4317                 return NT_STATUS_OK;
4318         }
4319
4320         /* First remove any existing ACE's with NFS style mode/uid/gid SIDs. */
4321         status = remove_virtual_nfs_aces(*ppdesc);
4322         if (!NT_STATUS_IS_OK(status)) {
4323                 DBG_WARNING("failed to remove MS NFS style ACEs\n");
4324                 return status;
4325         }
4326
4327         /* MS NFS style mode */
4328         sid_compose(&sid, &global_sid_Unix_NFS_Mode, fsp->fsp_name->st.st_ex_mode);
4329         init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
4330         status = security_descriptor_dacl_add(*ppdesc, &ace);
4331         if (!NT_STATUS_IS_OK(status)) {
4332                 DEBUG(1,("failed to add MS NFS style ACE\n"));
4333                 return status;
4334         }
4335
4336         /* MS NFS style uid */
4337         sid_compose(&sid, &global_sid_Unix_NFS_Users, fsp->fsp_name->st.st_ex_uid);
4338         init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
4339         status = security_descriptor_dacl_add(*ppdesc, &ace);
4340         if (!NT_STATUS_IS_OK(status)) {
4341                 DEBUG(1,("failed to add MS NFS style ACE\n"));
4342                 return status;
4343         }
4344
4345         /* MS NFS style gid */
4346         sid_compose(&sid, &global_sid_Unix_NFS_Groups, fsp->fsp_name->st.st_ex_gid);
4347         init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
4348         status = security_descriptor_dacl_add(*ppdesc, &ace);
4349         if (!NT_STATUS_IS_OK(status)) {
4350                 DEBUG(1,("failed to add MS NFS style ACE\n"));
4351                 return status;
4352         }
4353
4354         return NT_STATUS_OK;
4355 }
4356
4357 static NTSTATUS fruit_fset_nt_acl(vfs_handle_struct *handle,
4358                                   files_struct *fsp,
4359                                   uint32_t security_info_sent,
4360                                   const struct security_descriptor *orig_psd)
4361 {
4362         NTSTATUS status;
4363         bool do_chmod;
4364         mode_t ms_nfs_mode = 0;
4365         int result;
4366         struct security_descriptor *psd = NULL;
4367         uint32_t orig_num_aces = 0;
4368
4369         if (orig_psd->dacl != NULL) {
4370                 orig_num_aces = orig_psd->dacl->num_aces;
4371         }
4372
4373         psd = security_descriptor_copy(talloc_tos(), orig_psd);
4374         if (psd == NULL) {
4375                 return NT_STATUS_NO_MEMORY;
4376         }
4377
4378         DBG_DEBUG("fruit_fset_nt_acl: %s\n", fsp_str_dbg(fsp));
4379
4380         status = check_ms_nfs(handle, fsp, psd, &ms_nfs_mode, &do_chmod);
4381         if (!NT_STATUS_IS_OK(status)) {
4382                 DEBUG(1, ("fruit_fset_nt_acl: check_ms_nfs failed%s\n", fsp_str_dbg(fsp)));
4383                 TALLOC_FREE(psd);
4384                 return status;
4385         }
4386
4387         /*
4388          * If only ms_nfs ACE entries were sent, ensure we set the DACL
4389          * sent/present flags correctly now we've removed them.
4390          */
4391
4392         if (orig_num_aces != 0) {
4393                 /*
4394                  * Are there any ACE's left ?
4395                  */
4396                 if (psd->dacl->num_aces == 0) {
4397                         /* No - clear the DACL sent/present flags. */
4398                         security_info_sent &= ~SECINFO_DACL;
4399                         psd->type &= ~SEC_DESC_DACL_PRESENT;
4400                 }
4401         }
4402
4403         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
4404         if (!NT_STATUS_IS_OK(status)) {
4405                 DEBUG(1, ("fruit_fset_nt_acl: SMB_VFS_NEXT_FSET_NT_ACL failed%s\n", fsp_str_dbg(fsp)));
4406                 TALLOC_FREE(psd);
4407                 return status;
4408         }
4409
4410         if (do_chmod) {
4411                 result = SMB_VFS_FCHMOD(fsp, ms_nfs_mode);
4412                 if (result != 0) {
4413                         DBG_WARNING("%s, result: %d, %04o error %s\n",
4414                                 fsp_str_dbg(fsp),
4415                                 result,
4416                                 (unsigned)ms_nfs_mode,
4417                                 strerror(errno));
4418                         status = map_nt_error_from_unix(errno);
4419                         TALLOC_FREE(psd);
4420                         return status;
4421                 }
4422         }
4423
4424         TALLOC_FREE(psd);
4425         return NT_STATUS_OK;
4426 }
4427
4428 static struct vfs_offload_ctx *fruit_offload_ctx;
4429
4430 struct fruit_offload_read_state {
4431         struct vfs_handle_struct *handle;
4432         struct tevent_context *ev;
4433         files_struct *fsp;
4434         uint32_t fsctl;
4435         DATA_BLOB token;
4436 };
4437
4438 static void fruit_offload_read_done(struct tevent_req *subreq);
4439
4440 static struct tevent_req *fruit_offload_read_send(
4441         TALLOC_CTX *mem_ctx,
4442         struct tevent_context *ev,
4443         struct vfs_handle_struct *handle,
4444         files_struct *fsp,
4445         uint32_t fsctl,
4446         uint32_t ttl,
4447         off_t offset,
4448         size_t to_copy)
4449 {
4450         struct tevent_req *req = NULL;
4451         struct tevent_req *subreq = NULL;
4452         struct fruit_offload_read_state *state = NULL;
4453
4454         req = tevent_req_create(mem_ctx, &state,
4455                                 struct fruit_offload_read_state);
4456         if (req == NULL) {
4457                 return NULL;
4458         }
4459         *state = (struct fruit_offload_read_state) {
4460                 .handle = handle,
4461                 .ev = ev,
4462                 .fsp = fsp,
4463                 .fsctl = fsctl,
4464         };
4465
4466         subreq = SMB_VFS_NEXT_OFFLOAD_READ_SEND(mem_ctx, ev, handle, fsp,
4467                                                 fsctl, ttl, offset, to_copy);
4468         if (tevent_req_nomem(subreq, req)) {
4469                 return tevent_req_post(req, ev);
4470         }
4471         tevent_req_set_callback(subreq, fruit_offload_read_done, req);
4472         return req;
4473 }
4474
4475 static void fruit_offload_read_done(struct tevent_req *subreq)
4476 {
4477         struct tevent_req *req = tevent_req_callback_data(
4478                 subreq, struct tevent_req);
4479         struct fruit_offload_read_state *state = tevent_req_data(
4480                 req, struct fruit_offload_read_state);
4481         NTSTATUS status;
4482
4483         status = SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq,
4484                                                 state->handle,
4485                                                 state,
4486                                                 &state->token);
4487         TALLOC_FREE(subreq);
4488         if (tevent_req_nterror(req, status)) {
4489                 return;
4490         }
4491
4492         if (state->fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
4493                 tevent_req_done(req);
4494                 return;
4495         }
4496
4497         status = vfs_offload_token_ctx_init(state->fsp->conn->sconn->client,
4498                                             &fruit_offload_ctx);
4499         if (tevent_req_nterror(req, status)) {
4500                 return;
4501         }
4502
4503         status = vfs_offload_token_db_store_fsp(fruit_offload_ctx,
4504                                                 state->fsp,
4505                                                 &state->token);
4506         if (tevent_req_nterror(req, status)) {
4507                 return;
4508         }
4509
4510         tevent_req_done(req);
4511         return;
4512 }
4513
4514 static NTSTATUS fruit_offload_read_recv(struct tevent_req *req,
4515                                         struct vfs_handle_struct *handle,
4516                                         TALLOC_CTX *mem_ctx,
4517                                         DATA_BLOB *token)
4518 {
4519         struct fruit_offload_read_state *state = tevent_req_data(
4520                 req, struct fruit_offload_read_state);
4521         NTSTATUS status;
4522
4523         if (tevent_req_is_nterror(req, &status)) {
4524                 tevent_req_received(req);
4525                 return status;
4526         }
4527
4528         token->length = state->token.length;
4529         token->data = talloc_move(mem_ctx, &state->token.data);
4530
4531         tevent_req_received(req);
4532         return NT_STATUS_OK;
4533 }
4534
4535 struct fruit_offload_write_state {
4536         struct vfs_handle_struct *handle;
4537         off_t copied;
4538         struct files_struct *src_fsp;
4539         struct files_struct *dst_fsp;
4540         bool is_copyfile;
4541 };
4542
4543 static void fruit_offload_write_done(struct tevent_req *subreq);
4544 static struct tevent_req *fruit_offload_write_send(struct vfs_handle_struct *handle,
4545                                                 TALLOC_CTX *mem_ctx,
4546                                                 struct tevent_context *ev,
4547                                                 uint32_t fsctl,
4548                                                 DATA_BLOB *token,
4549                                                 off_t transfer_offset,
4550                                                 struct files_struct *dest_fsp,
4551                                                 off_t dest_off,
4552                                                 off_t num)
4553 {
4554         struct tevent_req *req, *subreq;
4555         struct fruit_offload_write_state *state;
4556         NTSTATUS status;
4557         struct fruit_config_data *config;
4558         off_t src_off = transfer_offset;
4559         files_struct *src_fsp = NULL;
4560         off_t to_copy = num;
4561         bool copyfile_enabled = false;
4562
4563         DEBUG(10,("soff: %ju, doff: %ju, len: %ju\n",
4564                   (uintmax_t)src_off, (uintmax_t)dest_off, (uintmax_t)num));
4565
4566         SMB_VFS_HANDLE_GET_DATA(handle, config,
4567                                 struct fruit_config_data,
4568                                 return NULL);
4569
4570         req = tevent_req_create(mem_ctx, &state,
4571                                 struct fruit_offload_write_state);
4572         if (req == NULL) {
4573                 return NULL;
4574         }
4575         state->handle = handle;
4576         state->dst_fsp = dest_fsp;
4577
4578         switch (fsctl) {
4579         case FSCTL_SRV_COPYCHUNK:
4580         case FSCTL_SRV_COPYCHUNK_WRITE:
4581                 copyfile_enabled = config->copyfile_enabled;
4582                 break;
4583         default:
4584                 break;
4585         }
4586
4587         /*
4588          * Check if this a OS X copyfile style copychunk request with
4589          * a requested chunk count of 0 that was translated to a
4590          * offload_write_send VFS call overloading the parameters src_off
4591          * = dest_off = num = 0.
4592          */
4593         if (copyfile_enabled && num == 0 && src_off == 0 && dest_off == 0) {
4594                 status = vfs_offload_token_db_fetch_fsp(
4595                         fruit_offload_ctx, token, &src_fsp);
4596                 if (tevent_req_nterror(req, status)) {
4597                         return tevent_req_post(req, ev);
4598                 }
4599                 state->src_fsp = src_fsp;
4600
4601                 status = vfs_stat_fsp(src_fsp);
4602                 if (tevent_req_nterror(req, status)) {
4603                         return tevent_req_post(req, ev);
4604                 }
4605
4606                 to_copy = src_fsp->fsp_name->st.st_ex_size;
4607                 state->is_copyfile = true;
4608         }
4609
4610         subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle,
4611                                               mem_ctx,
4612                                               ev,
4613                                               fsctl,
4614                                               token,
4615                                               transfer_offset,
4616                                               dest_fsp,
4617                                               dest_off,
4618                                               to_copy);
4619         if (tevent_req_nomem(subreq, req)) {
4620                 return tevent_req_post(req, ev);
4621         }
4622
4623         tevent_req_set_callback(subreq, fruit_offload_write_done, req);
4624         return req;
4625 }
4626
4627 static void fruit_offload_write_done(struct tevent_req *subreq)
4628 {
4629         struct tevent_req *req = tevent_req_callback_data(
4630                 subreq, struct tevent_req);
4631         struct fruit_offload_write_state *state = tevent_req_data(
4632                 req, struct fruit_offload_write_state);
4633         NTSTATUS status;
4634         unsigned int num_streams = 0;
4635         struct stream_struct *streams = NULL;
4636         unsigned int i;
4637         struct smb_filename *src_fname_tmp = NULL;
4638         struct smb_filename *dst_fname_tmp = NULL;
4639
4640         status = SMB_VFS_NEXT_OFFLOAD_WRITE_RECV(state->handle,
4641                                               subreq,
4642                                               &state->copied);
4643         TALLOC_FREE(subreq);
4644         if (tevent_req_nterror(req, status)) {
4645                 return;
4646         }
4647
4648         if (!state->is_copyfile) {
4649                 tevent_req_done(req);
4650                 return;
4651         }
4652
4653         /*
4654          * Now copy all remaining streams. We know the share supports
4655          * streams, because we're in vfs_fruit. We don't do this async
4656          * because streams are few and small.
4657          */
4658         status = vfs_fstreaminfo(state->src_fsp,
4659                                 req, &num_streams, &streams);
4660         if (tevent_req_nterror(req, status)) {
4661                 return;
4662         }
4663
4664         if (num_streams == 1) {
4665                 /* There is always one stream, ::$DATA. */
4666                 tevent_req_done(req);
4667                 return;
4668         }
4669
4670         for (i = 0; i < num_streams; i++) {
4671                 DEBUG(10, ("%s: stream: '%s'/%zu\n",
4672                           __func__, streams[i].name, (size_t)streams[i].size));
4673
4674                 src_fname_tmp = synthetic_smb_fname(
4675                         req,
4676                         state->src_fsp->fsp_name->base_name,
4677                         streams[i].name,
4678                         NULL,
4679                         state->src_fsp->fsp_name->twrp,
4680                         state->src_fsp->fsp_name->flags);
4681                 if (tevent_req_nomem(src_fname_tmp, req)) {
4682                         return;
4683                 }
4684
4685                 if (is_ntfs_default_stream_smb_fname(src_fname_tmp)) {
4686                         TALLOC_FREE(src_fname_tmp);
4687                         continue;
4688                 }
4689
4690                 dst_fname_tmp = synthetic_smb_fname(
4691                         req,
4692                         state->dst_fsp->fsp_name->base_name,
4693                         streams[i].name,
4694                         NULL,
4695                         state->dst_fsp->fsp_name->twrp,
4696                         state->dst_fsp->fsp_name->flags);
4697                 if (tevent_req_nomem(dst_fname_tmp, req)) {
4698                         TALLOC_FREE(src_fname_tmp);
4699                         return;
4700                 }
4701
4702                 status = copy_file(req,
4703                                    state->handle->conn,
4704                                    src_fname_tmp,
4705                                    dst_fname_tmp,
4706                                    OPENX_FILE_CREATE_IF_NOT_EXIST,
4707                                    0, false);
4708                 if (!NT_STATUS_IS_OK(status)) {
4709                         DEBUG(1, ("%s: copy %s to %s failed: %s\n", __func__,
4710                                   smb_fname_str_dbg(src_fname_tmp),
4711                                   smb_fname_str_dbg(dst_fname_tmp),
4712                                   nt_errstr(status)));
4713                         TALLOC_FREE(src_fname_tmp);
4714                         TALLOC_FREE(dst_fname_tmp);
4715                         tevent_req_nterror(req, status);
4716                         return;
4717                 }
4718
4719                 TALLOC_FREE(src_fname_tmp);
4720                 TALLOC_FREE(dst_fname_tmp);
4721         }
4722
4723         TALLOC_FREE(streams);
4724         TALLOC_FREE(src_fname_tmp);
4725         TALLOC_FREE(dst_fname_tmp);
4726         tevent_req_done(req);
4727 }
4728
4729 static NTSTATUS fruit_offload_write_recv(struct vfs_handle_struct *handle,
4730                                       struct tevent_req *req,
4731                                       off_t *copied)
4732 {
4733         struct fruit_offload_write_state *state = tevent_req_data(
4734                 req, struct fruit_offload_write_state);
4735         NTSTATUS status;
4736
4737         if (tevent_req_is_nterror(req, &status)) {
4738                 DEBUG(1, ("server side copy chunk failed: %s\n",
4739                           nt_errstr(status)));
4740                 *copied = 0;
4741                 tevent_req_received(req);
4742                 return status;
4743         }
4744
4745         *copied = state->copied;
4746         tevent_req_received(req);
4747
4748         return NT_STATUS_OK;
4749 }
4750
4751 static char *fruit_get_bandsize_line(char **lines, int numlines)
4752 {
4753         static regex_t re;
4754         static bool re_initialized = false;
4755         int i;
4756         int ret;
4757
4758         if (!re_initialized) {
4759                 ret = regcomp(&re, "^[[:blank:]]*<key>band-size</key>$", 0);
4760                 if (ret != 0) {
4761                         return NULL;
4762                 }
4763                 re_initialized = true;
4764         }
4765
4766         for (i = 0; i < numlines; i++) {
4767                 regmatch_t matches[1];
4768
4769                 ret = regexec(&re, lines[i], 1, matches, 0);
4770                 if (ret == 0) {
4771                         /*
4772                          * Check if the match was on the last line, sa we want
4773                          * the subsequent line.
4774                          */
4775                         if (i + 1 == numlines) {
4776                                 return NULL;
4777                         }
4778                         return lines[i + 1];
4779                 }
4780                 if (ret != REG_NOMATCH) {
4781                         return NULL;
4782                 }
4783         }
4784
4785         return NULL;
4786 }
4787
4788 static bool fruit_get_bandsize_from_line(char *line, size_t *_band_size)
4789 {
4790         static regex_t re;
4791         static bool re_initialized = false;
4792         regmatch_t matches[2];
4793         uint64_t band_size;
4794         int ret;
4795         bool ok;
4796
4797         if (!re_initialized) {
4798                 ret = regcomp(&re,
4799                               "^[[:blank:]]*"
4800                               "<integer>\\([[:digit:]]*\\)</integer>$",
4801                               0);
4802                 if (ret != 0) {
4803                         return false;
4804                 }
4805                 re_initialized = true;
4806         }
4807
4808         ret = regexec(&re, line, 2, matches, 0);
4809         if (ret != 0) {
4810                 DBG_ERR("regex failed [%s]\n", line);
4811                 return false;
4812         }
4813
4814         line[matches[1].rm_eo] = '\0';
4815
4816         ok = conv_str_u64(&line[matches[1].rm_so], &band_size);
4817         if (!ok) {
4818                 return false;
4819         }
4820         *_band_size = (size_t)band_size;
4821         return true;
4822 }
4823
4824 /*
4825  * This reads and parses an Info.plist from a TM sparsebundle looking for the
4826  * "band-size" key and value.
4827  */
4828 static bool fruit_get_bandsize(vfs_handle_struct *handle,
4829                                const char *dir,
4830                                size_t *band_size)
4831 {
4832 #define INFO_PLIST_MAX_SIZE 64*1024
4833         char *plist = NULL;
4834         struct smb_filename *smb_fname = NULL;
4835         files_struct *fsp = NULL;
4836         uint8_t *file_data = NULL;
4837         char **lines = NULL;
4838         char *band_size_line = NULL;
4839         size_t plist_file_size;
4840         ssize_t nread;
4841         int numlines;
4842         int ret;
4843         bool ok = false;
4844         NTSTATUS status;
4845
4846         plist = talloc_asprintf(talloc_tos(),
4847                                 "%s/%s/Info.plist",
4848                                 handle->conn->connectpath,
4849                                 dir);
4850         if (plist == NULL) {
4851                 ok = false;
4852                 goto out;
4853         }
4854
4855         smb_fname = synthetic_smb_fname(talloc_tos(),
4856                                         plist,
4857                                         NULL,
4858                                         NULL,
4859                                         0,
4860                                         0);
4861         if (smb_fname == NULL) {
4862                 ok = false;
4863                 goto out;
4864         }
4865
4866         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
4867         if (ret != 0) {
4868                 DBG_INFO("Ignoring Sparsebundle without Info.plist [%s]\n", dir);
4869                 ok = true;
4870                 goto out;
4871         }
4872
4873         plist_file_size = smb_fname->st.st_ex_size;
4874
4875         if (plist_file_size > INFO_PLIST_MAX_SIZE) {
4876                 DBG_INFO("%s is too large, ignoring\n", plist);
4877                 ok = true;
4878                 goto out;
4879         }
4880
4881         status = SMB_VFS_NEXT_CREATE_FILE(
4882                 handle,                         /* conn */
4883                 NULL,                           /* req */
4884                 smb_fname,                      /* fname */
4885                 FILE_GENERIC_READ,              /* access_mask */
4886                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
4887                 FILE_OPEN,                      /* create_disposition */
4888                 0,                              /* create_options */
4889                 0,                              /* file_attributes */
4890                 INTERNAL_OPEN_ONLY,             /* oplock_request */
4891                 NULL,                           /* lease */
4892                 0,                              /* allocation_size */
4893                 0,                              /* private_flags */
4894                 NULL,                           /* sd */
4895                 NULL,                           /* ea_list */
4896                 &fsp,                           /* result */
4897                 NULL,                           /* psbuf */
4898                 NULL, NULL);                    /* create context */
4899         if (!NT_STATUS_IS_OK(status)) {
4900                 DBG_INFO("Opening [%s] failed [%s]\n",
4901                          smb_fname_str_dbg(smb_fname), nt_errstr(status));
4902                 ok = false;
4903                 goto out;
4904         }
4905
4906         file_data = talloc_zero_array(talloc_tos(),
4907                                       uint8_t,
4908                                       plist_file_size + 1);
4909         if (file_data == NULL) {
4910                 ok = false;
4911                 goto out;
4912         }
4913
4914         nread = SMB_VFS_NEXT_PREAD(handle, fsp, file_data, plist_file_size, 0);
4915         if (nread != plist_file_size) {
4916                 DBG_ERR("Short read on [%s]: %zu/%zd\n",
4917                         fsp_str_dbg(fsp), nread, plist_file_size);
4918                 ok = false;
4919                 goto out;
4920
4921         }
4922
4923         status = close_file(NULL, fsp, NORMAL_CLOSE);
4924         fsp = NULL;
4925         if (!NT_STATUS_IS_OK(status)) {
4926                 DBG_ERR("close_file failed: %s\n", nt_errstr(status));
4927                 ok = false;
4928                 goto out;
4929         }
4930
4931         lines = file_lines_parse((char *)file_data,
4932                                  plist_file_size,
4933                                  &numlines,
4934                                  talloc_tos());
4935         if (lines == NULL) {
4936                 ok = false;
4937                 goto out;
4938         }
4939
4940         band_size_line = fruit_get_bandsize_line(lines, numlines);
4941         if (band_size_line == NULL) {
4942                 DBG_ERR("Didn't find band-size key in [%s]\n",
4943                         smb_fname_str_dbg(smb_fname));
4944                 ok = false;
4945                 goto out;
4946         }
4947
4948         ok = fruit_get_bandsize_from_line(band_size_line, band_size);
4949         if (!ok) {
4950                 DBG_ERR("fruit_get_bandsize_from_line failed\n");
4951                 goto out;
4952         }
4953
4954         DBG_DEBUG("Parsed band-size [%zu] for [%s]\n", *band_size, plist);
4955
4956 out:
4957         if (fsp != NULL) {
4958                 status = close_file(NULL, fsp, NORMAL_CLOSE);
4959                 if (!NT_STATUS_IS_OK(status)) {
4960                         DBG_ERR("close_file failed: %s\n", nt_errstr(status));
4961                 }
4962                 fsp = NULL;
4963         }
4964         TALLOC_FREE(plist);
4965         TALLOC_FREE(smb_fname);
4966         TALLOC_FREE(file_data);
4967         TALLOC_FREE(lines);
4968         return ok;
4969 }
4970
4971 struct fruit_disk_free_state {
4972         off_t total_size;
4973 };
4974
4975 static bool fruit_get_num_bands(vfs_handle_struct *handle,
4976                                 const char *bundle,
4977                                 size_t *_nbands)
4978 {
4979         char *path = NULL;
4980         struct smb_filename *bands_dir = NULL;
4981         struct smb_Dir *dir_hnd = NULL;
4982         const char *dname = NULL;
4983         char *talloced = NULL;
4984         long offset = 0;
4985         size_t nbands;
4986
4987         path = talloc_asprintf(talloc_tos(),
4988                                "%s/%s/bands",
4989                                handle->conn->connectpath,
4990                                bundle);
4991         if (path == NULL) {
4992                 return false;
4993         }
4994
4995         bands_dir = synthetic_smb_fname(talloc_tos(),
4996                                         path,
4997                                         NULL,
4998                                         NULL,
4999                                         0,
5000                                         0);
5001         TALLOC_FREE(path);
5002         if (bands_dir == NULL) {
5003                 return false;
5004         }
5005
5006         dir_hnd = OpenDir(talloc_tos(), handle->conn, bands_dir, NULL, 0);
5007         if (dir_hnd == NULL) {
5008                 TALLOC_FREE(bands_dir);
5009                 return false;
5010         }
5011
5012         nbands = 0;
5013
5014         while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
5015                != NULL)
5016         {
5017                 if (ISDOT(dname) || ISDOTDOT(dname)) {
5018                         continue;
5019                 }
5020                 nbands++;
5021         }
5022         TALLOC_FREE(dir_hnd);
5023
5024         DBG_DEBUG("%zu bands in [%s]\n", nbands, smb_fname_str_dbg(bands_dir));
5025
5026         TALLOC_FREE(bands_dir);
5027
5028         *_nbands = nbands;
5029         return true;
5030 }
5031
5032 static bool fruit_tmsize_do_dirent(vfs_handle_struct *handle,
5033                                    struct fruit_disk_free_state *state,
5034                                    const char *name)
5035 {
5036         bool ok;
5037         char *p = NULL;
5038         size_t sparsebundle_strlen = strlen("sparsebundle");
5039         size_t bandsize = 0;
5040         size_t nbands;
5041         off_t tm_size;
5042
5043         p = strstr(name, "sparsebundle");
5044         if (p == NULL) {
5045                 return true;
5046         }
5047
5048         if (p[sparsebundle_strlen] != '\0') {
5049                 return true;
5050         }
5051
5052         DBG_DEBUG("Processing sparsebundle [%s]\n", name);
5053
5054         ok = fruit_get_bandsize(handle, name, &bandsize);
5055         if (!ok) {
5056                 /*
5057                  * Beware of race conditions: this may be an uninitialized
5058                  * Info.plist that a client is just creating. We don't want let
5059                  * this to trigger complete failure.
5060                  */
5061                 DBG_ERR("Processing sparsebundle [%s] failed\n", name);
5062                 return true;
5063         }
5064
5065         ok = fruit_get_num_bands(handle, name, &nbands);
5066         if (!ok) {
5067                 /*
5068                  * Beware of race conditions: this may be a backup sparsebundle
5069                  * in an early stage lacking a bands subdirectory. We don't want
5070                  * let this to trigger complete failure.
5071                  */
5072                 DBG_ERR("Processing sparsebundle [%s] failed\n", name);
5073                 return true;
5074         }
5075
5076         /*
5077          * Arithmetic on 32-bit systems may cause overflow, depending on
5078          * size_t precision. First we check its unlikely, then we
5079          * force the precision into target off_t, then we check that
5080          * the total did not overflow either.
5081          */
5082         if (bandsize > SIZE_MAX/nbands) {
5083                 DBG_ERR("tmsize potential overflow: bandsize [%zu] nbands [%zu]\n",
5084                         bandsize, nbands);
5085                 return false;
5086         }
5087         tm_size = (off_t)bandsize * (off_t)nbands;
5088
5089         if (state->total_size + tm_size < state->total_size) {
5090                 DBG_ERR("tm total size overflow: bandsize [%zu] nbands [%zu]\n",
5091                         bandsize, nbands);
5092                 return false;
5093         }
5094
5095         state->total_size += tm_size;
5096
5097         DBG_DEBUG("[%s] tm_size [%jd] total_size [%jd]\n",
5098                   name, (intmax_t)tm_size, (intmax_t)state->total_size);
5099
5100         return true;
5101 }
5102
5103 /**
5104  * Calculate used size of a TimeMachine volume
5105  *
5106  * This assumes that the volume is used only for TimeMachine.
5107  *
5108  * - readdir(basedir of share), then
5109  * - for every element that matches regex "^\(.*\)\.sparsebundle$" :
5110  * - parse "\1.sparsebundle/Info.plist" and read the band-size XML key
5111  * - count band files in "\1.sparsebundle/bands/"
5112  * - calculate used size of all bands: band_count * band_size
5113  **/
5114 static uint64_t fruit_disk_free(vfs_handle_struct *handle,
5115                                 const struct smb_filename *smb_fname,
5116                                 uint64_t *_bsize,
5117                                 uint64_t *_dfree,
5118                                 uint64_t *_dsize)
5119 {
5120         struct fruit_config_data *config = NULL;
5121         struct fruit_disk_free_state state = {0};
5122         struct smb_Dir *dir_hnd = NULL;
5123         const char *dname = NULL;
5124         char *talloced = NULL;
5125         long offset = 0;
5126         uint64_t dfree;
5127         uint64_t dsize;
5128         bool ok;
5129
5130         SMB_VFS_HANDLE_GET_DATA(handle, config,
5131                                 struct fruit_config_data,
5132                                 return UINT64_MAX);
5133
5134         if (!config->time_machine ||
5135             config->time_machine_max_size == 0)
5136         {
5137                 return SMB_VFS_NEXT_DISK_FREE(handle,
5138                                               smb_fname,
5139                                               _bsize,
5140                                               _dfree,
5141                                               _dsize);
5142         }
5143
5144         dir_hnd = OpenDir(talloc_tos(), handle->conn, smb_fname, NULL, 0);
5145         if (dir_hnd == NULL) {
5146                 return UINT64_MAX;
5147         }
5148
5149         while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
5150                != NULL)
5151         {
5152                 ok = fruit_tmsize_do_dirent(handle, &state, dname);
5153                 if (!ok) {
5154                         TALLOC_FREE(talloced);
5155                         TALLOC_FREE(dir_hnd);
5156                         return UINT64_MAX;
5157                 }
5158                 TALLOC_FREE(talloced);
5159         }
5160
5161         TALLOC_FREE(dir_hnd);
5162
5163         dsize = config->time_machine_max_size / 512;
5164         dfree = dsize - (state.total_size / 512);
5165         if (dfree > dsize) {
5166                 dfree = 0;
5167         }
5168
5169         *_bsize = 512;
5170         *_dsize = dsize;
5171         *_dfree = dfree;
5172         return dfree / 2;
5173 }
5174
5175 static uint64_t fruit_fs_file_id(struct vfs_handle_struct *handle,
5176                                  const SMB_STRUCT_STAT *psbuf)
5177 {
5178         struct fruit_config_data *config = NULL;
5179
5180         SMB_VFS_HANDLE_GET_DATA(handle, config,
5181                                 struct fruit_config_data,
5182                                 return 0);
5183
5184         if (global_fruit_config.nego_aapl &&
5185             config->aapl_zero_file_id)
5186         {
5187                 return 0;
5188         }
5189
5190         return SMB_VFS_NEXT_FS_FILE_ID(handle, psbuf);
5191 }
5192
5193 static struct vfs_fn_pointers vfs_fruit_fns = {
5194         .connect_fn = fruit_connect,
5195         .disk_free_fn = fruit_disk_free,
5196
5197         /* File operations */
5198         .fchmod_fn = fruit_fchmod,
5199         .unlinkat_fn = fruit_unlinkat,
5200         .renameat_fn = fruit_renameat,
5201         .openat_fn = fruit_openat,
5202         .close_fn = fruit_close,
5203         .pread_fn = fruit_pread,
5204         .pwrite_fn = fruit_pwrite,
5205         .pread_send_fn = fruit_pread_send,
5206         .pread_recv_fn = fruit_pread_recv,
5207         .pwrite_send_fn = fruit_pwrite_send,
5208         .pwrite_recv_fn = fruit_pwrite_recv,
5209         .stat_fn = fruit_stat,
5210         .lstat_fn = fruit_lstat,
5211         .fstat_fn = fruit_fstat,
5212         .fstreaminfo_fn = fruit_fstreaminfo,
5213         .fntimes_fn = fruit_fntimes,
5214         .ftruncate_fn = fruit_ftruncate,
5215         .fallocate_fn = fruit_fallocate,
5216         .create_file_fn = fruit_create_file,
5217         .readdir_attr_fn = fruit_readdir_attr,
5218         .offload_read_send_fn = fruit_offload_read_send,
5219         .offload_read_recv_fn = fruit_offload_read_recv,
5220         .offload_write_send_fn = fruit_offload_write_send,
5221         .offload_write_recv_fn = fruit_offload_write_recv,
5222         .fs_file_id_fn = fruit_fs_file_id,
5223
5224         /* NT ACL operations */
5225         .fget_nt_acl_fn = fruit_fget_nt_acl,
5226         .fset_nt_acl_fn = fruit_fset_nt_acl,
5227 };
5228
5229 static_decl_vfs;
5230 NTSTATUS vfs_fruit_init(TALLOC_CTX *ctx)
5231 {
5232         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fruit",
5233                                         &vfs_fruit_fns);
5234         if (!NT_STATUS_IS_OK(ret)) {
5235                 return ret;
5236         }
5237
5238         vfs_fruit_debug_level = debug_add_class("fruit");
5239         if (vfs_fruit_debug_level == -1) {
5240                 vfs_fruit_debug_level = DBGC_VFS;
5241                 DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
5242                           "vfs_fruit_init"));
5243         } else {
5244                 DEBUG(10, ("%s: Debug class number of '%s': %d\n",
5245                            "vfs_fruit_init","fruit",vfs_fruit_debug_level));
5246         }
5247
5248         return ret;
5249 }