Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/untar/main.c

    r55092672 r1433ecda  
    3333 */
    3434
     35#include <stdio.h>
     36#include <stdlib.h>
    3537#include <errno.h>
    36 #include <stdio.h>
    37 #include <stdarg.h>
    38 #include <untar.h>
     38#include <str_error.h>
     39#include <vfs/vfs.h>
     40#include "tar.h"
    3941
    40 typedef struct {
    41         const char *filename;
    42         FILE *file;
    43 } tar_state_t;
     42static size_t get_block_count(size_t bytes)
     43{
     44        return (bytes + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE;
     45}
    4446
    45 static int tar_open(tar_file_t *tar)
     47static errno_t skip_blocks(FILE *tarfile, size_t valid_data_size)
    4648{
    47         tar_state_t *state = (tar_state_t *) tar->data;
    48 
    49         state->file = fopen(state->filename, "rb");
    50         if (state->file == NULL)
    51                 return errno;
    52 
     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        }
    5358        return EOK;
    5459}
    5560
    56 static void tar_close(tar_file_t *tar)
     61static errno_t handle_normal_file(const tar_header_t *header, FILE *tarfile)
    5762{
    58         tar_state_t *state = (tar_state_t *) tar->data;
    59         fclose(state->file);
     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
     72        errno_t rc = EOK;
     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;
    60102}
    61103
    62 static size_t tar_read(tar_file_t *tar, void *data, size_t size)
     104static errno_t handle_directory(const tar_header_t *header, FILE *tarfile)
    63105{
    64         tar_state_t *state = (tar_state_t *) tar->data;
    65         return fread(data, 1, size, state->file);
     106        errno_t rc;
     107
     108        rc = vfs_link_path(header->filename, KIND_DIRECTORY, NULL);
     109        if (rc != EOK) {
     110                if (rc != EEXIST) {
     111                        fprintf(stderr, "Failed to create directory %s: %s.\n",
     112                            header->filename, str_error(rc));
     113                        return rc;
     114                }
     115        }
     116
     117        return skip_blocks(tarfile, header->size);
    66118}
    67 
    68 static void tar_vreport(tar_file_t *tar, const char *fmt, va_list args)
    69 {
    70         vfprintf(stderr, fmt, args);
    71 }
    72 
    73 tar_file_t tar = {
    74         .open = tar_open,
    75         .close = tar_close,
    76 
    77         .read = tar_read,
    78         .vreport = tar_vreport
    79 };
    80119
    81120int main(int argc, char *argv[])
     
    86125        }
    87126
    88         tar_state_t state;
    89         state.filename = argv[1];
     127        const char *filename = argv[1];
    90128
    91         tar.data = (void *) &state;
    92         return untar(&tar);
     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                }
     143                errno_t rc = tar_header_parse(&header, &header_raw);
     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;
    93175}
    94176
Note: See TracChangeset for help on using the changeset viewer.