#include <errno.h>
#include <fcntl.h>
#include <glib.h>
+#include <glib/gstdio.h>
#include <JavaScriptCore/JavaScript.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
+#include <unistd.h>
#include "ascii.h"
#include "completion.h"
gboolean util_create_dir_if_not_exists(const char *dirpath)
{
if (g_mkdir_with_parents(dirpath, 0755) == -1) {
- g_critical("Could not create directory '%s': %s", dirpath, strerror(errno));
+ g_critical("Could not create directory '%s': %s", dirpath, g_strerror(errno));
return FALSE;
}
* @line: Line to be written as new first line into the file.
* The line ending is inserted automatic.
* @max_lines Maximum number of lines in file after the operation.
+ * @mode Mode (file permission as chmod(2)) used for the file when
+ * creating it.
*/
void util_file_prepend_line(const char *file, const char *line,
- unsigned int max_lines)
+ unsigned int max_lines, int mode)
{
char **lines;
GString *new_content;
}
g_strfreev(lines);
}
- g_file_set_contents(file, new_content->str, -1, NULL);
+ util_file_set_content(file, new_content->str, mode);
g_string_free(new_content, TRUE);
}
* @file: file to read from
* @item_count: will be filled with the number of remaining lines in file if it
* is not NULL.
+ * @mode Mode (file permission as chmod(2)) used for the file when
+ * creating it.
*
* Returned string must be freed with g_free.
*/
-char *util_file_pop_line(const char *file, int *item_count)
+char *util_file_pop_line(const char *file, int *item_count, int mode)
{
char **lines;
char *new,
/* minus one for last empty item and one for popped item */
count = len - 2;
new = g_strjoinv("\n", lines + 1);
- g_file_set_contents(file, new, -1, NULL);
+ util_file_set_content(file, new, mode);
g_free(new);
}
g_strfreev(lines);
return content;
}
+/**
+ * Atomicly writes contents to given file.
+ * Returns TRUE on success, FALSE otherwise.
+ */
+char *util_file_set_content(const char *file, const char *contents, int mode)
+{
+ gboolean retval = FALSE;
+ char *tmp_name;
+ int fd;
+ gsize length;
+
+ /* Create a temporary file. */
+ tmp_name = g_strconcat(file, ".XXXXXX", NULL);
+ errno = 0;
+ fd = g_mkstemp_full(tmp_name, O_RDWR, mode);
+ length = strlen(contents);
+
+ if (fd == -1) {
+ g_error("Failed to create file %s: %s", tmp_name, g_strerror(errno));
+
+ goto out;
+ }
+
+ /* Write the contents to the temporary file. */
+ while (length > 0) {
+ gssize s;
+ s = write(fd, contents, length);
+ if (s < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ g_error("Failed to write to file %s: write() failed: %s",
+ tmp_name, g_strerror(errno));
+ close(fd);
+ g_unlink(tmp_name);
+
+ goto out;
+ }
+
+ g_assert (s <= length);
+
+ contents += s;
+ length -= s;
+ }
+
+ if (!g_close(fd, NULL)) {
+ g_unlink(tmp_name);
+ goto out;
+ }
+
+ /* Atomic rename the temporary file into the destination file. */
+ if (g_rename(tmp_name, file) == -1) {
+ g_error("Failed to rename file %s to %s: g_rename() failed: %s",
+ tmp_name, file, g_strerror(errno));
+ g_unlink(tmp_name);
+ goto out;
+ }
+
+ retval = TRUE;
+
+out:
+ g_free(tmp_name);
+
+ return retval;
+}
+
/**
* Buil the path from given directory and filename and checks if the file
* exists. If the file does not exists and the create option is not set, this
gboolean util_file_append(const char *file, const char *format, ...);
gboolean util_file_prepend(const char *file, const char *format, ...);
void util_file_prepend_line(const char *file, const char *line,
- unsigned int max_lines);
-char *util_file_pop_line(const char *file, int *item_count);
+ unsigned int max_lines, int mode);
+char *util_file_pop_line(const char *file, int *item_count, int mode);
char *util_get_config_dir(void);
char *util_get_file_contents(const char *filename, gsize *length);
+char *util_file_set_content(const char *file, const char *contents, int mode);
char *util_get_filepath(const char *dir, const char *filename, gboolean create, int mode);
char **util_get_lines(const char *filename);
GList *util_file_to_unique_list(const char *filename, Util_Content_Func func,