~sheosi/helenos/lua

« back to all changes in this revision

Viewing changes to uspace/app/untar/main.c

  • Committer: Sergio Tortosa (sheosi)
  • Date: 2013-12-22 14:13:23 UTC
  • mfrom: (2032.1.12 mainline)
  • Revision ID: sertorbe@gmail.com-20131222141323-gbiqm4j2w9sbjty5
MergedĀ mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
42
static size_t get_block_count(size_t bytes) {
 
43
        return (bytes + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE;
 
44
}
 
45
 
 
46
static 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
 
 
60
static 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
 
 
103
static int handle_directory(const tar_header_t *header, FILE *tarfile)
 
104
{
 
105
        int rc = mkdir(header->filename, 0755);
 
106
        if ((rc == EEXIST) || (rc == EEXISTS)) {
 
107
                // printf("Note: directory %s already exists.\n", header->filename);
 
108
                rc = EOK;
 
109
        }
 
110
        if (rc != EOK) {
 
111
                fprintf(stderr, "Failed to create directory %s: %s.\n",
 
112
                    header->filename, str_error(rc));
 
113
                return rc;
 
114
        }
 
115
 
 
116
        return skip_blocks(tarfile, header->size);
 
117
}
 
118
 
 
119
int 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
 */