vfs_fruit: filter empty streams
authorRalph Boehme <slow@samba.org>
Sat, 20 Oct 2018 12:53:50 +0000 (14:53 +0200)
committerJeremy Allison <jra@samba.org>
Wed, 31 Oct 2018 20:27:20 +0000 (21:27 +0100)
First step in achieving macOS compliant behaviour wrt to empty streams:
- hide empty streams in streaminfo
- prevent opens of empty streams

This means that we may carry 0-byte sized streams in our streams
backend, but this shouldn't really hurt.

The previous attempt of deleting the streams when an SMB setinfo eof to
0 request came in, turned out be a road into desaster.

We could set delete-on-close on the stream, but that means we'd have to
check for it for every write on a stream and checking the
delete-on-close bits requires fetching the locking.tdb record, so this
is expensive and I'd like to avoid that overhead.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/knownfail.d/samba3.vfs.fruit
source3/modules/vfs_fruit.c

index 5ecba52..6307e2b 100644 (file)
@@ -1,5 +1,2 @@
 ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\)
 ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\)
-^samba3.vfs.fruit metadata_netatalk.setinfo eof stream\(nt4_dc\)
-^samba3.vfs.fruit metadata_stream.setinfo eof stream\(nt4_dc\)
-^samba3.vfs.fruit streams_depot.setinfo eof stream\(nt4_dc\)
index 52daf9a..70ddffe 100644 (file)
@@ -5598,6 +5598,36 @@ static NTSTATUS fruit_streaminfo_rsrc(vfs_handle_struct *handle,
        return status;
 }
 
+static void fruit_filter_empty_streams(unsigned int *pnum_streams,
+                                      struct stream_struct **pstreams)
+{
+       unsigned num_streams = *pnum_streams;
+       struct stream_struct *streams = *pstreams;
+       unsigned i = 0;
+
+       if (!global_fruit_config.nego_aapl) {
+               return;
+       }
+
+       while (i < num_streams) {
+               struct smb_filename smb_fname = (struct smb_filename) {
+                       .stream_name = streams[i].name,
+               };
+
+               if (is_ntfs_default_stream_smb_fname(&smb_fname)
+                   || streams[i].size > 0)
+               {
+                       i++;
+                       continue;
+               }
+
+               streams[i] = streams[num_streams - 1];
+               num_streams--;
+       }
+
+       *pnum_streams = num_streams;
+}
+
 static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
                                 struct files_struct *fsp,
                                 const struct smb_filename *smb_fname,
@@ -5619,6 +5649,8 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
                return status;
        }
 
+       fruit_filter_empty_streams(pnum_streams, pstreams);
+
        status = fruit_streaminfo_meta(handle, fsp, smb_fname,
                                       mem_ctx, pnum_streams, pstreams);
        if (!NT_STATUS_IS_OK(status)) {
@@ -5893,13 +5925,13 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
         * Cf the vfs_fruit torture tests in test_rfork_create().
         */
        if (global_fruit_config.nego_aapl &&
-           is_afpresource_stream(fsp->fsp_name) &&
-           create_disposition == FILE_OPEN)
+           create_disposition == FILE_OPEN &&
+           smb_fname->st.st_ex_size == 0 &&
+           is_ntfs_stream_smb_fname(smb_fname) &&
+           !(is_ntfs_default_stream_smb_fname(smb_fname)))
        {
-               if (fsp->fsp_name->st.st_ex_size == 0) {
-                       status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                       goto fail;
-               }
+               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               goto fail;
        }
 
        if (is_ntfs_stream_smb_fname(smb_fname)