1/*
2 * Copyright 2010, Axel D��rfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
5
6
7#include <fcntl.h>
8#include <stdio.h>
9#include <string.h>
10#include <unistd.h>
11
12#include <algorithm>
13
14
15void
16test_for_content(int fd, off_t start, const char* contents, size_t length)
17{
18	char buffer[4096];
19	while (length > 0) {
20		size_t toRead = std::min(length, sizeof(buffer));
21
22		if (pread(fd, buffer, toRead, start) != (ssize_t)toRead) {
23			perror("reading failed");
24			exit(1);
25		}
26
27		if (memcmp(contents, buffer, toRead)) {
28			fprintf(stderr, "Contents at %lld differ!\n", start);
29			exit(1);
30		}
31
32		contents += toRead;
33		start += toRead;
34		length -= toRead;
35	}
36}
37
38
39void
40test_for_zero(int fd, off_t start, off_t end)
41{
42	while (start < end) {
43		char buffer[4096];
44		size_t length = std::min((size_t)(end - start), sizeof(buffer));
45
46		if (pread(fd, buffer, length, start) != (ssize_t)length) {
47			perror("reading failed");
48			exit(1);
49		}
50
51		for (size_t i = 0; i < length; i++) {
52			if (buffer[i] != 0) {
53				fprintf(stderr, "Buffer at %lld is not empty (%#x)!\n",
54					start + i, buffer[i]);
55				exit(1);
56			}
57		}
58
59		start += length;
60	}
61}
62
63
64int
65main(int argc, char** argv)
66{
67	const char* name = "/tmp/seek_and_write";
68	bool prefill = true;
69
70	for (int i = 1; i < argc; i++) {
71		if (argv[i][0] == '-') {
72			if (argv[i][1] == 'n')
73				prefill = false;
74			else {
75				fprintf(stderr, "Unknown option\n");
76				return 1;
77			}
78
79			continue;
80		}
81
82		name = argv[i];
83	}
84
85	int fd = open(name, O_RDWR | O_TRUNC | O_CREAT, 0644);
86	if (fd < 0) {
87		perror("failed to open file");
88		return 1;
89	}
90
91	char buffer[256];
92	for (size_t i = 0; i < 256; i++)
93		buffer[i] = i;
94
95	if (prefill) {
96		// Write test data to file to make sure it's not empty
97
98		for (size_t i = 0; i < 100; i++) {
99			if (write(fd, buffer, sizeof(buffer)) != (ssize_t)sizeof(buffer)) {
100				perror("writing failed");
101				return 1;
102			}
103		}
104	}
105
106	// Truncate it again in order to remove its contents
107
108	ftruncate(fd, 0);
109
110	// Seek past its end, and write something
111
112	pwrite(fd, "---", 3, 100 * 1024);
113	pwrite(fd, "+++", 3, 200 * 1024);
114
115	// Test contents
116
117	test_for_zero(fd, 0, 100 * 1024);
118	test_for_content(fd, 100 * 1024, "---", 3);
119	test_for_zero(fd, 100 * 1024 + 256, 200 * 1024);
120	test_for_content(fd, 200 * 1024, "+++", 3);
121
122	return 0;
123}
124