Hubbry Logo
search
logo
2131397

Stat (system call)

logo
Community Hub0 Subscribers

Wikipedia

from Wikipedia

stat command line

stat() is a Unix system call that queries the file system for metadata about a file (including special files such as directories). The metadata contains many fields including type, size, ownership, permissions and timestamps.

For example, the ls command uses this system call to retrieve timestamps:

  • mtime: when last modified (ls -l)
  • atime: when last accessed (ls -lu)
  • ctime: when last status changed (ls -lc)

stat() appeared in Version 1 Unix. It is among the few original Unix system calls to change, with Version 4's addition of group permissions and larger file size.[1]

Since at least 2004, the same-named shell command stat has been available for Linux to expose features of the system call via a command-line interface.[2]

Functions

[edit]

The C POSIX library header sys/stat.h, found on POSIX and other Unix-like operating systems, declares stat() and related functions.

int stat(const char* path, struct stat* buf);
int lstat(const char* path, struct stat* buf);
int fstat(int filedesc, struct stat* buf);

Each function accepts a pointer to a struct stat buffer which the function loads with information about the specified file. As typical for system calls, each function returns 0 on success, or on failure, sets errno to indicate the failure condition and returns −1.

The stat() and lstat() functions accept a path argument that specifies a file. If the path identifies a symbolic link, stat() returns attributes of the link target, whereas lstat() returns attributes of the link itself. The fstat() function accepts a file descriptor argument instead of a path, and returns attributes of the file that it identifies.

The library has been extended to support large files. Functions stat64(), lstat64() and fstat64() load information into a struct stat64 buffer, which supports 64-bit sizes, allowing them to work with files 2 GiB and larger (up to 8 EiB). When the _FILE_OFFSET_BITS macro is defined as 64, the 64-bit functions are available as the original names.

Data structure

[edit]

The metadata structure is defined in the sys/stat.h header. The following shows the base fields, but an implementation is free to include additional fields:[3]

struct stat {
	mode_t st_mode;
	ino_t st_ino;
	dev_t st_dev;
	dev_t st_rdev;
	nlink_t	st_nlink;
	uid_t st_uid;
	gid_t st_gid;
	off_t st_size;
	struct timespec	st_atim;
	struct timespec	st_mtim;
	struct timespec st_ctim;
	blksize_t st_blksize;
	blkcnt_t st_blocks;
};

POSIX.1 does not require st_rdev, st_blocks and st_blksize members; these fields are defined as part of XSI option in the Single Unix Specification.

In older versions of POSIX.1 standard, the time-related fields were defined as st_atime, st_mtime and st_ctime, and were of type time_t. Since the 2008 version of the standard, these fields were renamed to st_atim, st_mtim and st_ctim, respectively, of type struct timespec, since this structure provides a higher resolution time unit. For the sake of compatibility, implementations can define the old names in terms of the tv_sec member of struct timespec. For example, st_atime can be defined as st_atim.tv_sec.[3]

Fields include:

Example

[edit]

The following C program reports metadata about each file passed via the command-line – using stat() to query the system for the information.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(int argc, char* argv[]) {
    struct stat sb;

    for (int i = 1; i < argc; i++) {
        if (stat(argv[i], &sb) == -1) {
            perror("stat failed");
            exit(EXIT_FAILURE);
        }

        printf("%s:\n", argv[i]);
        printf("\tinode: %u\n", sb.st_ino);
        printf("\tperms: %o\n", sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
        printf("\tlinks: %d\n", sb.st_nlink);
        printf("\tsize: %ld\n", sb.st_size);
        printf("\tatime: %s", ctime(&sb.st_atim.tv_sec));
        printf("\tmtime: %s", ctime(&sb.st_mtim.tv_sec));
        printf("\tctime: %s", ctime(&sb.st_ctim.tv_sec));
        printf("\n");
    }

    return 0;
}

References

[edit]
[edit]

Grokipedia

from Grokipedia
The stat system call is a POSIX-compliant function in Unix-like operating systems that retrieves metadata about a specified file, such as its type, permissions, ownership, size, and timestamps, and stores this information in a caller-provided struct stat buffer.[1] It operates by resolving the file pathname and following symbolic links, and does not require read, write, or execute permissions on the file itself, though access controls may restrict the operation.[1] Defined in the <sys/stat.h> header, the call conforms to IEEE Std 1003.1-2004 and later standards, making it a fundamental interface for file system queries across compliant systems like Linux, BSD, and others.[1] The prototype for stat is int stat(const char *restrict path, struct stat *restrict buf);, where path points to a null-terminated pathname string and buf is a pointer to the structure that will hold the file status details.[1] On success, it returns 0 and populates the buffer; on failure, it returns -1 and sets the global errno variable to indicate the error, such as EACCES for permission denial, ENOENT for non-existent file, or EOVERFLOW for size overflow issues.[1] This design ensures atomic retrieval of file attributes, which is essential for applications needing consistent metadata without concurrent modification risks during the query.[2] The struct stat structure, as defined in POSIX, includes key members for file identification and attributes: dev_t st_dev for the device ID, ino_t st_ino for the inode number (uniquely identifying the file on its device), mode_t st_mode for file type and protection bits, nlink_t st_nlink for the number of hard links, uid_t st_uid and gid_t st_gid for owner and group IDs, off_t st_size for the file size in bytes, and time_t fields like st_atime (last access), st_mtime (last modification), and st_ctime (last status change).[3] The traditional requirement to update st_atime on every file access has been criticized for negatively impacting file system performance, as it necessitates metadata writes even for read-only operations that could otherwise be served from cache.[4] To lessen this performance impact while preserving some utility of atime, Linux introduced the relatime mount option (introduced in kernel 2.6.20 and default since 2.6.30), which updates atime only if the previous access time is earlier than or equal to the current modify or change time, reducing unnecessary metadata writes for better performance while still supporting applications that rely on atime for relative checks.[2][4] Optional XSI extensions add dev_t st_rdev for special files, blksize_t st_blksize for optimal I/O block size, and blkcnt_t st_blocks for allocated disk blocks.[3] These fields enable diverse uses, from permission checks via st_mode macros like S_ISREG (regular file) to timestamp-based caching or synchronization.[3] Related variants extend stat's functionality: lstat behaves identically but does not follow symbolic links, returning metadata for the link itself; fstat uses a file descriptor instead of a pathname for already-open files; and fstatat combines descriptor-based directory resolution with flags for advanced control, such as AT_SYMLINK_NOFOLLOW.[2] These calls share the same struct stat and error semantics, with conformance to POSIX.1-2008, and have evolved historically on systems like Linux to handle 32-bit/64-bit compatibility through wrappers like newfstatat.[2] In practice, libraries like glibc invoke underlying kernel interfaces (e.g., sys_newstat on Linux) to perform the operation efficiently.[2]

Overview and History

Purpose and Functionality

The stat system call is a POSIX-compliant interface in Unix-like operating systems that retrieves metadata about a specified file by querying the file system and writing the information to a provided buffer.[1] It obtains attributes such as the file's type, size, permissions, ownership, and timestamps, enabling applications to inspect these properties without opening the file for reading or writing.[1] Primary use cases for stat include determining a file's type to guide processing logic, retrieving its size for managing storage allocation, verifying permissions to enforce access controls, and examining timestamps to support auditing, backup operations, or synchronization tasks.[1] These capabilities make stat essential for programs that need to evaluate file characteristics efficiently before performing further actions. In practice, stat underpins common utilities like the ls command, which invokes it to display detailed file information such as sizes and modification times, and the find command, which uses it to filter and select files based on criteria like ownership or timestamps.[2] This integration allows these tools to present or process file metadata without redundant file system probes. The stat call benefits from the kernel's virtual file system layer, which caches directory entries and inodes in memory, thereby avoiding direct disk access for metadata retrieval when the information is already resident in the kernel cache.[5]

Development and Evolution

The stat system call was introduced in Version 1 of Unix in 1971 by Ken Thompson and Dennis Ritchie as a basic file inquiry mechanism to retrieve inode attributes.[6] It underwent significant expansion in Version 4 Unix in 1973, incorporating group permissions and support for larger file sizes to address evolving multi-user requirements.[7] The system call was standardized in POSIX.1 in 1988, specifying required core fields such as st_mode, st_ino, st_dev, st_uid, st_gid, st_atime, st_mtime, st_ctime, and st_size, with optional XSI extensions including st_blksize and st_blocks, along with defined behaviors for file types.[8] POSIX.1-2008 further updated the standard to support nanosecond-precision timestamps through timespec structures for st_atime, st_mtime, and st_ctime fields.[9] In the Linux kernel, the ext3 filesystem, introduced in 2001, added support for extended attributes, enabling storage of metadata like Access Control Lists beyond traditional inode fields.[10] Similarly, BSD variants advanced the interface; FreeBSD introduced the st_birthtime field for file creation time in version 5.1 released in 2003, enhancing timestamp granularity for UFS2 and later filesystems.[11] More recently, Linux introduced the statx(2) system call in kernel version 4.11 (2017) to provide extended file status information, including birth time and security context, superseding traditional stat in some contexts.[12] The Single UNIX Specification Version 4 (SUSv4), aligned with POSIX.1-2008 and published in 2008 with ongoing editions through 2013, clarified the status of optional fields like st_blksize and st_blocks while maintaining core requirements, ensuring portability across conforming systems.[13] No major structural changes have occurred since 2013, though the call remains essential for compatibility in modern environments such as containers and embedded systems as of 2025.

System Call Interface

Prototypes and Parameters

The primary prototype for the stat() system call, as defined in the POSIX standard, is int stat(const char *restrict path, struct stat *restrict buf);.[1] This function retrieves file status information for the file specified by the pathname and stores it in the provided buffer.[1] To use stat(), programs must include the header <sys/stat.h>, which declares the function and the struct stat type.[1] On some Unix-like systems, such as Linux, the declaration may also be accessible via <unistd.h> due to header inclusions, though <sys/stat.h> is the standard and portable choice.[2] The path parameter is a pointer to a null-terminated string representing the filesystem pathname of the target file, which may be absolute or relative to the current working directory.[1] The buf parameter is a pointer to a struct stat object, which must be allocated with sufficient memory (at least sizeof(struct stat) bytes) to hold the retrieved metadata; failure to do so can lead to undefined behavior such as memory corruption.[1] Upon successful completion, the metadata written to buf may not reflect a fully consistent snapshot, as different fields could be obtained at slightly different times, particularly on systems like Linux.[2] The stat() function is thread-safe in POSIX-compliant environments, provided that the path string is not modified concurrently by other threads; it can be called safely from multiple threads within the same process. To enable the full POSIX feature set, including stat(), applications should define the feature test macro _POSIX_C_SOURCE to be at least 200112L before including any standard headers.[2]

Return Values and Errors

Upon successful completion, the stat system call returns 0 and populates the provided struct stat buffer with the file's status information.[1][2] In the event of failure, it returns -1 and sets the global errno variable to indicate the specific error condition.[1][2] The POSIX standard mandates support for the following errors:
  • EACCES: Search permission is denied for a component of the path prefix.[1]
  • EIO: An input/output error occurred while reading from the file system.[1]
  • ELOOP: A loop exists in symbolic links encountered during path resolution.[1]
  • ENAMETOOLONG: The length of the path exceeds {PATH_MAX}, or a path component exceeds {NAME_MAX}.[1]
  • ENOENT: A component of the path does not exist, or the path is an empty string.[1][2]
  • ENOTDIR: A component of the path prefix is not a directory.[1][2]
  • EOVERFLOW: The file size, block count, or device serial number cannot be represented correctly in the struct stat.[1][2]
Implementations may also report optional POSIX errors, such as exceeding {SYMLOOP_MAX} symbolic links (ELOOP) or pathname overflow after symbolic link expansion (ENAMETOOLONG).[1] Common errors across Unix-like systems further include:
  • EFAULT: A bad address was detected in the path argument or the buf buffer.[2]
  • ENOMEM: Insufficient kernel memory is available to process the request.[2]
Linux-specific extensions encompass additional conditions, such as EBADF for invalid file descriptors in variants like fstat, EINVAL for invalid flags in fstatat, and ESTALE for stale NFS file handles.[2][14]

File Status Data Structure

Core Fields

The core fields of the struct stat provide essential attributes of a file, as mandated by the POSIX standard, enabling applications to query fundamental metadata such as location, identity, type, ownership, size, and timestamps.[15] These fields are universally required across compliant systems and form the basis for file status examination without delving into implementation-specific extensions.[15] The st_dev field, of type dev_t, identifies the device ID of the filesystem containing the file, distinguishing files across different storage devices or partitions.[15] Similarly, st_ino, of type ino_t, holds the inode number, which uniquely identifies the file within its filesystem, allowing for precise file referencing even if pathnames change.[15] The st_mode field, of type mode_t, is a bitmask encoding both the file type and access permissions.[15] The file type is determined by masking with S_IFMT; for example, S_IFREG indicates a regular file, while other constants like S_IFDIR for directories or S_IFLNK for symbolic links specify alternatives.[15] Permission bits within st_mode include owner, group, and other categories, such as S_IRUSR for read permission by the owner, S_IWGRP for write by the group, and S_IXOTH for execute by others, enabling fine-grained access control evaluation.[15] Ownership is captured by st_uid (type uid_t), the user ID of the file's owner, and st_gid (type gid_t), the group ID associated with the file, which together determine applicable permissions based on the calling process's credentials.[15] The st_nlink field, of type nlink_t, represents the number of hard links to the file, reflecting how many directory entries point to the same inode; a value of 1 typically indicates no additional links beyond the primary one.[15] For size information, st_size (type off_t) reports the file's size in bytes, applicable to regular files; it is undefined for non-regular file types like directories or devices.[15] Timestamp fields provide temporal metadata using struct timespec, which includes tv_sec (seconds since the Epoch) and tv_nsec (nanoseconds) for sub-second precision.[15] Specifically, st_atim records the time of last access, st_mtim the time of last data modification, and st_ctim the time of last status change (such as permission or ownership updates).[15] These core fields exclude optional ones like st_blocks, which vary by implementation and are addressed elsewhere.[15]

Implementation Variations

The struct stat exhibits variations across standards and implementations, particularly in optional fields and extensions that enhance functionality beyond the POSIX core requirements. According to the Single UNIX Specification (SUSv4), fields such as st_rdev, which identifies the device for special files (character or block devices); st_blksize, indicating the optimal block size for I/O operations on the file; and st_blocks, representing the number of 512-byte blocks allocated to the file, are defined as optional XSI extensions. These fields are not mandated by base POSIX but provide additional metadata useful for device handling and storage analysis in UNIX-like systems supporting the XSI conformance option.[15] POSIX.1-2008 introduced enhancements to timestamp precision in the struct stat, replacing the previous time_t types for st_atime, st_mtime, and st_ctime with struct timespec members (st_atim, st_mtim, st_ctim) to support nanosecond resolution alongside seconds since the epoch. This update allows for finer-grained tracking of access, modification, and status change times, with compatibility macros like st_atime (equivalent to st_atim.tv_sec) ensuring backward compatibility. Implementations adhering to this standard must provide these nanosecond components when available from the underlying filesystem.[15] Platform-specific divergences further customize the structure. In Linux, on 32-bit systems, the off_t type for st_size is 64 bits when applications are compiled with the _FILE_OFFSET_BITS=64 feature test macro (available since glibc 2.4, released in 2006), enabling transparent support for large files greater than 2 GB via the stat64 system call wrapper. On 64-bit systems, off_t is 64 bits by default.[2] macOS extends the structure with st_flags, a field for user-defined file attributes (e.g., immutable or append-only flags), managed via chflags(2) and providing filesystem-specific controls not present in standard POSIX.[16] FreeBSD adds st_birthtim (a struct timespec), capturing the inode creation time (birth time) for filesystems that support it, such as UFS2 or ZFS, offering insight into file origination distinct from modification or access times.[17] Windows lacks a direct POSIX stat but provides equivalent functionality through _stat and variants in <sys/stat.h>, where st_size is typed as long long (64-bit integer) in 64-bit aware functions like _stat64 and _stati64 to handle large files, with additional fields like st_ino often set to 0 due to filesystem differences. Android's Bionic libc, as of its main branch in 2025, implements struct stat with architecture-dependent variations: 64-bit fields like st_dev, st_ino, st_size, and st_blocks on ARM and x86_64, including optional XSI fields and nanosecond timestamps, while ensuring POSIX compatibility with padding for alignment on 32-bit architectures. These adaptations reflect kernel and libc priorities, such as mobile storage efficiency in Android.[18][19] The fstat system call provides an alternative to the base stat call by operating on an open file descriptor rather than a pathname. Its prototype is int fstat(int fd, struct stat *buf);, where fd is the file descriptor of an open file, and buf is a pointer to a struct stat that will receive the file status information.[20] This approach avoids the need for path resolution, making it particularly useful for files that are already open, such as those accessed via descriptors from functions like open or socket.[20] For instance, in network servers, fstat is commonly employed to retrieve status information about open sockets without requiring a pathname, allowing efficient querying of connection details like mode and size.[21] In contrast, the lstat system call is similar to stat but handles symbolic links differently. Its prototype is int lstat(const char *path, struct stat *buf);, where path specifies the pathname, and buf receives the status data. Unlike stat, which follows symbolic links to return information about the target file, lstat returns attributes of the symbolic link itself when path refers to one.[22] Key differences include the treatment of metadata: for a symbolic link, lstat sets st_size to the length of the link's pathname string rather than the target's size, preserving details like the link's own mode and timestamps.[2] This behavior is essential in symlink-aware tools, such as the tar archival utility, which uses lstat to detect and properly handle symbolic links during backup operations without dereferencing them.[23] The fstatat system call extends this functionality by allowing status retrieval relative to a directory file descriptor, with optional flags for behavior control. Its prototype is int fstatat(int dirfd, const char *restrict path, struct stat *restrict buf, int [flag](/page/Flag));, where dirfd is a directory descriptor (or AT_FDCWD for current), path is the pathname (relative or absolute), buf receives the status, and flag can include AT_SYMLINK_NOFOLLOW to mimic lstat or AT_EMPTY_PATH for descriptor-only operation.[24] Introduced in POSIX.1-2008, fstatat supports safe pathname resolution in multithreaded or chrooted environments, such as when following relative paths without global state changes, and is particularly useful in libraries or containers for atomic file queries.[24] Both fstat and lstat share the core behaviors of the stat system call in terms of return values and most errors, succeeding with a return of 0 and populating the struct stat on success, or returning -1 and setting errno on failure.[20][22] Common errors mirror those of stat, such as ENOENT for non-existent paths (for lstat) or EACCES for permission issues. However, fstat includes descriptor-specific errors, notably EBADF if fd is not a valid open file descriptor.[20] These variants thus extend the stat interface to address scenarios involving open descriptors or symbolic links while maintaining POSIX compatibility.[20][22]

Large File Support Extensions

The stat64 system call extends the standard stat interface to support files larger than 2 GiB on 32-bit systems by using 64-bit data types for key fields.[2] Its prototype is int stat64(const char *path, struct stat64 *buf);, where path specifies the file path and buf points to a struct stat64 buffer to store the file status information.[2] This function follows symbolic links, unlike its counterpart lstat64.[25] The struct stat64 differs from the base struct stat primarily in the use of larger integer types to accommodate large files: st_size employs off64_t (64-bit offset), st_blocks uses blkcnt64_t (64-bit block count), and timestamps may include extended nanosecond components if supported by the system.[2] Additional enlargements include a larger st_ino field for inode numbers and expanded st_uid and st_gid fields to support 32-bit user and group IDs, as introduced in Linux 2.4.[2] Availability of stat64 varies by platform: it has been supported in Linux since kernel 2.4 for 32-bit architectures, enabled explicitly via the _LARGEFILE64_SOURCE feature test macro or through transparent large file support with _FILE_OFFSET_BITS=64.[2] In Solaris, stat64 was introduced in version 2.6 (released in 1997) to handle long files using 64-bit status arrays.[25] However, on 64-bit systems, stat64 is largely deprecated, as the standard stat already employs 64-bit types by default for these fields.[2] The development of these extensions stemmed from the POSIX Large File Summit, with the specification completed in 1996, which standardized mechanisms for transparent large file support across Unix-like systems, allowing 32-bit applications to handle files exceeding 2 GiB without explicit 64-bit calls in many cases.[26][27] As of 2025, stat64 remains relevant primarily as a legacy interface on resource-constrained 32-bit platforms, such as embedded ARM systems, where full 64-bit compilation is impractical.[2] Error handling for stat64 mirrors that of stat, including ENOENT for nonexistent paths and EACCES for permission denials, but it may additionally return ENOSYS if the system lacks large file support.[2] Related variants include lstat64 for symbolic links and fstat64 for file descriptors.[25]

Usage Examples

Basic Implementation

The basic implementation of the stat system call in C requires including the <sys/stat.h> header, which defines the function prototype and the struct stat data structure.[13] A simple program can invoke stat to retrieve file status information for a path provided as a command-line argument, checking the return value to confirm success.[13] Here is an example of a basic stat invocation:
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (stat(argv[1], &sb) == -1) {
        perror("stat");
        exit(EXIT_FAILURE);
    }

    printf("File status retrieved successfully.\n");
    return 0;
}
This code declares a struct stat variable, calls stat with the path and buffer pointer, and handles errors by printing a message via perror if the call fails (returning -1 and setting errno).[13][2] For files already open via a descriptor, the fstat variant is used, which requires including <fcntl.h> for the open function.[28] The following example opens a file read-write and retrieves its status:
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int fd = open(argv[1], O_RDWR);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (fstat(fd, &sb) == -1) {
        perror("fstat");
        close(fd);
        exit(EXIT_FAILURE);
    }

    close(fd);
    printf("File status retrieved successfully.\n");
    return 0;
}
This demonstrates obtaining status without resolving the path again, closing the descriptor afterward to release resources.[28] The lstat function provides similar functionality but does not follow symbolic links, allowing retrieval of the link's own status.[29] For a symbolic link, the st_mode field in the resulting struct stat will have the S_IFLNK type indicator.[29] An example invocation is:
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (lstat(argv[1], &sb) == -1) {
        perror("lstat");
        exit(EXIT_FAILURE);
    }

    printf("Symbolic link status retrieved successfully.\n");
    return 0;
}
Error checking follows the same pattern across variants: test for a -1 return and use perror to report the issue, such as permission denied or non-existent path.[2] To compile these examples, use a command like gcc -Wall example.c -o example, which links against the standard C library (libc) and enables warnings for robust code.[2]

Output Interpretation

The output of the stat() system call is a populated struct stat data structure, which provides metadata about the queried file or directory without requiring read, write, or execute permissions on the file itself. This structure, defined in <sys/stat.h>, contains fields that describe the file's identity, type, ownership, timestamps, and size, allowing applications to inspect file properties programmatically. Interpretation begins by examining the fields in the returned buffer, using macros like those in POSIX to decode elements such as file type from st_mode. All fields are meaningful for most file types unless otherwise specified, with timestamps representing seconds and nanoseconds since the Epoch (January 1, 1970, 00:00:00 UTC).[13][15] The st_dev and st_ino fields together uniquely identify the file within the filesystem: st_dev holds the device ID (e.g., major and minor numbers for the containing device), while st_ino is the file's serial number or inode. For special files like character or block devices, st_rdev provides the device's ID, which is unspecified for other file types. Ownership is indicated by st_uid (user ID of the owner) and st_gid (group ID), which can be mapped to usernames and group names using functions like getpwuid() and getgrgid(). The st_nlink field counts the number of hard links to the file, typically 1 for regular files and higher for directories or linked files.[15][2] File type and access permissions are encoded in st_mode, a bit field where the high-order bits (masked by S_IFMT) specify the type—such as S_IFREG for regular files, S_IFDIR for directories, S_IFLNK for symbolic links, or S_IFCHR/S_IFBLK for character/block special files—and the low-order bits define permissions (e.g., S_IRUSR for owner read, S_IWGRP for group write) plus special flags like S_ISUID for set-user-ID. Macros like S_ISREG(st.st_mode) test the type post-call. For symbolic links, lstat() (not stat()) populates st_mode with the link's type, while st_size gives the length of the target pathname in bytes.[15][2] Timestamp fields, defined as struct timespec (e.g., st_atim for last access, st_mtim for last modification, st_ctim for last status change), consist of tv_sec (time_t, seconds since the Epoch) and tv_nsec (nanoseconds). The tv_sec values are accessible via compatibility macros like st_atime, st_mtime, and st_ctime, convertible to human-readable strings via ctime() or localtime(). Nanosecond resolution is standardized in POSIX.1-2008 and supported on compliant systems, though some filesystems may not preserve it. These offer insights into file activity: st_atim records the last access time (updated on reads, though some filesystems disable this for performance via noatime mounts), st_mtim the last data modification (e.g., content changes), and st_ctim the last status change (e.g., permission or ownership updates). Interpretation must account for filesystem semantics.[15][13][2] Size-related fields include st_size, which for regular files gives the byte length (0 for directories), and for symbolic links, the target path length. The st_blksize field suggests the optimal I/O block size for the filesystem (e.g., 4096 bytes on many ext4 setups), aiding efficient reads/writes, while st_blocks counts the 512-byte blocks allocated on disk, useful for estimating actual storage used (which may exceed st_size due to fragmentation). These are implementation-defined and less portable; on Linux, st_blocks interpretation varies with filesystems like NFS. For large files, extended structures like stat64 or _LARGEFILE64_SOURCE may be needed on 32-bit systems to avoid overflow.[15][2] In practice, interpreting the output involves checking for errors first (e.g., ENOENT if the path does not exist), then using the fields to make decisions—like verifying writability via st_mode or checking freshness with timestamps. For example, a program might print file details as follows:
#include <sys/stat.h>
#include <stdio.h>
#include <time.h>

struct stat sb;
if (stat("example.txt", &sb) == 0) {
    printf("Size: %lld bytes\n", (long long)sb.st_size);
    printf("Modified: %s", ctime(&sb.st_mtime));
    if (S_ISREG(sb.st_mode)) {
        printf("Regular file\n");
    }
}
This approach emphasizes conceptual use over exhaustive printing, ensuring portability by relying on standard macros.[13][2]
User Avatar
No comments yet.