source: mainline/uspace/app/untar/main.c@ 6e5562a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6e5562a was 6e5562a, checked in by Jakub Jermar <jakub@…>, 8 years ago

Introduce vfs_link_path() and replace mkdir() with it

  • Property mode set to 100644
File size: 4.6 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 untar
30 * @{
31 */
32/** @file
33 */
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <errno.h>
38#include <str_error.h>
39#include <vfs/vfs.h>
40#include "tar.h"
41
42static size_t get_block_count(size_t bytes) {
43 return (bytes + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE;
44}
45
46static int skip_blocks(FILE *tarfile, size_t valid_data_size)
47{
48 size_t blocks_to_read = get_block_count(valid_data_size);
49 while (blocks_to_read > 0) {
50 uint8_t block[TAR_BLOCK_SIZE];
51 size_t actually_read = fread(block, TAR_BLOCK_SIZE, 1, tarfile);
52 if (actually_read != 1) {
53 return errno;
54 }
55 blocks_to_read--;
56 }
57 return EOK;
58}
59
60static int handle_normal_file(const tar_header_t *header, FILE *tarfile)
61{
62 // FIXME: create the directory first
63
64 FILE *file = fopen(header->filename, "wb");
65 if (file == NULL) {
66 fprintf(stderr, "Failed to create %s: %s.\n", header->filename,
67 str_error(errno));
68 return errno;
69 }
70
71 int rc = EOK;
72 size_t bytes_remaining = header->size;
73 size_t blocks = get_block_count(bytes_remaining);
74 while (blocks > 0) {
75 uint8_t block[TAR_BLOCK_SIZE];
76 size_t actually_read = fread(block, 1, TAR_BLOCK_SIZE, tarfile);
77 if (actually_read != TAR_BLOCK_SIZE) {
78 rc = errno;
79 fprintf(stderr, "Failed to read block for %s: %s.\n",
80 header->filename, str_error(rc));
81 break;
82 }
83 size_t to_write = TAR_BLOCK_SIZE;
84 if (bytes_remaining < TAR_BLOCK_SIZE) {
85 to_write = bytes_remaining;
86 }
87 size_t actually_written = fwrite(block, 1, to_write, file);
88 if (actually_written != to_write) {
89 rc = errno;
90 fprintf(stderr, "Failed to write to %s: %s.\n",
91 header->filename, str_error(rc));
92 break;
93 }
94 blocks--;
95 bytes_remaining -= TAR_BLOCK_SIZE;
96 }
97
98 fclose(file);
99
100 return rc;
101}
102
103static int handle_directory(const tar_header_t *header, FILE *tarfile)
104{
105 int rc;
106
107 rc = vfs_link_path(header->filename, KIND_DIRECTORY);
108 if (rc != EOK) {
109 if (rc != EEXIST) {
110 fprintf(stderr, "Failed to create directory %s: %s.\n",
111 header->filename, str_error(rc));
112 return rc;
113 }
114 }
115
116 return skip_blocks(tarfile, header->size);
117}
118
119int main(int argc, char *argv[])
120{
121 if (argc != 2) {
122 fprintf(stderr, "Usage: %s tar-file\n", argv[0]);
123 return 1;
124 }
125
126 const char *filename = argv[1];
127
128 FILE *tarfile = fopen(filename, "rb");
129 if (tarfile == NULL) {
130 fprintf(stderr, "Failed to open `%s': %s.\n", filename, str_error(errno));
131 return 2;
132 }
133
134 while (true) {
135 size_t header_ok;
136 tar_header_raw_t header_raw;
137 tar_header_t header;
138 header_ok = fread(&header_raw, sizeof(header_raw), 1, tarfile);
139 if (header_ok != 1) {
140 break;
141 }
142 int rc = tar_header_parse(&header, &header_raw);
143 if (rc == EEMPTY) {
144 continue;
145 }
146 if (rc != EOK) {
147 fprintf(stderr, "Failed parsing TAR header: %s.\n", str_error(rc));
148 break;
149 }
150
151 //printf(" ==> %s (%zuB, type %s)\n", header.filename,
152 // header.size, tar_type_str(header.type));
153
154 switch (header.type) {
155 case TAR_TYPE_DIRECTORY:
156 rc = handle_directory(&header, tarfile);
157 break;
158 case TAR_TYPE_NORMAL:
159 rc = handle_normal_file(&header, tarfile);
160 break;
161 default:
162 rc = skip_blocks(tarfile, header.size);
163 break;
164 }
165 if (rc != EOK) {
166 break;
167 }
168
169 }
170
171 fclose(tarfile);
172
173 return 0;
174}
175
176/** @}
177 */
Note: See TracBrowser for help on using the repository browser.