flatpak-dir.c (flatpak-1.15.0.tar.xz) | : | flatpak-dir.c (flatpak-1.15.1.tar.xz) | ||
---|---|---|---|---|
skipping to change at line 4545 | skipping to change at line 4545 | |||
if (!glnx_fstatat (dir_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, NULL)) | if (!glnx_fstatat (dir_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, NULL)) | |||
continue; | continue; | |||
if (stbuf.st_mtime >= now || | if (stbuf.st_mtime >= now || | |||
now - stbuf.st_mtime < SECS_PER_DAY) | now - stbuf.st_mtime < SECS_PER_DAY) | |||
continue; | continue; | |||
tmp = g_file_get_child (dir, dent->d_name); | tmp = g_file_get_child (dir, dent->d_name); | |||
/* We ignore errors here, no need to worry anyone */ | /* We ignore errors here, no need to worry anyone */ | |||
g_debug ("Deleting stale appstream deploy tmpdir %s", flatpak_file_get_pat | ||||
h_cached (tmp)); | ||||
(void)flatpak_rm_rf (tmp, NULL, NULL); | ||||
} | ||||
} | ||||
/* Like the function above, this looks for old temporary directories created by | ||||
* previous versions of flatpak_dir_deploy(). | ||||
* These are all directories starting with a dot. Such directories can be from a | ||||
* concurrent deploy, so we only remove directories older than a day to avoid | ||||
* races. | ||||
*/ | ||||
static void | ||||
remove_old_deploy_tmpdirs (GFile *dir) | ||||
{ | ||||
g_auto(GLnxDirFdIterator) dir_iter = { 0 }; | ||||
time_t now = time (NULL); | ||||
if (!glnx_dirfd_iterator_init_at (AT_FDCWD, flatpak_file_get_path_cached (dir) | ||||
, | ||||
FALSE, &dir_iter, NULL)) | ||||
return; | ||||
while (TRUE) | ||||
{ | ||||
struct stat stbuf; | ||||
struct dirent *dent; | ||||
g_autoptr(GFile) tmp = NULL; | ||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dir_iter, &dent, NULL, N | ||||
ULL)) | ||||
break; | ||||
if (dent == NULL) | ||||
break; | ||||
/* We ignore non-dotfiles and .timestamps as they are not tempfiles */ | ||||
if (dent->d_name[0] != '.' || | ||||
strcmp (dent->d_name, ".timestamp") == 0) | ||||
continue; | ||||
/* Check for right types and names. The format we’re looking for is: | ||||
* .[0-9a-f]{64}-[0-9A-Z]{6} */ | ||||
if (dent->d_type == DT_DIR) | ||||
{ | ||||
if (strlen (dent->d_name) != 72 || | ||||
dent->d_name[65] != '-') | ||||
continue; | ||||
} | ||||
else | ||||
continue; | ||||
/* Check that the file is at least a day old to avoid races */ | ||||
if (!glnx_fstatat (dir_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, | ||||
NULL)) | ||||
continue; | ||||
if (stbuf.st_mtime >= now || | ||||
now - stbuf.st_mtime < SECS_PER_DAY) | ||||
continue; | ||||
tmp = g_file_get_child (dir, dent->d_name); | ||||
/* We ignore errors here, no need to worry anyone */ | ||||
g_debug ("Deleting stale deploy tmpdir %s", flatpak_file_get_path_cached ( | ||||
tmp)); | ||||
(void)flatpak_rm_rf (tmp, NULL, NULL); | (void)flatpak_rm_rf (tmp, NULL, NULL); | |||
} | } | |||
} | } | |||
gboolean | gboolean | |||
flatpak_dir_deploy_appstream (FlatpakDir *self, | flatpak_dir_deploy_appstream (FlatpakDir *self, | |||
const char *remote, | const char *remote, | |||
const char *arch, | const char *arch, | |||
gboolean *out_changed, | gboolean *out_changed, | |||
GCancellable *cancellable, | GCancellable *cancellable, | |||
skipping to change at line 8507 | skipping to change at line 8568 | |||
const char *checksum_or_latest, | const char *checksum_or_latest, | |||
const char * const * subpaths, | const char * const * subpaths, | |||
const char * const * previous_ids, | const char * const * previous_ids, | |||
GCancellable *cancellable, | GCancellable *cancellable, | |||
GError **error) | GError **error) | |||
{ | { | |||
g_autofree char *resolved_ref = NULL; | g_autofree char *resolved_ref = NULL; | |||
g_autofree char *ref_id = NULL; | g_autofree char *ref_id = NULL; | |||
g_autoptr(GFile) root = NULL; | g_autoptr(GFile) root = NULL; | |||
g_autoptr(GFile) deploy_base = NULL; | g_autoptr(GFile) deploy_base = NULL; | |||
glnx_autofd int deploy_base_dfd = -1; | ||||
g_autoptr(GFile) checkoutdir = NULL; | g_autoptr(GFile) checkoutdir = NULL; | |||
g_autoptr(GFile) bindir = NULL; | g_autoptr(GFile) bindir = NULL; | |||
g_autofree char *checkoutdirpath = NULL; | g_autofree char *checkoutdirpath = NULL; | |||
const char *checkoutdir_basename; | ||||
g_autoptr(GFile) real_checkoutdir = NULL; | g_autoptr(GFile) real_checkoutdir = NULL; | |||
g_autoptr(GFile) dotref = NULL; | g_autoptr(GFile) dotref = NULL; | |||
g_autoptr(GFile) files_etc = NULL; | g_autoptr(GFile) files_etc = NULL; | |||
g_autoptr(GFile) deploy_data_file = NULL; | g_autoptr(GFile) deploy_data_file = NULL; | |||
g_autoptr(GVariant) commit_data = NULL; | g_autoptr(GVariant) commit_data = NULL; | |||
g_autoptr(GBytes) deploy_data = NULL; | g_autoptr(GBytes) deploy_data = NULL; | |||
g_autoptr(GFile) export = NULL; | g_autoptr(GFile) export = NULL; | |||
g_autoptr(GFile) extradir = NULL; | g_autoptr(GFile) extradir = NULL; | |||
g_autoptr(GKeyFile) keyfile = NULL; | g_autoptr(GKeyFile) keyfile = NULL; | |||
guint64 installed_size = 0; | guint64 installed_size = 0; | |||
OstreeRepoCheckoutAtOptions options = { 0, }; | OstreeRepoCheckoutAtOptions options = { 0, }; | |||
const char *checksum; | const char *checksum; | |||
glnx_autofd int checkoutdir_dfd = -1; | glnx_autofd int checkoutdir_dfd = -1; | |||
g_autoptr(GFile) tmp_dir_template = NULL; | ||||
g_autofree char *tmp_dir_path = NULL; | ||||
const char *xa_ref = NULL; | const char *xa_ref = NULL; | |||
g_autofree char *checkout_basename = NULL; | g_autofree char *checkout_basename = NULL; | |||
gboolean created_extra_data = FALSE; | gboolean created_extra_data = FALSE; | |||
g_autoptr(GVariant) commit_metadata = NULL; | g_autoptr(GVariant) commit_metadata = NULL; | |||
g_auto(GLnxLockFile) lock = { 0, }; | g_auto(GLnxLockFile) lock = { 0, }; | |||
g_autoptr(GFile) metadata_file = NULL; | g_autoptr(GFile) metadata_file = NULL; | |||
g_autofree char *metadata_contents = NULL; | g_autofree char *metadata_contents = NULL; | |||
gsize metadata_size = 0; | gsize metadata_size = 0; | |||
const char *flatpak; | const char *flatpak; | |||
g_auto(GLnxTmpDir) tmp_dir_handle = { 0, }; | ||||
if (!flatpak_dir_ensure_repo (self, cancellable, error)) | if (!flatpak_dir_ensure_repo (self, cancellable, error)) | |||
return FALSE; | return FALSE; | |||
ref_id = flatpak_decomposed_dup_id (ref); | ref_id = flatpak_decomposed_dup_id (ref); | |||
/* Keep a shared repo lock to avoid prunes removing objects we're relying on | /* Keep a shared repo lock to avoid prunes removing objects we're relying on | |||
* while we do the checkout. This could happen if the ref changes after we | * while we do the checkout. This could happen if the ref changes after we | |||
* read its current value for the checkout. */ | * read its current value for the checkout. */ | |||
if (!flatpak_dir_repo_lock (self, &lock, LOCK_SH, cancellable, error)) | if (!flatpak_dir_repo_lock (self, &lock, LOCK_SH, cancellable, error)) | |||
return FALSE; | return FALSE; | |||
deploy_base = flatpak_dir_get_deploy_dir (self, ref); | deploy_base = flatpak_dir_get_deploy_dir (self, ref); | |||
if (!glnx_opendirat (AT_FDCWD, flatpak_file_get_path_cached (deploy_base), TRU | ||||
E, &deploy_base_dfd, error)) | ||||
return FALSE; | ||||
/* There used to be a bug here where temporary files beneath @deploy_base were | ||||
not removed, | ||||
* which could use quite a lot of space over time, so we check for these and r | ||||
emove them. | ||||
* We only do so for the current app to avoid every deploy operation iterating | ||||
over | ||||
* every app directory and all their immediate descendents. That would be a bi | ||||
t much I/O. */ | ||||
remove_old_deploy_tmpdirs (deploy_base); | ||||
if (checksum_or_latest == NULL) | if (checksum_or_latest == NULL) | |||
{ | { | |||
g_debug ("No checksum specified, getting tip of %s from origin %s", flatpa k_decomposed_get_ref (ref), origin); | g_debug ("No checksum specified, getting tip of %s from origin %s", flatpa k_decomposed_get_ref (ref), origin); | |||
resolved_ref = flatpak_dir_read_latest (self, origin, flatpak_decomposed_g et_ref (ref), NULL, cancellable, error); | resolved_ref = flatpak_dir_read_latest (self, origin, flatpak_decomposed_g et_ref (ref), NULL, cancellable, error); | |||
if (resolved_ref == NULL) | if (resolved_ref == NULL) | |||
{ | { | |||
g_prefix_error (error, _("While trying to resolve ref %s: "), flatpak_ decomposed_get_ref (ref)); | g_prefix_error (error, _("While trying to resolve ref %s: "), flatpak_ decomposed_get_ref (ref)); | |||
return FALSE; | return FALSE; | |||
} | } | |||
skipping to change at line 8582 | skipping to change at line 8653 | |||
commit_metadata = g_variant_get_child_value (commit_data, 0); | commit_metadata = g_variant_get_child_value (commit_data, 0); | |||
checkout_basename = flatpak_dir_get_deploy_subdir (self, checksum, subpaths); | checkout_basename = flatpak_dir_get_deploy_subdir (self, checksum, subpaths); | |||
real_checkoutdir = g_file_get_child (deploy_base, checkout_basename); | real_checkoutdir = g_file_get_child (deploy_base, checkout_basename); | |||
if (g_file_query_exists (real_checkoutdir, cancellable)) | if (g_file_query_exists (real_checkoutdir, cancellable)) | |||
return flatpak_fail_error (error, FLATPAK_ERROR_ALREADY_INSTALLED, | return flatpak_fail_error (error, FLATPAK_ERROR_ALREADY_INSTALLED, | |||
_("%s commit %s already installed"), flatpak_deco mposed_get_ref (ref), checksum); | _("%s commit %s already installed"), flatpak_deco mposed_get_ref (ref), checksum); | |||
g_autofree char *template = g_strdup_printf (".%s-XXXXXX", checkout_basename); | g_autofree char *template = g_strdup_printf (".%s-XXXXXX", checkout_basename); | |||
tmp_dir_template = g_file_get_child (deploy_base, template); | ||||
tmp_dir_path = g_file_get_path (tmp_dir_template); | ||||
if (g_mkdtemp_full (tmp_dir_path, 0755) == NULL) | if (!glnx_mkdtempat (deploy_base_dfd, template, 0755, &tmp_dir_handle, NULL)) | |||
{ | { | |||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, | |||
_("Can't create deploy directory")); | _("Can't create deploy directory")); | |||
return FALSE; | return FALSE; | |||
} | } | |||
checkoutdir = g_file_new_for_path (tmp_dir_path); | checkoutdir = g_file_get_child (deploy_base, tmp_dir_handle.path); | |||
if (!ostree_repo_read_commit (self->repo, checksum, &root, NULL, cancellable, error)) | if (!ostree_repo_read_commit (self->repo, checksum, &root, NULL, cancellable, error)) | |||
{ | { | |||
g_prefix_error (error, _("Failed to read commit %s: "), checksum); | g_prefix_error (error, _("Failed to read commit %s: "), checksum); | |||
return FALSE; | return FALSE; | |||
} | } | |||
if (!flatpak_repo_collect_sizes (self->repo, root, &installed_size, NULL, canc ellable, error)) | if (!flatpak_repo_collect_sizes (self->repo, root, &installed_size, NULL, canc ellable, error)) | |||
return FALSE; | return FALSE; | |||
options.mode = OSTREE_REPO_CHECKOUT_MODE_USER; | options.mode = OSTREE_REPO_CHECKOUT_MODE_USER; | |||
options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; | options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; | |||
options.enable_fsync = FALSE; /* We checkout to a temp dir and sync before mov ing it in place */ | options.enable_fsync = FALSE; /* We checkout to a temp dir and sync before mov ing it in place */ | |||
options.bareuseronly_dirs = TRUE; /* https://github.com/ostreedev/ostree/pull/ 927 */ | options.bareuseronly_dirs = TRUE; /* https://github.com/ostreedev/ostree/pull/ 927 */ | |||
checkoutdirpath = g_file_get_path (checkoutdir); | checkoutdirpath = g_file_get_path (checkoutdir); | |||
checkoutdir_basename = tmp_dir_handle.path; /* so checkoutdirpath = deploy_ba se_dfd / checkoutdir_basename */ | ||||
if (subpaths == NULL || *subpaths == NULL) | if (subpaths == NULL || *subpaths == NULL) | |||
{ | { | |||
if (!ostree_repo_checkout_at (self->repo, &options, | if (!ostree_repo_checkout_at (self->repo, &options, | |||
AT_FDCWD, checkoutdirpath, | deploy_base_dfd, checkoutdir_basename, | |||
checksum, | checksum, | |||
cancellable, error)) | cancellable, error)) | |||
{ | { | |||
g_prefix_error (error, _("While trying to checkout %s into %s: "), che cksum, checkoutdirpath); | g_prefix_error (error, _("While trying to checkout %s into %s: "), che cksum, checkoutdirpath); | |||
return FALSE; | return FALSE; | |||
} | } | |||
} | } | |||
else | else | |||
{ | { | |||
g_autoptr(GFile) files = g_file_get_child (checkoutdir, "files"); | g_autoptr(GFile) files = g_file_get_child (checkoutdir, "files"); | |||
int i; | int i; | |||
if (!g_file_make_directory_with_parents (files, cancellable, error)) | if (!g_file_make_directory_with_parents (files, cancellable, error)) | |||
return FALSE; | return FALSE; | |||
options.subpath = "metadata"; | options.subpath = "metadata"; | |||
if (!ostree_repo_checkout_at (self->repo, &options, | if (!ostree_repo_checkout_at (self->repo, &options, | |||
AT_FDCWD, checkoutdirpath, | deploy_base_dfd, checkoutdir_basename, | |||
checksum, | checksum, | |||
cancellable, error)) | cancellable, error)) | |||
{ | { | |||
g_prefix_error (error, _("While trying to checkout metadata subpath: " )); | g_prefix_error (error, _("While trying to checkout metadata subpath: " )); | |||
return FALSE; | return FALSE; | |||
} | } | |||
for (i = 0; subpaths[i] != NULL; i++) | for (i = 0; subpaths[i] != NULL; i++) | |||
{ | { | |||
g_autofree char *subpath = g_build_filename ("files", subpaths[i], NUL L); | g_autofree char *subpath = g_build_filename ("files", subpaths[i], NUL L); | |||
g_autofree char *dstpath = g_build_filename (checkoutdirpath, "/files" , subpaths[i], NULL); | g_autofree char *dstpath = g_build_filename (checkoutdirpath, "/files" , subpaths[i], NULL); | |||
g_autofree char *dstpath_parent = g_path_get_dirname (dstpath); | g_autofree char *dstpath_parent = g_path_get_dirname (dstpath); | |||
g_autofree char *dstpath_relative_to_deploy_base = g_build_filename (c heckoutdir_basename, "/files", subpaths[i], NULL); | ||||
g_autoptr(GFile) child = NULL; | g_autoptr(GFile) child = NULL; | |||
child = g_file_resolve_relative_path (root, subpath); | child = g_file_resolve_relative_path (root, subpath); | |||
if (!g_file_query_exists (child, cancellable)) | if (!g_file_query_exists (child, cancellable)) | |||
{ | { | |||
g_debug ("subpath %s not in tree", subpaths[i]); | g_debug ("subpath %s not in tree", subpaths[i]); | |||
continue; | continue; | |||
} | } | |||
if (g_mkdir_with_parents (dstpath_parent, 0755)) | if (g_mkdir_with_parents (dstpath_parent, 0755)) | |||
{ | { | |||
glnx_set_error_from_errno (error); | glnx_set_error_from_errno (error); | |||
return FALSE; | return FALSE; | |||
} | } | |||
options.subpath = subpath; | options.subpath = subpath; | |||
if (!ostree_repo_checkout_at (self->repo, &options, | if (!ostree_repo_checkout_at (self->repo, &options, | |||
AT_FDCWD, dstpath, | deploy_base_dfd, dstpath_relative_to_dep loy_base, | |||
checksum, | checksum, | |||
cancellable, error)) | cancellable, error)) | |||
{ | { | |||
g_prefix_error (error, _("While trying to checkout subpath ‘%s’: " ), subpath); | g_prefix_error (error, _("While trying to checkout subpath ‘%s’: " ), subpath); | |||
return FALSE; | return FALSE; | |||
} | } | |||
} | } | |||
} | } | |||
/* Extract any extra data */ | /* Extract any extra data */ | |||
skipping to change at line 8878 | skipping to change at line 8949 | |||
/* Check the app is actually allowed to be used by this user. This can block | /* Check the app is actually allowed to be used by this user. This can block | |||
* on getting authorisation. */ | * on getting authorisation. */ | |||
if (!flatpak_dir_check_parental_controls (self, flatpak_decomposed_get_ref (re f), deploy_data, cancellable, error)) | if (!flatpak_dir_check_parental_controls (self, flatpak_decomposed_get_ref (re f), deploy_data, cancellable, error)) | |||
return FALSE; | return FALSE; | |||
deploy_data_file = g_file_get_child (checkoutdir, "deploy"); | deploy_data_file = g_file_get_child (checkoutdir, "deploy"); | |||
if (!flatpak_bytes_save (deploy_data_file, deploy_data, cancellable, error)) | if (!flatpak_bytes_save (deploy_data_file, deploy_data, cancellable, error)) | |||
return FALSE; | return FALSE; | |||
if (!glnx_opendirat (AT_FDCWD, checkoutdirpath, TRUE, &checkoutdir_dfd, error) ) | if (!glnx_opendirat (deploy_base_dfd, checkoutdir_basename, TRUE, &checkoutdir _dfd, error)) | |||
return FALSE; | return FALSE; | |||
if (syncfs (checkoutdir_dfd) != 0) | if (syncfs (checkoutdir_dfd) != 0) | |||
{ | { | |||
glnx_set_error_from_errno (error); | glnx_set_error_from_errno (error); | |||
return FALSE; | return FALSE; | |||
} | } | |||
if (!g_file_move (checkoutdir, real_checkoutdir, G_FILE_COPY_NO_FALLBACK_FOR_M OVE, | if (!g_file_move (checkoutdir, real_checkoutdir, G_FILE_COPY_NO_FALLBACK_FOR_M OVE, | |||
cancellable, NULL, NULL, error)) | cancellable, NULL, NULL, error)) | |||
return FALSE; | return FALSE; | |||
glnx_tmpdir_unset (&tmp_dir_handle); | ||||
if (!flatpak_dir_set_active (self, ref, checkout_basename, cancellable, error) ) | if (!flatpak_dir_set_active (self, ref, checkout_basename, cancellable, error) ) | |||
return FALSE; | return FALSE; | |||
if (!flatpak_dir_update_deploy_ref (self, flatpak_decomposed_get_ref (ref), ch ecksum, error)) | if (!flatpak_dir_update_deploy_ref (self, flatpak_decomposed_get_ref (ref), ch ecksum, error)) | |||
return FALSE; | return FALSE; | |||
return TRUE; | return TRUE; | |||
} | } | |||
/* -origin remotes are deleted when the last ref referring to it is undeployed * / | /* -origin remotes are deleted when the last ref referring to it is undeployed * / | |||
End of changes. 16 change blocks. | ||||
10 lines changed or deleted | 93 lines changed or added |