Crossfire Server, Trunk
microtar.cpp
Go to the documentation of this file.
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 "microtar.h"
29 
30 typedef struct {
31  char name[100];
32  char mode[8];
33  char owner[8];
34  char group[8];
35  char size[12];
36  char mtime[12];
37  char checksum[8];
38  char type;
39  char linkname[100];
40  char _padding[255];
42 
43 
44 static unsigned round_up(unsigned n, unsigned incr) {
45  return n + (incr - n % incr) % incr;
46 }
47 
48 
49 static unsigned checksum(const mtar_raw_header_t* rh) {
50  unsigned i;
51  unsigned char *p = (unsigned char*) rh;
52  unsigned res = 256;
53  for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) {
54  res += p[i];
55  }
56  for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) {
57  res += p[i];
58  }
59  return res;
60 }
61 
62 
63 static int tread(mtar_t *tar, void *data, unsigned size) {
64  int err = tar->read(tar, data, size);
65  tar->pos += size;
66  return err;
67 }
68 
69 
70 static int twrite(mtar_t *tar, const void *data, unsigned size) {
71  int err = tar->write(tar, data, size);
72  tar->pos += size;
73  return err;
74 }
75 
76 
77 static int write_null_bytes(mtar_t *tar, int n) {
78  int i, err;
79  char nul = '\0';
80  for (i = 0; i < n; i++) {
81  err = twrite(tar, &nul, 1);
82  if (err) {
83  return err;
84  }
85  }
86  return MTAR_ESUCCESS;
87 }
88 
89 
90 static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
91  unsigned chksum1, chksum2;
92 
93  /* If the checksum starts with a null byte we assume the record is NULL */
94  if (*rh->checksum == '\0') {
95  return MTAR_ENULLRECORD;
96  }
97 
98  /* Build and compare checksum */
99  chksum1 = checksum(rh);
100  sscanf(rh->checksum, "%o", &chksum2);
101  if (chksum1 != chksum2) {
102  return MTAR_EBADCHKSUM;
103  }
104 
105  /* Load raw header into header */
106  sscanf(rh->mode, "%o", &h->mode);
107  sscanf(rh->owner, "%o", &h->owner);
108  sscanf(rh->size, "%o", &h->size);
109  sscanf(rh->mtime, "%o", &h->mtime);
110  h->type = rh->type;
111  strcpy(h->name, rh->name);
112  strcpy(h->linkname, rh->linkname);
113 
114  return MTAR_ESUCCESS;
115 }
116 
117 
118 static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
119  unsigned chksum;
120 
121  /* Load header into raw header */
122  memset(rh, 0, sizeof(*rh));
123  sprintf(rh->mode, "%o", h->mode);
124  sprintf(rh->owner, "%o", h->owner);
125  sprintf(rh->size, "%o", h->size);
126  sprintf(rh->mtime, "%o", h->mtime);
127  rh->type = static_cast<char>(h->type) ? static_cast<char>(h->type) : static_cast<char>(MTAR_TREG);
128  strcpy(rh->name, h->name);
129  strcpy(rh->linkname, h->linkname);
130 
131  /* Calculate and write checksum */
132  chksum = checksum(rh);
133  sprintf(rh->checksum, "%06o", chksum);
134  rh->checksum[7] = ' ';
135 
136  return MTAR_ESUCCESS;
137 }
138 
139 
140 const char* mtar_strerror(int err) {
141  switch (err) {
142  case MTAR_ESUCCESS : return "success";
143  case MTAR_EFAILURE : return "failure";
144  case MTAR_EOPENFAIL : return "could not open";
145  case MTAR_EREADFAIL : return "could not read";
146  case MTAR_EWRITEFAIL : return "could not write";
147  case MTAR_ESEEKFAIL : return "could not seek";
148  case MTAR_EBADCHKSUM : return "bad checksum";
149  case MTAR_ENULLRECORD : return "null record";
150  case MTAR_ENOTFOUND : return "file not found";
151  }
152  return "unknown error";
153 }
154 
155 
156 static int file_write(mtar_t *tar, const void *data, unsigned size) {
157  unsigned res = fwrite(data, 1, size, reinterpret_cast<FILE *>(tar->stream));
158  return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL;
159 }
160 
161 static int file_read(mtar_t *tar, void *data, unsigned size) {
162  unsigned res = fread(data, 1, size, reinterpret_cast<FILE *>(tar->stream));
163  return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
164 }
165 
166 static int file_seek(mtar_t *tar, unsigned offset) {
167  int res = fseek(reinterpret_cast<FILE *>(tar->stream), offset, SEEK_SET);
168  return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
169 }
170 
171 static int file_close(mtar_t *tar) {
172  fclose(reinterpret_cast<FILE *>(tar->stream));
173  return MTAR_ESUCCESS;
174 }
175 
176 
177 int mtar_open(mtar_t *tar, const char *filename, const char *mode) {
178  int err;
179  mtar_header_t h;
180 
181  /* Init tar struct and functions */
182  memset(tar, 0, sizeof(*tar));
183  tar->write = file_write;
184  tar->read = file_read;
185  tar->seek = file_seek;
186  tar->close = file_close;
187 
188  /* Assure mode is always binary */
189  if ( strchr(mode, 'r') ) mode = "rb";
190  if ( strchr(mode, 'w') ) mode = "wb";
191  if ( strchr(mode, 'a') ) mode = "ab";
192  /* Open file */
193  tar->stream = fopen(filename, mode);
194  if (!tar->stream) {
195  return MTAR_EOPENFAIL;
196  }
197  /* Read first header to check it is valid if mode is `r` */
198  if (*mode == 'r') {
199  err = mtar_read_header(tar, &h);
200  if (err != MTAR_ESUCCESS) {
201  mtar_close(tar);
202  return err;
203  }
204  }
205 
206  /* Return ok */
207  return MTAR_ESUCCESS;
208 }
209 
210 
211 int mtar_close(mtar_t *tar) {
212  return tar->close(tar);
213 }
214 
215 
216 int mtar_seek(mtar_t *tar, unsigned pos) {
217  int err = tar->seek(tar, pos);
218  tar->pos = pos;
219  return err;
220 }
221 
222 
223 int mtar_rewind(mtar_t *tar) {
224  tar->remaining_data = 0;
225  tar->last_header = 0;
226  return mtar_seek(tar, 0);
227 }
228 
229 
230 int mtar_next(mtar_t *tar) {
231  int err, n;
232  mtar_header_t h;
233  /* Load header */
234  err = mtar_read_header(tar, &h);
235  if (err) {
236  return err;
237  }
238  /* Seek to next record */
239  n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
240  return mtar_seek(tar, tar->pos + n);
241 }
242 
243 
244 int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) {
245  int err;
247  /* Start at beginning */
248  err = mtar_rewind(tar);
249  if (err) {
250  return err;
251  }
252  /* Iterate all files until we hit an error or find the file */
253  while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) {
254  if ( !strcmp(header.name, name) ) {
255  if (h) {
256  *h = header;
257  }
258  return MTAR_ESUCCESS;
259  }
260  mtar_next(tar);
261  }
262  /* Return error */
263  if (err == MTAR_ENULLRECORD) {
264  err = MTAR_ENOTFOUND;
265  }
266  return err;
267 }
268 
269 
271  int err;
273  /* Save header position */
274  tar->last_header = tar->pos;
275  /* Read raw header */
276  err = tread(tar, &rh, sizeof(rh));
277  if (err) {
278  return err;
279  }
280  /* Seek back to start of header */
281  err = mtar_seek(tar, tar->last_header);
282  if (err) {
283  return err;
284  }
285  /* Load raw header into header struct and return */
286  return raw_to_header(h, &rh);
287 }
288 
289 
290 int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
291  int err;
292  /* If we have no remaining data then this is the first read, we get the size,
293  * set the remaining data and seek to the beginning of the data */
294  if (tar->remaining_data == 0) {
295  mtar_header_t h;
296  /* Read header */
297  err = mtar_read_header(tar, &h);
298  if (err) {
299  return err;
300  }
301  /* Seek past header and init remaining data */
302  err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
303  if (err) {
304  return err;
305  }
306  tar->remaining_data = h.size;
307  }
308  /* Read data */
309  err = tread(tar, ptr, size);
310  if (err) {
311  return err;
312  }
313  tar->remaining_data -= size;
314  /* If there is no remaining data we've finished reading and seek back to the
315  * header */
316  if (tar->remaining_data == 0) {
317  return mtar_seek(tar, tar->last_header);
318  }
319  return MTAR_ESUCCESS;
320 }
321 
322 
325  /* Build raw header and write */
326  header_to_raw(&rh, h);
327  tar->remaining_data = h->size;
328  return twrite(tar, &rh, sizeof(rh));
329 }
330 
331 
332 int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) {
333  mtar_header_t h;
334  /* Build header */
335  memset(&h, 0, sizeof(h));
336  strcpy(h.name, name);
337  h.size = size;
338  h.type = MTAR_TREG;
339  h.mode = 0664;
340  /* Write header */
341  return mtar_write_header(tar, &h);
342 }
343 
344 
345 int mtar_write_dir_header(mtar_t *tar, const char *name) {
346  mtar_header_t h;
347  /* Build header */
348  memset(&h, 0, sizeof(h));
349  strcpy(h.name, name);
350  h.type = MTAR_TDIR;
351  h.mode = 0775;
352  /* Write header */
353  return mtar_write_header(tar, &h);
354 }
355 
356 
357 int mtar_write_data(mtar_t *tar, const void *data, unsigned size) {
358  int err;
359  /* Write data */
360  err = twrite(tar, data, size);
361  if (err) {
362  return err;
363  }
364  tar->remaining_data -= size;
365  /* Write padding if we've written all the data for this file */
366  if (tar->remaining_data == 0) {
367  return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos);
368  }
369  return MTAR_ESUCCESS;
370 }
371 
372 
374  /* Write two NULL records */
375  return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2);
376 }
mtar_t::close
int(* close)(mtar_t *tar)
Definition: microtar.h:55
mtar_raw_header_t::mtime
char mtime[12]
Definition: microtar.cpp:36
write_null_bytes
static int write_null_bytes(mtar_t *tar, int n)
Definition: microtar.cpp:77
MTAR_EFAILURE
@ MTAR_EFAILURE
Definition: microtar.h:18
mtar_raw_header_t::mode
char mode[8]
Definition: microtar.cpp:32
n
based on the size of the this randomly makes land number of spaces randomly lower or higher The default is Note that this is run also based on the the altitude amount will likely be less So if you do something like l and n
Definition: land.6.txt:25
round_up
static unsigned round_up(unsigned n, unsigned incr)
Definition: microtar.cpp:44
mtar_header_t::type
unsigned type
Definition: microtar.h:43
mtar_find
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h)
Definition: microtar.cpp:244
MTAR_EWRITEFAIL
@ MTAR_EWRITEFAIL
Definition: microtar.h:21
mtar_t
Definition: microtar.h:51
mtar_header_t::size
unsigned size
Definition: microtar.h:41
file_close
static int file_close(mtar_t *tar)
Definition: microtar.cpp:171
mtar_next
int mtar_next(mtar_t *tar)
Definition: microtar.cpp:230
checksum
static unsigned checksum(const mtar_raw_header_t *rh)
Definition: microtar.cpp:49
mode
linux kernel c mode(defun linux-c-mode() "C mode with adjusted defaults for use with the Linux kernel."(interactive)(c-mode)(c-set-style "K&R")(setq c-basic-offset 8))
mtar_header_t::mtime
unsigned mtime
Definition: microtar.h:42
npc_dialog.filename
filename
Definition: npc_dialog.py:99
file_read
static int file_read(mtar_t *tar, void *data, unsigned size)
Definition: microtar.cpp:161
MTAR_ENOTFOUND
@ MTAR_ENOTFOUND
Definition: microtar.h:25
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
mtar_raw_header_t::checksum
char checksum[8]
Definition: microtar.cpp:37
header_to_raw
static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h)
Definition: microtar.cpp:118
mtar_header_t::name
char name[100]
Definition: microtar.h:44
mtar_close
int mtar_close(mtar_t *tar)
Definition: microtar.cpp:211
mtar_open
int mtar_open(mtar_t *tar, const char *filename, const char *mode)
Definition: microtar.cpp:177
mtar_t::pos
unsigned pos
Definition: microtar.h:57
microtar.h
mtar_raw_header_t::name
char name[100]
Definition: microtar.cpp:31
mtar_finalize
int mtar_finalize(mtar_t *tar)
Definition: microtar.cpp:373
mtar_write_data
int mtar_write_data(mtar_t *tar, const void *data, unsigned size)
Definition: microtar.cpp:357
mtar_write_file_header
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size)
Definition: microtar.cpp:332
mtar_rewind
int mtar_rewind(mtar_t *tar)
Definition: microtar.cpp:223
navar-midane_time.data
data
Definition: navar-midane_time.py:11
mtar_seek
int mtar_seek(mtar_t *tar, unsigned pos)
Definition: microtar.cpp:216
mtar_t::read
int(* read)(mtar_t *tar, void *data, unsigned size)
Definition: microtar.h:52
mtar_read_header
int mtar_read_header(mtar_t *tar, mtar_header_t *h)
Definition: microtar.cpp:270
mtar_strerror
const char * mtar_strerror(int err)
Definition: microtar.cpp:140
file_seek
static int file_seek(mtar_t *tar, unsigned offset)
Definition: microtar.cpp:166
mtar_t::remaining_data
unsigned remaining_data
Definition: microtar.h:58
mtar_header_t
Definition: microtar.h:38
mtar_t::stream
void * stream
Definition: microtar.h:56
mtar_write_header
int mtar_write_header(mtar_t *tar, const mtar_header_t *h)
Definition: microtar.cpp:323
offsetof
#define offsetof(type, member)
Definition: shstr.h:37
mtar_header_t::mode
unsigned mode
Definition: microtar.h:39
mtar_t::last_header
unsigned last_header
Definition: microtar.h:59
mtar_raw_header_t::type
char type
Definition: microtar.cpp:38
MTAR_TREG
@ MTAR_TREG
Definition: microtar.h:29
MTAR_EBADCHKSUM
@ MTAR_EBADCHKSUM
Definition: microtar.h:23
mtar_raw_header_t::size
char size[12]
Definition: microtar.cpp:35
MTAR_ESUCCESS
@ MTAR_ESUCCESS
Definition: microtar.h:17
MTAR_ESEEKFAIL
@ MTAR_ESEEKFAIL
Definition: microtar.h:22
mtar_write_dir_header
int mtar_write_dir_header(mtar_t *tar, const char *name)
Definition: microtar.cpp:345
mtar_raw_header_t
Definition: microtar.cpp:30
tread
static int tread(mtar_t *tar, void *data, unsigned size)
Definition: microtar.cpp:63
MTAR_EOPENFAIL
@ MTAR_EOPENFAIL
Definition: microtar.h:19
file_write
static int file_write(mtar_t *tar, const void *data, unsigned size)
Definition: microtar.cpp:156
MTAR_TDIR
@ MTAR_TDIR
Definition: microtar.h:34
mtar_header_t::linkname
char linkname[100]
Definition: microtar.h:45
MTAR_EREADFAIL
@ MTAR_EREADFAIL
Definition: microtar.h:20
raw_to_header
static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh)
Definition: microtar.cpp:90
hall_of_fame.header
list header
Definition: hall_of_fame.py:38
MTAR_ENULLRECORD
@ MTAR_ENULLRECORD
Definition: microtar.h:24
mtar_header_t::owner
unsigned owner
Definition: microtar.h:40
twrite
static int twrite(mtar_t *tar, const void *data, unsigned size)
Definition: microtar.cpp:70
mtar_raw_header_t::linkname
char linkname[100]
Definition: microtar.cpp:39
altar_valkyrie.res
int res
Definition: altar_valkyrie.py:74
mtar_t::seek
int(* seek)(mtar_t *tar, unsigned pos)
Definition: microtar.h:54
mtar_raw_header_t::owner
char owner[8]
Definition: microtar.cpp:33
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
mtar_t::write
int(* write)(mtar_t *tar, const void *data, unsigned size)
Definition: microtar.h:53
mtar_read_data
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size)
Definition: microtar.cpp:290