No Linux, você pode usar fallocate()
para desalocar os dados no início do arquivo.
Deallocating file space
Specifying the FALLOC_FL_PUNCH_HOLE flag (available since Linux 2.6.38) in mode deallocates space (i.e., creates a hole) in the byte range starting at offset and continuing for len bytes. Within the specified range, partial filesystem blocks are zeroed, and whole filesystem blocks are removed from the file. After a successful call, subsequent reads from this range will return zeroes.
...
Isso não alterará o tamanho do arquivo informado por ls
ou stat
ou similar, mas reduzirá o uso real do disco como arquivo será esparso . Tentar ler os "buracos" no arquivo ainda terá sucesso e retornará 0
-filled bytes para o processo de leitura.
Algo parecido com isto:
size_t maxSize = 512UL * 1024UL * 1024UL;
char buffer[ 8 * 1024 ];
struct stat sb;
int in = open( inputFile, O_RDONLY );
int out = open( outputFile, O_WRONLY | O_CREAT | O_APPEND, 0644 );
fstat( out, &sb );
size_t fileSize = sb.st_size;
for ( ;; )
{
ssize_t bytesRead = read( in, buffer, sizeof( buffer ) );
if ( bytesRead < 0 )
{
break;
}
ssize_t bytesWritten = write( out, buffer, bytesRead );
if ( bytesWritten < 0 )
{
break;
}
fileSize += bytesWritten;
if ( fileSize > maxSize )
{
fsync( out );
off_t endOfHole = fileSize - maxSize;
fallocate( out, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0UL, endOfHole );
}
}
Isso é suportado apenas no XFS, BTRFS, EXT4 e tmpfs.
Ele também precisa de muito mais verificação de erros e pode até não ser compilado como está. Também é muito ineficiente, uma vez que o tamanho máximo é atingido, ele chamará fallocate()
para cada read()
/ write()
cycle, e ele perfurará o "buraco" do início do arquivo toda vez.
Também não faz sentido usar o fread()
/ fwrite()
em buffer para esse padrão de IO. Apenas read()
/ write()
pedaços grandes o suficiente.