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