How do stat(), fstat(), and lstat() work, and what information does struct stat contain?
The stat() family of functions retrieves file metadata without opening the file.
Prototypes:
#include <sys/stat.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
Differences:
stat()follows symbolic links (returns info about the target)lstat()does NOT follow symlinks (returns info about the link itself)fstat()works on an already-open file descriptor
struct stat fields:
st_dev-- device ID of filesystemst_ino-- inode numberst_mode-- file type and permissionsst_nlink-- number of hard linksst_uid/st_gid-- owner user/group IDst_size-- file size in bytes (for regular files)st_blksize-- optimal I/O block sizest_blocks-- number of 512-byte blocks allocatedst_atime-- last access timest_mtime-- last modification timest_ctime-- last status change time (NOT creation time on most UNIX systems)
File type macros (applied to st_mode):
S_ISREG()-- regular fileS_ISDIR()-- directoryS_ISLNK()-- symbolic linkS_ISCHR()/S_ISBLK()-- character/block deviceS_ISFIFO()-- FIFO/pipeS_ISSOCK()-- socket
1. Call stat(path, &sb) or lstat(path, &sb) or fstat(fd, &sb)
2. Check return value (0 = success, -1 = error)
3. Use S_ISREG(sb.st_mode), S_ISDIR(sb.st_mode), etc. for file type
4. Use sb.st_mode & 0777 for permission bits
5. sb.st_size for file size, sb.st_nlink for hard link count
6. sb.st_mtime for last modification time
#include <sys/stat.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
void print_file_info(const char *path) {
struct stat sb;
if (lstat(path, &sb) == -1) {
perror(path);
return;
}
printf("File: %s\n", path);
printf(" Inode: %lu\n", (unsigned long)sb.st_ino);
printf(" Size: %lld bytes\n", (long long)sb.st_size);
printf(" Links: %lu\n", (unsigned long)sb.st_nlink);
printf(" Mode: %o\n", (unsigned int)(sb.st_mode & 07777));
/* File type */
printf(" Type: ");
if (S_ISREG(sb.st_mode)) printf("regular file\n");
else if (S_ISDIR(sb.st_mode)) printf("directory\n");
else if (S_ISLNK(sb.st_mode)) printf("symbolic link\n");
else if (S_ISCHR(sb.st_mode)) printf("character device\n");
else if (S_ISBLK(sb.st_mode)) printf("block device\n");
else if (S_ISFIFO(sb.st_mode)) printf("FIFO\n");
else if (S_ISSOCK(sb.st_mode)) printf("socket\n");
/* Timestamps */
char timebuf[64];
struct tm *tm = localtime(&sb.st_mtime);
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm);
printf(" Modified: %s\n", timebuf);
}
int main(void) {
print_file_info("/etc/passwd");
print_file_info("/tmp");
return 0;
}
- •stat() follows symlinks; lstat() does not; fstat() uses an fd
- •struct stat contains inode, size, permissions, timestamps, link count
- •Use S_ISREG/S_ISDIR/S_ISLNK macros on st_mode for file type
- •st_ctime is status change time, NOT creation time
- •st_blocks counts 512-byte blocks regardless of filesystem block size
- •stat() on a symlink returns info about the target; use lstat() for the link itself
- •st_size for symlinks is the length of the target path string, not the target file size
- •st_size for directories is filesystem-dependent and does not reflect content count
- •st_ctime changes on chmod/chown/link/unlink, not just content changes