Notes on advanced programming in UNIX Environment Chapter 4 - files and directories

1. Functions stat, fstat, fstatat and lstat

Returns the specified file information

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
int fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags);
  • The stat function returns the file information specified by pathname and saves it in the statbuf parameter

  • The fstat function is similar to stat except that the file is identified by the file descriptor fd

  • lstat is similar to stat, except that when pathname is a symbolic link, you get the information of the symbolic link file itself, not the file information pointed to by the symbolic link.

  • In fstatat, if pathname is an absolute pathname, the dirfd parameter is ignored; If pathname is a relative pathname, dirfd indicates the starting address of the relative path (that is, dirfd is the file descriptor of the open directory file); If dirfd is set to AT_FDCWD, the starting address of the relative path is the working directory of the process. Set the flags parameter to at_ SYMLINK_ When nofollow, fstatat does not follow the symbolic link, but returns the information of the symbolic link file itself.

    # define AT_SYMLINK_NOFOLLOW	0x100	/* Do not follow symbolic links.  */
    

The struct stat structure saves various information of the file. The above function saves the file information in this structure:

struct stat {
    dev_t     st_dev;         /* File system device number */
    ino_t     st_ino;         /* inode number */
    mode_t    st_mode;        /* File type and access rights */
    nlink_t   st_nlink;       /* Number of hard links */
    uid_t     st_uid;         /* Owner uid */
    gid_t     st_gid;         /* Owner gid */
    dev_t     st_rdev;        /* Actual device number of special file (block, character, special file) */
    off_t     st_size;        /* File size (bytes) */
    blksize_t st_blksize;     /* Appropriate block length for file I/O */
    blkcnt_t  st_blocks;      /* The number of 512 byte blocks allocated by the file */

    struct timespec st_atim;  /* Last access time of file data */
    struct timespec st_mtim;  /* Last modification time of file data */
    struct timespec st_ctim;  /* inode Last change time of node state */

    #define st_atime st_atim.tv_sec      /* Backward compatibility */
    #define st_mtime st_mtim.tv_sec
    #define st_ctime st_ctim.tv_sec
};

The timespec structure defines the time in seconds and nanoseconds

struct timespec {
	__kernel_time_t	tv_sec;			/* second */
	long		tv_nsec;		/* nanosecond */
};

2. Document type

Most files on UNIX systems are ordinary files or directories, but there are some other file types.

The file information is saved in the st of the stat structure_ Mode member

2.1 regular file

The most commonly used file type, which contains some form of data. As for whether the data is text or binary, it makes no difference to the UNIX kernel.

2.2 directory file

This file contains the names of other files and pointers to information related to these files. Any process with read permission to a directory file can read the contents of the directory, but only the kernel can write the directory file directly.

2.3 block special file

Provides buffered access to devices, such as tapes, with each access taking a fixed length as a unit.

2.4 character special file

Provides unbuffered access to the device, and the length of each access is variable. All devices in the system are either character special files or block special files.

2.5 FIFO

This type of file is used for interprocess communication and is sometimes called a named pipe

2.6 socket

This type of file is used for network communication between processes, and can also be used for non network communication between processes on a host.

2.7 symbolic link

This type of file points to another file, similar to a shortcut.

2.8 document type judgment

St in the file information (stat structure object) obtained through stat System Call_ Mode member, which holds file type information and access rights. The file type can be determined by the following macro

macrofile type
S_ISREG()Ordinary file
S_ISDIR()Catalog file
S_ISCHR()Character special file
S_ISBLK()Block special file
S_ISFIFO()Pipeline or FIFO
S_ISLNK()Symbolic link
S_ISSOCK()socket

Example: judging file type

int main(int argc, char* argv[]) {
    struct stat st;
    stat(argv[1],&st);
    if(S_ISREG(st.st_mode)) {
        cout << "Ordinary file" << endl;
    } else if(S_ISDIR(st.st_mode)) {
        cout << "Catalog file" << endl;
    } else {
        cout << "Other documents" << endl;
    }
}
$ ./a.out  t.txt 
> Ordinary file

3. Set the user ID bit and set the group ID bit

There are 6 ID s associated with a process:

Actual user ID
Actual group ID
Who are we actually, the actual users who perform this process. These two ID s are taken from the password file when the user logs in
effective uid
Valid group ID
Affiliate group ID
For file access check
Saved settings user ID
Saved settings group ID
Save with exec function

Generally, the effective user ID is equal to the actual user ID, and the effective group ID is equal to the actual group ID.

Distinguish the six IDS * * from the owner and group owner of each file** The six IDS mentioned here are associated with the process, and the owner uid and owner gid associated with each file are determined by the st in the stat structure_ Uid and st_gid specifies.

Set user ID bit and set group ID bit:

Set a special flag in the file mode word (st_mode) of the stat structure, which means that when the file is executed, the valid user ID of the process is set to the file owner uid. This flag is the file mode word St_ One bit in mode: sets the user ID bit

Similarly, another special flag can be set in the file mode word, which means that when the file is executed, the valid group ID of the process is set to the file owner gid. This flag is the file mode word St_ One bit in mode: sets the group ID bit.

You can set a special flag in the file mode word (st_mode), which means that when the file is executed, the valid user ID of the process is set as the file owner uid. Similarly, another special flag can be set in the file mode word, which means that when the file is executed, the valid group ID of the process is set to the file owner gid.

For example, if the file owner is a superuser and the set user ID bit of the file is set, the process will have superuser permission when the file is executed (because the valid user ID is set to the user owner uid).

Since both the user ID bit and the group ID bit are set, they are included in the st of the file stat_ Mode member, so you can use the following constants to determine whether these two flag bits are set by bitwise AND

S_ISUID // Get s_ The status of the isuid bit. Judge whether the user ID bit is set
S_ISGID // Get s_ The status of the isgid bit. Determine whether the set group ID bit is set
if(S_ISUID & st.st_mode) {
    cout << "Set user ID position" << endl;
} else {
    cout << "User not set ID position" << endl;
}

if(S_ISGID & st.st_mode) {
    cout << "Setting group set ID position" << endl;
} else {
    cout << "No set group ID position" << endl;
}

4. File access rights

St of stat structure_ The mode member also contains the access permission bits to the file

Each file has 9 access bits, which can be divided into 3 categories

st_mode bitmeaning
S_IRUSRUser read
S_IWUSRUser write
S_IXUSRUser execution
S_IRGRPGroup reading
S_IWGRPGroup write
S_IXGRPGroup execution
S_IROTHOther reading
S_IWOTHOther write
S_IXOTHOther execution

The definitions in C are as follows:

# define S_IRUSR	0400       /* Read by owner.  */
# define S_IWUSR	0200      /* Write by owner.  */
# define S_IXUSR	0100       /* Execute by owner.  */
/* Read, write, and execute by owner.  */
# define S_IRWXU	(S_IRUSR|S_IWUSR|S_IXUSR)

# define S_IRGRP	(S_IRUSR >> 3)  /* Read by group.  */
# define S_IWGRP	(S_IWUSR >> 3)  /* Write by group.  */
# define S_IXGRP	(S_IXUSR >> 3)  /* Execute by group.  */
/* Read, write, and execute by group.  */
# define S_IRWXG	(S_IRWXU >> 3)

# define S_IROTH	(S_IRGRP >> 3)  /* Read by others.  */
# define S_IWOTH	(S_IWGRP >> 3)  /* Write by others.  */
# define S_IXOTH	(S_IXGRP >> 3)  /* Execute by others.  */
/* Read, write, and execute by others.  */
# define S_IRWXO	(S_IRWXG >> 3)

Where user refers to the file owner, group refers to the user of the file owner's group, and others refer to other users

**Note that the last parameter of the open function and the creat e function is also bitwise or obtained through the above constants** It can also be set by numbers such as 0777.

These 9 file access permission bits can be modified by chmod command

  • When opening any type of file by name, you need to ensure that you have execution permission for each directory file in the name.

    For example, to open the file / usr/include/stdio.h, you need to have permissions not only on the stdio.h file, but also on the directories /, / usr, / usr/include.

    It should be noted that the read permission and execution permission of the directory file are different. Read permission allows us to read the directory and get a list of all file names in the directory. Execution permission allows us to search through the directory.

  • The read permission of a file determines whether we can open it for read operation, which is the same as the o of the open function_ Rdonly and O_RDWR flag related

  • The write permission of a file determines whether we can open it for write operation, which is the same as the o of the open function_ Wronly and O_RDWR flag related

  • Specify o for a file in open_ TRUNC flag. You need to have write permission for the file

  • In order to create new files in a directory, you need to have execute and write permissions to that directory.

  • To delete a file, you need to have execute and write permissions on the directory, and you don't need permissions on the file itself

  • If you use the exec function family to execute a file, you need the execution permission of the file, and the file must be a normal file type.

File access test process:

Every time a process opens, creates, or deletes a file, the kernel performs a file access test check. The test involves the st of the file_ Uid and st_gid, valid user ID and valid group ID and affiliate group ID of the process.

  1. If the valid user ID of the process is 0 (superuser), access is allowed. This gives the super user full freedom to process the entire file system
  2. If the valid user ID of the process is equal to the st of the file_ Uid (that is, the process owns the file), then access is allowed if the appropriate access permission bit of the owner is set. For example, if the process reads and opens the file, the user read bit of the file should be 1; If the process opens the file, the user write bit of the file should be 1; If the process executes to open the cover file, the user execution bit of the file should be 1.
  3. If the valid group ID or affiliate group ID of the process is equal to the st of the file_ GID, then access is allowed if the appropriate permission bit of the group is set
  4. If the appropriate access permission bit of other users is set, access is allowed.

It should be noted that the permission test process is executed step by step in sequence. If the process has this file, test the permissions according to the second step, and the subsequent steps will not be executed; If the process does not own the file, but the process belongs to an appropriate group, test the permissions according to step 3, and the subsequent steps will not be executed.

5. Ownership of new documents and directories

The ownership rules of the new directory are the same as those of the new file

  • The user ID of the new file is set to a valid user ID of the process
  • The group ID of the new file is set to the valid group ID of the process or the group ID of the directory where the file is located.

6. Functions access and factessat

Test the access rights according to the actual user ID

int access(const char *pathname, int mode);
int faccessat(int dirfd, const char *pathname, int mode, int flags);
// 0 is returned for success, and - 1 is returned for failure, and errno is set

In factessat, when pathname is an absolute path, dirfd ignores it; If pathname is a relative path and dirfd is AT_FDCWD, the starting directory of the relative path is the working directory of the process, otherwise the starting directory of the relative path is the directory file opened by dirfd

  • mode parameter:

    • F_OK: verify that the file exists

    • R_OK/W_OK/X_OK: these three constants are bitwise and can detect read-write execution permissions

      #define	R_OK	4		/* Test for read permission.  */
      #define	W_OK	2		/* Test for write permission.  */
      #define	X_OK	1		/* Test for execute permission.  */
      #define	F_OK	0		/* Test for existence.  */
      
  • flags parameter: if set to at_ In eAccess, the access check uses the valid user ID and valid group ID of the calling process instead of the actual user ID and actual group ID.

Use example:

    if(access("t1.txt",R_OK) < 0) {
        perror("file does not exist");
    }

7. Function umask

It is used to set the file mode before creating a file (the default permission mask when creating a file): the specified permission set in the shielding word will not be set when creating a file (that is, the permission is shielded)

mode_t umask(mode_t mask); // Return to the previous file mode to create a mask word

The parameter mask can be the bit-by-bit or composition of the nine constants in Section 4 (or other write permissions are masked through the number such as 0002), specifying which permissions are masked.

This function is often used in conjunction with the open and create functions to set the file mode and create a mask word through the umask function. When a process creates a new file or directory, it must use the file mode to create a mask word. The previous open function has a parameter mode. When open sets the file access permission according to mode, the file mode creates a bit of 1 in the mask word, and the corresponding bit in the file mode must be closed.

Example: create files through umask and open

    umask(0); // No permission bits are masked
    open("tt.txt",O_RDWR | O_CREAT,0777); // Create files with 0777 permissions
    umask(S_IRGRP | S_IWGRP); // Group read and write permission bits are masked
    open("tt1.txt",O_RDWR | O_CREAT,0777); // Create files according to 0777 permissions (note that two permission bits are blocked)
$ ls -la
> -rwxrwxrwx 1 root root    0 Oct 21 12:36 tt.txt # The visible file permission is 0777
> -rwx--xrwx 1 root root    0 Oct 21 12:36 tt1.txt # It can be seen that group read and write permissions are blocked

8. Function chmod, fchmod, fchmodat

Change access to existing files

The valid user ID of the process must be equal to the uid of the file owner, or the process has super user permission to successfully call the following function to modify the file access permission.

int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
//0 is returned for success and - 1 is returned for failure
  • Parameter flags: when at is set_ SYMLINK_ Nofollow, fchmodat does not follow the symbolic link, but for the symbolic link file itself.

  • Parameter mode: bitwise or of the following constants

    modeexplain
    S_ISUID
    S_ISGID
    Set user ID bit during execution
    Set group ID bit during execution
    S_IRWXU
    S_IRUSR
    S_IWUSR
    S_IXUSR
    Owner read / write execution permission
    Owner read permission
    Owner write permission
    Owner execution permission
    S_IRWXG
    S_IRGRP
    S_IWGRP
    S_IXGRP
    Group read / write execution permission
    Group read permission
    Group write permission
    Group execution permission
    S_IRWXO
    S_IROTH
    S_IWOTH
    S_IXOTH
    Other read / write execution permissions
    Additional read permissions
    Other write permissions
    Other execution permissions

9. chown, fchown, fchownat, lchown functions

Change the user ID and group ID of the file

int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags);
//0 is returned for success and - 1 is returned for failure

If the owner and group parameters are - 1, the corresponding ID will not be modified.

For the lchown function, if it is a symbolic link file, the symbolic link file itself is modified, not the file it points to

For the fchownat function, if flags is set to AT_SYMLINK_NOFOLLOW flag, the symbolic link file itself is modified, not the file it points to

be careful:

  • Only the superuser process can change the owner of a file. A file owner can change a file group to any group that the owner belongs to. The superuser process can change the group at will.
  • If these functions are called by a non super user process (valid user ID is not 0), the set user ID bit and set group ID bit of the file are cleared when they are returned successfully

10. Document length

St of stat struct object_ The size member variable indicates the length (bytes) of the file. This field is only meaningful for ordinary files, directory files and symbolic links.

  • For ordinary files, the length can be 0. When you start reading the file, you will get eof
  • For a directory file, its length is usually an integer multiple of a number (16 or 512).
  • For symbolic links, the file length is usually the actual number of bytes of the file name it points to (excluding null bytes at the end of the string)

St of stat_ Blksize members:

The appropriate block length for file I/O. When using st_ When blksize is used for read operations, it takes the least amount of time to read a file. Standard I/O library functions also attempt to read and write st at once_ Blksize bytes of data.

St of stat_ Blocks members:

Number of 512 byte blocks

Holes in file:

Ordinary files can contain holes. The offset set exceeds the end of the file and is caused by writing some data. Since no holes can be stored on the disk, the file size printed by ls command and du command is inconsistent.

ls: print out the number of bytes of file content, including the empty size

du: print out the disk space occupied by the specified directory or file. (512 or 1024 byte blocks)

int fd = open("tt.txt",O_RDWR | O_CREAT | O_TRUNC,0777);
lseek(fd, 200000, SEEK_END);
char buf[10] = "abc";
write(fd, buf, 3);
close(fd);
$ ls -l tt.txt 
> -rwxr-xr-x 1 root root 200003 Oct 21 15:09 tt.txt
$ du -h tt.txt # Disk size occupied by printing files in units of K, M and G
> 4.0K    tt.txt

It can be seen that the actual disk space occupied by the file is smaller than the file content, because the file contains holes, and holes can not be stored in the disk. The 4KB disk space occupied by this file is due to the linux ext4 file system, and the disk block length is 4096 bytes (4KB). Therefore, the file occupies only one disk block of data

11. File truncation

Use the truncate and ftruncate functions to truncate files

int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);

Truncate the file to length bytes. If the previous file is greater than length, it will be truncated to length; If the previous file is less than length, the file length increases, and the increased part is read as 0 (that is, a hole can be created in the file)

12. File system

You can divide a disk into one or more partitions. Each partition can contain a file system. An inode node is a fixed length record entry that contains most of the information about the file.

Inodes also consume hard disk space, and the operating system automatically divides the hard disk into two areas. One is the data area, which stores file data; The other is the inode table, which stores the information contained in the inode. The size of each inode node is generally 128 bytes or 256 bytes

  • In the figure above, you can see that the directory entries in two directory files point to the same i node. Each inode has a link count (hard link), which is the number of directory entries pointing to the inode. Only when the link count is 0 can the file be deleted (releasing the disk data block occupied by the file). This is why the function to delete a directory entry is unlink instead of delete. In the stat data structure, St_ The nlink member variable indicates the number of hard links of the file.
  • In addition to hard links (the inode number of a directory item directly represents the linked inode node), there is also a link called a symbolic link. The actual content of the symbolic link file (the content in its data block) is the name of the file to which it points
  • Inode contains all the information of the file: file type, file access permission bit, file length, pointer to file database, etc. Most of the information in the stat structure is taken from inode.
  • Because the inode number in the directory entry points to the corresponding inode node in the same file system, one directory entry cannot point to the inode node of another file system, so inodes cannot cross file systems
  • Rename the file: it does not change the actual content of the file, just construct a new directory entry pointing to the existing inode and delete the old directory entry. The number of hard links remains unchanged.

Link count for catalog files:

mkdir testdir

If you create a new directory testdir, the file system instance is shown in the figure.

It can be seen that the link count of any leaf directory (directory without subdirectories) file is always 2 (testdir directory entry in the parent directory file and. Directory entry in testdir directory file)

The directory file link count that is not a leaf directory is greater than or equal to 3 (the directory entry of the parent directory file, the. Directory entry of the directory file, the... Directory entry of the child directory file). Note that each subdirectory in the parent directory will cause the link count of the parent directory file to + 1 (the... Directory entry in the subdirectory file)

13. Functions link, linkat, unlink, remove

Any file can have multiple directory entries pointing to its inode node. You can use the link or link system call to create a hard link to an existing file

int link(const char *oldpath, const char *newpath);
int linkat(int olddirfd, const char *oldpath,int newdirfd, const char *newpath, int flags);

flags parameter: set this parameter to at when the existing file is a symbolic link file_ SYMLINK_ Follow creates a hard link to the symbolic link target, otherwise it creates a hard link to the symbolic link file itself.

To delete an existing directory entry, you can use the unlink or unlink function. This operation requires write and execute permissions on the directory.

int unlink(const char *pathname);
int unlinkat(int dirfd, const char *pathname, int flags);

Parameter flags: when set to at_ When the removedir flag is, unlink deletes the directory similar to rmdir, otherwise unlink and unlink perform the same operation.

  • Delete directory entries so that the number of hard links to inode nodes is - 1.

  • Only when the number of hard links is 0 can the file content be deleted. However, if a process opens the file, its contents cannot be deleted. When a process closes a file, the kernel first checks the number of processes that open the file. If it is 0, the kernel checks the number of hard links. If it is also 0, the file content is deleted.

  • Note that unlink only deletes the directory entry, not the file content. The file content must be hard links, the number is 0, and no process will delete the file.

  • If pathname is a symbolic link, unlink deletes the symbolic link itself.

You can also use the remove function to unlink a file or directory:

int remove(const char *pathname);

remove is equivalent to unlink for files and rmdir for directories

14. Functions rename and rename at

Used for file or directory renaming

int rename(const char *oldpath, const char *newpath);
int renameat(int olddirfd, const char *oldpath,int newdirfd, const char *newpath);
  • If oldpath or newpath is a symbolic link, you are dealing with the symbolic link file itself, not the file it points to.

15. Create and read symbolic links

A symbolic link is an indirect pointer to a file. The saved content of the data block pointed to by the inode pointer of the symbolic link file is the target file name it points to (therefore, for symbolic links, the file length is usually the actual number of bytes of the file name it points to, and does not contain null). Symbolic links are similar to shortcuts.

Symbolic links are not required to be in the same file system, that is, the target file and symbolic link file can be in different file systems

Create a symbolic link through the symlink and symlink functions

int symlink(const char *target, const char *linkpath);
int symlinkat(const char *target, int newdirfd, const char *linkpath);

Since the open function follows the symbolic link (open is the target file pointed to by the symbolic link file), if you want to read the contents of the symbolic link file itself, you can use the readlink and readlink functions

ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
//The number of bytes read is returned successfully, and - 1 is returned for failure

Note that the symbolic link content returned in buf does not end with null.

The readlink function actually integrates all the operations of the open, read and close functions.

16. Timing of documents

St in stat structure_ atime,st_mtime,st_ctime members are file time information

fieldexplainFunction example of modifying this time
st_atimeLast access time of file dataread
st_mtimeLast modification time of file datawrite
st_ctimeinode node state last changedchmod,chown

Note the difference between modification time (st_atime) and state change time (st_ctime). The former is the latest modification time of the file content, and the latter is the last modification time of the inode node. For example, changing the file access permission, changing the user ID, changing the number of links, etc., these operations do not change the actual content of the file, because the inode node and the actual content of the file are stored separately.

A directory is a file that contains a directory entry (file name and associated inode node number). Adding, deleting, or modifying a directory item will affect the three times of its directory (st_atime, st_mtime, st_ctime). For example, creating a new file affects the directory containing the new file.

However, reading and writing a file has no effect on the directory.

17. Futimes, utimensat and utimes functions

Used to modify the access and modification time of file content.

The futimens and utimensat functions can specify nanosecond timestamps. The data structure used is the same timespec as in stat

int futimens(int fd, const struct timespec times[2]);
int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);
struct timespec {
	__kernel_time_t	tv_sec;			/* second */
	long		tv_nsec;		/* nanosecond */
};
  • Parameter times:

    Is an array containing two elements. The first element is the access time and the second element is the modification time. These two time values are the number of seconds since 1970, and the part less than seconds is expressed in nanoseconds.

    • If times is nullptr, the access time and modification time are set to the current time
    • TV of an element_ Nsec member set to UTIME_NOW, the corresponding time is set to the current time and TV is ignored_ SEC member
    • TV of an element_ Nsec member set to UTIME_OMIT, the corresponding time remains unchanged and TV is ignored_ SEC member
    • Permission check: when times is not empty and tv_nsec members are UTIME_OMIT, no permission check is performed; Otherwise, a permission check on the file is performed
  • Parameter flags:

    If at is set_ SYMLINK_ Nofollow flag, the time of the symbolic link itself will be modified; Otherwise, the file pointed to by the symbolic link file is modified.

You can also set the access time and modification time through the utimes function

int utimes(const char *filename, const struct timeval times[2]);
struct timeval {
    long tv_sec;        /* seconds */
    long tv_usec;       /* microseconds */
};

times is a pointer to a struct array containing two elements. The array elements are access time and modification time respectively.

18. Functions mkdir, mkdirat, rmdir

Create a directory using the mkdir and mkdirat functions

int mkdir(const char *pathname, mode_t mode);
int mkdirat(int dirfd, const char *pathname, mode_t mode);

The parameter mode is the directory file access permission. This permission is masked by the file mode creation mask word

A common error is to specify the read-write permission of the directory file, but do not specify the execution permission. For a directory file, at least the execution permission should be set to allow access to the files in the directory

Use the rmdir function to delete an empty directory

int rmdir(const char *pathname);

19. Read directory

Any user with access to a directory can read the directory, but only the kernel can write directory files. The write permission bit and execution permission bit of a directory file determine whether files can be created or deleted in the directory.

19.1 open directory file

Use opendir, fdopendir to open the directory file.

Returns a pointer to the directory stream, which is positioned on the first entry of the directory. Each entry in the directory points to a file in the directory. There are two special directory entries in the directory, namely ".." and "..." are the directory file and the upper level directory file respectively. Failure returns NULL

DIR *opendir(const char *name);
DIR *fdopendir(int fd);

19.2 reading directory entries

The readdir() function returns a pointer to the dirent structure, which represents the next directory entry in the directory stream. NULL is returned when the end of the directory stream is reached or an error occurs

struct dirent * readdir(DIR * dirp);
struct dirent {
    ino_t          d_ino;       /* inode number */
    off_t          d_off;       /* not an offset */
    unsigned short d_reclen;    /* The entry length */
    unsigned char  d_type;      /* file type */
    char           d_name[256]; /* File name, 255 characters maximum */
};

19.3 close directory file

Close a directory file opened by the opendir function through closedir, that is, close the directory stream referred to by the parameter dir

int closedir(DIR *dir);

19.4 setting the directory stream read location

rewinddir() is used to set the parameter dir to read the directory stream at the beginning

void rewinddir(DIR *dirp);

The return value of the telldir() function records the current location of a directory stream. This return value represents the offset from the beginning of the catalog file

long telldir(DIR *dirp);

seekdir() is used to set the parameter dir directory stream reading location. When readdir() is called, it will start reading from this new location. The parameter offset represents the offset from the beginning of the directory file

void seekdir(DIR *dir, long loc);

19.5 example of reading directory item information in directory file:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>

int main(){
    DIR* dir = opendir("/home/xtark/wudi/210525");
    struct dirent *d;
    while(d = readdir(dir)){
        printf("the inode number is : %ld\n",d->d_ino);
        printf("the d_off is %ld\n",d->d_off);
        printf("the lengh of this record is %d\n",d->d_reclen);
        printf("the type of this file is %d\n",d->d_type);
        printf("the file name is %s\n\n\n",d->d_name);
    }
}

Operation result: it can be seen that there are two directory items, namely ".." and "..." pointing to the directory file and the upper level directory file respectively

xtark@xtark-vmpc:~/desktop/linux_study/section8$ gcc test1.c
xtark@xtark-vmpc:~/desktop/linux_study/section8$ ./a.out 
the inode number is : 1045496
the d_off is : 2240378328779100918
the lengh of this record is : 32
the type of this file is : 8
the file name is : test.o


the inode number is : 1045454
the d_off is : 2801854051817173045
the lengh of this record is : 24
the type of this file is : 4
the file name is : .


the inode number is : 1045439
the d_off is : 2838125603082282148
the lengh of this record is : 24
the type of this file is : 4
the file name is : ..


the inode number is : 1045490
the d_off is : 3113460208815849764
the lengh of this record is : 32
the type of this file is : 8
the file name is : test.h

20. Functions chdir, fchdir, getcwd

Each process has a current working directory, which is the starting point for all relative pathnames. When a user logs in to the UNIX system, its current working directory is the sixth field of the user login entry in the password file / etc/passwd - the user's starting directory.

Note: if the program in directory B is run in directory A, the working directory of process B is directory A

The current working directory of the calling process can be changed through the chdir function and fchdir function

int chdir(const char *path);
int fchdir(int fd);

Get the current working directory of the calling process through the getcwd function

char *getcwd(char *buf, size_t size);

The principle is to start from the current working directory (.), use... To find its upper level directory, and then read its directory item until the inode number in the directory item is the same as that in the working directory. In this way, the file name is obtained from the directory item and moved up layer by layer until the root directory is encountered

21. Equipment special documents

St in stat_ The dev member is the device number (primary and secondary device number) of the file system where the file is located.

St in stat_ The rdev member is only useful in character special files and block special files and represents the device number (primary and secondary device number) of the actual device

The storage device where each file system is located has its primary and secondary device numbers. The master device number is used to distinguish different types of devices. Devices of the same type have the same driver, and the master device number is used to identify the driver. The secondary equipment number is used to distinguish different equipment of the same type, indicating which equipment it refers to.

For ordinary files, the primary device number identifies the primary device number of the actual storage device storing the file, and the secondary device number represents the partition of the file system (different partitions of the same storage device can be regarded as different devices).

Get the primary and secondary device numbers in the device number through the major and minor macros.

struct stat st;
stat("tt.txt",&st);
cout << "Main equipment No.:" << major(st.st_dev) << "Secondary equipment No.:" << minor(st.st_dev) << endl;
// Print: main equipment No.: 252 secondary equipment No.: 1

Tags: C Unix server

Posted on Thu, 21 Oct 2021 10:38:58 -0400 by 90Nz0