gfileutils: Add a mode argument to g_file_set_contents_full()

This is used when creating the temporary file, or new file from scratch.

I wondered about also allowing the file owner and group to be set, but
that’s not as generally applicable — if your process is operating across
multiple user IDs then it likely has some fairly OS-specific
requirements and will need tighter control of its syscalls anyway.

(Eventually, support for setting the file owner and group atomically
could be added by writing out a file using `O_TMPFILE` so it’s not
addressable, and then linking it into the file system in place of the
old file using something like `renameat2(AT_EMPTY_PATH)` or `linkat()`.
That’s currently not possible without patching the kernel with
https://marc.info/?l=linux-fsdevel&m=152472898003523&w=2, as far as I
know at the moment.)

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Fixes: #1203
This commit is contained in:
Philip Withnall 2020-05-27 13:24:28 +01:00
parent f3cea1c464
commit 24ed91ce33
2 changed files with 14 additions and 5 deletions

View File

@ -1219,7 +1219,8 @@ steal_fd (int *fd_ptr)
* *
* Writes all of @contents to a file named @filename. This is a convenience * Writes all of @contents to a file named @filename. This is a convenience
* wrapper around calling g_file_set_contents() with `flags` set to * wrapper around calling g_file_set_contents() with `flags` set to
* `G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING`. * `G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING` and
* `mode` set to `0666`.
* *
* Returns: %TRUE on success, %FALSE if an error occurred * Returns: %TRUE on success, %FALSE if an error occurred
* *
@ -1233,7 +1234,8 @@ g_file_set_contents (const gchar *filename,
{ {
return g_file_set_contents_full (filename, contents, length, return g_file_set_contents_full (filename, contents, length,
G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_CONSISTENT |
G_FILE_SET_CONTENTS_ONLY_EXISTING, error); G_FILE_SET_CONTENTS_ONLY_EXISTING,
0666, error);
} }
/** /**
@ -1243,6 +1245,7 @@ g_file_set_contents (const gchar *filename,
* @contents: (array length=length) (element-type guint8): string to write to the file * @contents: (array length=length) (element-type guint8): string to write to the file
* @length: length of @contents, or -1 if @contents is a nul-terminated string * @length: length of @contents, or -1 if @contents is a nul-terminated string
* @flags: flags controlling the safety vs speed of the operation * @flags: flags controlling the safety vs speed of the operation
* @mode: file mode, as passed to `open()`; typically this will be `0666`
* @error: return location for a #GError, or %NULL * @error: return location for a #GError, or %NULL
* *
* Writes all of @contents to a file named @filename, with good error checking. * Writes all of @contents to a file named @filename, with good error checking.
@ -1296,6 +1299,10 @@ g_file_set_contents (const gchar *filename,
* Note that the name for the temporary file is constructed by appending up * Note that the name for the temporary file is constructed by appending up
* to 7 characters to @filename. * to 7 characters to @filename.
* *
* If the file didnt 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.
*
* Returns: %TRUE on success, %FALSE if an error occurred * Returns: %TRUE on success, %FALSE if an error occurred
* *
* Since: 2.66 * Since: 2.66
@ -1305,6 +1312,7 @@ g_file_set_contents_full (const gchar *filename,
const gchar *contents, const gchar *contents,
gssize length, gssize length,
GFileSetContentsFlags flags, GFileSetContentsFlags flags,
int mode,
GError **error) GError **error)
{ {
g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (filename != NULL, FALSE);
@ -1340,7 +1348,7 @@ g_file_set_contents_full (const gchar *filename,
tmp_filename = g_strdup_printf ("%s.XXXXXX", filename); tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
errno = 0; errno = 0;
fd = g_mkstemp_full (tmp_filename, O_RDWR | O_BINARY, 0666); fd = g_mkstemp_full (tmp_filename, O_RDWR | O_BINARY, mode);
if (fd == -1) if (fd == -1)
{ {
@ -1426,7 +1434,7 @@ consistent_out:
#endif #endif
errno = 0; errno = 0;
direct_fd = g_open (filename, open_flags, 0666); direct_fd = g_open (filename, open_flags, mode);
if (direct_fd < 0) if (direct_fd < 0)
{ {
@ -1440,7 +1448,7 @@ consistent_out:
if (saved_errno == ELOOP) if (saved_errno == ELOOP)
return g_file_set_contents_full (filename, contents, length, return g_file_set_contents_full (filename, contents, length,
flags | G_FILE_SET_CONTENTS_CONSISTENT, flags | G_FILE_SET_CONTENTS_CONSISTENT,
error); mode, error);
#endif #endif
set_file_error (error, set_file_error (error,

View File

@ -130,6 +130,7 @@ gboolean g_file_set_contents_full (const gchar *filename,
const gchar *contents, const gchar *contents,
gssize length, gssize length,
GFileSetContentsFlags flags, GFileSetContentsFlags flags,
int mode,
GError **error); GError **error);
G_GNUC_END_IGNORE_DEPRECATIONS G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL