/** * test application that demonstrates the use of sparse files * plus mmap to efficiently process large data sets * * Copyright (C) 2009 Cliff Brake * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #include #include #include #include #include #include #include #include #include #include void display_help(void) { printf("Usage: sparse_file_mmap_test [OPTION]\n" "\n" " -s, --filesize File size to allocate\n" " -o, --offset Will write a few bytes every offset bytes\n" " -m, --modify Modify existing file\n" " -d, --data Data to write to file at offset location (0-255)\n"); exit(0); } int filesize = 3*1024*1024; int offset = 1*1024*1024; int modify = 0; unsigned char data = 'x'; void process_options(int argc, char * argv[]) { for (;;) { int option_index = 0; static const char *short_options = "s:o:md:"; static const struct option long_options[] = { {"help", no_argument, 0, 0}, {"filesize", required_argument, 0, 's'}, {"offset", required_argument, 0, 'o'}, {"modify", no_argument, 0, 'm'}, {"data", required_argument, 0, 'd'}, {0,0,0,0}, }; int c = getopt_long(argc, argv, short_options, long_options, &option_index); if (c == EOF) { break; } switch (c) { case 0: display_help(); break; case 's': filesize = atoi(optarg); break; case 'o': offset = atoi(optarg); break; case 'm': modify = 1; break; case 'd': data = atoi(optarg); break; } } } #define FILENAME "sparse-file" int main(int argc, char **argv) { process_options(argc, argv); printf("Sparse File mmap() test\n"); printf("Filesize = %i, offset = %i, data = %i\n", filesize, offset, data); int fd; if (modify) { fd = open(FILENAME, O_RDWR); if (fd == -1) { printf("Error opening file\n"); exit(-1); } } else { /* deleting is required, otherwise, old file contents are used */ unlink(FILENAME); fd = open(FILENAME, O_RDWR|O_CREAT, 0666); if (fd == -1) { printf("Error creating file\n"); exit(-1); } /* go to location corresponding to the last byte, and write a dummpy byte */ if (lseek(fd, filesize - 1, SEEK_SET) == -1) { printf("Error seeking to end of file\n"); exit(-1); } if (write(fd, "", 1) == -1) { printf("Error writing at end of file\n"); exit(-1); } } unsigned char *p = mmap(0, filesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { printf("Error mmap'ing file: %s\n", strerror(errno)); exit(-1); } int i; /* write data to file */ for (i=0; i < filesize; i+=offset) { p[i] = data; } if (munmap(p, filesize) < 0) { printf("Error unmapping file\n"); exit(-1); } fsync(fd); close(fd); /* try to determine the "compression" on disk due to sparse file */ struct stat s; stat(FILENAME, &s); // I was hoping that blocks could be used to compute size on disk, but does not seem to work ... // printf("size = %i, size on disk = %i, compression = %.2f %%\n", // (int)(s.st_size), (int)(s.st_blocks*s.st_blksize), 100 - ((float)(s.st_blocks*s.st_blksize)/s.st_size)*100); printf("size = %i KB\n", (int)(s.st_size)/1024); printf("size on disk (KB):\n"); system("du " FILENAME); }