lseek(2)

๐Ÿ’– NAME ๐Ÿ’–

okay so bestie, gather round, we're talking about lseek(2) from the System Calls Manual โ€” and what it does is reposition the read/write file offset. that's it, that's the whole job, and it does it flawlessly. no cap. ๐Ÿ‘‘


๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library (libc, -lc) โ€” the classic, the blueprint, the one you already have linked. ๐Ÿซถ


๐ŸŽ€ SYNOPSIS ๐ŸŽ€

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

look at that signature. clean. iconic. three args and a dream. โœจ


๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

so lseek() takes the file offset of the open file description that's chillin' behind the file descriptor fd, and it moves it to offset, based on whatever whence tells it to do. whence can be any of these, and I need you to know all three fr fr:

  • SEEK_SET โ€” the file offset gets set to offset bytes. boom, absolute. no vibes, just coordinates. ๐Ÿ’…
  • SEEK_CUR โ€” the file offset gets set to wherever it currently is, plus offset bytes. yes, relative, we love a glow-up from the current position. ๐Ÿฆ‹
  • SEEK_END โ€” the file offset gets set to the size of the file, plus offset bytes. the end of the file is the starting line now. ๐ŸŒธ

and here's the unhinged part that's actually real: lseek() lets you set the file offset beyond the end of the file (but heads up โ€” this does not change the size of the file). so if you later write data at that point, any subsequent reads of the data in the gap โ€” that's a "hole", bestie โ€” return null bytes ('\0') until data is actually written into that gap. it's giving void energy. ๐Ÿ•ณ๏ธ

๐ŸŒธ Seeking file data and holes ๐ŸŒธ

since Linux 3.1, Linux has supported two extra values for whence, and they're lowkey the most interesting part:

  • SEEK_DATA โ€” adjust the file offset to the next location in the file that's greater than or equal to offset and containing data. and if offset points to data? then the file offset is just set to offset. easy. ๐Ÿ’–
  • SEEK_HOLE โ€” adjust the file offset to the next hole in the file that's greater than or equal to offset. if offset points into the middle of a hole, the file offset is set to offset. and if there is no hole past offset, the file offset gets adjusted to the end of the file โ€” because (say it with me) there is an implicit hole at the end of any file. periodt. ๐Ÿ•ณ๏ธโœจ

in both of the above cases, lseek() fails if offset points past the end of the file.

these operations let applications map holes in a sparsely allocated file. super useful for stuff like file backup tools โ€” they can save space when creating backups and preserve holes, if they have a mechanism for discovering holes. king behavior. ๐Ÿ‘‘

for the purposes of these operations, a hole is a sequence of zeros that (normally) has not been allocated in the underlying file storage. BUT โ€” and this is the part where you stop and pay attention โ€” a filesystem is not obliged to report holes, so these operations are not a guaranteed mechanism for mapping the storage space actually allocated to a file. (also: a sequence of zeros that actually has been written to the underlying storage may not be reported as a hole.) in the simplest implementation, a filesystem can support the operations by making SEEK_HOLE always return the offset of the end of the file, and making SEEK_DATA always return offset โ€” like, even if the location referred to by offset is a hole, it can be considered to consist of data that is a sequence of zeros. ๐Ÿ™ˆ

the _GNU_SOURCE feature test macro must be defined in order to obtain the definitions of SEEK_DATA and SEEK_HOLE from <unistd.h>. don't forget it, bestie, or you'll be staring at compiler errors wondering why your whole life is falling apart. ๐Ÿ˜ญ

the SEEK_HOLE and SEEK_DATA operations are supported for the following filesystems โ€” yup, a whole list, we love a list:

  • Btrfs (since Linux 3.1)
  • OCFS (since Linux 3.2)
  • XFS (since Linux 3.5)
  • ext4 (since Linux 3.8)
  • tmpfs(5) (since Linux 3.8)
  • NFS (since Linux 3.18)
  • FUSE (since Linux 4.5)
  • GFS2 (since Linux 4.15)

๐Ÿ’… RETURN VALUE ๐Ÿ’…

upon successful completion, lseek() returns the resulting offset location, measured in bytes from the beginning of the file. ๐ŸŽฏ

on error, the value (off_t) -1 is returned and errno is set to indicate the error. not the vibe, but that's how you'll know. ๐Ÿ’€


๐Ÿ˜ญ ERRORS ๐Ÿ˜ญ

  • EBADF โ€” fd is not an open file descriptor. bestie the door isn't even there. ๐Ÿšช
  • EINVAL โ€” whence is not valid. or: the resulting file offset would be negative, or beyond the end of a seekable device. ๐Ÿšซ
  • ENXIO โ€” whence is SEEK_DATA or SEEK_HOLE, and offset is beyond the end of the file, or whence is SEEK_DATA and offset is within a hole at the end of the file. ๐Ÿ™ˆ
  • EOVERFLOW โ€” the resulting file offset cannot be represented in an off_t. too big, too powerful, overflowed. ๐Ÿ˜ต
  • ESPIPE โ€” fd is associated with a pipe, socket, or FIFO. girl, that thing cannot be seeked, respectfully. ๐Ÿšฐ

๐Ÿซถ VERSIONS ๐Ÿซถ

on Linux, using lseek() on a terminal device fails with the error ESPIPE. noted! ๐Ÿ“


๐Ÿ‘‘ STANDARDS ๐Ÿ‘‘

POSIX.1-2024. certified, canon, official. we love a standard that just gets it. โœจ


๐ŸŒˆ HISTORY ๐ŸŒˆ

  • 4.3BSD, SVr4, POSIX.1-1988.
  • SEEK_DATA, SEEK_HOLE โ€” Solaris 10, FreeBSD 7.0, DragonFly BSD 2.3.1, POSIX.1-2024.

a little lore for the history girlies. ๐Ÿ“œ


โญ NOTES โญ

  • see open(2) for a discussion of the relationship between file descriptors, open file descriptions, and files. the whole polycule situation, explained over there. ๐Ÿ‘€
  • if the O_APPEND file status flag is set on the open file description, then a write(2) always moves the file offset to the end of the file, regardless of the use of lseek(). so your little seek? overruled. sorry bestie. ๐Ÿ’€
  • some devices are incapable of seeking, and POSIX does not specify which devices must support lseek(). mystery is the point. ๐Ÿฆ‹

๐Ÿ”ฅ SEE ALSO ๐Ÿ”ฅ

dup(2), fallocate(2), fork(2), open(2), fseek(3), posix_fallocate(3)


and that's the whole thing, bestie โ€” every last byte of it, non-negotiable, exactly as written. this masterpiece is brought to you by Linux man-pages 6.20, dated 2026-06-13, and honestly? iconic. ate and left no crumbs. stay seekable out there. ๐Ÿ’–โœจ๐ŸŽ€๐Ÿฆ‹๐ŸŒธ๐Ÿ’…๐Ÿซถ๐Ÿ‘‘๐ŸŒˆโญ

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: BSD-4-Clause-UC
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms