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
Объяснение непереносимой версии:
Файл создан со случайными разрешениями мусора. С gcc
5.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?)