Subversion Repositories Kolibri OS

Rev

Rev 9095 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2017 rxi
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  5.  * of this software and associated documentation files (the "Software"), to
  6.  * deal in the Software without restriction, including without limitation the
  7.  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8.  * sell copies of the Software, and to permit persons to whom the Software is
  9.  * furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice shall be included in
  12.  * all copies or substantial portions of the Software.
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20.  * IN THE SOFTWARE.
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <stddef.h>
  26. #include <string.h>
  27.  
  28. #include <sys/ksys.h>
  29.  
  30. #include "microtar.h"
  31.  
  32. typedef struct {
  33.   char name[100];
  34.   char mode[8];
  35.   char owner[8];
  36.   char group[8];
  37.   char size[12];
  38.   char mtime[12];
  39.   char checksum[8];
  40.   char type;
  41.   char linkname[100];
  42.   char _padding[255];
  43. } mtar_raw_header_t;
  44.  
  45. static void * mtar_memset( void * s, int c, size_t n ){
  46.   unsigned char * p = ( unsigned char * ) s;
  47.   while ( n-- ){
  48.       *p++ = ( unsigned char ) c;
  49.   }
  50.   return s;
  51. }
  52.  
  53. #ifdef MTAR_OBJ
  54. // All pointers was changed for compatible to latest version tcc and the libc.obj headers
  55. size_t (*_fread)(void *restrict, size_t size, size_t count, FILE *restrict)=NULL;
  56. size_t (*_fwrite)(const void *restrict, size_t size, size_t count, FILE *restrict)=NULL;
  57. int    (*_fclose)(FILE *)=NULL;
  58. FILE*  (*_fopen)(const char *restrict, const char *restrict)=NULL;
  59. int    (*_fseek)(FILE *, long, int)=NULL;
  60. long   (*_ftell)(FILE *)=NULL;
  61. int    (*_sprintf)(char* buffer, const char* format, ...)=NULL;
  62. int    (*_sscanf)(const char*, const char *restrict, ...)=NULL;
  63. int    (*_strcmp)(const char * s1, const char* s2)=NULL;
  64. char*  (*_strchr)(const char* s, int c)=NULL;
  65. char*  (*_strcpy)(char*  s1, const char* s2)=NULL;
  66.  
  67. #endif
  68.  
  69. static unsigned round_up(unsigned n, unsigned incr) {
  70.   return n + (incr - n % incr) % incr;
  71. }
  72.  
  73.  
  74. static unsigned checksum(const mtar_raw_header_t* rh) {
  75.   unsigned i;
  76.   unsigned char *p = (unsigned char*) rh;
  77.   unsigned res = 256;
  78.   for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) {
  79.     res += p[i];
  80.   }
  81.   for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) {
  82.     res += p[i];
  83.   }
  84.   return res;
  85. }
  86.  
  87.  
  88. static int tread(mtar_t *tar, void *data, unsigned size) {
  89.   int err = tar->read(tar, data, size);
  90.   tar->pos += size;
  91.   return err;
  92. }
  93.  
  94.  
  95. static int twrite(mtar_t *tar, const void *data, unsigned size) {
  96.  
  97.   int err = tar->write(tar, data, size);
  98.   tar->pos += size;
  99.   return err;
  100. }
  101.  
  102.  
  103. static int write_null_bytes(mtar_t *tar, int n) {
  104.   int i, err;
  105.   char nul = '\0';
  106.   for (i = 0; i < n; i++) {
  107.     err = twrite(tar, &nul, 1);
  108.     if (err) {
  109.       return err;
  110.     }
  111.   }
  112.   return MTAR_ESUCCESS;
  113. }
  114.  
  115.  
  116. static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
  117.   unsigned chksum1, chksum2;
  118.  
  119.   /* If the checksum starts with a null byte we assume the record is NULL */
  120.   if (*rh->checksum == '\0') {
  121.     return MTAR_ENULLRECORD;
  122.   }
  123.  
  124.   /* Build and compare checksum */
  125.   chksum1 = checksum(rh);
  126.   _sscanf(rh->checksum, "%o", &chksum2);
  127.   if (chksum1 != chksum2) {
  128.     return MTAR_EBADCHKSUM;
  129.   }
  130.  
  131.   /* Load raw header into header */
  132.   _sscanf(rh->mode, "%o", &h->mode);
  133.   _sscanf(rh->owner, "%o", &h->owner);
  134.   _sscanf(rh->size, "%o", &h->size);
  135.   _sscanf(rh->mtime, "%o", &h->mtime);
  136.   h->type = rh->type;
  137.   _strcpy(h->name, rh->name);
  138.   _strcpy(h->linkname, rh->linkname);
  139.  
  140.   return MTAR_ESUCCESS;
  141. }
  142.  
  143.  
  144. static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
  145.   unsigned chksum;
  146.  
  147.   /* Load header into raw header */
  148.   mtar_memset(rh, 0, sizeof(*rh));
  149.   _sprintf(rh->mode, "%o", h->mode);
  150.   _sprintf(rh->owner, "%o", h->owner);
  151.   _sprintf(rh->size, "%o", h->size);
  152.   _sprintf(rh->mtime, "%o", h->mtime);
  153.   rh->type = h->type ? h->type : MTAR_TREG;
  154.   _strcpy(rh->name, h->name);
  155.   _strcpy(rh->linkname, h->linkname);
  156.  
  157.   /* Calculate and write checksum */
  158.   chksum = checksum(rh);
  159.   _sprintf(rh->checksum, "%06o", chksum);
  160.   rh->checksum[7] = ' ';
  161.  
  162.   return MTAR_ESUCCESS;
  163. }
  164.  
  165.  
  166. const char* mtar_strerror(int err) {
  167.   switch (err) {
  168.     case MTAR_ESUCCESS     : return "success";
  169.     case MTAR_EFAILURE     : return "failure";
  170.     case MTAR_EOPENFAIL    : return "could not open";
  171.     case MTAR_EREADFAIL    : return "could not read";
  172.     case MTAR_EWRITEFAIL   : return "could not write";
  173.     case MTAR_ESEEKFAIL    : return "could not seek";
  174.     case MTAR_EBADCHKSUM   : return "bad checksum";
  175.     case MTAR_ENULLRECORD  : return "null record";
  176.     case MTAR_ENOTFOUND    : return "file not found";
  177.   }
  178.   return "unknown error";
  179. }
  180.  
  181.  
  182. static int file_write(mtar_t *tar, const void *data, unsigned size) {
  183.   unsigned res = _fwrite(data, 1, size, tar->stream);
  184.   return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL;
  185. }
  186.  
  187. static int file_read(mtar_t *tar, void *data, unsigned size) {
  188.   unsigned res = _fread(data, 1, size, tar->stream);
  189.   return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
  190. }
  191.  
  192. static int file_seek(mtar_t *tar, unsigned offset) {
  193.     int res = _fseek(tar->stream, offset, SEEK_SET);
  194.   return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
  195. }
  196.  
  197. static int file_close(mtar_t *tar) {
  198.   _fclose(tar->stream);
  199.   return MTAR_ESUCCESS;
  200. }
  201.  
  202.  
  203. int mtar_open(mtar_t *tar, const char *filename, const char *mode) {
  204.   int err;
  205.   mtar_header_t h;
  206.  
  207.   /* Init tar struct and functions */
  208.   mtar_memset(tar, 0, sizeof(*tar));
  209.   tar->write = file_write;
  210.   tar->read = file_read;
  211.   tar->seek = file_seek;
  212.   tar->close = file_close;
  213.  
  214.   /* Assure mode is always binary */
  215.   if ( _strchr(mode, 'r') ) mode = "rb";
  216.   if ( _strchr(mode, 'w') ) mode = "wb";
  217.   if ( _strchr(mode, 'a') ) mode = "ab";
  218.   /* Open file */
  219.   tar->stream = _fopen(filename, mode);
  220.   if (!tar->stream) {
  221.     return MTAR_EOPENFAIL;
  222.   }
  223.   /* Read first header to check it is valid if mode is `r` */
  224.   if (*mode == 'r') {
  225.     err = mtar_read_header(tar, &h);
  226.     if (err != MTAR_ESUCCESS) {
  227.       mtar_close(tar);
  228.       return err;
  229.     }
  230.   }
  231.  
  232.   /* Return ok */
  233.   return MTAR_ESUCCESS;
  234. }
  235.  
  236.  
  237. int mtar_close(mtar_t *tar) {
  238.   return tar->close(tar);
  239. }
  240.  
  241.  
  242. int mtar_seek(mtar_t *tar, unsigned pos) {
  243.   int err = tar->seek(tar, pos);
  244.   tar->pos = pos;
  245.   return err;
  246. }
  247.  
  248.  
  249. int mtar_rewind(mtar_t *tar) {
  250.   tar->remaining_data = 0;
  251.   tar->last_header = 0;
  252.   return mtar_seek(tar, 0);
  253. }
  254.  
  255.  
  256. int mtar_next(mtar_t *tar) {
  257.   int err, n;
  258.   mtar_header_t h;
  259.   /* Load header */
  260.   err = mtar_read_header(tar, &h);
  261.   if (err) {
  262.     return err;
  263.   }
  264.   /* Seek to next record */
  265.   n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
  266.   return mtar_seek(tar, tar->pos + n);
  267. }
  268.  
  269.  
  270. int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) {
  271.   int err;
  272.   mtar_header_t header;
  273.   /* Start at beginning */
  274.   err = mtar_rewind(tar);
  275.   if (err) {
  276.     return err;
  277.   }
  278.   /* Iterate all files until we hit an error or find the file */
  279.   while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) {
  280.     if ( !_strcmp(header.name, name) ) {
  281.       if (h) {
  282.         *h = header;
  283.       }
  284.       return MTAR_ESUCCESS;
  285.     }
  286.     mtar_next(tar);
  287.   }
  288.   /* Return error */
  289.   if (err == MTAR_ENULLRECORD) {
  290.     err = MTAR_ENOTFOUND;
  291.   }
  292.   return err;
  293. }
  294.  
  295.  
  296. int mtar_read_header(mtar_t *tar, mtar_header_t *h) {
  297.   int err;
  298.   mtar_raw_header_t rh;
  299.   /* Save header position */
  300.   tar->last_header = tar->pos;
  301.   /* Read raw header */
  302.   err = tread(tar, &rh, sizeof(rh));
  303.   if (err) {
  304.     return err;
  305.   }
  306.   /* Seek back to start of header */
  307.   err = mtar_seek(tar, tar->last_header);
  308.   if (err) {
  309.     return err;
  310.   }
  311.   /* Load raw header into header struct and return */
  312.   return raw_to_header(h, &rh);
  313. }
  314.  
  315.  
  316. int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
  317.   int err;
  318.   /* If we have no remaining data then this is the first read, we get the size,
  319.    * set the remaining data and seek to the beginning of the data */
  320.   if (tar->remaining_data == 0) {
  321.     mtar_header_t h;
  322.     /* Read header */
  323.     err = mtar_read_header(tar, &h);
  324.     if (err) {
  325.       return err;
  326.     }
  327.     /* Seek past header and init remaining data */
  328.     err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
  329.     if (err) {
  330.       return err;
  331.     }
  332.     tar->remaining_data = h.size;
  333.   }
  334.   /* Read data */
  335.   err = tread(tar, ptr, size);
  336.   if (err) {
  337.     return err;
  338.   }
  339.   tar->remaining_data -= size;
  340.   /* If there is no remaining data we've finished reading and seek back to the
  341.    * header */
  342.   if (tar->remaining_data == 0) {
  343.     return mtar_seek(tar, tar->last_header);
  344.   }
  345.   return MTAR_ESUCCESS;
  346. }
  347.  
  348.  
  349. int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
  350.   mtar_raw_header_t rh;
  351.   /* Build raw header and write */
  352.   header_to_raw(&rh, h);
  353.   tar->remaining_data = h->size;
  354.   return twrite(tar, &rh, sizeof(rh));
  355. }
  356.  
  357. int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) {
  358.   mtar_header_t h;
  359.   /* Build header */
  360.   mtar_memset(&h, 0, sizeof(h));
  361.   _strcpy(h.name, name);
  362.   h.size = size;
  363.   h.type = MTAR_TREG;
  364.   h.mode = 0664;
  365.   /* Write header */
  366.   return mtar_write_header(tar, &h);
  367. }
  368.  
  369.  
  370. int mtar_write_dir_header(mtar_t *tar, const char *name) {
  371.   mtar_header_t h;
  372.   /* Build header */
  373.   mtar_memset(&h, 0, sizeof(h));
  374.   _strcpy(h.name, name);
  375.   h.type = MTAR_TDIR;
  376.   h.mode = 0775;
  377.   /* Write header */
  378.   return mtar_write_header(tar, &h);
  379. }
  380.  
  381.  
  382. int mtar_write_data(mtar_t *tar, const void *data, unsigned size) {
  383.   int err;
  384.   /* Write data */
  385.   err = twrite(tar, data, size);
  386.   if (err) {
  387.     return err;
  388.   }
  389.   tar->remaining_data -= size;
  390.   /* Write padding if we've written all the data for this file */
  391.   if (tar->remaining_data == 0) {
  392.     return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos);
  393.   }
  394.   return MTAR_ESUCCESS;
  395. }
  396.  
  397.  
  398. int mtar_finalize(mtar_t *tar) {
  399.   /* Write two NULL records */
  400.   return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2);
  401. }
  402.  
  403. /* Load libc.obj */
  404.  
  405. #ifdef MTAR_OBJ
  406.  
  407. #include <sys/ksys.h>
  408.  
  409. int mtar_init(){
  410.   ksys_dll_t *libc = _ksys_dlopen("/sys/lib/libc.obj");
  411.   if(!libc){
  412.     _ksys_debug_puts("mtar.obj: libc.obj not loaded!");
  413.     return 1;
  414.   }
  415.  
  416.   _fread  = _ksys_dlsym(libc, "fread");
  417.   _fwrite = _ksys_dlsym(libc, "fwrite");
  418.   _fclose = _ksys_dlsym(libc, "fclose");
  419.   _fopen  = _ksys_dlsym(libc, "fopen");
  420.   _fseek  = _ksys_dlsym(libc, "fseek");
  421.   _ftell  = _ksys_dlsym(libc, "ftell");
  422.   _sprintf= _ksys_dlsym(libc, "sprintf");
  423.   _sscanf = _ksys_dlsym(libc, "sscanf");
  424.   _strcmp = _ksys_dlsym(libc, "strcmp");
  425.   _strchr = _ksys_dlsym(libc, "strchr");
  426.   _strcpy = _ksys_dlsym(libc, "strcpy");
  427.   return 0;
  428. }
  429.  
  430.  
  431. ksys_dll_t EXPORTS[] = {
  432.   {"mtar_init", mtar_init},
  433.   {"mtar_open", mtar_open},
  434.   {"mtar_close", mtar_close},
  435.   {"mtar_seek", mtar_seek},
  436.   {"mtar_rewind", mtar_rewind},
  437.   {"mtar_next", mtar_next},
  438.   {"mtar_find", mtar_find},
  439.   {"mtar_read_header", mtar_read_header},
  440.   {"mtar_read_data", mtar_read_data},
  441.   {"mtar_write_header", mtar_write_header},
  442.   {"mtar_write_file_header", mtar_write_file_header},
  443.   {"mtar_write_dir_header",  mtar_write_dir_header},
  444.   {"mtar_write_data",mtar_write_data},
  445.   {"mtar_finalize", mtar_finalize},
  446.   {"mtar_strerror", mtar_strerror},
  447.   NULL
  448. };
  449.  
  450. #endif
  451.