source: mainline/uspace/app/untar/main.c@ 1433ecda

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1433ecda was 1433ecda, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix cstyle: make ccheck-fix and commit only files where all the changes are good.

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