source: mainline/uspace/app/untar/main.c@ bc41f3a3

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

UNIX-like I/O functions should use errno to return error code for many reasons.

  • Property mode set to 100644
File size: 4.5 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 <sys/stat.h>
38#include <errno.h>
39#include <str_error.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 if (mkdir(header->filename, 0755) != 0) {
106 if (errno != EEXIST) {
107 fprintf(stderr, "Failed to create directory %s: %s.\n",
108 header->filename, str_error(errno));
109 return errno;
110 }
111 }
112
113 return skip_blocks(tarfile, header->size);
114}
115
116int main(int argc, char *argv[])
117{
118 if (argc != 2) {
119 fprintf(stderr, "Usage: %s tar-file\n", argv[0]);
120 return 1;
121 }
122
123 const char *filename = argv[1];
124
125 FILE *tarfile = fopen(filename, "rb");
126 if (tarfile == NULL) {
127 fprintf(stderr, "Failed to open `%s': %s.\n", filename, str_error(errno));
128 return 2;
129 }
130
131 while (true) {
132 size_t header_ok;
133 tar_header_raw_t header_raw;
134 tar_header_t header;
135 header_ok = fread(&header_raw, sizeof(header_raw), 1, tarfile);
136 if (header_ok != 1) {
137 break;
138 }
139 int rc = tar_header_parse(&header, &header_raw);
140 if (rc == EEMPTY) {
141 continue;
142 }
143 if (rc != EOK) {
144 fprintf(stderr, "Failed parsing TAR header: %s.\n", str_error(rc));
145 break;
146 }
147
148 //printf(" ==> %s (%zuB, type %s)\n", header.filename,
149 // header.size, tar_type_str(header.type));
150
151 switch (header.type) {
152 case TAR_TYPE_DIRECTORY:
153 rc = handle_directory(&header, tarfile);
154 break;
155 case TAR_TYPE_NORMAL:
156 rc = handle_normal_file(&header, tarfile);
157 break;
158 default:
159 rc = skip_blocks(tarfile, header.size);
160 break;
161 }
162 if (rc != EOK) {
163 break;
164 }
165
166 }
167
168 fclose(tarfile);
169
170 return 0;
171}
172
173/** @}
174 */
Note: See TracBrowser for help on using the repository browser.