diff --git a/glib/gfileutils.c b/glib/gfileutils.c index bc4bcf1f4..1768358fe 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -1318,8 +1318,8 @@ g_file_set_contents (const gchar *filename, * to 7 characters to @filename. * * If the file didn’t exist before and is created, it will be given the - * permissions from @mode. Otherwise, the permissions of the existing file may - * be changed to @mode depending on @flags, or they may remain unchanged. + * permissions from @mode. Otherwise, the permissions of the existing file will + * remain unchanged. * * Returns: %TRUE on success, %FALSE if an error occurred * @@ -1362,6 +1362,7 @@ g_file_set_contents_full (const gchar *filename, gboolean retval; int fd; gboolean do_fsync; + GStatBuf old_stat; tmp_filename = g_strdup_printf ("%s.XXXXXX", filename); @@ -1379,6 +1380,26 @@ g_file_set_contents_full (const gchar *filename, goto consistent_out; } + /* Maintain the permissions of the file if it exists */ + if (!g_stat (filename, &old_stat)) + { +#ifndef G_OS_WIN32 + if (fchmod (fd, old_stat.st_mode)) +#else /* G_OS_WIN32 */ + if (chmod (tmp_filename, old_stat.st_mode)) +#endif /* G_OS_WIN32 */ + { + int saved_errno = errno; + if (error) + set_file_error (error, + tmp_filename, _ ("Failed to set permissions of “%s”: %s"), + saved_errno); + g_unlink (tmp_filename); + retval = FALSE; + goto consistent_out; + } + } + do_fsync = fd_should_be_fsynced (fd, filename, flags); if (!write_to_file (contents, length, g_steal_fd (&fd), tmp_filename, do_fsync, error)) { diff --git a/glib/tests/fileutils.c b/glib/tests/fileutils.c index fdc9ce3de..57e0a6f2e 100644 --- a/glib/tests/fileutils.c +++ b/glib/tests/fileutils.c @@ -1687,7 +1687,9 @@ test_set_contents_full (void) EXISTING_FILE_DIRECTORY, } existing_file; - int new_mode; /* only relevant if @existing_file is %EXISTING_FILE_NONE */ + /* only relevant if @existing_file is + * %EXISTING_FILE_NONE or %EXISTING_FILE_REGULAR */ + int mode; gboolean use_strlen; gboolean expected_success; @@ -1698,6 +1700,8 @@ test_set_contents_full (void) { EXISTING_FILE_NONE, 0644, FALSE, TRUE, 0 }, { EXISTING_FILE_NONE, 0644, TRUE, TRUE, 0 }, { EXISTING_FILE_NONE, 0600, FALSE, TRUE, 0 }, + // Assume umask is 022, ensures that we preserve perms with, eg. 077 + { EXISTING_FILE_REGULAR, 0666, FALSE, TRUE, 0 }, { EXISTING_FILE_REGULAR, 0644, FALSE, TRUE, 0 }, #ifndef G_OS_WIN32 { EXISTING_FILE_SYMLINK, 0644, FALSE, TRUE, 0 }, @@ -1742,6 +1746,8 @@ test_set_contents_full (void) g_assert_no_errno (g_fsync (fd)); close (fd); + g_assert_no_errno (chmod (file_name, tests[i].mode)); + #ifndef G_OS_WIN32 /* Pass an existing symlink to g_file_set_contents_full() to see * what it does. */ @@ -1785,7 +1791,7 @@ test_set_contents_full (void) /* Set the file contents */ ret = g_file_set_contents_full (set_contents_name, "b", tests[i].use_strlen ? -1 : 1, - flags, tests[i].new_mode, &error); + flags, tests[i].mode, &error); if (!tests[i].expected_success) { @@ -1809,10 +1815,10 @@ test_set_contents_full (void) g_assert_no_errno (g_lstat (set_contents_name, &statbuf)); - if (tests[i].existing_file == EXISTING_FILE_NONE) + if (tests[i].existing_file & (EXISTING_FILE_NONE | EXISTING_FILE_REGULAR)) { int mode = statbuf.st_mode & ~S_IFMT; - int new_mode = tests[i].new_mode; + int new_mode = tests[i].mode; #ifdef G_OS_WIN32 /* on windows, group and others perms handling is different */ /* only check the rwx user permissions */