Chapter 4. Files and Directories
4.2 stat, fstat, and lstat Functions
#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
Returns: All three return: 0 if OK, -1 on error.
Given a pathname, the stat function returns a structure of information about the named file. The fstat function obtains information about the file that is already open on the descriptor filedes. The lstat function is similar to stat, but when the named file is a symbolic link, lstat returns information about the symbolic link, not the file referenced by the symbolic link.
The second argument is a pointer to a structure that we must supply. The function fills in the structure pointed to by buf.
The biggest user of the stat functions is probably the ls –l command, to learn all the information about a file.
4.3 File Types
Most files on a UNIX system are either regular files or directories, but there are additional types of files. The types are:
1. Regular file. S_ISREG()
2. Directory file. S_ISDIR()
3. Block special file. S_ISBLK()
4. Character special file. S_ISCHR()
5. FIFO. S_ISFIFO()
6. Socket. S_ISSOCK()
7. Symbolic link. S_ISLNK()
The type of a file is encoded in the st_mode member of the stat structure.
4.4 Set-User-ID and Set-Group-ID
User IDs and group IDs associated with each process
real user ID
real group ID
:who we really are
effective user ID
effective group ID
supplementary group IDs
:used for file access permission checks
saved set-user-ID
saved set-group-ID
:saved by exec functions
Every file has an owner and a group owner. The owner is specified by the st_uid member of the stat structure; the group owner, by the st_gid member.
4.5 File Access Permissions
The st_mode value also encodes the access permission bits for the file.
The nine file access permission bits, from <sys/stat.h>
st_mode mask Meaning
S_IRUSR user-read
S_IWUSR user-write
S_IXUSR user-execute
S_IRGRP group-read
S_IWGRP group-write
S_IXGRP group-execute
S_IROTH other-read
S_IWOTH other-write
S_IXOTH other-execute
The first rule is that whenever we want to open any type of file by name, we must have execute permission in each directory mentioned in the name, including the current directory, if it is implied. This is why the execute permission bit for a directory is often called the search bit.
We cannot create a new file in a directory unless we have write permission and execute permission in the directory.
To delete an existing file, we need write permission and execute permission in the directory containing the file. We do not need read permission for the file itself.
The file access tests performed by the kernel are as follows:
1. If the effective user ID of the process is 0, access is allowed.
2. If the effective user ID of the process equals the owner ID of the file, access is allowed if the appropriate user access permission bit is set. Otherwise, permission is denied.
3. If the effective group ID of the process or one of the supplementary group IDs of the process equals the group ID of the file, access is allowed if the appropriate group access permission bit is set. Otherwise, permission is denied.
4. If the appropriate other access permission bit is set, access is allowed. Otherwise, permission is denied.
These four steps are tried in sequence.
4.6 Ownership of New Files and Directories
The user ID of a new file is set to the effective user ID of the process. POSIX.1 allows an implementation to choose one of the following options to determine the group ID of a new file./
1. The group ID of a new file can be the effective group ID of the process.
2. The group ID of a new file can be the group ID of the directory in which the file is being created.
4.7 access Function
The access function bases its tests on the real user and group IDs.
#include <unistd.h>
int access(const char *pathname, int mode);
Returns: 0 if OK, -1 on error.
The mode:
mode Description
R_OK test for read permission
W_OK test for write permission
X_OK test for execute permission
F_OK test for existence of file
4.8 umask Function
The umask function sets the file mode creation mask for the process and returns the previous value.
#include <sys/stat.h>
mode_t umask(mode_t cmask);
Returns: previous file mode creation mask
The cmask argument is formed as the bitwise OR of the nine constant from: S_IRUSR, S_IWUSR, and so on.
The file node creation mask is used whenever the process creates a new file or a new directory. We describe how to create a new directory. Any bits that are on in the file mode creation mask are turned off in the file’s mode.
4.9 chmod and fchmod Functions
These two functions allow us to change the file access permission for an existing file.
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);
Both return: o if OK, -1 on error.
The chmod function operates on the specified file, whereas the fchmod function operates on a file that has already been opened.
To change the permission bits of a file, the effective user ID of the process must be equal to the owner ID of the file, or the process must have superuser permission.
4.10 Sticky Bit
On contemporary systems, the use of the sticky bit has been extended. The Single UNIX Specification allows the sticky bit to be set for a directory. If the bit is set for a directory, a file in the directory can be removed or renamed only if the user has write permission for the directory and one of the following:
Owns the file
Owns the directory
Is the superuser
4.11 chown, fchown, and lchown Functions
The chown functions allow us to change the user ID of a file and the group ID of a file.
#include <unistd.h>
int chown(const char *pathname, uis_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
All three return: 0 if OK, - 1on error.
These three functions operate similarly unless the referenced file is a symbolic link. In that case, lchown changes the owners of the symbolic link itself, not the file pointed to by the symbolic link.
If either of the arguments owner or group is -1, the corresponding ID is left unchanged.
When _POSIX_CHOWN_RESTRICTED is in effect, you can’t change the user ID of other users’ files. You can change the group ID of files that you own, but only to groups that you belong to.
4.12 File Size
The st_size member of the stat structure contains the size of the file in bytes. This is meaningful only for regular files, directories, and symbolic links.
Holes in a File
Holes are created by seeking past the current end of file and writing some data.
4.13 File Truncation
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);
Both return: 0 if OK, -1 on error.
These two functions truncate an existing file to length bytes.
If the previous size was led than length, the effect is system dependent.
4.14 File Systems
Disk drive, partitions, and a file system
The i-nodes are fixed-length entries that contain most of the information about a file.
//img
Cylinder group’s i-nodes and data blocks in more detail
//img
More Info: http://blog.youkuaiyun.com/wanpengcoder/archive/2010/12/08/6063076.aspx
4.15 link, unlink, remove, and rename Functions
The way we create a link to an existing file is with the link function.
#include <unistd.h>
int link(const char *existingpath, const char *newpath);
Returns: 0 if OK, -1 on error.
The creation of the new directory entry and the increment of the link count must be atomic operation.
To remove an existing directory entry, we call the unlink function.
#include <unistd.h>
int unlink(const char *pathname);
Returns: 0 if OK, -1 on error.
We’ve mentioned before that to unlink a file, we must have write permission and execute permission in the directory containing the directory entry, as it is the directory entry that we will be removing. If the sticky bit is set in this directory we must have write permission for the directory and one of the following:
Own the file.
Own the directory.
Have superuser privileges.
Only when the link count reaches 0 can the contents of file be deleted.
The process creates a file using either open or creat and then immediately calls unlink. The file is not deleted, however, because it is still open.
If pathname is a symbolic link, unlink removes the symbolic link, not the file referenced by the link. There is no function to remove the file referenced by a symbolic link given the name of the link.
We can also unlink a file or a directory with the remove function. For a file, remove is identical to unlink. For a directory, remove is identical to rmdir.
#include <stdio.h>
int remove(const char *pathname);
Returns: 0 if OK, -1 on error.
A file or a directory id renamed with the rename function.
#include <stdio.h>
int rename(const char *oldname, const char *newname);
Returns: 0 if OK, -1 on error.
If newname already exists, we need permissions as if we were deleting it. Also, because we’re removing the directory entry for oldname and possibly creating a directory entry for newname, we need write permission and execute permission in the directory containing oldname and in the directory containing newname.
4.16 Symbolic Links
Symbolic links were introduced to get around the limitations of hard links.
Hard links normally require that the link and the file reside in the same file system
Only the superuser can create a hard link to a directory.
There are no file system limitations on a symbolic link and what it points to, and anyone can create a symbolic link to a directory.
//img
4.17 symlink and readlink Functions
A symbolic link is created with the symlink function.
#include <unistd.h>
int symlink(const char *actualpath, const char *sympath);
Returns: 0 if OK, -1 on error.
Because the open function follows a symbolic link, we need a way to open the link itself and read the name in the link. The readlink function does this.
#include <unistd.h>
ssize_t readlink(const char *restrict pathname, char *restrict buf, size_t bufsize);
Returns: number of bytes read if OK, -1 on error.
4.18 File Times
//img
Note the different between the modification time and the changed-status time. The modification time is when the contents of the file were last modified. The changed-status time is when the i-node of the file was last modified.
4.19 utime Function
The access time and the modification time of a file can be changed with the utime function.
#include <utime.h>
int utime(const char *pathname, const struct utimbuf *times);
Returns: 0 if OK, -1 on error.
struct utimbuf{
time_t actime;
time_t modtime;
};
The operation of this function, and the privileges required to execute it, depend on whether the times argument is NULL.
If times is a null pointer, the access time and modification time are both set to the current time.
If times is a non-null pointer, the access time and the modification time are set to the values in the structure pointed to by times.
Note that we are unable to specify a value for the changed-status time, st_ctime the time the i-node was last changed as this field automatically updated when the utime function is called.
4.20 mkdir and rmdir Functions
Directories are created with the mkdir function and deleted with the rmdir function.
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
Returns: 0 if OK, -1 on error.
A common mistake is to specify the same mode as for a file: read and write permissions only. But for a directory, we normally want at least one of the execute bits enabled, to allow access to filenames within the directory.
An empty directory is deleted with the rmdir function.
#include <unistd.h>
int rmdir(const char *pathnem);
Returns: 0 if OK, -1 on error.
4.21 Reading Directories
Directoried can be read by anyone who has access permission to read the directory. But only the kernel can write to a directory, to preserve file system sanity.
#include <dirent.h>
DIR *opendir(const char *pathname);
Returns: pointer if OK, NULL on error.
struct dirent *readdir(DIR *dp);
Returns: pointer if OK, NULL at end of directory or error.
void rewinddir(DIR *dp);
int closedir(DIR *dp);
Returns: 0 if OK, -1 on error.
long telldir(DIR *dp);
Returns: current location in directory associated with dp
void seekdir(DIR *dp, long loc);
dirent structure:
struct dirent{
ino_t d_ino; /* i-node number */
char d_name[NAME_MAX + 1]; /* null-terminated filename */
};
The pointer to a DIR structure that is returned by opendir is then used with the other five functions. The opendir function initializes things so that the first readdir reads the first entry in the directory. The ordering of entries within the directory is implementation dependent and is usually not alphabetical.
4.22 chdir, fchdir, and getcwd Functions
The current working directory is an attribute of a process; the home directory is an attribute of a login name.
We can change the current working directory of the calling process by calling the chdir or fchdir functions.
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
Both return: 0 if OK, -1 on error.
Get absolute pathname of the current working directory.
#include <unistd.h>
char *getcwd(char *buf, size_t size);
Returns: buf if OK, NULL on error.
4.23 Device Special Files
Every file system is known by its major and minor device numbers, which are encoded in the primitive system data type dev_t.
We can usually access the major and minor device numbers through two macros defined by most implementations: major and minor.
The st_dev value for every filename on a system is the device number of the file system containing that filename and its corresponding i-node.
Only character special files and block special files have an st_rdev value.
4.24 Summary of File Access Permission Bits
//img