lib/repofile: Follow symlinks for `g_file_read()`
authorColin Walters <walters@verbum.org>
Wed, 7 Jun 2017 19:25:21 +0000 (15:25 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Wed, 7 Jun 2017 20:54:32 +0000 (20:54 +0000)
This avoids `ostree cat /path/to/symlink` crashing, a longstanding embarassing
issue.

Closes: #915
Approved by: jlebon

src/libostree/ostree-repo-file.c
tests/basic-test.sh

index 2a90f6c7f1828e1e624d6c48dd7db5b5beb01999..fcc435a8b6a1d3382e78997685f9d443a816f384 100644 (file)
@@ -928,9 +928,23 @@ ostree_repo_file_read (GFile         *file,
 
   checksum = ostree_repo_file_get_checksum (self);
 
-  if (!ostree_repo_load_file (self->repo, checksum, &ret_stream,
-                              NULL, NULL, cancellable, error))
+  g_autoptr(GFileInfo) finfo = NULL;
+  if (!ostree_repo_load_file (self->repo, checksum, NULL,
+                              &finfo, NULL, cancellable, error))
     return NULL;
+  if (g_file_info_get_file_type (finfo) == G_FILE_TYPE_REGULAR)
+    {
+      if (!ostree_repo_load_file (self->repo, checksum, &ret_stream,
+                                  NULL, NULL, cancellable, error))
+        return NULL;
+    }
+  else
+    {
+      g_autoptr(GFile) parent = g_file_get_parent (file);
+      const char *target = g_file_info_get_symlink_target (finfo);
+      g_autoptr(GFile) dest = g_file_resolve_relative_path (parent, target);
+      return g_file_read (dest, cancellable, error);
+    }
 
   return g_steal_pointer (&ret_stream);
 }
index 829452440da51504a4e3d1cb9f4fb79947d352ac..f5af93b19de4ef9c9da0e1312334834f508aaea8 100644 (file)
@@ -338,8 +338,30 @@ $OSTREE prune
 echo "ok prune didn't fail"
 
 cd ${test_tmpdir}
+# Verify we can't cat dirs
+for path in / /baz; do
+    if $OSTREE cat test2 $path 2>err.txt; then
+        assert_not_reached "cat directory"
+    fi
+    assert_file_has_content err.txt "open directory"
+done
+rm checkout-test2 -rf
 $OSTREE cat test2 /yet/another/tree/green > greenfile-contents
 assert_file_has_content greenfile-contents "leaf"
+$OSTREE checkout test2 checkout-test2
+ls -alR checkout-test2
+ln -sr checkout-test2/{four,four-link}
+ln -sr checkout-test2/{baz/cow,cow-link}
+ln -sr checkout-test2/{cow-link,cow-link-link}
+$OSTREE commit -b test2-withlink --tree=dir=checkout-test2
+if $OSTREE cat test2-withlink /four-link 2>err.txt; then
+    assert_not_reached "cat directory"
+fi
+assert_file_has_content err.txt "open directory"
+for path in /cow-link /cow-link-link; do
+    $OSTREE cat test2-withlink $path >contents.txt
+    assert_file_has_content contents.txt moo
+done
 echo "ok cat-file"
 
 cd ${test_tmpdir}