vfs_fruit: detect empty resource forks in ad_convert()
authorRalph Boehme <slow@samba.org>
Tue, 2 Oct 2018 14:05:28 +0000 (16:05 +0200)
committerJeremy Allison <jra@samba.org>
Wed, 31 Oct 2018 20:27:17 +0000 (21:27 +0100)
For some reason the macOS client often writes AppleDouble files with a
non-zero sized resource fork, but the resource fork data is just
boilerplate data with the following string close to the start

  This resource fork intentionally left blank

A dump with apple_dump looks like this:

Entry ID   : 00000002 : Resource Fork
Offset     : 00000052 : 82
Length     : 0000011E : 286

-RAW DUMP--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)
00000000   : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
00000010   : 54 68 69 73 20 72 65 73 6F 75 72 63 65 20 66 6F : This resource fo
00000020   : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally
00000030   : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 :  left blank   ..
00000040   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
00000050   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
00000060   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
00000070   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
00000080   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
00000090   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
000000A0   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
000000B0   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
000000C0   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
000000D0   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
000000E0   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
000000F0   : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
00000100   : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
00000110   : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF       : ..............

We can safely discard this Resource Fork data.

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

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 f2a2704..8b9aed4 100644 (file)
@@ -1,4 +1,3 @@
 ^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_conversion wipe_intentionally_left_blank_rfork.convert_xattr_and_empty_rfork_then_delete\(nt4_dc\)
 ^samba3.vfs.fruit_conversion delete_empty_adfiles.convert_xattr_and_empty_rfork_then_delete\(nt4_dc\)
index 06b534d..4c731da 100644 (file)
@@ -468,6 +468,45 @@ static const uint32_t set_eid[] = {
        AD_DEV, AD_INO, AD_SYN, AD_ID
 };
 
+static char empty_resourcefork[] = {
+       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
+       0x54, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73,
+       0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x66, 0x6F,
+       0x72, 0x6B, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E,
+       0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x6C, 0x79,
+       0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x62, 0x6C,
+       0x61, 0x6E, 0x6B, 0x20, 0x20, 0x20, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x1C, 0x00, 0x1E, 0xFF, 0xFF
+};
+
 struct fio {
        /* tcon config handle */
        struct fruit_config_data *config;
@@ -1282,6 +1321,70 @@ static bool ad_convert_truncate(struct adouble *ad,
        return true;
 }
 
+static bool ad_convert_blank_rfork(struct adouble *ad,
+                                  bool *blank)
+{
+       struct fruit_config_data *config = NULL;
+       uint8_t *map = MAP_FAILED;
+       size_t maplen;
+       int cmp;
+       ssize_t len;
+       int rc;
+       bool ok;
+
+       *blank = false;
+
+       SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config,
+                               struct fruit_config_data, return false);
+
+       if (!config->wipe_intentionally_left_blank_rfork) {
+               return true;
+       }
+
+       if (ad_getentrylen(ad, ADEID_RFORK) != sizeof(empty_resourcefork)) {
+               return true;
+       }
+
+       maplen = ad_getentryoff(ad, ADEID_RFORK) +
+               ad_getentrylen(ad, ADEID_RFORK);
+
+       /* FIXME: direct use of mmap(), vfs_aio_fork does it too */
+       map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED,
+                  ad->ad_fd, 0);
+       if (map == MAP_FAILED) {
+               DBG_ERR("mmap AppleDouble: %s\n", strerror(errno));
+               return false;
+       }
+
+       cmp = memcmp(map + ADEDOFF_RFORK_DOT_UND,
+                    empty_resourcefork,
+                    sizeof(empty_resourcefork));
+       rc = munmap(map, maplen);
+       if (rc != 0) {
+               DBG_ERR("munmap failed: %s\n", strerror(errno));
+               return false;
+       }
+
+       if (cmp != 0) {
+               return true;
+       }
+
+       ad_setentrylen(ad, ADEID_RFORK, 0);
+
+       ok = ad_pack(ad);
+       if (!ok) {
+               return false;
+       }
+
+       len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
+       if (len != AD_DATASZ_DOT_UND) {
+               return false;
+       }
+
+       *blank = true;
+       return true;
+}
+
 /**
  * Convert from Apple's ._ file to Netatalk
  *
@@ -1296,13 +1399,19 @@ static int ad_convert(struct adouble *ad,
 {
        bool ok;
        bool converted_xattr = false;
+       bool blank;
 
        ok = ad_convert_xattr(ad, smb_fname, &converted_xattr);
        if (!ok) {
                return -1;
        }
 
-       if (converted_xattr) {
+       ok = ad_convert_blank_rfork(ad, &blank);
+       if (!ok) {
+               return -1;
+       }
+
+       if (converted_xattr || blank) {
                ok = ad_convert_truncate(ad, smb_fname);
                if (!ok) {
                        return -1;