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