source: mainline/uspace/app/untar/main.c@ 6283cefb

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

Let vfs_link() and vfs_link_path() return the linked file handle

Add an output argument to both vfs_link() and vfs_link_path() so that the
client may receive the file handle of the linked file or directory. This
makes it easy to work with the new file or directory as it is ready to be
opened or in case of a directory to use it as a parent for further
operations without the need for additional vfs_lookup().

  • 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, NULL);
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.