1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
// Take files given on stdin and make them into a ramfs image of our
// own, (stupid) simple format.
// In the format: for each file comes the null-terminated string
// with filename, then null-padding until a 4-aligned offset, then
// 4-byte little-endian size of the file and then the contents
// of the file and then another null-padding until a 4-aligned offset.
// Files encoded this way go one after another (so it's easy to add
// something at the beginning).
// At the and comes one null-byte (as if a file with empty name
// was there).
#include <stdint.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <sys/stat.h>
#include <string.h>
#define ANSI_FG_RED "\033[0;31m"
#define ANSI_FG_DEFAULT "\033[0;39m"
int main(int argc, char **argv)
{
// process files in the order they are provided on the command line
for (int i = 1; i < argc; i++)
{
struct stat fileinfo;
if (stat(argv[i], &fileinfo))
err(-1, "couldn't stat " ANSI_FG_RED "%s" ANSI_FG_DEFAULT,
argv[i]);
if (!S_ISREG(fileinfo.st_mode))
errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT
" is not a regular file.", argv[i]);
// don't allow files with size so big, that it can't be encoded
// in a 4-byte unsigned int... In practice even smaller files
// won't fit on the rpi.
if (fileinfo.st_size > UINT32_MAX)
errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT
" is too big.", argv[i]);
uint32_t file_size = fileinfo.st_size;
uint32_t name_size = strlen(argv[i]) + 1; // 1 for null-byte
if (fwrite(argv[i], 1, name_size, stdout) != name_size)
errx(-1, "error writing to stdout");
// pad with null-bytes until a 4-aligned offset
for (uint32_t j = 0; (j + name_size) & 0b11; j++)
if (putchar('\0'))
errx(-1, "error writing to stdout");
// TODO convert file_size to little endian first (in case our
// host is be).
if (fwrite(&file_size, 4, 1, stdout) != 1)
errx(-1, "error writing to stdout");
// flush b4 running cat, so that stuff we've written comes
// b4 the actual file contents in the output
if (fflush(stdout))
err(-1, "couldn't flush stdout");
// we don't copy the actual file ourselves - we run cat for that
pid_t pid;
int wstatus;
switch (pid = fork())
{
case -1:
err(-1, "couldn't fork");
case 0:
if (execlp("cat", "cat", argv[i], NULL))
err(-1, "couldn't execute cat");
default:
if (wait(&wstatus) == -1)
err(-1, "error waiting for child");
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus))
exit(-1);
}
// again, pad with null-bytes until a 4-aligned offset
for (uint32_t j = 0; (j + file_size) & 0b11; j++)
if (putchar('\0'))
errx(-1, "error writing to stdout");
}
if (putchar('\0'))
errx(-1, "error writing to stdout");
return 0;
}
|