stat file from DIR *

Learn stat file from dir * with practical examples, diagrams, and best practices. Covers c, linux development techniques with visual explanations.

Understanding stat and lstat for File Information in C on Linux

Hero image for stat file from DIR *

Explore how to use the stat and lstat system calls in C to retrieve detailed file and directory metadata on Linux systems, including handling symbolic links.

When working with files and directories in C on Linux, understanding their metadata is crucial. The stat and lstat system calls provide a powerful way to retrieve this information, such as file type, permissions, size, ownership, and timestamps. This article will guide you through using these functions, explaining their differences, especially concerning symbolic links, and providing practical code examples.

The stat and lstat System Calls

Both stat and lstat are POSIX-compliant functions declared in <sys/stat.h>. They take a file path as input and populate a struct stat with various attributes of the file or directory. The primary difference lies in how they handle symbolic links:

  • stat(): If the path refers to a symbolic link, stat() dereferences it and returns information about the target file or directory.
  • lstat(): If the path refers to a symbolic link, lstat() returns information about the symbolic link itself, not its target.
flowchart TD
    A[Input Path] --> B{Is Path a Symbolic Link?}
    B -- Yes --> C{Function Called?}
    B -- No --> D[Get Info for File/Directory]

    C -- stat() --> E[Dereference Link]
    E --> D

    C -- lstat() --> F[Get Info for Symbolic Link Itself]
    F --> G[Return Link Info]
    D --> G

Flowchart illustrating the difference between stat and lstat when encountering a symbolic link.

Understanding struct stat

The struct stat is a comprehensive data structure that holds all the metadata about a file. Key members include:

  • st_mode: File type and permissions (e.g., S_ISREG(), S_ISDIR(), S_ISLNK() for type; S_IRUSR, S_IWGRP for permissions).
  • st_ino: Inode number.
  • st_dev: ID of device containing file.
  • st_nlink: Number of hard links.
  • st_uid: User ID of owner.
  • st_gid: Group ID of owner.
  • st_size: Total size in bytes.
  • st_blksize: Block size for filesystem I/O.
  • st_blocks: Number of 512B blocks allocated.
  • st_atime: Time of last access.
  • st_mtime: Time of last modification.
  • st_ctime: Time of last status change.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>

void print_file_info(const char *path, const struct stat *sb) {
    printf("\nFile: %s\n", path);
    printf("  Type: ");
    switch (sb->st_mode & S_IFMT) {
        case S_IFBLK:  printf("block device\n");            break;
        case S_IFCHR:  printf("character device\n");        break;
        case S_IFDIR:  printf("directory\n");             break;
        case S_IFIFO:  printf("FIFO/pipe\n");             break;
        case S_IFLNK:  printf("symlink\n");               break;
        case S_IFREG:  printf("regular file\n");          break;
        case S_IFSOCK: printf("socket\n");                break;
        default:       printf("unknown?\n");              break;
    }

    printf("  Inode: %ld\n", (long) sb->st_ino);
    printf("  Device: %ld\n", (long) sb->st_dev);
    printf("  Links: %ld\n", (long) sb->st_nlink);
    
    struct passwd *pw = getpwuid(sb->st_uid);
    struct group *gr = getgrgid(sb->st_gid);
    printf("  Owner: %s (UID %ld)\n", pw ? pw->pw_name : "unknown", (long) sb->st_uid);
    printf("  Group: %s (GID %ld)\n", gr ? gr->gr_name : "unknown", (long) sb->st_gid);

    printf("  Size: %lld bytes\n", (long long) sb->st_size);
    printf("  Blocks: %lld (%lld bytes)\n", (long long) sb->st_blocks, (long long) sb->st_blocks * 512);
    printf("  Access: %s", ctime(&sb->st_atime));
    printf("  Modify: %s", ctime(&sb->st_mtime));
    printf("  Change: %s", ctime(&sb->st_ctime));

    printf("  Permissions: ");
    printf((S_ISDIR(sb->st_mode)) ? "d" : "-");
    printf((sb->st_mode & S_IRUSR) ? "r" : "-");
    printf((sb->st_mode & S_IWUSR) ? "w" : "-");
    printf((sb->st_mode & S_IXUSR) ? "x" : "-");
    printf((sb->st_mode & S_IRGRP) ? "r" : "-");
    printf((sb->st_mode & S_IWGRP) ? "w" : "-");
    printf((sb->st_mode & S_IXGRP) ? "x" : "-");
    printf((sb->st_mode & S_IROTH) ? "r" : "-");
    printf((sb->st_mode & S_IWOTH) ? "w" : "-");
    printf((sb->st_mode & S_IXOTH) ? "x" : "-");
    printf("\n");
}

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

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

    // Using stat()
    if (stat(argv[1], &sb) == -1) {
        perror("stat");
        // exit(EXIT_FAILURE); // Don't exit, try lstat next
    } else {
        printf("--- Using stat() ---");
        print_file_info(argv[1], &sb);
    }

    // Using lstat()
    if (lstat(argv[1], &sb) == -1) {
        perror("lstat");
        exit(EXIT_FAILURE);
    } else {
        printf("\n--- Using lstat() ---");
        print_file_info(argv[1], &sb);
    }

    return 0;
}

C program demonstrating stat and lstat to retrieve and print file information.

Practical Use Cases and Considerations

The stat and lstat functions are fundamental for many system-level tasks:

  • File Type Checking: Determine if a path refers to a regular file, directory, symbolic link, etc., using macros like S_ISREG(), S_ISDIR(), S_ISLNK().
  • Permission Checks: Verify read, write, or execute permissions before attempting file operations.
  • Disk Usage Analysis: Get file sizes and block usage.
  • Backup Utilities: Identify modified files based on st_mtime.
  • Symbolic Link Handling: lstat is essential when you need to operate on the symbolic link itself (e.g., deleting the link, not its target) or determine if a path is a symbolic link.

Remember to always check the return value of stat and lstat for errors. A return value of -1 indicates an error, and errno will be set accordingly (e.g., ENOENT if the file does not exist, EACCES for permission issues).