Вы здесь

lseek

С каждым открытым файлом в UNIX связано понятие позиции чтения-записи. Это понятие не применимо к сокетам и каналам, но обычном файле у нас есть внутренняя нумерация байт, начинающаяся с нуля, и некая условная головка чтения-записи. Позиция головки одна для чтения и записи. При открытии файла на чтение или на запись головка выставляется на начало файла. При каждой операции чтения-записи головка устанавливается на позиции за последним считанным-записанным байтом. Особый случай - это открытие файла на дозапись с флагом O_APPEND. В этом случае каждая операция записи предварительно перемещает головку в конец файла. Конец файла - это позиция равная числу байт в файле. Если мы начнем запись в конец файла, то будем писать после последнего существующего байта. Если начнем читать, то прочитаем 0 байт, что является признаком конца файла.

Иногда появляется желание переместиться по файлу вперед или назад и начать читать или писать с некой определенной позиции. Для того чтобы управлять положением головки используется вызов lseek, который изменяет положение головки чтения-записи. lseek получает файловый дескриптор и два значения: значение смещения и макрос whence, который описывает откуда это смещение отсчитывается. В man странице написано, что использование слова whence нарушает правила английского языка, но сохраняется по историческим причинам.

Параметр whence может принимать три значения:
SEEK_CUR - смещение относительно текущей позиции. Если смещение положительное, то головка смещается к концу файла, если отрицательное - то ближе к началу файла.
SEEK_END - смещение вычисляется относительно текущего размера файла.
SEEK_SET - смещение от начала файла. Отрицательное смещение не имеет смысла.
В качестве результата lseek возвращает текущую позицию относительно начала файла.

Смещение 0 от текущей позиции не меняет положение головки, но возвращает текущую позицию. Нулевое смещение относительно конца файлы вернет его текущий размер, но переместит головку. Слишком большое отрицательное смещение переводит головку в нулевую позицию.

У вызова lseek есть проблема, связанная с разрядностью чисел.

В 32 разрядных системах максимальное значение целочисленного смещения четыре гигабайта, в то время как все современные файловые системы поддерживают файлы большего размера. Проблема в том, что мы просто не можем записать значение смещение больше 4ГБ. Тем не менее выполняя последовательные вызовы lseek мы можем перемещаться неограниченно далеко.

В таком случае lseek возвращает -1 и выставляет переменную errno в значение EOVERFLOW.

Чтобы работать со сверхбольшими файлами в 32 разрядной системе компилятор gcc и библиотека gnulibc предоставляют специальную функцию lseek64, у которой в качестве параметра offset передается структура, состоящая из двух целочисленных значений. Для ее использования необходимо открывать файл с флагом O_LARGEFILE и указывать при компиляции особые макросы -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS.