public
Last active

  • Download Gist
file-size.c
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
#include <assert.h>
#include <dispatch/dispatch.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/event.h>
#include <sys/event.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/types.h>
#include <unistd.h>
 
#define FILENAME "/tmp/.some-tmp-file"
#define MAX_FILE_SIZE 10*1000*1000
 
int get_fd_size(int fd)
{
off_t eof_pos = lseek(fd, 0, SEEK_END);
return eof_pos;
}
 
void go_on(int fd)
{
int ret = -1;
int kq = kqueue();
struct kevent changelist[1];
 
if (kq < 0) {
/* errno set by kqueue */
ret = -1;
goto out;
}
 
memset(changelist, 0, sizeof(changelist));
EV_SET(&changelist[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE | NOTE_RENAME | NOTE_EXTEND, 0, 0);
 
if (kevent(kq, changelist, 1, NULL, 0, NULL) < 0) {
/* errno set by kevent */
ret = -1;
goto out;
}
while (1) {
{
/* Step 1: Check the size */
off_t new_sz = get_fd_size(fd);
printf("new size: %lld\n", new_sz);
if (new_sz >= MAX_FILE_SIZE) {
printf("Ok, success\n");
exit(0);
}
}
 
{
/* Step 2: Wait for growth */
struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 };
int suc_kev = kevent(kq, NULL, 0, changelist, 1, &timeout);
 
if (0 == suc_kev) {
/* That's a timeout */
off_t new_sz = get_fd_size(fd);
printf("Timeout (%lld)\n", new_sz);
errno = ETIMEDOUT;
ret = -1;
goto out;
} else if (suc_kev > 0) {
char *type = "?";
if ( changelist[0].filter == EVFILT_VNODE &&
changelist[0].fflags & NOTE_EXTEND) {
type = "EXTEND";
}
if ( changelist[0].filter == EVFILT_VNODE &&
changelist[0].fflags & NOTE_WRITE) {
type = "WRITE";
}
printf("kevent %s #%p (%p | %p)\n", type, changelist[0].ident, changelist[0].data, changelist[0].udata);
if (changelist[0].filter == EVFILT_VNODE) {
if (changelist[0].fflags & NOTE_RENAME || changelist[0].fflags & NOTE_DELETE) {
/* file was deleted, renamed, ... */
printf("Renamed\n");
errno = ENOENT;
ret = -1;
goto out;
}
}
} else {
/* errno set by kevent */
printf("Error: %d\n", errno);
ret = -1;
goto out;
}
}
}
 
out: {
int errno_save = errno;
if (kq >= 0) {
close(kq);
}
errno = errno_save;
return;
}
}
 
void do_writes(int xfd)
{
 
int fd = open(FILENAME, O_WRONLY);
const int write_fd = dup(fd);
const off_t size_per_write = MAX_FILE_SIZE / 10;
const off_t desired_size = MAX_FILE_SIZE;
char *buf = malloc(size_per_write);
memset(buf, 'A', size_per_write);
for (int i=0; i<desired_size / size_per_write; i++) {
#ifndef USE_FTRUNCATE
{
ssize_t suc_write = write(write_fd, buf, size_per_write);
assert(suc_write == size_per_write);
}
#else
ftruncate(write_fd, (1+i) * size_per_write);
#endif
printf("wrote\n");
fsync(write_fd);
usleep(100000);
}
free(buf);
 
{
struct stat stat_buf = {0};
fstat(write_fd, &stat_buf);
printf("writing thread finished: desired: %lld, actual: %lld\n", desired_size, stat_buf.st_size);
 
}
/*
close(write_fd);
close(fd);
*/
}
 
int main()
{
int fd = open(FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0777);
assert(fd >= 0);
dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), (void *)fd, do_writes);
 
go_on(fd);
return 0;
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.