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
|
static FILE *tempFileDes (void) {
int fd;
FILE *f;
char *template;
const char *tmpDir;
const char *tag = "/TempFileXXXXXXXXXX";
size_t tmpDirLen, tagLen;
mode_t m;
tmpDir = getenv ("TMP");
if (NULL == tmpDir) {
tmpDir = getenv ("TMPDIR");
if (NULL == tmpDir)
tmpDir = "/var/tmp";
}
tmpDirLen = strlen(tmpDir);
tagLen = strlen(tag);
template = malloc_safe (tmpDirLen + tagLen + 1);
strncpy (template, tmpDir, tmpDirLen + 1);
strncpy (template + tmpDirLen, tag, tagLen + 1);
m = umask(077);
fd = mkstemp_safe (template);
f = fdopen_safe (fd, "w+");
(void)umask(m);
unlink_safe (template);
free (template);
return f;
}
typedef struct {
FILE *f;
} *WriteToDiskData;
void GC_diskBack_read (void *data, pointer buf, size_t size) {
FILE *f;
const size_t READ_CHUNK_SIZE = 0x2000000; /* 32M */
f = ((WriteToDiskData)data)->f;
fseek_safe (f, 0, SEEK_SET);
/* fread (_, 1, size, _) succeeds
* with size >= 2^31
* for a 32-bit executable on 64-bit linux.
* Nonetheless, match GC_diskBack_write.
*/
while (size > 0) {
size_t s = min (READ_CHUNK_SIZE, size);
fread_safe (buf, 1, s, f);
buf += s;
size -= s;
}
}
void GC_diskBack_close (void *data) {
FILE *f;
f = ((WriteToDiskData)data)->f;
fclose_safe (f);
free (data);
}
void *GC_diskBack_write (pointer buf, size_t size) {
FILE *f;
WriteToDiskData d;
const size_t WRITE_CHUNK_SIZE = 0x2000000; /* 32M */
f = tempFileDes ();
/* fwrite (_, 1, size, _) fails
* (with no helpful error conditions!)
* with size >= 2^31
* on x86-linux.
*/
while (size > 0) {
size_t s = min (WRITE_CHUNK_SIZE, size);
fwrite_safe (buf, 1, s, f);
buf += s;
size -= s;
}
d = (WriteToDiskData)(malloc_safe (sizeof(*d)));
d->f = f;
return d;
}
|