mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-05-18 11:41:58 +02:00
gfileutils: Preserve mode during atomic updates
If g_file_set_contents{_full,} is replacing an existing file, require that the tmpfile have the same mode as the existing file. This prevents the umask from taking effect for consistent writes to existing files. Closes GNOME/dconf#76
This commit is contained in:
parent
437f3a134d
commit
3cc0c0de33
@ -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))
|
||||
{
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user