C в amd64 Linux, 36 байт (только временная метка), 52 49 байт (реальная активность диска)
Я жестко open(2)кодирую флаги, так что это не переносимо на другие ABI. Linux на других платформах, вероятно, использует то же самое O_TRUNCи т. Д., Но другие операционные системы POSIX не могут.
+4 байта для передачи правильного аргумента разрешения, чтобы убедиться, что файл создан с правами записи владельца, см. Ниже. (Это работает с gcc 5.2)
несколько переносимый ANSI C, 38/51 байт (только временная метка), 52/67 байт (реальная активность диска)
Основано на ответе @ Cat с подсказкой @Jens.
Первое число для реализаций, где intможет содержать FILE *fopen()возвращаемое значение, второе число, если мы не можем этого сделать. В Linux адреса кучи находятся в младших 32 битах адресного пространства, поэтому он работает даже без -m32или -mx32. (Объявление void*fopen();короче чем #include <stdio.h>)
Только метаданные ввода-вывода метки времени :
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"));}
Запись байта, фактически попадание на диск в Linux 4.2.0 + XFS + lazytime:
main(){for(;write(open("a",577),"",1);close(3));}
writeэто условие цикла for, которое хорошо, поскольку оно всегда возвращает 1. closeэто приращение.
// 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
Объяснение непереносимой версии:
Файл создан со случайными разрешениями мусора. С gcc5.2, с -O0или -O3, бывает, что есть разрешение владельца на запись, но это не гарантируется. 0666является десятичным 438. 3-й аргумент to openзаймет еще 4 байта . Мы уже жестко программируем O_TRUNC и так далее, но это может нарушить другой компилятор или libc на том же ABI.
Мы не можем опустить 2-й аргумент в open, потому что значение мусора включает в себя O_EXCL, и O_TRUNC|O_APPEND, так что open не удается с EINVAL.
Нам не нужно сохранять возвращаемое значение из open(). Мы предполагаем это 3, потому что так будет всегда. Даже если мы начнем с открытия fd 3, он будет закрыт после первой итерации. В худшем случае, openпродолжает открывать новые fds до тех пор, пока 3 не станет последним доступным дескриптором файла. Таким образом, до первых 65531 write()вызовов может произойти сбой EBADF, но затем он будет работать нормально при каждом openсоздании fd = 3.
577 = 0x241 = O_WRONLY|O_CREAT|O_TRUNCв x86-64 Linux. Без O_TRUNCэтого время модификации и изменения inode не обновляются, поэтому более короткое значение arg невозможно. O_TRUNCвсе еще важно для версии, которая вызываетwrite фактическую активность диска, а не перезаписывает на месте.
Я вижу некоторые ответы, которые open("a",1). O_CREAT требуется, если aеще не существует. O_CREATопределяется как восьмеричное 0100 (64, 0x40) в Linux.
Нет утечки ресурсов, поэтому он может работать вечно. straceвыход:
open("a", O_WRONLY|O_CREAT|O_TRUNC, 03777762713526650) = 3
close(3) = 0
... repeating
или же
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
Я получил десятичное значение openфлагов для этого ABI, используемого strace -eraw=openв моей версии C ++.
В файловой системе с lazytimeвключенной опцией монтирования Linux изменение, затрагивающее только метки времени inode, будет вызывать только одну запись в сутки. Если эта опция монтирования отключена, обновление метки времени может стать жизнеспособным способом изнашивания вашего SSD. (Тем не менее, несколько других ответов делают только ввод / вывод метаданных).
альтернативы:
короче нерабочий :
main(){for(;;)close(write(open("a",577),"",3));}использует writeвозвращаемое значение для передачи 3аргумента для закрытия. Он сохраняет другой байт, но не работает с gcc -O0 или -O3 на amd64. Мусор в 3-м аргументе openотличается и не включает разрешения на запись. aсоздается в первый раз, но все будущие итерации терпят неудачу -EACCESS.
длиннее, работает, с разными системными вызовами :
main(c){for(open("a",65);pwrite(3,"",1);)sync();} перезаписывает байт на месте и вызывает sync()синхронизацию всех файловых систем в масштабе всей системы. Это поддерживает свет на диске.
Нам не важно, какой байт, поэтому мы не передаем 4-й аргумент в pwrite. Yay для разреженных файлов:
$ ll -s a
300K -rwx-wx--- 1 peter peter 128T May 15 11:43 a
Полагаю, что запись одного байта со смещением ~ 128 ТБ привела к тому, что xfs использовал пространство в 300 КБ для хранения карты экстентов. Не пытайтесь сделать это на OS X с HFS +: IIRC, HFS + не поддерживает разреженные файлы, поэтому он заполнит диск.
XFS - это правильная 64-битная файловая система, поддерживающая отдельные файлы до 8 эксабайт . т.е. 2 ^ 63-1, максимальное значение off_tможет удерживаться.
strace выход:
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ли правильный ответ Bash?)