source: mainline/uspace/lib/untar/untar.c@ 41408d94

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 41408d94 was f47c2dc1, checked in by jxsvoboda <5887334+jxsvoboda@…>, 6 years ago

removed some trailing whitespace

  • Property mode set to 100644
File size: 4.7 KB
Line 
1/*
2 * Copyright (c) 2013 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libuntar
30 * @{
31 */
32/** @file
33 */
34
35#include <stdlib.h>
36#include <stdio.h>
37#include <stdarg.h>
38#include <str_error.h>
39#include <vfs/vfs.h>
40#include "private/tar.h"
41#include "untar.h"
42
43static size_t get_block_count(size_t bytes)
44{
45 return (bytes + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE;
46}
47
48static int tar_open(tar_file_t *tar)
49{
50 return tar->open(tar);
51}
52
53static void tar_close(tar_file_t *tar)
54{
55 tar->close(tar);
56}
57
58static size_t tar_read(tar_file_t *tar, void *data, size_t size)
59{
60 return tar->read(tar, data, size);
61}
62
63static void tar_report(tar_file_t *tar, const char *fmt, ...)
64{
65 va_list args;
66 va_start(args, fmt);
67
68 tar->vreport(tar, fmt, args);
69
70 va_end(args);
71}
72
73static errno_t tar_skip_blocks(tar_file_t *tar, size_t valid_data_size)
74{
75 size_t blocks_to_read = get_block_count(valid_data_size);
76
77 while (blocks_to_read > 0) {
78 uint8_t block[TAR_BLOCK_SIZE];
79 size_t actually_read = tar_read(tar, block, TAR_BLOCK_SIZE);
80 if (actually_read != TAR_BLOCK_SIZE)
81 return errno;
82
83 blocks_to_read--;
84 }
85
86 return EOK;
87}
88
89static errno_t tar_handle_normal_file(tar_file_t *tar,
90 const tar_header_t *header)
91{
92 // FIXME: create the directory first
93
94 FILE *file = fopen(header->filename, "wb");
95 if (file == NULL) {
96 tar_report(tar, "Failed to create %s: %s.\n", header->filename,
97 str_error(errno));
98 return errno;
99 }
100
101 errno_t rc = EOK;
102 size_t bytes_remaining = header->size;
103 size_t blocks = get_block_count(bytes_remaining);
104
105 while (blocks > 0) {
106 uint8_t block[TAR_BLOCK_SIZE];
107 size_t actually_read = tar_read(tar, block, TAR_BLOCK_SIZE);
108 if (actually_read != TAR_BLOCK_SIZE) {
109 rc = errno;
110 tar_report(tar, "Failed to read block for %s: %s.\n",
111 header->filename, str_error(rc));
112 break;
113 }
114
115 size_t to_write = TAR_BLOCK_SIZE;
116 if (bytes_remaining < TAR_BLOCK_SIZE)
117 to_write = bytes_remaining;
118
119 size_t actually_written = fwrite(block, 1, to_write, file);
120 if (actually_written != to_write) {
121 rc = errno;
122 tar_report(tar, "Failed to write to %s: %s.\n",
123 header->filename, str_error(rc));
124 break;
125 }
126
127 blocks--;
128 bytes_remaining -= TAR_BLOCK_SIZE;
129 }
130
131 fclose(file);
132 return rc;
133}
134
135static errno_t tar_handle_directory(tar_file_t *tar, const tar_header_t *header)
136{
137 errno_t rc = vfs_link_path(header->filename, KIND_DIRECTORY, NULL);
138 if (rc != EOK) {
139 if (rc != EEXIST) {
140 tar_report(tar, "Failed to create directory %s: %s.\n",
141 header->filename, str_error(rc));
142 return rc;
143 }
144 }
145
146 return tar_skip_blocks(tar, header->size);
147}
148
149int untar(tar_file_t *tar)
150{
151 int rc = tar_open(tar);
152 if (rc != EOK) {
153 tar_report(tar, "Failed to open: %s.\n", str_error(rc));
154 return rc;
155 }
156
157 while (true) {
158 tar_header_raw_t header_raw;
159 size_t header_ok = tar_read(tar, &header_raw, sizeof(header_raw));
160 if (header_ok != sizeof(header_raw))
161 break;
162
163 tar_header_t header;
164 errno_t rc = tar_header_parse(&header, &header_raw);
165 if (rc == EEMPTY)
166 continue;
167
168 if (rc != EOK) {
169 tar_report(tar, "Failed parsing TAR header: %s.\n", str_error(rc));
170 break;
171 }
172
173 switch (header.type) {
174 case TAR_TYPE_DIRECTORY:
175 rc = tar_handle_directory(tar, &header);
176 break;
177 case TAR_TYPE_NORMAL:
178 rc = tar_handle_normal_file(tar, &header);
179 break;
180 default:
181 rc = tar_skip_blocks(tar, header.size);
182 break;
183 }
184
185 if (rc != EOK)
186 break;
187 }
188
189 tar_close(tar);
190 return EOK;
191}
192
193/** @}
194 */
Note: See TracBrowser for help on using the repository browser.