summaryrefslogtreecommitdiff
path: root/gsystem-file-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsystem-file-utils.c')
-rw-r--r--gsystem-file-utils.c111
1 files changed, 89 insertions, 22 deletions
diff --git a/gsystem-file-utils.c b/gsystem-file-utils.c
index 6291027..0486bf8 100644
--- a/gsystem-file-utils.c
+++ b/gsystem-file-utils.c
@@ -476,10 +476,36 @@ gsystem_fileutil_gen_tmp_name (const char *prefix,
}
/**
- * gs_file_open_in_tmpdir:
- * @tmpdir: Directory to place temporary file
+ * gs_file_open_dir_fd:
+ * @path: Directory name
+ * @out_fd: (out): File descriptor for directory
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * On success, sets @out_fd to a file descriptor for the directory
+ * that can be used with UNIX functions such as openat().
+ */
+gboolean
+gs_file_open_dir_fd (GFile *path,
+ int *out_fd,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /* Linux specific probably */
+ *out_fd = open (gs_file_get_path_cached (path), O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC);
+ if (*out_fd == -1)
+ {
+ _set_error_from_errno (error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * gs_file_open_in_tmpdir_at:
+ * @tmpdir_fd: Directory to place temporary file
* @mode: Default mode (will be affected by umask)
- * @out_file: (out) (transfer full): Newly created file path
+ * @out_name: (out) (transfer full): Newly created file name
* @out_stream: (out) (transfer full) (allow-none): Newly created output stream
* @cancellable:
* @error:
@@ -487,32 +513,22 @@ gsystem_fileutil_gen_tmp_name (const char *prefix,
* Like g_file_open_tmp(), except the file will be created in the
* provided @tmpdir, and allows specification of the Unix @mode, which
* means private files may be created. Return values will be stored
- * in @out_file, and optionally @out_stream.
+ * in @out_name, and optionally @out_stream.
*/
gboolean
-gs_file_open_in_tmpdir (GFile *tmpdir,
- int mode,
- GFile **out_file,
- GOutputStream **out_stream,
- GCancellable *cancellable,
- GError **error)
+gs_file_open_in_tmpdir_at (int tmpdir_fd,
+ int mode,
+ char **out_name,
+ GOutputStream **out_stream,
+ GCancellable *cancellable,
+ GError **error)
{
gboolean ret = FALSE;
const int max_attempts = 128;
guint i;
- DIR *d = NULL;
- int dfd = -1;
char *tmp_name = NULL;
int fd;
- d = opendir (gs_file_get_path_cached (tmpdir));
- if (!d)
- {
- _set_error_from_errno (error);
- goto out;
- }
- dfd = dirfd (d);
-
/* 128 attempts seems reasonable... */
for (i = 0; i < max_attempts; i++)
{
@@ -520,7 +536,7 @@ gs_file_open_in_tmpdir (GFile *tmpdir,
tmp_name = gsystem_fileutil_gen_tmp_name (NULL, NULL);
do
- fd = openat (dfd, tmp_name, O_WRONLY | O_CREAT | O_EXCL, mode);
+ fd = openat (tmpdir_fd, tmp_name, O_WRONLY | O_CREAT | O_EXCL, mode);
while (fd == -1 && errno == EINTR);
if (fd < 0 && errno != EEXIST)
{
@@ -537,11 +553,62 @@ gs_file_open_in_tmpdir (GFile *tmpdir,
}
ret = TRUE;
- *out_file = g_file_get_child (tmpdir, tmp_name);
+ gs_transfer_out_value (out_name, &tmp_name);
if (out_stream)
*out_stream = g_unix_output_stream_new (fd, TRUE);
out:
+ g_free (tmp_name);
+ return ret;
+}
+
+/**
+ * gs_file_open_in_tmpdir:
+ * @tmpdir: Directory to place temporary file
+ * @mode: Default mode (will be affected by umask)
+ * @out_file: (out) (transfer full): Newly created file path
+ * @out_stream: (out) (transfer full) (allow-none): Newly created output stream
+ * @cancellable:
+ * @error:
+ *
+ * Like g_file_open_tmp(), except the file will be created in the
+ * provided @tmpdir, and allows specification of the Unix @mode, which
+ * means private files may be created. Return values will be stored
+ * in @out_file, and optionally @out_stream.
+ */
+gboolean
+gs_file_open_in_tmpdir (GFile *tmpdir,
+ int mode,
+ GFile **out_file,
+ GOutputStream **out_stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ DIR *d = NULL;
+ int dfd = -1;
+ char *tmp_name = NULL;
+ GOutputStream *ret_stream = NULL;
+
+ d = opendir (gs_file_get_path_cached (tmpdir));
+ if (!d)
+ {
+ _set_error_from_errno (error);
+ goto out;
+ }
+ dfd = dirfd (d);
+
+ if (!gs_file_open_in_tmpdir_at (dfd, mode, &tmp_name,
+ out_stream ? &ret_stream : NULL,
+ cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ *out_file = g_file_get_child (tmpdir, tmp_name);
+ gs_transfer_out_value (out_stream, &ret_stream);
+ out:
if (d) (void) closedir (d);
+ g_clear_object (&ret_stream);
+ g_free (tmp_name);
return ret;
}