Add one-line GPL boilerplate to numerous (but not all yet) source files.
[oweals/busybox.git] / archival / libunarchive / data_extract_all.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
4  */
5
6 #include <sys/types.h>
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <utime.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15
16 #include "libbb.h"
17 #include "unarchive.h"
18
19 void data_extract_all(archive_handle_t *archive_handle)
20 {
21         file_header_t *file_header = archive_handle->file_header;
22         int dst_fd;
23         int res;
24
25         if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) {
26                 char *name = bb_xstrdup(file_header->name);
27                 bb_make_directory (dirname(name), -1, FILEUTILS_RECUR);
28                 free(name);
29         }
30
31         /* Check if the file already exists */
32         if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
33                 /* Remove the existing entry if it exists */
34                 if (((file_header->mode & S_IFMT) != S_IFDIR) && (unlink(file_header->name) == -1) && (errno != ENOENT)) {
35                         bb_perror_msg_and_die("Couldnt remove old file");
36                 }
37         }
38         else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) {
39                 /* Remove the existing entry if its older than the extracted entry */
40                 struct stat statbuf;
41                 if (lstat(file_header->name, &statbuf) == -1) {
42                         if (errno != ENOENT) {
43                                 bb_perror_msg_and_die("Couldnt stat old file");
44                         }
45                 }
46                 else if (statbuf.st_mtime <= file_header->mtime) {
47                         if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
48                                 bb_error_msg("%s not created: newer or same age file exists", file_header->name);
49                         }
50                         data_skip(archive_handle);
51                         return;
52                 }
53                 else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
54                         bb_perror_msg_and_die("Couldnt remove old file %s", file_header->name);
55                 }
56         }
57
58         /* Handle hard links separately
59          * We identified hard links as regular files of size 0 with a symlink */
60         if (S_ISREG(file_header->mode) && (file_header->link_name) && (file_header->size == 0)) {
61                 /* hard link */
62                 res = link(file_header->link_name, file_header->name);
63                 if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
64                         bb_perror_msg("Couldnt create hard link");
65                 }
66         } else {
67                 /* Create the filesystem entry */
68                 switch(file_header->mode & S_IFMT) {
69                         case S_IFREG: {
70                                 /* Regular file */
71                                 dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL);
72                                 bb_copyfd_size(archive_handle->src_fd, dst_fd, file_header->size);
73                                 close(dst_fd);
74                                 break;
75                                 }
76                         case S_IFDIR:
77                                 res = mkdir(file_header->name, file_header->mode);
78                                 if ((errno != EISDIR) && (res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
79                                         bb_perror_msg("extract_archive: %s", file_header->name);
80                                 }
81                                 break;
82                         case S_IFLNK:
83                                 /* Symlink */
84                                 res = symlink(file_header->link_name, file_header->name);
85                                 if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
86                                         bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name);
87                                 }
88                                 break;
89                         case S_IFSOCK:
90                         case S_IFBLK:
91                         case S_IFCHR:
92                         case S_IFIFO:
93                                 res = mknod(file_header->name, file_header->mode, file_header->device);
94                                 if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
95                                         bb_perror_msg("Cannot create node %s", file_header->name);
96                                 }
97                                 break;
98                         default:
99                                 bb_error_msg_and_die("Unrecognised file type");
100                 }
101         }
102
103         if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) {
104                 lchown(file_header->name, file_header->uid, file_header->gid);
105         }
106         if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM) &&
107                  (file_header->mode & S_IFMT) != S_IFLNK)
108         {
109                 chmod(file_header->name, file_header->mode);
110         }
111
112         if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) {
113                 struct utimbuf t;
114                 t.actime = t.modtime = file_header->mtime;
115                 utime(file_header->name, &t);
116         }
117 }