Created
March 29, 2019 16:37
-
-
Save kostikbel/5319d0d7d52e0f9199ddf2b5a75a6438 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $Id: seek_hole.c,v 1.2 2012/05/26 04:50:22 kostik Exp kostik $ */ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#define ERROR(str) \ | |
fprintf(stderr, "%s: pos=%ju, errno=%d\n", str, (uintmax_t)pos, errno) | |
static int | |
reset_file(int fd) | |
{ | |
int ret; | |
ret = ftruncate(fd, 0); | |
if (ret < 0) { | |
fprintf(stderr, "Truncate failed: %d\n", errno); | |
return 1; | |
} | |
return 0; | |
} | |
static int block_size; | |
int | |
main(int argc, char **argv) | |
{ | |
char *buf; | |
ssize_t bytes; | |
off_t pos; | |
int prealloc_is_hole = 0; | |
int whole_file_is_data = 0; | |
int ret; | |
int i; | |
int fd; | |
fd = open("testfile", O_RDWR|O_CREAT|O_TRUNC, 0644); | |
if (fd < 0) { | |
fprintf(stderr, "Failed to open testfile: %s\n", | |
strerror(errno)); | |
return 1; | |
} | |
block_size = fpathconf(fd, _PC_MIN_HOLE_SIZE); | |
if (block_size == -1) { | |
fprintf(stderr, "Cannot get hole size: %s\n", strerror(errno)); | |
return (1); | |
} | |
buf = malloc(block_size * 4); | |
/* Empty file */ | |
printf("Testing an empty file\n"); | |
pos = lseek(fd, 0, SEEK_DATA); | |
if (pos != -1) { | |
if (errno == EINVAL) { | |
fprintf(stderr, "Kernel does not support seek " | |
"hole/data\n"); | |
close(fd); | |
return 1; | |
} | |
if (errno != ENXIO) | |
ERROR("Seek data did not return a proper error"); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, 0, SEEK_HOLE); | |
if (pos != -1 && errno != ENXIO) { | |
ERROR("Seek hole did not return a proper error"); | |
close(fd); | |
return 1; | |
} | |
memset(buf, 'a', block_size * 4); | |
/* | |
* All data file | |
*/ | |
printf("Testing a normal data filled file\n"); | |
for (i = 0; i < 4; i++) { | |
bytes = write(fd, buf, block_size); | |
if (bytes < block_size) { | |
fprintf(stderr, "Failed to write to testfile: %d\n", | |
errno); | |
close(fd); | |
return 1; | |
} | |
} | |
pos = lseek(fd, 0, SEEK_HOLE); | |
if (pos != (block_size * 4) || pos == -1) { | |
ERROR("Seek hole failed to dump us out at the end of the file"); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, 0, SEEK_DATA); | |
if (pos != 0) { | |
ERROR("Seek data failed to dump us out at the beginning of the" | |
" file"); | |
close(fd); | |
return 1; | |
} | |
/* | |
* File with a hole at the front and data at the end | |
*/ | |
printf("Testing file with hole at the start and data in the rest\n"); | |
if (reset_file(fd)) { | |
close(fd); | |
return 1; | |
} | |
bytes = pwrite(fd, buf, block_size * 3, block_size); | |
if (bytes < (block_size * 3)) { | |
fprintf(stderr, "Failed to write to testfile\n"); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, 0, SEEK_HOLE); | |
if (pos != 0 && pos != (block_size * 4)) { | |
ERROR("Seek hole failed to return 0"); | |
close(fd); | |
return 1; | |
} else if (pos == (block_size * 4)) { | |
whole_file_is_data = 1; | |
printf("Current file system views treats the entire file as " | |
"data\n"); | |
} | |
pos = lseek(fd, 0, SEEK_DATA); | |
if (pos != block_size && (pos != 0 && whole_file_is_data)) { | |
if (whole_file_is_data) | |
ERROR("Seek data failed to return 0"); | |
else | |
ERROR("Seek data failed to return block_size"); | |
close(fd); | |
return 1; | |
} | |
if (whole_file_is_data) { | |
pos = lseek(fd, 1, SEEK_DATA); | |
if (pos != -1 && errno != ENXIO) { | |
ERROR("Seek data failed to return an error"); | |
close(fd); | |
return 1; | |
} | |
} | |
#if 0 | |
/* | |
* File with a hole at the end and data at the beginning | |
*/ | |
printf("Testing file with hole at the end and data at the beginning\n"); | |
if (reset_file(fd)) { | |
close(fd); | |
return 1; | |
} | |
ret = ftruncate(fd, block_size * 4); | |
if (ret < 0) { | |
fprintf(stderr, "Truncate failed: %d\n", errno); | |
close(fd); | |
return 1; | |
} | |
pwrite(fd, buf, block_size * 3, 0); | |
if (bytes < (block_size * 3)) { | |
fprintf(stderr, "Failed to write to testfile: %d\n", errno); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, 0, SEEK_HOLE); | |
if (pos != (block_size * 3) && (pos != (block_size * 4) && whole_file_is_data)) { | |
ERROR("Seeking hole didn't work right"); | |
close(fd); | |
return 1; | |
} | |
if (whole_file_is_data) { | |
pos = lseek(fd, pos, SEEK_HOLE); | |
if (pos != -1 && errno != ENXIO) { | |
ERROR("Seeking hole didn't return error"); | |
close(fd); | |
return 1; | |
} | |
printf("No more tests to run since we treat the whole file as " | |
"data\n"); | |
goto out; | |
} | |
pos = lseek(fd, pos, SEEK_HOLE); | |
if (pos != (block_size * 3)) { | |
ERROR("Seek hole didn't return same position"); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, pos+1, SEEK_HOLE); | |
if (pos != (block_size * 4)) { | |
ERROR("Seek hole didn't return the end of the file"); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, pos, SEEK_DATA); | |
if (pos != -1 && errno != ENXIO) { | |
ERROR("Seek data didn't return ENXIO"); | |
close(fd); | |
return 1; | |
} | |
#endif | |
/* | |
* Hole - Data - Hole - Data file | |
*/ | |
printf("Testing file [Hole][Data][Hole][Data]\n"); | |
if (reset_file(fd)) { | |
close(fd); | |
return 1; | |
} | |
ret = ftruncate(fd, block_size * 4); | |
if (ret < 0) { | |
fprintf(stderr, "ftruncate failed: %d\n", errno); | |
close(fd); | |
return 1; | |
} | |
bytes = pwrite(fd, buf, block_size, block_size); | |
if (bytes < block_size) { | |
fprintf(stderr, "Failed to write: %d\n", errno); | |
close(fd); | |
return 1; | |
} | |
bytes = pwrite(fd, buf, block_size, block_size * 3); | |
if (bytes < block_size) { | |
fprintf(stderr, "Failed to write: %d\n", errno); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, 0, SEEK_DATA); | |
if (pos != block_size) { | |
ERROR("Seek data did not return block_size"); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, pos, SEEK_HOLE); | |
if (pos != (block_size * 2)) { | |
ERROR("Seek hole did not return block_size*2"); | |
close(fd); | |
return 1; | |
} | |
pos = lseek(fd, pos, SEEK_DATA); | |
if (pos != (block_size * 3)) { | |
ERROR("Seek data did not return block_size*3"); | |
close(fd); | |
return 1; | |
} | |
out: | |
close(fd); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment