Skip to content

Commit

Permalink
rofiles: Fix --copyup when creating a new file
Browse files Browse the repository at this point in the history
This tripped up the `docbook-dtds` `%post` in my experiments
with doing rpm-ostree for buildroots.

I cloned and built [xfstests](https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git)
but haven't yet investigated actually running it.

In the meantime let's do the obvious fix here; we need to distinguish
between "copyup enabled" and "actually did a copyup" in the open path
at least, since if we didn't do a copyup we don't need to re-open.
  • Loading branch information
cgwalters committed Jan 6, 2018
1 parent 46a841a commit b707a07
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 12 deletions.
15 changes: 11 additions & 4 deletions src/rofiles-fuse/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,14 @@ gioerror_to_errno (GIOErrorEnum e)
}

static int
verify_write_or_copyup (const char *path, const struct stat *stbuf)
verify_write_or_copyup (const char *path, const struct stat *stbuf,
gboolean *out_did_copyup)
{
struct stat stbuf_local;

if (out_did_copyup)
*out_did_copyup = FALSE;

/* If a stbuf wasn't provided, gather it now */
if (!stbuf)
{
Expand All @@ -272,6 +276,8 @@ verify_write_or_copyup (const char *path, const struct stat *stbuf)
g_autoptr(GError) tmp_error = NULL;
if (!ostree_break_hardlink (basefd, path, FALSE, NULL, &tmp_error))
return -gioerror_to_errno ((GIOErrorEnum)tmp_error->code);
if (out_did_copyup)
*out_did_copyup = TRUE;
}
else
return -EROFS;
Expand All @@ -286,7 +292,7 @@ verify_write_or_copyup (const char *path, const struct stat *stbuf)
*/
#define PATH_WRITE_ENTRYPOINT(path) do { \
path = ENSURE_RELPATH (path); \
int r = verify_write_or_copyup (path, NULL); \
int r = verify_write_or_copyup (path, NULL, NULL); \
if (r != 0) \
return r; \
} while (0)
Expand Down Expand Up @@ -374,15 +380,16 @@ do_open (const char *path, mode_t mode, struct fuse_file_info *finfo)
return -errno;
}

int r = verify_write_or_copyup (path, &stbuf);
gboolean did_copyup;
int r = verify_write_or_copyup (path, &stbuf, &did_copyup);
if (r != 0)
{
(void) close (fd);
return r;
}

/* In the copyup case, we need to re-open */
if (opt_copyup)
if (did_copyup)
{
(void) close (fd);
/* Note that unlike the initial open, we will pass through
Expand Down
51 changes: 43 additions & 8 deletions tests/test-rofiles-fuse.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,54 @@ echo "ok flock"

# And now with --copyup enabled

fusermount -u ${test_tmpdir}/mnt
assert_not_has_file mnt/firstfile
rofiles-fuse --copyup checkout-test2 mnt
copyup_reset() {
cd ${test_tmpdir}
fusermount -u mnt
rm checkout-test2 -rf
$OSTREE checkout -H test2 checkout-test2
rofiles-fuse --copyup checkout-test2 mnt
}

assert_test_file() {
t=$1
f=$2
if ! test ${t} "${f}"; then
ls -al "${f}"
fatal "Failed test ${t} ${f}"
fi
}

copyup_reset
assert_file_has_content mnt/firstfile first
echo "ok copyup mount"

# Test O_TRUNC directly
firstfile_orig_inode=$(stat -c %i checkout-test2/firstfile)
for path in firstfile{,-link}; do
echo truncating > mnt/${path}
assert_file_has_content mnt/${path} truncating
assert_not_file_has_content mnt/${path} first
done
echo -n truncating > mnt/firstfile
assert_streq "$(cat mnt/firstfile)" truncating
firstfile_new_inode=$(stat -c %i checkout-test2/firstfile)
assert_not_streq "${firstfile_orig_inode}" "${firstfile_new_inode}"
assert_test_file -f checkout-test2/firstfile

copyup_reset
firstfile_link_orig_inode=$(stat -c %i checkout-test2/firstfile-link)
firstfile_orig_inode=$(stat -c %i checkout-test2/firstfile)
# Now write via the symlink
echo -n truncating > mnt/firstfile-link
assert_streq "$(cat mnt/firstfile)" truncating
firstfile_new_inode=$(stat -c %i checkout-test2/firstfile)
firstfile_link_new_inode=$(stat -c %i checkout-test2/firstfile-link)
assert_not_streq "${firstfile_orig_inode}" "${firstfile_new_inode}"
assert_streq "${firstfile_link_orig_inode}" "${firstfile_link_new_inode}"
assert_test_file -f checkout-test2/firstfile
# Verify we didn't replace the link with a regfile somehow
assert_test_file -L checkout-test2/firstfile-link

# These both end up creating new files; in the sed case we'll then do a rename()
copyup_reset
echo "hello new file" > mnt/a-new-non-copyup-file
assert_file_has_content_literal mnt/a-new-non-copyup-file "hello new file"
sed -i -e s,first,second, mnt/firstfile
assert_file_has_content_literal mnt/firstfile "second"

echo "ok copyup"

0 comments on commit b707a07

Please sign in to comment.