To the fourth chapter, I do not know when to read the book, the delay too much time.
The fourth chapter is based on the third chapter, mainly describes the other properties of the file system and the nature of the document.
4.2 Stat, Fstat, Fstatat, Lstat functions
Let's take a look at the prototypes of these four functions:
#include <sys/stat.h>///usr/include/x86_64-linux-gnu/sys/int stat (const char *__restrict __file, struct stat *__ Restrict __buf) int fstat (int __fd, struct stat *__buf) int fstatat (int __fd, const char *__restrict __file, struct stat * __restrict __buf, int __flag) int lstat (const char *__restrict __file, struct stat *__restrict __buf)
The functions of these functions are summed up in the following: To obtain the stat structure. The difference is that the stat function obtains this structure through the file name; Fstat through the document descriptor; Lstat returns information about the symbolic link, not the file referenced by the symbolic link Fstatat returns a stat struct with a file (file name) under the current folder (which is pointed to by FD).
Well, regardless of the function of the above functions, the core is to return the stat structure, stat is defined as follows:
struct Stat {__dev_t st_dev;/* Device. */#ifndef __x86_64__ unsigned short int __pad1; #endif # if defined __x86_64__ | | !defined __use_file_offset64 __ino_t st_ino;/* file serial number.*/#else __ino_t __st_ino;/* 32bit file serial numb er.*/#endif #ifndef __x86_64__ __mode_t st_mode;/* File mode. */__nlink_t st_nlink;/* Link count. */#else __nlink_t st_nlink;/* Link count. */__mode_t st_mode;/* File mode. */#endif __uid_t st_uid;/* User ID of the file ' s owner.*/__gid_t st_gid;/* Group ID of the file ' s group.*/#ifdef __ x86_64__ int __pad0; #endif __dev_t st_rdev;/* device number, if device. */#ifndef __x86_64__ unsigned short int __pad2; #endif # if defined __x86_64__ | | !defined __use_file_offset64 __off_t st_size;/* size of FILE, in bytes. */#else __off64_t st_size;/* size of file, in bytes. */#endif __blksize_t st_blksize;/* Optimal block size for I/O. */#if defined __x86_64__ | | !defined __use_file_offset64 __blkcnt_t St_blocks;/* number 512-byte blocks allocated. */#else __blkcnt64_t st_blocks;/* number 512-byte blocks allocated. */#endif #ifdef __USE_XOPEN2K8/* nanosecond resolution timestamps is stored in a format equivalent to ' struct TI Mespec '. The the type used whenever possible but the Unix namespace rules does not allow the identifier ' Timespec ' to appear in the <sys/stat.h> header. Therefore we have to handle the use of this header in strictly standard-compliant sources special. */struct Timespec st_atim;/* time of last access. */struct Timespec st_mtim;/* time of last modification. */struct Timespec st_ctim;/* time of last status change. */# define st_atime st_atim.tv_sec/* backward compatibility. */# define St_mtime st_mtim.tv_sec# define St_ctime st_ctim.tv_sec#else __time_t st_atime;/* time of last access. */__syscall_ulong_t st_atimensec;/* nscecs of last access. */__time_t st_mtime;/* time of last modification. */ __syscall_ulong_t st_mtimensec;/* nsecs of last modification. */__time_t st_ctime;/* time of last status change. */__syscall_ulong_t st_ctimensec;/* nsecs of last status change. */#endif #ifdef __x86_64__ __syscall_slong_t __glibc_reserved[3]; #else # ifndef __use_file_offset64 unsigned long int __GLIBC_RESERVED4; unsigned long int __glibc_reserved5;# else __ino64_t st_ino;/* File serial number.*/# endif#endif};
4.3 File types
After looking at the stat structure above, I feel the contents of stat structure at random, then we study several important fields, first of all:
__mode_t St_mode;
First look at the "__mode_t" type, the definition is located in:/usr/include/x86_64-linux-gnu/bits/type.h, the following is defined as follows:
# define __std_typetypedef__std_type __mode_t_type __mode_t; #define __mode_t_type __u32_type///usr/include/x86_64- Linux-gnu/bits/typesize.h#define __u32_type unsigned int
This whole bunch, backwards.
According to Apue, the files include the following categories:
- Normal file
- Catalog files
- Block Special files
- Character Special files
- Fifo
- Sockets
- Symbolic Links
Well, take a look at what Linux is about, or in/usr/include/x86_64-linux-gnu/sys/stat.h.
#define__S_ISTYPE (Mode, mask) ((mode) & __s_ifmt = = (mask)) #defineS_ISDIR (mode) __s_istype (mode), __s_ifdir) # DEFINES_ISCHR (mode) __s_istype (mode), __S_IFCHR) #defineS_ISBLK (mode) __s_istype (mode), __s_ifblk #defineS_ISREG ( mode) __s_istype (mode), __s_ifreg) #ifdef __s_ififo# define S_ISFIFO (mode) __s_istype (mode), __s_ififo) #endif #ifdef _ _s_iflnk# define S_ISLNK (mode) __s_istype (mode), __s_iflnk) #endif # define S_issock (mode) __s_istype (mode), __s_ Ifsock) #ifdef __use_posix199309# define S_TYPEISMQ (BUF) __s_typeismq (BUF) # define S_TYPEISSEM (BUF) __s_typeissem (BUF) # define S_TYPEISSHM (BUF) __s_typeisshm (BUF) #endif
Well, as you can see from the definition above, these macro definitions are essentially "and operations" with a parameter and __s_ifmt, and the resulting value is compared to the original function of the function, and finally returns 0 or 1.
In the previous chapter we left a doubt that the Lseek function can set the offset of a file, but if the file descriptor points to a pipe, FIFO (named pipe), network socket, Lseek returns-1, and errno is set to Espipe. So we got a conclusion. File descriptors 0, 1, 2 are pipes or named pipes. Now it's time to experiment and verify:
#include <sys/stat.h> #include <stdio.h> #include <unistd.h>int main () {struct stat Buf;fstat (stdin_ FILENO,&BUF), if (S_isfifo (buf.st_mode));p rintf ("stdin is fifo\n"); Fstat (STDOUT_FILENO,&BUF); if (S_isfifo ( Buf.st_mode));p rintf ("stdout is fifo\n"), Fstat (STDERR_FILENO,&BUF), if (S_isfifo (buf.st_mode));p rintf ("STDERR is fifo\n "); return 0;}
The results of the operation are as follows:
./test_stat stdin is Fifostdout are Fifostderr is FIFO
The above experiment also validates our speculation that file descriptors 0, 1, and 2 are pipes or named pipes.
Section 4.4 focuses on setting the user ID and user group ID problems, the book gives some analysis, but I feel that is not very clear, so to share an article blog:http://blog.chinaunix.net/uid-18905703-id-3843177.html
On the above concepts, combined with some of the information I have seen, to give you a simple summary. On the distinction between these concepts, or from the phenomenon, a program to perform first to know the program's "Valid User ID", "valid group ID", "Satellite group ID", know that the above three "id" is not enough, we also check whether the current user "id" is the above three "id" match, The current user "id" is the "actual user ID" and "actual group ID", which is the authentication information used to log into the system. In general, when executing a program file, the valid user ID of the process is usually the actual user ID, and the valid group ID is usually the actual group ID. However, there are special circumstances that are mentioned in the Book passwd command execution, the detailed analysis of this command you can refer to the above blog.
4.5 File access rights
This section is mainly to share with you in the process of accessing the file to use the hidden permissions, which is hidden in addition to the permissions required to access the file, but also the additional permissions required, the specific content is as follows:
- When you open any type of file by file name, you should have execute permissions on each directory contained in the file name (absolute path), including the current working directory that it may imply. It is also important to emphasize the different meanings of Read and execute permissions for a directory, and Read permissions allow us to read the directory and get a list of all the filenames in that directory. When a directory is a component of the pathname of a file that we want to access, execute permissions on that directory allow us to use that directory (that is, to search for that directory for a specific file name).
- The Read permission for a file determines whether we can open an existing file for read operations. This is related to the o_rdonly and o_rdwr of the open function.
- The Write permission for a file determines whether we can open an existing file for write operations. This is related to the o_wronly and o_rdwr of the open function.
- In order to specify the O_TRUNC flag for a file in the open function, you must have write access to the file.
- In order to create a new file in a directory, you must have write permissions and execute permissions on the directory. You need to execute permissions because you need to find the file in the current directory before you create the file.
- In order to delete an existing file, you must have write permissions and execute permissions on the directory that contains the file (before or after you delete it). There is no need for read or write access to the file itself.
- If you execute a file with any one of the 7 exec functions, you must have execute permissions on the file. The file must also be a different file.
Each time a process opens, creates, or deletes a file, the kernel performs a file access test, which involves two aspects: the owner of the file and the process of performing the operation on the one hand. Managing the owner of a file mainly involves: St_uid (user ID), st_gid (user group ID), three fields for rights management of a process: Valid user ID, limited group ID, and satellite group ID.
There is a bit of information that identifies the process and file permissions, and then it is to compare these bits of information, if the match is the right, if not, it does not mean that the corresponding permissions. The following are the specific test procedures performed by the kernel:
- If the process's valid user ID is 0 (superuser), access is allowed. This gives the super user the fullest freedom to process the entire file system.
- If the valid user ID of the process equals the owner ID of the file (that is, the process owns the file), access is allowed if the owner's appropriate access permission bit is set, otherwise access is denied.
- If the valid group ID of the process or one of the satellite group IDs of the process is equal to the group ID of the file, access is allowed if the appropriate access permission bit for the group is set, otherwise access is denied.
- Access is allowed if the appropriate access permission bit for other users is set, otherwise access is denied.
The above 4 steps are executed sequentially, where the execution of a permission rule matches the test step out, and the next test steps are no longer performed.
4.6 Ownership of new files and directories
When creating a new file using open or create, the user ID of the new file is set to a valid user ID for the process. There are two options for the group ID:
- The group ID of the new file can be a valid group ID for the process.
- The group ID of the new file can be the group ID of the directory in which it resides. This option enables files and directories created under a directory to have a group ID for that directory, and the group ownership of files and directories is passed down from that point.
For Linux operating systems, if the set group ID bit is set, the group ID of the new file is set to the group ID of the directory, otherwise the group ID of the new file is set to the valid group ID of the process.
Well, having said so much about permissions, let's go back and look at the problem left in the previous chapter, when the question left was "to create a file without write permission, that is, the file has Read permission at this time, and then writes the data, according to my experiment, if the file does not exist, it can be successfully written." The file already exists, and no permissions error occurs when you open the file with read and write permissions. We can understand the latter error, there is no permission, so later we added "Write permission", you can write the data successfully, but for the 1th is not very clear: "There is no write permission but can write data?" ”。
4.7 Access and FACCESSAT functions
Let's take a look at the prototypes of these two functions:
#include <unistd.h>extern int access (const char *__name, int __type) __throw __nonnull ((1)); extern int Faccessat ( int __fd, const char *__file, int __type, int __flag) __throw __nonnull ((2)) __wur;
The function of these two functions is to test the access ability of the file according to the actual user ID and the actual group ID, note that the two permissions must be tested successfully in order to return success, otherwise the return failure. Let's take a look at what permissions we can test, which are defined in <unistd.h> as defined for the function's type parameter.
#defineR_OK4/* Test for Read permission. */////////////////through annotations to see its function, test Read permissions #definew_ok2/* test *///Test Write permission #definex_ok1/* test for execute permission. *///Test Execution Permissions #definef_ok0/* test for existence. *//test is present
The access function can be found by its definition, using the file name to identify the files being tested. The Faccessat function determines the test file with the file name by using FD (point to a folder). Where the __flag parameter of the FACCESSAT function is set to at_eaccess, the access check uses the valid user ID and valid group ID of the calling process (again, as in the previous test order, it jumps out of the match) instead of the actual user ID and the actual group ID.
Through the example in the book, the functions of access functions are tested simply, the source code is as follows:
#include <unistd.h> #include <stdio.h> #include <fcntl.h>int main (int argc,char* argv[]) {if (Access ( ARGV[1],R_OK) <0) perror (argv[0]), else printf ("Read access ok\n"), if (open (argv[1],o_rdonly) <0) perror (argv[0]) ; else printf ("Open for reading ok\n"); return 0;}
The results of the operation are as follows:
./test_access test_accessread Access Okopen for reading OK
Let's take a look at the operation of the/etc/shadow file:
./test_access/etc/shadow./test_access:permission Denied./test_access:permission denied
No permissions to run, so make some adjustments and try again:
SU//switch to root user chown root test_access//switch User ID to root, this step allows you to open the file using the Open function chmod u+s test_access//open user set User ID bit, Set the role of the user ID bit in a nutshell is "the performer will have the permissions of the program owner", in our case, the ordinary user has the root user Read permissions ls-l test_access//The program owner has become the root user, and set the user ID bit is also set --"s". -rwsrwxr-x 1 root 8712 June 17:36 test_accessexit//return to normal user./test_access/etc/shadow./test_access:permission denied//original Set the "s" bit, the ordinary user should have the same permissions as the root user, that is, the normal user can also read the permissions, but because the access function with the actual user ID and the actual group ID test, so there is no permission error. Open for reading OK//Similarly, because the "s" bit is set, and the root user has Read permissions, the normal user has the same permissions as the root user, which can be opened by using the Open function.
(See the following blog:http://blog.csdn.net/david_xtd/article/details/7229325 about how Ubuntu switches to super users).
4.8 umask function
The Umask function creates a masking word for the process settings file mode and returns the previous value (this is one of the few return functions that have no errors). Function Prototypes:
#include <sys/stat.h>extern __mode_t umask (__mode_t __mask) __throw;
Where the parameter cmask is composed of several bitwise "or" of 9 constants. In file mode, a bit of 1 is created in the mask word, and the corresponding bit in the mode of the file must be closed.
Through an example to feel the function of the following functions, the source code is as follows:
#include <fcntl.h> #include <unistd.h> #define RWRWRW (s_irusr| s_iwusr| s_irgrp| s_iwgrp| s_iroth| S_iwoth) int main (int argc,char* argv[]) {umask (0), if (creat ("foo", RWRWRW) <0) perror (argv[0]); Umask (s_irgrp| s_iwgrp| s_iroth| S_iwoth), if (Creat ("Bar", RWRWRW) <0) perror (argv[0]); return 0;}
The results of the operation are as follows:
ls-l foo BAR-RW-------1 andywang andywang 0 June 21:16 bar-rw-rw-rw-1 andywang andywang 0 June 21:16 foo
The experiment shows that umask (0) does not block any words, so the Foo file can be created according to the permissions we set, but it is shielded by the Umask function before the bar file is created s_irgrp| s_iwgrp| s_iroth| S_iwoth, the read-write permission for the file is preserved only when the bar is created s_irusr| S_iwusr. Through this experiment, we can conclude that the effect of umask can be continued until the process is over. Changing the file mode of a process creating a mask word does not affect the mask word of its parent process (often the shell). But I don't know if the EXEC function can continue the effect of the Umask function, here's a question?
4.9 chmod, Fchmod, Fchmodat functions
Let's take a look at the function prototypes:
#include <sys/stat.h>extern int chmod (const char *__file, __mode_t __mode) __throw __nonnull ((1)); extern int F chmod (int __fd, __mode_t __mode) __throw;extern int fchmodat (int __fd, const char *__file, __mode_t __mode, int __flag) __throw __nonnull ((2)) __wur;
The function of the above three functions is to change the access rights of existing files. The CHMOD function operates on the specified file, while the FCHMOD function operates on the file that is already open. The Fchmodat function operates on a file that is already open. The Fchmodat function and the chmod function are the same in the following two cases: one is the absolute path of the pathname parameter, the other is the value of the FD parameter is AT_FDCWD and the pathname parameter is the relative path. Otherwise, Fchmodat calculates the pathname relative to the Open directory (which is pointed to by the FD parameter). The flag parameter can be used to change the behavior of the Fchmodat, and when the At_symlink_nofollow flag is set, Fchmodat does not follow the symbolic link.
In order to change the permission bit for a file, the process's valid user ID must be equal to the file owner ID, or the process must have superuser privileges.
In addition to the 9 permission bits mentioned in the preceding article, there are 6 permission bits, all of which are as follows:
#defineS_ISUID __s_isuid/* Set user ID on execution. */#defineS_ISGID__S_ISGID/* Set group ID on execution. */# define s_isvtx __S_ISVTX#define S_IRUSR __S_IREAD /* Read by owner. */#define S_IWUSR __S_IWRITE /* Write by owner. */#define S_IXUSR __S_IEXEC /* Execute by owner. */#define S_IRWXU (__s_iread|__s_iwrite|__s_iexec) # 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 &NBSP;S_IRWXG&NBsp; (S_irwxu >> 3) #define S_IROTH (s_irgrp >> 3) /* Read by others. */#define S_IWOTH (s_iwgrp >> 3) & nbsp /* Write by others. */#define S_IXOTH (s_ixgrp >> 3) /* Execute by others. *//* Read, write, and Execute by others. */#define S_IRWXO (S_IRWXG >> 3)
OK, or a combination of the example of the book to see, the source code is as follows:
#include <unistd.h> #include <sys/stat.h> #include <stdio.h>int main (int argc,char* argv[]) {struct Stat statbuf;if (stat ("foo", &statbuf) <0) perror (argv[0]); if (chmod ("foo", (Statbuf.st_mode & ~S_IXGRP) | S_isgid) <0) perror (argv[0]); if (chmod ("Bar", s_irusr| s_iwusr| s_irgrp| S_iroth) <0) perror (argv[0]); return 0;}
The result of the operation is as follows, or the file created with the Umask function continues the experiment.
Ls-l Bar foo-rw-------1 andywang andywang 0 June 22:31 bar-rw-r--r--1 andywang andywang 0 June 22:31 foo
After running chmod, the results are as follows:
Ls-l Bar foo-rw-r--r--1 andywang andywang 0 June 22:32 bar-rw-rwsrw-1 andywang andywang 0 June 22:32 foo
Let's take a look at the bar file. Relatively simple, is to discard the original file permissions, according to the new file permissions to set.
Then it is foo file, first through the STAT function to obtain the existing file permissions, and then to close the "group execution" permission through the operation, and open the "set group ID when executing" flag (in the LS command "S" embodiment). One thing to note here is that the "s" representation does not include the execution bit, and "s" represents the execution bit. Chmod does not affect the last modified time of the file.
Okay, that's all. Let's take a look at how file permissions are calculated, and we already know how the file permission flags are defined, let's look at the specific values:
#define__S_ISUID04000/* Set user ID on execution. */#define__S_ISGID02000/* Set group ID on execution. */#define__S_ISVTX01000/* Save swapped text after use (sticky). */#define__S_IREAD0400/* Read by Owner. */#define__S_IWRITE0200/* Write by Owner. */#define__S_IEXEC0100/* Execute by Owner. */
(The above definition is in/usr/include/x86_64-linux-gnu/bits/stat.h)
OK, the actual value of the file permissions is:
#defineS_ISUID __s_isuid//04000, the number begins with "0", indicating that it is a 8 binary digital #defines_isgid__s_isgid//02000# define S_ISVTX __s_isvtx// 01000#define s_irusr __s_iread //0400#define s_iwusr __s_iwrite //0200#define s_ IXUSR __s_iexec //0100#define s_irwxu (__s_iread|__s_iwrite|__s_iexec)//0700#define S_ Irgrp (s_irusr >> 3) //shift left three bit, change to 0040#define s_iwgrp (s_iwusr >> 3) //shift left three bit, Change to 0020#define s_ixgrp (s_ixusr >> 3) //shift left three bits to 0010/* Read, write, and execute by group. */#define s_irwxg (S_irwxu >> 3)//shift left three bit to 0070#define s_iroth (s_irgrp >> 3) / /On the basis of 0040 again to shift left three bits, into 0004#define s_iwoth (s_iwgrp >> 3) //0002#define s_ixoth (s_ IXGRP >> 3) //0001/* Read, write, and execute by others. * /#define S_IRWXO (s_irwxg >> 3)//0007
From the above calculation, you can find that the value of the permission bit is exactly the same as the value used in the "chmod" command, using the "|" Between different permissions Computation, there is no problem with it.
Let's take a look at the calculation performed by closing a flag bit, as shown in the example above, to turn off a permission bit using the "reverse first, then proceed with the operation". or combined with the above code to see, "S_IXGRP" The value of "0010" Programming 2 is "000001000" (the first 0 does not participate in the operation), at this time represents only "group execution" permission to open, reverse to "111110111", only "group execution" bit off, At this point, the "group execution" bit must be closed, while the other permission bits remain unchanged, thus enabling the ability to turn off the "group execution" bit.
Apue Reading Notes-fourth chapter documents and catalogues