Unix C Programming - file stat


apue

0x01.API

1.stat()/fstat()/fstatat()/lstat()

int stat (const char *filename, struct stat *buf)
int fstat (int filedes, struct stat *buf)
int lstat (const char *filename, struct stat *buf)
int fstatat(int fd, const char* restrict pathname, struct stat *restrict buff, int flag)
                                            - 成功返回:0;失败返回:-1

This four functions are all to read file attribute.
stat() read file stat by file path, return file stat by stat point.
fstat() read through a file decription.
fstatat() read from a file decription and a relative catalog, flag is to control whether followed with a symbolic link.

stat struct information here:

struct stat {
    mode_t st_mode;     // File mode, include file type / permission bits
    ino_t st_ino;        // File serial number
    dev_t st_dev;        // Identifies the device containing the file.
    nlink_t st_nlink;    // Hard links number of file.
    uid_t st_uid;        // The user ID of the file’s owner.
    gid_t st_gid;        // The group ID of the file. See File Owner.
    off_t st_size    ;    // Regular file size in bytes.
    time_t st_atime;    // Last access time.
    unsigned long int st_atime_usec;    // Fractional part of the last access time.
    time_t st_mtime;    // Last modification time
    unsigned long int st_mtime_usec;    // Fractional part of last modification time.
    time_t st_ctime;    // Last attributes modification time. 
    unsigned long int st_ctime_usec;    // Fractional part of the time.
    blkcnt_t st_blocks;    // This is the amount of disk space that the file occupies, measured in units of 512-byte blocks.

File type contains in mode_t st_mode. We can determine the file type with the macros.

mode_t st_mode macros


Follow description of stat, writing an example to read file stat:

#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
int main(int argc, char** argv) {
    if (argc < 2) {
        printf("Usage: %s filepath\n", argv[0]);
        return 0;
    }
    struct stat buff;
    char ptr[512];
    for (int i = 1; i < argc; ++i) {
        if (lstat(argv[i], &buff) < 0) {
            printf("last(%s) error\n", argv[i]);
            continue;
        }
        if (S_ISREG(buff.st_mode))
            sprintf(ptr, "%s: regular file\n", argv[i]);
        else if (S_ISDIR(buff.st_mode))
            sprintf(ptr, "%s: directory\n", argv[i]);
        else if (S_ISCHR(buff.st_mode))
            sprintf(ptr, "%s: character special\n", argv[i]);
        else if (S_ISBLK(buff.st_mode))
            sprintf(ptr, "%s: block special\n", argv[i]);
        else if (S_ISFIFO(buff.st_mode))
            sprintf(ptr, "%s: FIFO file\n", argv[i]);
        else if (S_ISLNK(buff.st_mode))
            sprintf(ptr, "%s: link file\n", argv[i]);
        else if (S_ISSOCK(buff.st_mode))
            sprintf(ptr, "%s: sock", argv[i]);
        printf("%s", ptr);
        printf("name = %s, uid = %d, guid = %d\naccess time = %smodification time = %ssize = %lld, serial = %llu", argv[i], buff.st_uid, buff.st_gid, ctime(&buff.st_atime), ctime(&buff.st_ctime), buff.st_size, buff.st_ino);
        printf("\n<===========================>\n");
    }
    return 0;
}

➜ $: gcc stat.c
➜ $: ./a.out stat.c

stat.c: regular file
name = stat.c, uid = 501, guid = 20
access time = Fri Mar  3 21:29:07 2017
modification time = Fri Mar  3 21:29:07 2017
size = 1320, serial = 4675975
<===========================>

2.access()/faccessat()

int access (const char *filename, int mode)
int faccessat (int fd, const char *filename, int mode, int flag)
                                            - 成功返回:0;失败返回:-1

access()/faccessat() is used to test file access permission.
mode defined in macros: R_OK, W_OK, X_OK, is to check read/write/exec permission of a file.
access() = faccess() when int fd is absolute path file description or when fd = AT_FDCWD and filepath is relative path, example:

#include <stdio.h>
#include <fcntl.h>
int main(int argc, char** argv) {
    if (argc != 2) {
        printf("Usage: %s filepath\n", argv[0]);
        return 0;
    }
    if (access(argv[1], R_OK) < 0)
        printf("%s: access error\n", argv[1]);
    else
        printf("%s: access ok\n", argv[1]);

    if (open(argv[1], O_RDONLY) < 0)
        printf("%s: open error\n", argv[1]);
    else
        printf("%s: open successfuly\n", argv[1]);
    return 0;
}

3.umask()

#include <sys/stat.h>
mode_t umask (mode_t mask)
                                - 返回:mode_t

In *nix, user permission is defined as 4+2+1, 4 = read permission, 2 = write permission, 1 = exec permission, for the more, if you have no permission to a directory, you can`t read this directory. Some common umask values are 002 to prevent others from writing your files, 022 to prevent group members and others from writing your files, and 027 to prevent group members from writing your files and others from reading, writing, or executing your files. We can read user permission from this picture:

permission


struct mode_t defined here:

S_IRUSR     // Read permission bit for the owner. 0400
S_IWUSR    // Write permission bit for the owner. 0200
S_IXUSR    // Execute (for ordinary files) or search (for directories) permission bit for the owner. 0100
S_IRWXU     // This is equivalent to ‘(S_IRUSR | S_IWUSR | S_IXUSR)’.

S_IRGRP    // Read permission bit for the group owner. 0040
S_IWGRP    // Write permission bit for the group owner. 0020.
S_IXGRP    // Execute or search permission bit for the group owner. 0010
S_IRWXG    // This is equivalent to ‘(S_IRGRP | S_IWGRP | S_IXGRP)’.

S_IROTH    // Read permission bit for other users. 0004
S_IWOTH    // Write permission bit for other users. 0002
S_IXOTH    // Execute or search permission bit for other users. 0001
S_IRWXO    // This is equivalent to ‘(S_IROTH | S_IWOTH | S_IXOTH)’.

The Single UNIX Specification requires that the shell support a symbolic form of the umask command. Unlike the octal format, the symbolic format specifies which permissions are to be allowed instead of which ones are to be denied:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc, char** argv) {
    int fd;
     mode_t oldmask;
    printf("Your old umask is %i\n",oldmask = umask(S_IRWXG));
      if ((fd = creat("umask.file", S_IRWXU | S_IRWXG)) < 0)
           perror("creat() error");
      else {
           system("ls -l umask.file");
        close(fd);
        unlink("umask.file");
      }
      umask(oldmask);
     return 0;
}

➜ $: gcc umask.c
➜ $: ./a.out

Your old umask is 18
-rwx------  1 homeway  staff  0 Mar  3 22:41 umask.file

4.chmod()/fchmod()/fchmodat()

#include <sys/types.h>
#include <sys/stat.h> 
int chmod(const char *path, mode_t mode);
int fchmod(int fildes, mode_t mode); 
int fchmodat(int fildes, const char *pathname, mode_t, int flag);
                                            - 成功返回:0;失败返回:-1

This three is easy to use, like command line: chmod xxxx filepath

5.chown()/fchown()/fchownat()

#include <sys/types.h>
#include <unistd.h> 
int chown(const char *path, uid_t owner, gid_t group); 
int fchown(int fd, uid_t owner, gid_t group); 
int lchown(const char *path, uid_t owner, gid_t group); 
                                            - 成功返回:0;失败返回:-1

These system calls change the owner and group of the file specified by path or by fd.

An example to show how to use chmod/chown here:

#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char** argv) {
    if (argc != 2) {
        printf("Usage: %s filename", argv[0]);
        return 0;
    }
    char cmd[128];
    sprintf(cmd, "ls -l %s", argv[1]);
    printf("%s: file permission:\n", argv[1]);
    system(cmd);
    if (chmod(argv[1], (S_IRWXU | S_IRGRP | S_IROTH)) < 0) {
        printf("%s: chmod error", argv[1]);
        return 0;
    } else {
        printf("\n%s: chmod => -rwxr--r--\n", argv[1]);
    }
    system(cmd);
}

➜ $: gcc chmod.c
➜ $: ./a.out chmod

chmod: file permission:
-rwxr--r--  1 homeway  staff  13708 Mar  3 23:03 chmod
chmod: chmod => -rwxr--r--
-rwxr--r--  1 homeway  staff  13708 Mar  3 23:03 chmod

6.truncate()/ftruncate()

#include <unistd.h>
#include <sys/types.h> 
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length); 
                                            - 成功返回:0;失败返回:-1

The truncate()/ftruncate() functions cause the regular file named by path or referenced by fd to be truncated to a size of precisely length bytes.

If the file previously was larger than this size, the extra data is lost. If the file previously was shorter, it is extended, and the extended part reads as null bytes (‘\0’). The file offset is not changed.

With ftruncate(), the file must be open for writing; with truncate(), the file must be writable.

#include <stdio.h>
#include <unistd.h>
int str2int(char* s) {
    int sum = 0, len = (int)strlen(s);
    for (int i = 0; i < len; ++i) 
        sum = sum * 10 + s[i] - '0';
    return sum;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        printf("Usage: %s pathname length", argv[0]);
        return 0;
    }
    char cmd[128];
    sprintf(cmd, "ls -l %s", argv[1]);
    system(cmd);
    if (truncate(argv[1], (off_t)(str2int(argv[2]))) < 0) {
        printf("%s: truncate(%s, %s) error", argv[1], argv[1], argv[2]);
    }
    system(cmd);
    return 0;
}

➜ $: gcc truncate.c
➜ $: ./a.out truncate 1024

-rwxr-xr-x  1 homeway  staff  13700 Mar  3 23:07 truncate
-rwxr-xr-x  1 homeway  staff  1024 Mar  3 23:08 truncate

// TODO…


0x02.ERROR

Error code see here: http://homeway.me/2017/03/02/apue-file-io/#error



Reference:

– Base api information are in book, so in my blog I only write some useful example.



本文出自 夏日小草,转载请注明出处:http://homeway.me/2017/03/03/apue-file-stat/

-by小草

2017-03-03 23:18:34

Fork me on GitHub