summaryrefslogtreecommitdiffstats
path: root/examples/c4cat.c
blob: 04f51b667a194720018875892ec467acfeea9444 (plain)
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

#include "cc4group.h"

bool catNormalFile(const char* const path, const off_t size)
{
	int file = open(path, O_RDONLY);
	if(file == -1)
	{
		fprintf(stderr, "ERROR: Reading \"%s\": %s\n", path, strerror(errno));
		return false;
	}

	void* mappedFile = mmap(NULL, size, PROT_READ, MAP_PRIVATE, file, 0);

	if(close(file) == -1)
	{
		fprintf(stderr, "ERROR: Closing \"%s\": %s\n", path, strerror(errno));
	}

	if(mappedFile == MAP_FAILED)
	{
		fprintf(stderr, "ERROR: Mapping \"%s\" for reading: %s\n", path, strerror(errno));
		return false;
	}

	if(write(STDOUT_FILENO, mappedFile, size) != size)
	{
		fprintf(stderr, "ERROR: Writing file contents of \"%s\" to stdout: %s\n", path, strerror(errno));
	}

	if(munmap(mappedFile, size) == -1)
	{
		fprintf(stderr, "ERROR: Unmapping \"%s\": %s\n", path, strerror(errno));
	}

	return true;
}

bool catFileWithPathsAndSize(const char* const completePath, const char* const groupPath, off_t fileSize)
{
	if(strcmp(groupPath, completePath) == 0)
	{
		return catNormalFile(completePath, fileSize);
	}

	const char* pathInGroup = completePath + strlen(groupPath) + 1;
	CC4Group* group = cc4group.new();
	if(!cc4group.openExisting(group, groupPath))
	{
		fprintf(stderr, "ERROR: Can not open group file \"%s\": %s\n", groupPath, cc4group.getErrorMessage(group));
		return false;
	}

	const void* data;
	size_t size;
	bool success = cc4group.getEntryData(group, pathInGroup, &data, &size);

	if(success)
	{
		if(write(STDOUT_FILENO, data, size) != (ssize_t)size)
		{
			fprintf(stderr, "ERROR: Writing file contents of \"%s\" to stdout: %s\n", completePath, strerror(errno));
		}
	}
	else
	{
		fprintf(stderr, "ERROR: Reading \"%s\" from \"%s\": %s\n", pathInGroup, groupPath, strerror(ENOENT));
	}

	cc4group.delete(group);

	return success;
}

bool catFile(const char* const completePath)
{
	struct stat st;

	char* groupPath = strdup(completePath);
	char* slash;
	for(slash = groupPath + strlen(groupPath); slash != NULL; slash = strrchr(groupPath, '/'))
	{
		*slash = '\0';
		if(stat(groupPath, &st) == 0 && !S_ISDIR(st.st_mode))
		{
			break;
		}
	}

	bool success;
	if(slash == NULL)
	{
		fprintf(stderr, "ERROR: Reading \"%s\": %s\n", completePath, strerror(ENOENT));
		success = false;
	}
	else
	{
		success = catFileWithPathsAndSize(completePath, groupPath, st.st_size);
	}

	free(groupPath);
	return success;
}

int main(int argc, char* argv[])
{
	if(argc < 2)
	{
		fprintf(stderr, "USAGE: %s <entry path>...\n", argv[0]);
		return EXIT_FAILURE;
	}

	bool success = true;
	for(int i = 1; i < argc; ++i)
	{
		success &= catFile(argv[i]);
	}

	return success ? EXIT_SUCCESS : EXIT_FAILURE;
}