File Position/Offset (lseek64()
)#
#include <sys/types.h>
#include <unistd.h>
off64_t lseek64(int fd, off64_t offset, int whence);
File Offset, And read()/write()
#
read()
always reads from current file offsetOffset is advanced as part of the read operation
(Same with
write()
)⟶ offset is part of the “open file description” (
struct file
) in kernel space
How lseek64()
Works#
⟶ how to determine current offset, how to explicitly set offset?
lseek()
can only handle 32 bit offsets (historical baggage)⟶
lseek64()
Possible values for
whence
Macro
Description
SEEK_SET
The file offset is set to
offset
bytes, absolutely.SEEK_CUR
The file offset is set to its current location plus
offset
bytes, relatively.SEEK_END
The file offset is set to the size of the file plus
offset
bytes, relatively.
Getting Current Offset#
Use
SEEK_CUR
withoffset
0 to get current position:lseek64(fd, 0, SEEK_CUR)
. (“Add 0 to current position, and return new position”)The following program visualizes what’s shown in the sketch above
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <print>
int main()
{
int fd = open("/etc/passwd", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
off64_t pos = lseek64(fd, 0, SEEK_CUR);
if (pos == -1) {
perror("lseek");
return 1;
}
std::println("initial offset: {}", pos);
char buf[10];
ssize_t nread = read(fd, buf, 10);
if (nread == -1) {
perror("read");
return 1;
}
pos = lseek64(fd, 0, SEEK_CUR);
if (pos == -1) {
perror("lseek");
return 1;
}
std::println("offset after 10 bytes read: {}", pos);
return 0; // <-- fd automatically closed at exit
}
$ ./sysprog-lseek-getpos
initial offset: 0
offset after 10 bytes read: 10
Setting File Offset#
Use
offset
parameter, in combination withSEEK_SET
,SEEK_CUR
andSEEK_END
The program below drops an
'X'
in position 2 of/tmp/somefile
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <print>
int main()
{
int fd = open("/tmp/somefile", O_WRONLY|O_CREAT|O_EXCL, 0666);
if (fd == -1) {
perror("open");
return 1;
}
off64_t pos = lseek64(fd, 2, SEEK_SET); // <-- absolute position 2
if (pos == -1) {
perror("lseek");
return 1;
}
char byte = 'X';
ssize_t nwritten = write(fd, &byte, 1); // <-- drop an 'X' to current position (2)
if (nwritten == -1) {
perror("write");
return 1;
}
return 0; // <-- fd automatically closed at exit
}
$ echo 012345 > /tmp/somefile
$ ./sysprog-lseek-setpos-write
$ cat /tmp/somefile
01X345
Holes In Files?#
One of the more obscure UNIX features
Set the offset beyond file size
Drop at least one byte there
⟶ gap does not occupy space
⟶ reading from holes yields 0-bytes
Holes In Files (Program)#
The following program uses
/tmp/somefile
from aboveAdds a hole according to the sketch
Note how it does not consume disk space correspondingly (
btrfs
works differently/specially though)
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <print>
int main()
{
int fd = open("/tmp/somefile", O_WRONLY|O_CREAT|O_EXCL, 0666);
if (fd == -1) {
perror("open");
return 1;
}
off64_t pos = lseek64(fd, 10000, SEEK_SET); // <-- absolute position 10000
if (pos == -1) {
perror("lseek");
return 1;
}
char byte = 'X';
ssize_t nwritten = write(fd, &byte, 1); // <-- drop byte at 10000
if (nwritten == -1) {
perror("write");
return 1;
}
return 0; // <-- fd automatically closed at exit
}