Skip .DS_Store files in server side utils
authorDaniel Gustafsson <[email protected]>
Tue, 13 Feb 2024 12:47:12 +0000 (13:47 +0100)
committerDaniel Gustafsson <[email protected]>
Tue, 13 Feb 2024 12:47:12 +0000 (13:47 +0100)
The macOS Finder application creates .DS_Store files in directories
when opened,  which creates problems for serverside utilities which
expect all files to be PostgreSQL specific files.  Skip these files
when encountered in pg_checksums, pg_rewind and pg_basebackup.

This was extracted from a larger patchset for skipping hidden files
and system files, where the concencus was to just skip these. Since
this is equally likely to happen in every version, backpatch to all
supported versions.

Reported-by: Mark Guertin <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tobias Bussmann <[email protected]>
Discussion: https://postgr.es/m/E258CE50-AB0E-455D-8AAD-BB4FE8F882FB@gmail.com
Backpatch-through: v12

doc/src/sgml/protocol.sgml
doc/src/sgml/ref/pg_basebackup.sgml
doc/src/sgml/ref/pg_rewind.sgml
src/backend/replication/basebackup.c
src/bin/pg_basebackup/t/010_pg_basebackup.pl
src/bin/pg_checksums/pg_checksums.c
src/bin/pg_checksums/t/002_actions.pl
src/bin/pg_rewind/filemap.c
src/bin/pg_rewind/t/003_extrafiles.pl

index a23a1033632d96779f23ced350e0664e5aa8f7e8..ba605059fc21cfe2fe31ecc236a8f2c42df85102 100644 (file)
@@ -2842,7 +2842,7 @@ The commands accepted in replication mode are:
         <para>
          Files other than regular files and directories, such as symbolic
          links (other than for the directories listed above) and special
-         device files, are skipped.  (Symbolic links
+         device and operating system files, are skipped.  (Symbolic links
          in <filename>pg_tblspc</filename> are maintained.)
         </para>
        </listitem>
index 9e6807b4574d0327e4a090de39c1d7742ab4717f..e1d24f805ede5d01a6afe8e3dfc8d9cfc0c3e831 100644 (file)
@@ -832,7 +832,8 @@ PostgreSQL documentation
    The backup will include all files in the data directory and tablespaces,
    including the configuration files and any additional files placed in the
    directory by third parties, except certain temporary files managed by
-   PostgreSQL.  But only regular files and directories are copied, except that
+   PostgreSQL and operating system files.  But only regular files and
+   directories are copied, except that
    symbolic links used for tablespaces are preserved.  Symbolic links pointing
    to certain directories known to PostgreSQL are copied as empty directories.
    Other symbolic links and special device files are skipped.
index 47c5549230187603b3263ce43878b00e19048de4..2f431302495620deb0a0ab85ee129879c62592f8 100644 (file)
@@ -374,8 +374,9 @@ GRANT EXECUTE ON function pg_catalog.pg_read_binary_file(text, bigint, bigint, b
       <filename>backup_label</filename>,
       <filename>tablespace_map</filename>,
       <filename>pg_internal.init</filename>,
-      <filename>postmaster.opts</filename>, and
-      <filename>postmaster.pid</filename>, as well as any file or directory
+      <filename>postmaster.opts</filename>,
+      <filename>postmaster.pid</filename> and
+      <filename>.DS_Store</filename> as well as any file or directory
       beginning with <filename>pgsql_tmp</filename>, are omitted.
      </para>
     </step>
index d142cc213191a310710dbdd283696f85303f6990..7ed82a76ff89d7ec40328f3c225ed6d748640ff5 100644 (file)
@@ -1272,6 +1272,10 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
                    strlen(PG_TEMP_FILE_PREFIX)) == 0)
            continue;
 
+       /* Skip macOS system files */
+       if (strcmp(de->d_name, ".DS_Store") == 0)
+           continue;
+
        /*
         * Check if the postmaster has signaled us to exit, and abort with an
         * error in that case. The error handler further up will call
index e23ac607aae0c9f99bb26c83f1f94231fbac3602..43d18fe4ccf53ddeb590167c3f624edf1b4c09d0 100644 (file)
@@ -76,6 +76,16 @@ foreach my $filename (
    close $file;
 }
 
+# Test that macOS system files are skipped. Only test on non-macOS systems
+# however since creating incorrect .DS_Store files on a macOS system may have
+# unintended side effects.
+if ($Config{osname} ne 'darwin')
+{
+   open my $file, '>>', "$pgdata/.DS_Store";
+   print $file "DONOTCOPY";
+   close $file;
+}
+
 # Connect to a database to create global/pg_internal.init.  If this is removed
 # the test to ensure global/pg_internal.init is not copied will return a false
 # positive.
@@ -144,6 +154,12 @@ foreach my $filename (
    ok(!-f "$tempdir/backup/$filename", "$filename not copied");
 }
 
+# We only test .DS_Store files being skipped on non-macOS systems
+if ($Config{osname} ne 'darwin')
+{
+   ok(!-f "$tempdir/backup/.DS_Store", ".DS_Store not copied");
+}
+
 # Unlogged relation forks other than init should not be copied
 ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
    'unlogged init fork in backup');
index 831cf42d3ad19fcca76cdd4454f5bc98520f0f6a..b97d0f32903d68653c69f8a64950be6efe2a7a8e 100644 (file)
@@ -338,6 +338,10 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly)
                    strlen(PG_TEMP_FILES_DIR)) == 0)
            continue;
 
+       /* Skip macOS system files */
+       if (strcmp(de->d_name, ".DS_Store") == 0)
+           continue;
+
        snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name);
        if (lstat(fn, &st) < 0)
        {
index 761f7ab53b62e06f3e0e84dbb40db44f0498c855..a8ced3b4bed7dccf1e5d4e59adb3ad3edf4a69dd 100644 (file)
@@ -6,6 +6,7 @@
 
 use strict;
 use warnings;
+use Config;
 use PostgresNode;
 use TestLib;
 
@@ -114,6 +115,12 @@ append_to_file "$pgdata/global/pgsql_tmp/1.1",        "foo";
 append_to_file "$pgdata/global/pg_internal.init",     "foo";
 append_to_file "$pgdata/global/pg_internal.init.123", "foo";
 
+# These are non-postgres macOS files, which should be ignored by the scan.
+# Only perform this test on non-macOS systems though as creating incorrect
+# system files may have side effects on macOS.
+append_to_file "$pgdata/global/.DS_Store", "foo"
+   unless ($Config{osname} eq 'darwin');
+
 # Enable checksums.
 command_ok([ 'pg_checksums', '--enable', '--no-sync', '-D', $pgdata ],
    "checksums successfully enabled in cluster");
index 2618b4c957b2f526f2fb81fc86bbe321ff9f6f1c..f3ce4f6828892507d559f13e4a1f2fae65a0b1fd 100644 (file)
@@ -648,6 +648,10 @@ decide_file_action(file_entry_t *entry)
    if (strcmp(path, "global/pg_control") == 0)
        return FILE_ACTION_NONE;
 
+   /* Skip macOS system files */
+   if (strstr(path, ".DS_Store") != NULL)
+       return FILE_ACTION_NONE;
+
    /*
     * Remove all files matching the exclusion filters in the target.
     */
index baea3836b6f13c0a65f291c03c2461b94db64691..be60ecaaee4d6323091f66736c4c5c3c2d9e6c2f 100644 (file)
@@ -5,6 +5,7 @@
 
 use strict;
 use warnings;
+use Config;
 use TestLib;
 use Test::More tests => 5;
 
@@ -53,6 +54,10 @@ sub run_test
    append_to_file
      "$test_standby_datadir/tst_standby_dir/standby_subdir/standby_file4",
      "in standby4";
+   # Skip testing .DS_Store files on macOS to avoid risk of side effects
+   append_to_file
+     "$test_standby_datadir/tst_standby_dir/.DS_Store",
+     "macOS system file" unless ($Config{osname} eq 'darwin');
 
    mkdir "$test_primary_datadir/tst_primary_dir";
    append_to_file "$test_primary_datadir/tst_primary_dir/primary_file1",