Thanks to some interesting input, I decided that I should extend upon my file copy previous example. In case, you are wondering, I chose to use fwrite, fread etc.. on this application, but the same is possible with read/write to copy a "sparse file" or a file with "file holes"
As per input, here is how I create my sparse file using the dd command:
-
$ dd if=/dev/zero of=sparse.img bs=1 count=0 seek=128M
-
0+0 records in
-
0+0 records out
-
0 bytes (0 B) copied, 0.000530044 s, 0.0 kB/s
-
$ du -h sparse.img ; du -h --apparent-size sparse.img
-
0 sparse.img
-
128M sparse.img
Then after compiling and executing my application, I see:
-
gcc -Wall -o cpy cpy2.c
-
./cpy sparse.img output.img
-
]du -h output.img; du -h --apparent-size output.img
-
0 output.img
-
128M output.img
-
/**
-
* @file cpy2.c
-
* @author Ron Brash ([email protected]
-
* @date Sept 22, 2014
-
* @brief C program demonstrating how to duplicate a file which
-
* contains a "file hole" or in other words - a "sparse file".
-
*/
-
#define _GNU_SOURCE
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <sys/stat.h>
-
#include <sys/types.h>
-
#include <fcntl.h>
-
#include <error.h>
-
#include <string.h>
-
#include <unistd.h>
-
#include <ctype.h>
-
#include <stdint.h>
-
-
#include <assert.h>
-
-
static off_t fsize(const char *filename);
-
-
/**
-
* fsize(const char *filename)
-
*
-
* @brief Returns the filesize of a file using stat.h
-
* @param filename
-
* @return -1 if there is an error, zero or positive value otherwise
-
*/
-
static off_t fsize(const char *filename)
-
{
-
struct stat st = { 0 };
-
-
if (stat(filename, &st) == 0) {
-
-
return st.st_size;
-
}
-
-
return (-1);
-
}
-
-
/**
-
* main(int argc, char **argv)
-
*
-
* @brief A main function
-
* @param argc
-
* @param argv
-
* @return -1 if error, 0 for success
-
*/
-
int main(int argc, char **argv)
-
{
-
FILE *inputFP = NULL;
-
FILE *outputFP = NULL;
-
char buf[BUFSIZ] = { };
-
register ssize_t file_size = 0;
-
ssize_t apparent_size = 0;
-
-
/* Open a file descriptor for the input file */
-
if ((inputFP = fopen(argv[1], "r")) == NULL) {
-
perror("Error opening input file descriptor");
-
return (-1);
-
}
-
-
/* Determine the file_size of the input file */
-
if ((apparent_size = fsize(argv[1])) < 0) {
-
perror("Unable to determine accurate size of file");
-
return (-1);
-
}
-
printf("file's apparent size:%i\n", (unsigned int)apparent_size);
-
-
/* Open a file descriptor for the output file */
-
if ((outputFP = fopen(argv[2], "w")) == NULL) {
-
perror("Error opening output file descriptor");
-
return (-1);
-
}
-
-
/* Advise the kernel that there will be a long sequential write */
-
if (posix_fadvise(fileno(inputFP), 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
-
perror("Unable to advise the kernel for the upcoming sequential write");
-
// Continue anyways...
-
}
-
-
/* Create a file using ftruncate and lets carry on */
-
if (ftruncate(fileno(outputFP), apparent_size) < 0) {
-
perror("Unable to create a file that will have a similar size to the original");
-
return (-1);
-
}
-
-
register int i = 0;
-
register unsigned long holeSize = 0;
-
while ((file_size = fread(buf, sizeof(char), sizeof(buf), inputFP)) > 0) {
-
-
for (i = 0; i < file_size; i++) {
-
-
if (buf[i] == '\0') {
-
holeSize++;
-
continue;
-
}
-
-
fseek(outputFP, holeSize, SEEK_CUR);
-
fwrite(&buf[i], 1, 1, outputFP);
-
-
if (ferror(outputFP)) {
-
perror("write\n");
-
break;
-
}
-
holeSize = 0;
-
-
}
-
-
}
-
-
/* Close the input file descriptor */
-
if (fclose(inputFP) < 0) {
-
perror("closing inputFP");
-
return (-1);
-
}
-
-
/* Close the output file descriptor */
-
if (fclose(outputFP) < 0) {
-
perror("closing outputFP");
-
return (-1);
-
}
-
-
return 0;
-
}
Blog tags:
Attachment | Size |
---|---|
Sparse File copy application in C | 2.77 KB |
Add new comment