четверг, 19 июля 2012 г.

lseek

Роберт Лав, как оказалось, пишет довольно увлекательно. Узнал для себя немало нового из его книги "Linux. Системное программирование". Одним из открытий хочу поделиться.
Системный вызов lseek() предназначен для установки позиции в файле, соответствующем файловому дескриптору. Однако у него есть одно забавное применение. Возможно использовать lseek() для 'перемотки' файла за его(файла) предел. Если после этого записать что-то в текущую позицию, место между концом файла и позицией заполнится нулями.
Таким образом, возможно быстрое создание файла (почти)любого размера. К примеру, на 16 терабайт(предел в файловой системе ext4):

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
 int fd = open(argv[1], O_WRONLY | O_CREAT | O_LARGEFILE, 0644);
 int ret;
 off64_t ret64;

 off64_t kilo = 1024;
 off64_t megabyte = kilo * kilo;
 off64_t terabyte = megabyte * megabyte;
 off64_t offset = 16 * terabyte - megabyte;

 if (fd < 1) {
  perror("open");
  return -1;
 }

 ret64 = lseek64(fd, offset, SEEK_END);
 if (ret64 < 1) {
  perror("lseek");
  return -1;
 }

 ret = write(fd, "0", 1);
 if (ret < 1) {
  perror("write");
  return -1;
 }
 write(STDOUT_FILENO, "Success!\n", 10); 

 return 0;
}

Код следует компилировать с флагом -D_GNU_SOURCE. Пользователи 32-разрядных систем могут получить работающий код, слегка изменив программу. Однако они всё равно будут ограничены 2 гигабайтами - размером off_t. Впрочем, можно использовать fsetpos().

Комментариев нет: