static gboolean relabel_one_path (OstreeSePolicy *sepolicy, GFile *path, GFileInfo *info, GPtrArray *path_parts, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autofree char *relpath = NULL; g_autofree char *new_label = NULL; relpath = ptrarray_path_join (path_parts); if (!ostree_sepolicy_restorecon (sepolicy, relpath, info, path, OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL | OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING, &new_label, cancellable, error)) { g_prefix_error (error, "Setting context of %s: ", gs_file_get_path_cached (path)); goto out; } if (new_label) g_print ("Set label of '%s' (as '%s') to '%s'\n", gs_file_get_path_cached (path), relpath, new_label); ret = TRUE; out: return ret; }
static gboolean chown_internal (GFile *path, gboolean dereference_links, guint32 owner, guint32 group, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int res; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; do if (dereference_links) res = chown (gs_file_get_path_cached (path), owner, group); else res = lchown (gs_file_get_path_cached (path), owner, group); while (G_UNLIKELY (res != 0 && errno == EINTR)); if (res < 0) { gs_set_prefix_error_from_errno (error, errno, "chown"); goto out; } ret = TRUE; out: return ret; }
/** * rpmostree_prepare_rootfs_for_commit: * * Walk over the root filesystem and perform some core conversions * from RPM conventions to OSTree conventions. For example: * * * Move /etc to /usr/etc * * Checksum the kernel in /boot * * Migrate content in /var to systemd-tmpfiles */ gboolean rpmostree_prepare_rootfs_for_commit (GFile *rootfs, JsonObject *treefile, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_free char *dest_rootfs_path = NULL; dest_rootfs_path = g_strconcat (gs_file_get_path_cached (rootfs), ".post", NULL); if (!glnx_shutil_rm_rf_at (AT_FDCWD, dest_rootfs_path, cancellable, error)) goto out; { gs_unref_object GFile *dest_rootfs = g_file_new_for_path (dest_rootfs_path); if (!create_rootfs_from_yumroot_content (dest_rootfs, rootfs, treefile, cancellable, error)) goto out; } if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (rootfs), cancellable, error)) goto out; if (TEMP_FAILURE_RETRY (renameat (AT_FDCWD, dest_rootfs_path, AT_FDCWD, gs_file_get_path_cached (rootfs))) != 0) { glnx_set_error_from_errno (error); goto out; } ret = TRUE; out: return ret; }
char * ot_editor_prompt (OstreeRepo *repo, const char *input, GCancellable *cancellable, GError **error) { glnx_unref_object GSubprocess *proc = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GFileIOStream) io = NULL; GOutputStream *output; const char *editor; char *ret = NULL; g_autofree char *args = NULL; editor = get_editor (); if (editor == NULL) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Terminal is dumb, but EDITOR unset"); goto out; } file = g_file_new_tmp (NULL, &io, error); if (file == NULL) goto out; output = g_io_stream_get_output_stream (G_IO_STREAM (io)); if (!g_output_stream_write_all (output, input, strlen (input), NULL, cancellable, error) || !g_io_stream_close (G_IO_STREAM (io), cancellable, error)) goto out; { g_autofree char *quoted_file = g_shell_quote (gs_file_get_path_cached (file)); args = g_strconcat (editor, " ", quoted_file, NULL); } proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_INHERIT, error, "/bin/sh", "-c", args, NULL); if (!g_subprocess_wait_check (proc, cancellable, error)) { g_prefix_error (error, "There was a problem with the editor '%s'", editor); goto out; } ret = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (file), NULL, cancellable, error); out: if (file) (void )g_file_delete (file, NULL, NULL); return ret; }
/** * rpmostree_prepare_rootfs_for_commit: * * Walk over the root filesystem and perform some core conversions * from RPM conventions to OSTree conventions. For example: * * * Move /etc to /usr/etc * * Checksum the kernel in /boot * * Migrate content in /var to systemd-tmpfiles */ gboolean rpmostree_prepare_rootfs_for_commit (GFile *rootfs, JsonObject *treefile, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFile *rootfs_tmp = NULL; gs_free char *rootfs_tmp_path = NULL; rootfs_tmp_path = g_strconcat (gs_file_get_path_cached (rootfs), ".tmp", NULL); rootfs_tmp = g_file_new_for_path (rootfs_tmp_path); if (!gs_shutil_rm_rf (rootfs_tmp, cancellable, error)) goto out; if (!create_rootfs_from_yumroot_content (rootfs_tmp, rootfs, treefile, cancellable, error)) goto out; if (!gs_shutil_rm_rf (rootfs, cancellable, error)) goto out; if (!gs_file_rename (rootfs_tmp, rootfs, cancellable, error)) goto out; ret = TRUE; out: return ret; }
/** * gs_file_read_noatime: * @file: a #GFile * @cancellable: a #GCancellable * @error: a #GError * * Like g_file_read(), but try to avoid updating the file's * access time. This should be used by background scanning * components such as search indexers, antivirus programs, etc. * * Returns: (transfer full): A new input stream, or %NULL on error */ GInputStream * gs_file_read_noatime (GFile *file, GCancellable *cancellable, GError **error) { const char *path = NULL; int fd; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; path = gs_file_get_path_cached (file); if (path == NULL) { char *uri; uri = g_file_get_uri (file); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "%s has no associated path", uri); g_free (uri); return NULL; } if (!gs_file_openat_noatime (AT_FDCWD, path, &fd, cancellable, error)) return NULL; return g_unix_input_stream_new (fd, TRUE); }
static gboolean prepare_root_ssh (GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GFile *root_ssh_path = g_file_new_for_path ("/root/.ssh"); if (!g_file_query_exists (root_ssh_path, NULL)) { if (!g_file_make_directory (root_ssh_path, cancellable, error)) goto out; if (!gs_file_chmod (root_ssh_path, 0700, cancellable, error)) goto out; /* Ignore errors here to be simple, otherwise we'd have to link * to libselinux etc. */ (void) gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_NULL, cancellable, error, "restorecon", gs_file_get_path_cached (root_ssh_path), NULL); } ret = TRUE; out: return ret; }
/** * gs_file_chmod: * @path: Path to file * @mode: UNIX mode * @cancellable: a #GCancellable * @error: a #GError * * Merely wraps UNIX chmod(). * * Returns: %TRUE on success, %FALSE on error */ gboolean gs_file_chmod (GFile *path, guint mode, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int res; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; do res = chmod (gs_file_get_path_cached (path), mode); while (G_UNLIKELY (res != 0 && errno == EINTR)); if (res < 0) { gs_set_prefix_error_from_errno (error, errno, "chmod"); goto out; } ret = TRUE; out: return ret; }
/** * gs_shutil_rm_rf: * @path: A file or directory * @cancellable: * @error: * * Recursively delete the filename referenced by @path; it may be a * file or directory. No error is thrown if @path does not exist. */ gboolean gs_shutil_rm_rf (GFile *path, GCancellable *cancellable, GError **error) { return gs_shutil_rm_rf_at (-1, gs_file_get_path_cached (path), cancellable, error); }
/** * ot_gfile_replace_contents_fsync: * * Like g_file_replace_contents(), except always uses fdatasync(). */ gboolean ot_gfile_replace_contents_fsync (GFile *path, GBytes *contents, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int parent_dfd; const char *target_basename = gs_file_get_basename_cached (path); g_autoptr(GFile) parent = NULL; parent = g_file_get_parent (path); if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (parent), TRUE, &parent_dfd, error)) goto out; if (!ot_file_replace_contents_at (parent_dfd, target_basename, contents, TRUE, cancellable, error)) goto out; ret = TRUE; out: if (parent_dfd != -1) (void) close (parent_dfd); return ret; }
/** * gs_file_create: * @file: Path to non-existent file * @mode: Unix access permissions * @out_stream: (out) (transfer full) (allow-none): Newly created output, or %NULL * @cancellable: a #GCancellable * @error: a #GError * * Like g_file_create(), except this function allows specifying the * access mode. This allows atomically creating private files. */ gboolean gs_file_create (GFile *file, int mode, GOutputStream **out_stream, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int fd; GOutputStream *ret_stream = NULL; fd = open_nointr (gs_file_get_path_cached (file), O_WRONLY | O_CREAT | O_EXCL, mode); if (fd < 0) { gs_set_prefix_error_from_errno (error, errno, "open"); goto out; } if (fchmod (fd, mode) < 0) { close (fd); gs_set_prefix_error_from_errno (error, errno, "fchmod"); goto out; } ret_stream = g_unix_output_stream_new (fd, TRUE); ret = TRUE; gs_transfer_out_value (out_stream, &ret_stream); out: g_clear_object (&ret_stream); return ret; }
/** * ot_util_ensure_directory_and_fsync: * @dir: Path to a directory * @cancellable: Cancellable * @error: Error * * Create @dir (and all intermediate parent directories), ensuring * that all entries are on disk. */ gboolean ot_util_ensure_directory_and_fsync (GFile *dir, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int parentfd = -1; const char *basename = gs_file_get_basename_cached (dir); g_autoptr(GFile) parent = g_file_get_parent (dir); again: parentfd = open (gs_file_get_path_cached (parent), O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC); if (parentfd == -1) { if (errno == ENOENT) { if (!ot_util_ensure_directory_and_fsync (parent, cancellable, error)) goto out; goto again; } else { int errsv = errno; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), "opendir: %s", g_strerror (errsv)); goto out; } } if (mkdirat (parentfd, basename, 0777) == -1) { if (errno == EEXIST) { ; } else { int errsv = errno; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), "mkdirat: %s", g_strerror (errsv)); goto out; } } if (fsync (parentfd) == -1) { int errsv = errno; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), "fsync: %s", g_strerror (errsv)); goto out; } ret = TRUE; out: if (parentfd != -1) (void) close (parentfd); return ret; }
/** * ostree_sysroot_get_deployment_origin_path: * @deployment_path: A deployment path * * Returns: (transfer full): Path to deployment origin file */ GFile * ostree_sysroot_get_deployment_origin_path (GFile *deployment_path) { g_autoptr(GFile) deployment_parent = g_file_get_parent (deployment_path); return ot_gfile_resolve_path_printf (deployment_parent, "%s.origin", gs_file_get_path_cached (deployment_path)); }
gboolean rpmostree_get_pkglist_for_root (GFile *root, HySack *out_sack, HyPackageList *out_pkglist, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int rc; _cleanup_hysack_ HySack sack = NULL; _cleanup_hyquery_ HyQuery query = NULL; _cleanup_hypackagelist_ HyPackageList pkglist = NULL; #if BUILDOPT_HAWKEY_SACK_CREATE2 sack = hy_sack_create (NULL, NULL, gs_file_get_path_cached (root), NULL, HY_MAKE_CACHE_DIR); #else sack = hy_sack_create (NULL, NULL, gs_file_get_path_cached (root), HY_MAKE_CACHE_DIR); #endif if (sack == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to create sack cache"); goto out; } rc = hy_sack_load_system_repo (sack, NULL, 0); if (!hif_error_set_from_hawkey (rc, error)) { g_prefix_error (error, "Failed to load system repo: "); goto out; } query = hy_query_create (sack); hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME); pkglist = hy_query_run (query); ret = TRUE; gs_transfer_out_value (out_sack, &sack); gs_transfer_out_value (out_pkglist, &pkglist); out: return ret; }
/** * gs_file_rename: * @from: Current path * @to: New path * @cancellable: a #GCancellable * @error: a #GError * * This function wraps the raw Unix function rename(). * * Returns: %TRUE on success, %FALSE on error */ gboolean gs_file_rename (GFile *from, GFile *to, GCancellable *cancellable, GError **error) { if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; if (rename (gs_file_get_path_cached (from), gs_file_get_path_cached (to)) < 0) { gs_set_prefix_error_from_errno (error, errno, "rename"); return FALSE; } return TRUE; }
gboolean ostree_bootconfig_parser_parse (OstreeBootconfigParser *self, GFile *path, GCancellable *cancellable, GError **error) { return ostree_bootconfig_parser_parse_at (self, AT_FDCWD, gs_file_get_path_cached (path), cancellable, error); }
static gboolean copy_exports (GFile *source, GFile *destination, const char *source_prefix, const char *required_prefix, GCancellable *cancellable, GError **error) { if (!gs_file_ensure_directory (destination, TRUE, cancellable, error)) return FALSE; /* The fds are closed by this call */ if (!export_dir (AT_FDCWD, gs_file_get_path_cached (source), source_prefix, AT_FDCWD, gs_file_get_path_cached (destination), required_prefix, cancellable, error)) return FALSE; return TRUE; }
/** * gs_file_set_all_xattrs: * @file: File descriptor * @xattrs: Extended attributes * @cancellable: Cancellable * @error: Error * * For each attribute in @xattrs, set its value on the file or * directory referred to by @file. This function does not remove any * attributes not in @xattrs. */ gboolean gs_file_set_all_xattrs (GFile *file, GVariant *xattrs, GCancellable *cancellable, GError **error) { return glnx_dfd_name_set_all_xattrs (AT_FDCWD, gs_file_get_path_cached (file), xattrs, cancellable, error); }
static gboolean ensure_sysroot_fd (OstreeSysroot *self, GError **error) { if (self->sysroot_fd == -1) { if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->path), TRUE, &self->sysroot_fd, error)) return FALSE; } return TRUE; }
/** * gs_file_unlink: * @path: Path to file * @cancellable: a #GCancellable * @error: a #GError * * Like g_file_delete(), except this function does not follow Unix * symbolic links, and will delete a symbolic link even if it's * pointing to a nonexistent file. In other words, this function * merely wraps the raw Unix function unlink(). * * Returns: %TRUE on success, %FALSE on error */ gboolean gs_file_unlink (GFile *path, GCancellable *cancellable, GError **error) { if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; if (unlink (gs_file_get_path_cached (path)) < 0) { gs_set_prefix_error_from_errno (error, errno, "unlink"); return FALSE; } return TRUE; }
static void print_diff_item (char prefix, GFile *base, GFile *file) { if (g_file_is_native (file)) { g_autofree char *relpath = g_file_get_relative_path (base, file); g_print ("%c %s\n", prefix, relpath); } else { g_print ("%c %s\n", prefix, gs_file_get_path_cached (file)); } }
/** * gs_file_open_dir_fd: * @path: Directory name * @out_fd: (out): File descriptor for directory * @cancellable: Cancellable * @error: Error * * On success, sets @out_fd to a file descriptor for the directory * that can be used with UNIX functions such as openat(). */ gboolean gs_file_open_dir_fd (GFile *path, int *out_fd, GCancellable *cancellable, GError **error) { /* Linux specific probably */ *out_fd = open (gs_file_get_path_cached (path), O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC); if (*out_fd == -1) { gs_set_prefix_error_from_errno (error, errno, "open"); return FALSE; } return TRUE; }
/** * gs_file_ensure_directory_mode: * @dir: Path to create as directory * @mode: Create directory with these permissions * @cancellable: a #GCancellable * @error: a #GError * * Wraps UNIX mkdir() function with support for @cancellable, and * uses @error instead of errno. */ gboolean gs_file_ensure_directory_mode (GFile *dir, guint mode, GCancellable *cancellable, GError **error) { if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; if (mkdir (gs_file_get_path_cached (dir), mode) == -1 && errno != EEXIST) { gs_set_prefix_error_from_errno (error, errno, "mkdir"); return FALSE; } return TRUE; }
/** * rpmostreed_sysroot_populate : * * loads internals and starts monitoring * * Returns: True on success */ gboolean rpmostreed_sysroot_populate (RpmostreedSysroot *self, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GFile) sysroot_file = NULL; const char *sysroot_path; g_return_val_if_fail (self != NULL, FALSE); sysroot_path = rpmostree_sysroot_get_path (RPMOSTREE_SYSROOT (self)); sysroot_file = g_file_new_for_path (sysroot_path); self->ot_sysroot = ostree_sysroot_new (sysroot_file); /* This creates and caches an OstreeRepo instance inside * OstreeSysroot to ensure subsequent ostree_sysroot_get_repo() * calls won't fail. */ if (!ostree_sysroot_get_repo (self->ot_sysroot, &self->repo, cancellable, error)) goto out; if (!sysroot_populate_deployments_unlocked (self, NULL, error)) goto out; if (self->monitor == NULL) { const char *sysroot_path = gs_file_get_path_cached (ostree_sysroot_get_path (self->ot_sysroot)); g_autofree char *sysroot_deploy_path = g_build_filename (sysroot_path, "ostree/deploy", NULL); g_autoptr(GFile) sysroot_deploy = g_file_new_for_path (sysroot_deploy_path); self->monitor = g_file_monitor (sysroot_deploy, 0, NULL, error); if (self->monitor == NULL) goto out; self->sig_changed = g_signal_connect (self->monitor, "changed", G_CALLBACK (on_deploy_changed), self); } ret = TRUE; out: return ret; }
/** * gs_file_ensure_directory: * @dir: Path to create as directory * @with_parents: Also create parent directories * @cancellable: a #GCancellable * @error: a #GError * * Like g_file_make_directory(), except does not throw an error if the * directory already exists. */ gboolean gs_file_ensure_directory (GFile *dir, gboolean with_parents, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GError *temp_error = NULL; GFile *parent = NULL; if (!g_file_make_directory (dir, cancellable, &temp_error)) { if (with_parents && g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { parent = g_file_get_parent (dir); if (parent) { g_clear_error (&temp_error); if (!glnx_shutil_mkdir_p_at (AT_FDCWD, gs_file_get_path_cached (parent), 0777, cancellable, error)) goto out; } if (!gs_file_ensure_directory (dir, FALSE, cancellable, error)) goto out; } else if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { g_propagate_error (error, temp_error); goto out; } else g_clear_error (&temp_error); } ret = TRUE; out: g_clear_object (&parent); return ret; }
static gboolean get_file_checksum (OstreeDiffFlags flags, GFile *f, GFileInfo *f_info, char **out_checksum, GCancellable *cancellable, GError **error) { g_autofree char *ret_checksum = NULL; if (OSTREE_IS_REPO_FILE (f)) { ret_checksum = g_strdup (ostree_repo_file_get_checksum ((OstreeRepoFile*)f)); } else { g_autoptr(GVariant) xattrs = NULL; g_autoptr(GInputStream) in = NULL; if (!(flags & OSTREE_DIFF_FLAGS_IGNORE_XATTRS)) { if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f), &xattrs, cancellable, error)) return FALSE; } if (g_file_info_get_file_type (f_info) == G_FILE_TYPE_REGULAR) { in = (GInputStream*)g_file_read (f, cancellable, error); if (!in) return FALSE; } g_autofree guchar *csum = NULL; if (!ostree_checksum_file_from_input (f_info, xattrs, in, OSTREE_OBJECT_TYPE_FILE, &csum, cancellable, error)) return FALSE; ret_checksum = ostree_checksum_from_bytes (csum); } ot_transfer_out_value(out_checksum, &ret_checksum); return TRUE; }
/* Given a directory @d, find the first child that is a directory, * returning it in @out_subdir. If there are multiple directories, * return an error. */ static gboolean find_ensure_one_subdirectory (GFile *d, GFile **out_subdir, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gs_unref_object GFileEnumerator *direnum = NULL; gs_unref_object GFile *ret_subdir = NULL; direnum = g_file_enumerate_children (d, "standard::name,standard::type", 0, cancellable, error); if (!direnum) goto out; while (TRUE) { GFileInfo *file_info; GFile *child; if (!gs_file_enumerator_iterate (direnum, &file_info, &child, cancellable, error)) goto out; if (!file_info) break; if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { if (ret_subdir) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Multiple subdirectories found in: %s", gs_file_get_path_cached (d)); goto out; } ret_subdir = g_object_ref (child); } } ret = TRUE; gs_transfer_out_value (out_subdir, &ret_subdir); out: return ret; }
/** * gs_file_map_readonly: * @file: a #GFile * @cancellable: * @error: * * Return a #GBytes which references a readonly view of the contents of * @file. This function uses #GMappedFile internally. * * Returns: (transfer full): a newly referenced #GBytes */ GBytes * gs_file_map_readonly (GFile *file, GCancellable *cancellable, GError **error) { GMappedFile *mfile; GBytes *ret; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; mfile = g_mapped_file_new (gs_file_get_path_cached (file), FALSE, error); if (!mfile) return NULL; ret = g_mapped_file_get_bytes (mfile); g_mapped_file_unref (mfile); return ret; }
static void ostree_sysroot_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { OstreeSysroot *self = OSTREE_SYSROOT (object); switch (prop_id) { case PROP_PATH: /* Canonicalize */ self->path = g_file_new_for_path (gs_file_get_path_cached (g_value_get_object (value))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/** * gs_file_sync_data: * @file: a #GFile * @cancellable: * @error: * * Wraps the UNIX fsync() function (or fdatasync(), if available), which * ensures that the data in @file is on non-volatile storage. */ gboolean gs_file_sync_data (GFile *file, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int res; int fd = -1; if (!gs_file_openat_noatime (AT_FDCWD, gs_file_get_path_cached (file), &fd, cancellable, error)) goto out; do { #ifdef __linux res = fdatasync (fd); #else res = fsync (fd); #endif } while (G_UNLIKELY (res != 0 && errno == EINTR)); if (res != 0) { gs_set_prefix_error_from_errno (error, errno, "fdatasync"); goto out; } res = close_nointr (fd); if (res != 0) { gs_set_prefix_error_from_errno (error, errno, "close"); goto out; } fd = -1; ret = TRUE; out: if (fd != -1) close_nointr_noerror (fd); return ret; }