+/* List of directories whose statuses we need to extract after we've
+ finished extracting their subsidiary files. If you consider each
+ contiguous subsequence of elements of the form [D]?[^D]*, where [D]
+ represents an element where AFTER_LINKS is nonzero and [^D]
+ represents an element where AFTER_LINKS is zero, then the head
+ of the subsequence has the longest name, and each non-head element
+ in the prefix is an ancestor (in the directory hierarchy) of the
+ preceding element. */
+
+struct delayed_set_stat
+ {
+ /* Next directory in list. */
+ struct delayed_set_stat *next;
+
+ /* Metadata for this directory. */
+ dev_t dev;
+ ino_t ino;
+ mode_t mode; /* The desired mode is MODE & ~ current_umask. */
+ uid_t uid;
+ gid_t gid;
+ struct timespec atime;
+ struct timespec mtime;
+
+ /* An estimate of the directory's current mode, along with a mask
+ specifying which bits of this estimate are known to be correct.
+ If CURRENT_MODE_MASK is zero, CURRENT_MODE's value doesn't
+ matter. */
+ mode_t current_mode;
+ mode_t current_mode_mask;
+
+ /* This directory is an intermediate directory that was created
+ as an ancestor of some other directory; it was not mentioned
+ in the archive, so do not set its uid, gid, atime, or mtime,
+ and don't alter its mode outside of MODE_RWX. */
+ bool interdir;
+
+ /* Whether symbolic links should be followed when accessing the
+ directory. */
+ int atflag;
+
+ /* Do not set the status of this directory until after delayed
+ links are created. */
+ bool after_links;
+
+ /* Directory that the name is relative to. */
+ int change_dir;
+
+ /* extended attributes*/
+ char *cntx_name;
+ char *acls_a_ptr;
+ size_t acls_a_len;
+ char *acls_d_ptr;
+ size_t acls_d_len;
+ size_t xattr_map_size;
+ struct xattr_array *xattr_map;
+ /* Length and contents of name. */
+ size_t file_name_len;
+ char file_name[1];
+ };
+
+static struct delayed_set_stat *delayed_set_stat_head;
+
+/* List of links whose creation we have delayed. */
+struct delayed_link
+ {
+ /* The next delayed link in the list. */
+ struct delayed_link *next;
+
+ /* The device, inode number and birthtime of the placeholder.
+ birthtime.tv_nsec is negative if the birthtime is not available.
+ Don't use mtime as this would allow for false matches if some
+ other process removes the placeholder. Don't use ctime as
+ this would cause race conditions and other screwups, e.g.,
+ when restoring hard-linked symlinks. */
+ dev_t dev;
+ ino_t ino;
+ struct timespec birthtime;
+
+ /* True if the link is symbolic. */
+ bool is_symlink;
+
+ /* The desired metadata, valid only the link is symbolic. */
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ struct timespec atime;
+ struct timespec mtime;
+
+ /* The directory that the sources and target are relative to. */
+ int change_dir;
+
+ /* A list of sources for this link. The sources are all to be
+ hard-linked together. */
+ struct string_list *sources;
+
+ /* SELinux context */
+ char *cntx_name;
+
+ /* ACLs */
+ char *acls_a_ptr;
+ size_t acls_a_len;
+ char *acls_d_ptr;
+ size_t acls_d_len;
+
+ size_t xattr_map_size;
+ struct xattr_array *xattr_map;
+
+ /* The desired target of the desired link. */
+ char target[1];
+ };
+
+static struct delayed_link *delayed_link_head;
+
+struct string_list
+ {
+ struct string_list *next;
+ char string[1];
+ };
+
+/* Set up to extract files. */
+void
+extr_init (void)
+{
+ we_are_root = geteuid () == ROOT_UID;
+ same_permissions_option += we_are_root;
+ same_owner_option += we_are_root;
+
+ /* Option -p clears the kernel umask, so it does not affect proper
+ restoration of file permissions. New intermediate directories will
+ comply with umask at start of program. */
+
+ newdir_umask = umask (0);
+ if (0 < same_permissions_option)
+ current_umask = 0;
+ else
+ {
+ umask (newdir_umask); /* restore the kernel umask */
+ current_umask = newdir_umask;
+ }
+}