Subversion Repositories Kolibri OS

Rev

Rev 8791 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8791 turbocat 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 
24
#include 
25
#include 
26
#include 
27
 
28
#include 
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
 
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 
408
 
409
int mtar_init(){
9095 turbocat 410
  ksys_dll_t *libc = _ksys_dlopen("/sys/lib/libc.obj");
8791 turbocat 411
  if(!libc){
412
    _ksys_debug_puts("mtar.obj: libc.obj not loaded!");
413
    return 1;
414
  }
415
 
9095 turbocat 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");
8791 turbocat 427
  return 0;
428
}
429
 
430
 
9095 turbocat 431
ksys_dll_t EXPORTS[] = {
8791 turbocat 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