-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheager_lib.c
304 lines (266 loc) · 8.83 KB
/
eager_lib.c
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#include "eager_lib.h"
#ifdef __FreeBSD__
#define BUF_SIZE 8192
#define min(a,b) (((a)<(b))?(a):(b))
void fatal
(const char *err)
{
perror(err);
abort();
}
int std_copy(int in_fd, int out_fd, int unused, int size)
{
char buf[4096];
int err = -1;
int bytes;
while( (bytes = read(in_fd, buf, size)) > 0 )
{
if(write(out_fd, buf, bytes) != bytes)
{
perror("write:");
goto out;
}
}
err = 0;
out:
return err;
}
ssize_t
send_file(int out_fd, int in_fd, off_t *offset, size_t count)
{
off_t orig = 0;
if (offset != NULL) {
/* Save current file offset and set offset to value in '*offset' */
orig = lseek(in_fd, 0, SEEK_CUR);
if (orig == -1)
return -1;
if (lseek(in_fd, *offset, SEEK_SET) == -1)
return -1;
}
size_t totSent = 0;
while (count > 0) {
size_t toRead = min(BUF_SIZE, count);
char buf[BUF_SIZE];
ssize_t numRead = read(in_fd, buf, toRead);
if (numRead == -1)
return -1;
if (numRead == 0)
break; /* EOF */
ssize_t numSent = write(out_fd, buf, numRead);
if (numSent == -1)
return -1;
if (numSent == 0) /* Should never happen */
fatal("send_file: write() transferred 0 bytes");
count -= numSent;
totSent += numSent;
}
if (offset != NULL) {
/* Return updated file offset in '*offset', and reset the file offset
to the value it had when we were called. */
*offset = lseek(in_fd, 0, SEEK_CUR);
if (*offset == -1)
return -1;
if (lseek(in_fd, orig, SEEK_SET) == -1)
return -1;
}
return totSent;
}
#endif
int safeOpen3(const char *pathname, int flags, mode_t mode) {
int fd = open(pathname, flags, mode);
if (fd < 0) {
printf("could not open file%s\n", pathname);
exit(1);
}
return fd;
}
int safeOpen(const char *pathname, int flags) {
// The mode will be ignored anyway
return safeOpen3(pathname, flags, S_IRWXU);
}
off_t safeLseek(int fd) {
off_t offset = lseek(fd, 0, SEEK_CUR);
if (offset < 0) {
printf("ERROR: %s, when lseek-ing!\n", strerror(errno));
exit(1);
}
return offset;
}
/**
* Copied from: http://code.activestate.com/recipes/577384-setting-a-file-descriptor-to-blocking-or-non-block/
* Set a file descriptor to blocking or non-blocking mode.
*
* @param fd The file descriptor
* @param blocking 0:non-blocking mode, 1:blocking mode
*
**/
void fdSetBlocking(int fd, int blocking) {
/* Save the current flags */
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
printf("could not get file descriptor %d flags\n", fd);
exit(1);
}
if (blocking) {
flags &= ~O_NONBLOCK;
} else {
flags |= O_NONBLOCK;
}
int res = fcntl(fd, F_SETFL, flags);
if (res == -1) {
printf("could not set file descriptor %d to blocking\n", fd);
exit(1);
}
return;
}
int tryOpenOutput(const char *pathname) {
int outputFd = open(pathname, O_WRONLY | O_NONBLOCK);
if (outputFd < 0) {
// ENXIO means that noone has opened the output file for
// reading, in that case we can read some of our input.
if (errno != ENXIO) {
printf("could not open output file(s)\n");
exit(1);
}
}
return outputFd;
}
int blockOpenOutput(const char *pathname) {
int outputFd = open(pathname, O_WRONLY);
if (outputFd < 0) {
printf("could not open output file: %s\n", pathname);
exit(1);
}
fdSetBlocking(outputFd, 0);
return outputFd;
}
// Returns the number of bytes read, or 0 if the input was done.
int readInputWriteToFile(int inputFd, int intermediateWriter, int bufferSize) {
ssize_t res =
#ifdef __linux__
splice(inputFd, 0, intermediateWriter, 0, bufferSize, 0);
#else
// https://man.openbsd.org/sosplice.9
// naive implementation to match our needs, maybe we could we use sosplice, somove
std_copy(inputFd, intermediateWriter, 0, bufferSize);
#endif
if (res < 0) {
printf("Error: Couldn't read from inputaa!\n");
exit(1);
}
return res;
}
int bufferedReadInputWriteToFile(int inputFd, int intermediateWriter, int bufferSize) {
// TODO: Maybe allocate that buffer as a static or global to not
// allocate it in the stack several times.
ssize_t inputBytesRead = 0;
ssize_t inputBytesWritten = 0;
printf("Is it valid to allocate an array of variable size?\n");
exit(1);
char inputBuf[bufferSize];
inputBytesRead = read(inputFd, inputBuf, sizeof(inputBuf));
if (inputBytesRead < 0) {
printf("Error: Couldn't read from input@@!\n");
exit(1);
}
if (inputBytesRead == 0) {
/* printf("Input is done!\n"); */
return 0;
}
/* printf("Read %ld bytes from input\n", inputBytesRead); */
inputBytesWritten = write(intermediateWriter, inputBuf, inputBytesRead);
// TODO: I probably have to gracefully handle this case
if (inputBytesWritten != inputBytesRead) {
printf("Error: Didn't write all bytes to intermediate file!\n");
exit(1);
}
return inputBytesRead;
}
// Returns the number of bytes written or 0 if the output is done
int writeOutput(int outputFd, const char* outputBuf, ssize_t bytesToWrite) {
ssize_t bytesWritten =
write(outputFd, outputBuf, bytesToWrite);
if (bytesWritten < 0) {
printf("Error: Couldn't write to output!\n");
exit(1);
}
return bytesWritten;
}
// Returns 0 if output was done or a positive number otherwise
int emptyBuffer(int outputFd, const char* outputBuf, ssize_t* outputBytesRead, ssize_t* outputBytesWritten) {
ssize_t newBytesWritten = 1;
while(*outputBytesRead - *outputBytesWritten > 0) {
newBytesWritten = writeOutput(outputFd, outputBuf, *outputBytesRead - *outputBytesWritten);
if (newBytesWritten == 0) {
debug("Output is done!\n");
break;
} else if (newBytesWritten < *outputBytesRead - *outputBytesWritten) {
debug("didn't write everything\n");
}
*outputBytesWritten += newBytesWritten;
}
return newBytesWritten;
}
void bufferedOutputRestIntermediateFile(int outputFd, int intermediateWriter, int intermediateReader,
char* outputBuf, int* doneWriting) {
ssize_t outputBytesRead = 0;
ssize_t outputBytesWritten = 0;
// If writing is not done and there are things left in the buffer
// or file, empty the buffer and intermediate files
ssize_t intermediateFileBytesToOutput =
safeLseek(intermediateWriter) - safeLseek(intermediateReader);
// TODO: Is there a way to optimize this by just copying the rest
// of the input in the output at once (e.g. by using cat)?
while(!(*doneWriting) && intermediateFileBytesToOutput > 0) {
// Fill the intermediate buffer
if (intermediateFileBytesToOutput > 0) {
outputBytesRead =
read(intermediateReader, outputBuf,
MIN(intermediateFileBytesToOutput, sizeof(intermediateReader)));
if (outputBytesRead < 0) {
printf("Error: Didn't read from intermediate file!\n");
exit(1);
}
outputBytesWritten = 0;
}
// Empty the intermediate buffer
if (emptyBuffer(outputFd, outputBuf, &outputBytesRead, &outputBytesWritten) == 0) {
*doneWriting = 1;
break;
}
intermediateFileBytesToOutput =
safeLseek(intermediateWriter) - safeLseek(intermediateReader);
}
return;
}
ssize_t safeWriteOutput(int outputFd, int intermediateReader,
off_t intermediateFileDiff, int* doneWriting) {
ssize_t res;
res =
#ifdef __linux__
sendfile
#else
send_file
#endif
(outputFd, intermediateReader, 0, intermediateFileDiff);
if (res < 0 && errno != EAGAIN) {
printf("ERROR: %s, when outputing %ld bytes!\n", strerror(errno), intermediateFileDiff);
exit(1);
} else if (res == 0) {
debug("We tried to write %d, but output is done!\n", intermediateFileDiff);
*doneWriting = 1;
}
return res;
}
void outputRestIntermediateFile(int outputFd, int intermediateWriter,
int intermediateReader, int* doneWriting) {
off_t finalOffset = safeLseek(intermediateWriter);
off_t intermediateFileBytesToOutput;
ssize_t res;
do {
intermediateFileBytesToOutput =
finalOffset - safeLseek(intermediateReader);
res = safeWriteOutput(outputFd, intermediateReader, intermediateFileBytesToOutput, doneWriting);
} while (!(*doneWriting) && res < intermediateFileBytesToOutput);
return;
}