C no amd64 Linux, 36 bytes (somente timestamp), 52 49 bytes (atividade em disco real)
Eu open(2)
codifico os sinalizadores, portanto, isso não é portátil para outras ABIs. O Linux em outras plataformas provavelmente usa o mesmo O_TRUNC
, etc., mas outros sistemas operacionais POSIX podem não.
+4 bytes para passar um argumento de permissão correto para garantir que o arquivo seja criado com acesso de gravação do proprietário, veja abaixo. (Isso funciona com o gcc 5.2)
ANSI C um tanto portátil, 38/51 bytes (somente carimbo de data / hora), 52/67 bytes (atividade em disco real)
Com base na resposta de @ Cat, com uma dica de @Jens.
O primeiro número é para implementações em que um int
pode reter FILE *fopen()
o valor de retorno, o segundo número, se não pudermos fazer isso. No Linux, os endereços de heap estão com pouco espaço de endereço de 32 bits; portanto, ele funciona mesmo sem -m32
ou -mx32
. (A declaração void*fopen();
é menor que #include <stdio.h>
)
Somente E / S de metadados de carimbo de data e hora :
main(){for(;;)close(open("a",577));} // Linux x86-64
//void*fopen(); // compile with -m32 or -mx32 or whatever, so an int holds a pointer.
main(){for(;;)fclose(fopen("a","w"));}
Escrevendo um byte, atingindo o disco no Linux 4.2.0 + XFS + lazytime
:
main(){for(;write(open("a",577),"",1);close(3));}
write
é a condição do loop for, o que é bom, pois sempre retorna 1. close
é o incremento.
// semi-portable: storing a FILE* in an int. Works on many systems
main(f){for(;f=fopen("a","w");fclose(f))fputc(0,f);} // 52 bytes
// Should be highly portable, except to systems that require prototypes for all functions.
void*f,*fopen();main(){for(;f=fopen("a","w");fclose(f))fputc(0,f);} // 67 bytes
Explicação da versão não portátil:
O arquivo é criado com permissões aleatórias de lixo. Com o gcc
5.2, com -O0
ou -O3
, inclui permissão de gravação do proprietário, mas isso não é garantido. 0666
é decimal 438. Um terceiro argumento open
levaria outros 4 bytes . Nós já estamos codificando O_TRUNC e assim por diante, mas isso pode ocorrer com um compilador ou libc diferente na mesma ABI.
Não podemos omitir o segundo argumento para open
, porque o valor do lixo inclui O_EXCL
, e O_TRUNC|O_APPEND
, portanto, a abertura falha com EINVAL
.
Não precisamos salvar o valor de retorno open()
. Nós assumimos que é 3
, porque sempre será. Mesmo se começarmos com o fd 3 aberto, ele será fechado após a primeira iteração. Na pior das hipóteses, open
continua abrindo novos fds até que 3 seja o último descritor de arquivo disponível. Portanto, até as primeiras 65531 write()
chamadas podem falhar EBADF
, mas funcionarão normalmente com toda a open
criação de fd = 3.
577 = 0x241 = O_WRONLY|O_CREAT|O_TRUNC
no x86-64 Linux. Sem O_TRUNC
, o tempo de modificação do inode e o tempo de alteração não são atualizados, portanto, um argumento mais curto não é possível. O_TRUNC
ainda é essencial para a versão que chama write
para produzir a atividade real do disco, não para reescrever no local.
Eu vejo algumas respostas isso open("a",1)
. O_CREAT é necessário se a
ainda não existir. O_CREAT
é definido como octal 0100 (64, 0x40) no Linux.
Nenhum vazamento de recursos, portanto, ele pode ser executado para sempre. strace
resultado:
open("a", O_WRONLY|O_CREAT|O_TRUNC, 03777762713526650) = 3
close(3) = 0
... repeating
ou
open("a", O_WRONLY|O_CREAT|O_TRUNC, 01) = 3
write(3, "\0", 1) = 1 # This is the terminating 0 byte in the empty string we pass to write(2)
close(3) = 0
Eu tenho o valor decimal dos open
sinalizadores para este ABI usando strace -eraw=open
na minha versão C ++.
Em um sistema de arquivos com a lazytime
opção de montagem Linux ativada, uma alteração que afeta apenas os carimbos de data / hora do inode causará apenas uma gravação a cada 24 horas. Com essa opção de montagem desativada, a atualização do carimbo de data / hora pode ser uma maneira viável de desgastar seu SSD. (No entanto, várias outras respostas fazem apenas E / S de metadados).
alternativas:
menos tempo de trabalho :
main(){for(;;)close(write(open("a",577),"",3));}
usa write
o valor de retorno para passar um 3
argumento para fechar. Ele salva outro byte, mas não funciona com o gcc -O0 ou -O3 no amd64. O lixo no terceiro argumento para open
é diferente e não inclui permissão de gravação. a
é criado na primeira vez, mas todas as iterações futuras falham -EACCESS
.
por mais tempo, trabalhando, com diferentes chamadas do sistema :
main(c){for(open("a",65);pwrite(3,"",1);)sync();}
reescreve um byte no local e chama sync()
para sincronizar todos os sistemas de arquivos em todo o sistema. Isso mantém a luz da unidade acesa.
Nós não nos importamos com qual byte, então não passamos o quarto argumento para escrever. Yay para arquivos esparsos:
$ ll -s a
300K -rwx-wx--- 1 peter peter 128T May 15 11:43 a
Escrever um byte em um deslocamento de ~ 128TiB levou ao xfs usando 300kiB de espaço para armazenar o mapa de extensão, eu acho. Não tente fazer isso no OS X com o HFS +: IIRC, o HFS + não suporta arquivos esparsos; portanto, ele preencherá o disco.
O XFS é um sistema de arquivos adequado de 64 bits, suportando arquivos individuais de até 8 exabytes . ou seja, 2 ^ 63-1, o valor máximo off_t
pode ser mantido.
strace
resultado:
open("a", O_WRONLY|O_CREAT, 03777711166007270) = 3
pwrite(3, "\0", 1, 139989929353760) = 1
sync() = 0
pwrite(3, "\0", 1, 139989929380071) = 1
sync() = 0
...
/dev/null
? (Éyes>/dev/null
uma resposta Bash válido?)