tar: add support for PAX-encoded path=LONGFILENAME
[platform/upstream/busybox.git] / archival / libarchive / data_extract_to_command.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4  */
5
6 #include "libbb.h"
7 #include "bb_archive.h"
8
9 enum {
10         //TAR_FILETYPE,
11         TAR_MODE,
12         TAR_FILENAME,
13         TAR_REALNAME,
14 #if ENABLE_FEATURE_TAR_UNAME_GNAME
15         TAR_UNAME,
16         TAR_GNAME,
17 #endif
18         TAR_SIZE,
19         TAR_UID,
20         TAR_GID,
21         TAR_MAX,
22 };
23
24 static const char *const tar_var[] = {
25         // "FILETYPE",
26         "MODE",
27         "FILENAME",
28         "REALNAME",
29 #if ENABLE_FEATURE_TAR_UNAME_GNAME
30         "UNAME",
31         "GNAME",
32 #endif
33         "SIZE",
34         "UID",
35         "GID",
36 };
37
38 static void xputenv(char *str)
39 {
40         if (putenv(str))
41                 bb_error_msg_and_die(bb_msg_memory_exhausted);
42 }
43
44 static void str2env(char *env[], int idx, const char *str)
45 {
46         env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str);
47         xputenv(env[idx]);
48 }
49
50 static void dec2env(char *env[], int idx, unsigned long long val)
51 {
52         env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val);
53         xputenv(env[idx]);
54 }
55
56 static void oct2env(char *env[], int idx, unsigned long val)
57 {
58         env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val);
59         xputenv(env[idx]);
60 }
61
62 void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
63 {
64         file_header_t *file_header = archive_handle->file_header;
65
66 #if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
67         char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
68         if (!sctx)
69                 sctx = archive_handle->tar__sctx[PAX_GLOBAL];
70         if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
71                 setfscreatecon(sctx);
72                 free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
73                 archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
74         }
75 #endif
76
77         if ((file_header->mode & S_IFMT) == S_IFREG) {
78                 pid_t pid;
79                 int p[2], status;
80                 char *tar_env[TAR_MAX];
81
82                 memset(tar_env, 0, sizeof(tar_env));
83
84                 xpipe(p);
85                 pid = BB_MMU ? xfork() : xvfork();
86                 if (pid == 0) {
87                         /* Child */
88                         /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */
89                         oct2env(tar_env, TAR_MODE, file_header->mode);
90                         str2env(tar_env, TAR_FILENAME, file_header->name);
91                         str2env(tar_env, TAR_REALNAME, file_header->name);
92 #if ENABLE_FEATURE_TAR_UNAME_GNAME
93                         str2env(tar_env, TAR_UNAME, file_header->tar__uname);
94                         str2env(tar_env, TAR_GNAME, file_header->tar__gname);
95 #endif
96                         dec2env(tar_env, TAR_SIZE, file_header->size);
97                         dec2env(tar_env, TAR_UID, file_header->uid);
98                         dec2env(tar_env, TAR_GID, file_header->gid);
99                         close(p[1]);
100                         xdup2(p[0], STDIN_FILENO);
101                         signal(SIGPIPE, SIG_DFL);
102                         execl(archive_handle->tar__to_command_shell,
103                                 archive_handle->tar__to_command_shell,
104                                 "-c",
105                                 archive_handle->tar__to_command,
106                                 NULL);
107                         bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
108                 }
109                 close(p[0]);
110                 /* Our caller is expected to do signal(SIGPIPE, SIG_IGN)
111                  * so that we don't die if child don't read all the input: */
112                 bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size);
113                 close(p[1]);
114
115                 if (safe_waitpid(pid, &status, 0) == -1)
116                         bb_perror_msg_and_die("waitpid");
117                 if (WIFEXITED(status) && WEXITSTATUS(status))
118                         bb_error_msg_and_die("'%s' returned status %d",
119                                 archive_handle->tar__to_command, WEXITSTATUS(status));
120                 if (WIFSIGNALED(status))
121                         bb_error_msg_and_die("'%s' terminated on signal %d",
122                                 archive_handle->tar__to_command, WTERMSIG(status));
123
124                 if (!BB_MMU) {
125                         int i;
126                         for (i = 0; i < TAR_MAX; i++) {
127                                 if (tar_env[i])
128                                         bb_unsetenv_and_free(tar_env[i]);
129                         }
130                 }
131         }
132
133 #if 0 /* ENABLE_FEATURE_TAR_SELINUX */
134         if (sctx)
135                 /* reset the context after creating an entry */
136                 setfscreatecon(NULL);
137 #endif
138 }