aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/file-utils.c13
-rw-r--r--src/file-utils.h4
-rw-r--r--src/view.c19
3 files changed, 27 insertions, 9 deletions
diff --git a/src/file-utils.c b/src/file-utils.c
index 75bcb48..db06ff3 100644
--- a/src/file-utils.c
+++ b/src/file-utils.c
@@ -109,6 +109,14 @@ teco_file_set_attributes(const gchar *filename, teco_file_attributes_t attrs)
#ifdef G_OS_UNIX
+/*
+ * NOTE: This version does not resolve symlinks to non-existing paths.
+ * It could be improved by repeating readlink() and g_canonicalize_filename(),
+ * but it would require glib v2.58.0.
+ * Alternatively we could also iteratively resolve all path components.
+ * Currently, we simply do not rely on successful canonicalization of
+ * yet non-existing paths.
+ */
gchar *
teco_file_get_absolute_path(const gchar *path)
{
@@ -137,13 +145,12 @@ teco_file_is_visible(const gchar *path)
#if GLIB_CHECK_VERSION(2,58,0)
/*
- * FIXME: This should perhaps be preferred on any platform.
- * But it will complicate preprocessing.
+ * NOTE: Does not resolve symlinks.
*/
gchar *
teco_file_get_absolute_path(const gchar *path)
{
- return g_canonicalize_filename(path, NULL);
+ return path ? g_canonicalize_filename(path, NULL) : NULL;
}
#else /* !GLIB_CHECK_VERSION(2,58,0) */
diff --git a/src/file-utils.h b/src/file-utils.h
index 12a9b83..9a2f8d6 100644
--- a/src/file-utils.h
+++ b/src/file-utils.h
@@ -32,9 +32,7 @@ void teco_file_set_attributes(const gchar *filename, teco_file_attributes_t attr
/**
* Get absolute/full version of a possibly relative path.
* The path is tried to be canonicalized so it does
- * not contain relative components.
- * Works with existing and non-existing paths (in the latter case,
- * heuristics may be applied).
+ * not contain relative components and symlinks.
* Depending on platform and existence of the path,
* canonicalization might fail, but the path returned is
* always absolute.
diff --git a/src/view.c b/src/view.c
index 702c5b6..53199bd 100644
--- a/src/view.c
+++ b/src/view.c
@@ -550,16 +550,16 @@ teco_view_save_to_file(teco_view_t *ctx, const gchar *filename, GError **error)
file_stat.st_gid = -1;
#endif
teco_file_attributes_t attributes = TECO_FILE_INVALID_ATTRIBUTES;
+ gboolean undo_remove_file = FALSE;
if (teco_undo_enabled) {
- if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
+ undo_remove_file = !g_file_test(filename, G_FILE_TEST_IS_REGULAR);
+ if (!undo_remove_file) {
#ifdef G_OS_UNIX
g_stat(filename, &file_stat);
#endif
attributes = teco_file_get_attributes(filename);
teco_make_savepoint(filename);
- } else {
- teco_undo_remove_file_push(filename);
}
}
@@ -568,6 +568,18 @@ teco_view_save_to_file(teco_view_t *ctx, const gchar *filename, GError **error)
if (!channel)
return FALSE;
+ if (undo_remove_file) {
+ /*
+ * The file is new, so has to be removed on undo.
+ * If `filename` is a symlink, it's crucial to resolve it now,
+ * since early canonicalization may have failed (for non-existent
+ * path segments).
+ * Now, `filename` is guaranteed to exist.
+ */
+ g_autofree gchar *filename_canon = teco_file_get_absolute_path(filename);
+ teco_undo_remove_file_push(filename_canon);
+ }
+
/*
* teco_view_save_to_channel() expects a buffered and blocking channel
*/
@@ -576,6 +588,7 @@ teco_view_save_to_file(teco_view_t *ctx, const gchar *filename, GError **error)
if (!teco_view_save_to_channel(ctx, channel, error)) {
g_prefix_error(error, "Error writing file \"%s\": ", filename);
+ /* file might also be removed (in interactive mode) */
return FALSE;
}