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