lib/core: Add a "break hardlink" API
This imports the code from rpm-ostree: https://github.com/projectatomic/rpm-ostree/blob/9ff9f6c997d914cb7d97d6b59d8045ba64a1882c/src/libpriv/rpmostree-util.c#L742 I plan to use this for rofiles-fuse to implement copyup: https://github.com/ostreedev/ostree/issues/1377 But it's just obviously generally useful for projects using libostree I think. Closes: #1378 Approved by: jlebon
This commit is contained in:
1 parent
d340fe4060
commit
4a2e08148d
5 files changed
+157
No files matched your search
@@ -22,6 +22,7 @@
|
||||
LIBOSTREE_2017.15 {
|
||||
ostree_repo_fsck_object;
|
||||
ostree_repo_mark_commit_partial;
|
||||
ostree_break_hardlink;
|
||||
} LIBOSTREE_2017.14;
|
||||
|
||||
/* Stub section for the stable release *after* this development one; don't
|
||||
|
||||
@@ -749,6 +749,86 @@ ostree_content_file_parse (gboolean compressed,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_break_hardlink:
|
||||
* @dfd: Directory fd
|
||||
* @path: Path relative to @dfd
|
||||
* @skip_xattrs: Do not copy extended attributes
|
||||
* @error: error
|
||||
*
|
||||
* In many cases using libostree, a program may need to "break"
|
||||
* hardlinks by performing a copy. For example, in order to
|
||||
* logically append to a file.
|
||||
*
|
||||
* This function performs full copying, including e.g. extended
|
||||
* attributes and permissions of both regular files and symbolic links.
|
||||
*
|
||||
* If the file is not hardlinked, this function does nothing and
|
||||
* returns successfully.
|
||||
*
|
||||
* This function does not perform synchronization via `fsync()` or
|
||||
* `fdatasync()`; the idea is this will commonly be done as part
|
||||
* of an `ostree_repo_commit_transaction()`, which itself takes
|
||||
* care of synchronization.
|
||||
*
|
||||
* Since: 2017.15
|
||||
*/
|
||||
gboolean ostree_break_hardlink (int dfd,
|
||||
const char *path,
|
||||
gboolean skip_xattrs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
struct stat stbuf;
|
||||
|
||||
if (!glnx_fstatat (dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW, error))
|
||||
return FALSE;
|
||||
|
||||
if (!S_ISLNK (stbuf.st_mode) && !S_ISREG (stbuf.st_mode))
|
||||
return glnx_throw (error, "Unsupported type for entry '%s'", path);
|
||||
|
||||
const GLnxFileCopyFlags copyflags =
|
||||
skip_xattrs ? GLNX_FILE_COPY_NOXATTRS : 0;
|
||||
|
||||
if (stbuf.st_nlink > 1)
|
||||
{
|
||||
guint count;
|
||||
gboolean copy_success = FALSE;
|
||||
char *path_tmp = glnx_strjoina (path, ".XXXXXX");
|
||||
|
||||
for (count = 0; count < 100; count++)
|
||||
{
|
||||
g_autoptr(GError) tmp_error = NULL;
|
||||
|
||||
glnx_gen_temp_name (path_tmp);
|
||||
|
||||
if (!glnx_file_copy_at (dfd, path, &stbuf, dfd, path_tmp, copyflags,
|
||||
cancellable, &tmp_error))
|
||||
{
|
||||
if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||
continue;
|
||||
g_propagate_error (error, g_steal_pointer (&tmp_error));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
copy_success = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!copy_success)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
|
||||
"Exceeded limit of %u file creation attempts", count);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!glnx_renameat (dfd, path_tmp, dfd, path, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_checksum_file_from_input:
|
||||
* @file_info: File information
|
||||
|
||||
@@ -438,6 +438,13 @@ gboolean ostree_checksum_file (GFile *f,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_break_hardlink (int dfd,
|
||||
const char *path,
|
||||
gboolean skip_xattrs,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* OstreeChecksumFlags:
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user