Files and File Modes in Linux C

Most resources on a *nix system can be accessed as a file, per the everything-is-a-file philosophy. Files come in a number of types, such as regular storage files, named and unnamed pipes, directories, devices, symbolic links and sockets.

Regular files are regular files, pipes are a data channel, directories contain a list of files stored in the directory, device files provide an interface to devices, symbolic links store a path to another file, and sockets are like pipes, but pipes that allow processes on separate machines to communicate.

Most files on a Linux system are either files or directories.

The stat() function can be used to access a file’s metadata. The stat() function accepts a pathname and stores the file’s metadata in a stat structure, which is supplied to it as the second argument. The stat() function’s prototype is stored in sys/stat.h, which also includes the definition for the stat structure (via bits/stat.h).  

Basically, we need to include sys/stat.h. Then, we need to declare a struct stat. Finally, we call stat(), passing as the first parameter the file we want to get the metadata of, and as the second argument we will pass the address of the struct stat variable we declared.

#include <stdio.h>
#include <sys/stat.h>


int main(void){

    char *szFileName = "test.txt";
    struct stat SMetaData;

    stat(szFileName, &SMetaData);

    //inode num is st_ino
    //of type ino_t (unsigned long)
    printf("%s \tinode: %lu\n", szFileName, SMetaData.st_ino);

    return 0;
}

The file’s type and it’s permissions are encoded together in one field in the stat structure, the st_mode field. The file’s mode is 16 bits in length, with the four high-order bits representing the file’s type, and the remaining lower 12 bits representing access permissions and their modifiers.

#include <stdio.h>
#include <sys/stat.h>

int main(void){

    char *szPath = "test.txt";
    mode_t sMode;

    struct stat SMeta;

    stat(szPath, &SMeta);

    sMode = SMeta.st_mode;

    printf("The mode for %s is %d\n", szPath, sMode);

    for(int i = 15; i >= 0; i--){
        if(sMode & (1 << i)){
            putchar('1');
        } else {
            putchar('0');
        }
        if(i==12){
            putchar(' ');
        }
    }

    putchar('\n');    

    return 0;
}

The bitmask for all file type fields is S_IFMT. By anding this value with the st_mode value, we can extract the file type information from the file’s mode field. We recall here that anding is used to apply a mask to a binary value. The binary AND operation returns a 1 when both bits are on, and a 0 where either bit is off, and uses the & operator.

#include <stdio.h>
#include <sys/stat.h>

int main(void){

    char *szPath = "test.txt";
    struct stat SBuff;

    stat(szPath, &SBuff);

    printf("inode: %lu \t", SBuff.st_ino);
    printf("name: %s \t", szPath);
    printf("type: ");

    switch(SBuff.st_mode & S_IFMT){
        case S_IFREG:
            printf("Regular File\n");
            break;
        case S_IFDIR:
            printf("Directory\n");
            break;
        case S_IFBLK:
            printf("Block Device\n");
            break;
        case S_IFCHR:
            printf("Character Device\n");
            break;
        case S_IFSOCK:
            printf("Socket\n");
            break;
        case S_IFLNK:
            printf("Symbolic Link\n");
            break;
    }

    return 0;

}

Again, the file type is encoded in the st_mode field of the stat structure. There are a set of macros that can help us to decipher the file type from the st_mode field. Each macro returns true if the file type is found in the mode, false if otherwise.

#include <stdio.h>
#include <sys/stat.h>

void printType(mode_t iMode);

int main(void){

    char *caArray[] = {"dir", "/run/avahi-daemon/socket", "test.txt", "/dev/sda", "/dev/tty0"};
    struct stat SBuffer;

    for(int i = 0; i < 5; i++){
        stat(caArray[i], &SBuffer);
        printf("File Name: %s\t", caArray[i]);
        printf("Inode: %lu\t", SBuffer.st_ino);
        printf("Type: ");
        printType(SBuffer.st_mode);
        printf("\n");
    }

    return 0;
}


void printType(mode_t iMode){
    if(S_ISREG(iMode)){
        printf("regular file");
        return;
    }
    if(S_ISDIR(iMode)){
        printf("directory");
        return;
    }
    if(S_ISBLK(iMode)){
        printf("block device");
        return;
    }
    if(S_ISCHR(iMode)){
        printf("character device");
        return;
    }
    if(S_ISSOCK(iMode)){
        printf("socket");
        return;
    }
}

The one thing to be aware of is that the stat() follows symbolic links; if we want to get metadata regarding the symbolic link itself, we should use the lstat() function. We will be returning to this at a later time.

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s