Add Book to My BookshelfPurchase This Book Online

Chapter 5 - Files and Directories

UNIX Systems Programming for SVR4
David A. Curry
 Copyright © 1996 O'Reilly & Associates, Inc.

Changing File Attributes
Most of a file's attributes can be changed, and this is something that systems programs do quite often. This section describes how to change each of the following attributes: permissions, owner, group, size, access time, and modification time. In the next section, you will learn how to change one other attribute, the number of links.
Changing a File's Permission Bits
Each file or directory has three sets of permissions associated with it; one set for the user who owns the file, one set for the users in the group with which the file is associated (the group owner of the file), and one set for all other users (the world permissions). Each set of permissions contains three identical permission bits that control the following:
read
If set, the file or directory can be read. In the case of a directory, read permission allows a user to see the contents of the directory (the names of the files it contains), but not to access them.
write
If set, the file or directory can be written (modified). In the case of a directory, write permission implies the ability to create, delete, and rename files. Note that the ability to delete a file is not controlled by the file's permission bits, but rather by the permission bits on the directory containing the file.
execute
If set, the file or directory can be executed (searched). In the case of a file, execute permission implies the ability to run the program contained in that file. Executing compiled (binary) programs requires only execute permission on the file, while executing shell scripts requires both read and execute permission, because the shell must be able to read commands from the file. In the case of a directory, execute permission implies permission to search the directory; that is, permission to access the files contained therein. Note that access to files is not controlled by read permission on the directory (read permission controls whether the files are visible, not accessible).
In addition, there is a fourth set of three bits that indicate special features associated with the file:
set-user-id
If set, this bit controls the set user ID status of a file. Set user ID status means that when a program is executed, it executes with the permissions of the user who owns the program, in addition to the permissions of the user running the program. For example, the sendmail command is usually set user ID root, because it has to be able to write in the mail spool directory, which ordinary users are not allowed to do. This bit is meaningless on non-executable files and on directories.
set-group-id
If set on an executable file, this bit controls the set group ID status of a file. This behaves in exactly the same way as the set-user-id bit, except that the program operates with the permissions of the group associated with the file. On directories, it controls how the group associated with a file is determined. If set, the group associated with a newly created file is the same as the group associated with the directory. If not set, the group associated with a newly created file is the user's primary group ID. If this bit is set on a file and the group execute bit is not set on that file, then manadatory file and record locks are enabled on that file (see Chapter 6, Special File Operations).
sticky
If set, the sticky bit originally told the operating system to keep the text segment of an executable file on the swap disk, so that the program could start more quickly. This use has been mostly discarded now that UNIX is a paging system instead of a swapping system. Now, the sticky bit is used on directories. If a directory is writable and has the sticky bit set, files in that directory can be removed or renamed only if one or more of the following conditions are true:
 The user owns the file he is trying to rename or remove.
 The user owns the directory itself.
 The file is writable by the user (this condition is not checked by all versions of UNIX).
 The user is the superuser.
SunOS 4.x and Solaris 2.x also use the sticky bit on files that are used for swapping, to disable some filesystem cache operations.
When specifying file permissions, octal numbers are usually used, because each octal digit corresponds to three bits. Table 5-1 shows the numbers that correspond to the various permissions.
Table 5-1:  File Permission Bits
Permission
Owner
Group
Others
Permission
Value
read
0400
040
04
set-user-id
04000
write
0200
020
02
set-group-id
02000
execute
0100
010
01
sticky
01000
none
0000
000
00
none
00000
To determine the value to use for a specific set of permissions, you can just add these values together. For example, to create the value that grants the owner read, write, and execute permission; the group read and execute permission; and no permissions for all others, you use:
    mode = 0400 + 0200 + 0100 + 040 + 010 + 0
    mode = 0700 + 050 + 0
    mode = 0750
The following two functions change the mode of a file:
    #include <sys/types.h>
    #include <sys/stat.h>
    int chmod(const char *path, mode_t mode);
    int fchmod(int fd, mode_t mode);
The chmod function changes the permission bits on the file named in path to the bits contained in mode; the fchmod function changes the permission bits on the file referred to by the open file descriptor fd. The values for mode are chosen as described previously. Note that although the chmod command accepts a number without a leading zero and interprets it as octal, the leading zero must always be used in C programs to tell the compiler that the number is octal and not decimal. Only the owner of a file or the superuser can change its permissions. Upon success, chmod and fchmod return 0. If an error occurs, they return -1 and place an error code in the external variable errno.
Changing a File's Ownership
Sometimes, it is necessary for a system program to change the ownership of a file. This is often the case when a program running as the superuser creates files; it must change the ownership of those files so that regular users can access them. There are three functions provided for changing the ownership of a file:
    #include <sys/types.h>
    #include <unistd.h>
    int chown(const char *path, uid_t owner, gid_t group);
    int lchown(const char *path, uid_t owner, gid_t group);
    int fchown(int fd, uid_t owner, gid_t group);
The chown function changes the user ID of the file specified by path to the one contained in owner, and the group ID of the file to the one contained in group; the fchown function performs the same changes, but on the file referred to by the open file descriptor fd. The lchown function is exactly like chown, except when path refers to a symbolic link. In this case, lchown changes the user ID and group ID of the link itself, while chown changes the user ID and group ID of the file to which the link points. If either owner or group are given as -1, then the corresponding user ID or group ID is not changed. All three functions return 0 if the changes succeed; if the changes fail, -1 is returned and the reason for failure is stored in the external variable errno.
If chown, lchown, or fchown are invoked by a process that is not operating with superuser permissions, then the set-user-id and set-group-id bits on the file are cleared.
On POSIX systems such as SVR4, there are two different ways in which these functions can be used, based on a system configuration option called _POSIX_CHOWN_RESTRICTED. If this option is not in effect, then the process calling these functions must either have the same effective user ID as the owner of the file or be operating with superuser permissions, to be allowed to change the ownership of the file. It can change the owner and group of the file to any value. In effect, this allows a user to give away her files to any other user. Most System V systems behave in this way. If the _POSIX_CHOWN_RESTRICTED option is in effect, then only the superuser can change the owner of a file. A process that is not running with superuser permissions can only change the group of a file to one of the groups of which that process is a member. This is the way most BSD systems behave; the original reason for this restriction was to make disk quotas possible.
The methods used to obtain the values for owner and group are discussed in Chapter 8, Users and Groups.
Changing a File's Size
Sometimes it is desirable to set a file's length to a specified size. There are two functions available to do this:
    #include <unistd.h>
    int truncate(const char *path, off_t length);
    int ftruncate(int fd, off_t length);
The truncate function sets the size of the file named in path to length bytes, while ftruncate sets the size of the file referred to by the open file descriptor fd. If the file is longer than length bytes, the excess data is discarded. If the file is shorter than length bytes, it is padded on the end with zero bytes. The process must have write permission on the file (and fd must be open for writing) for these functions to succeed. If they succeed, 0 is returned; if an error occurs, -1 is returned and the reason for failure is stored in the external variable errno.
Changing a File's Access and Modification Times
It is also sometimes necessary to change the access and modification times for a file; for example, the tar program does this to preserve the original access and modification times on files extracted from the archive. There are two functions available to do this:
    #include <sys/types.h>
    #include <utime.h>
    int utime(const char *path, const struct utimbuf *times);
    #include <sys/types.h>
    #include <sys/time.h>
    int utimes(const char *path, const struct timeval *tvp);
The two functions are identical except in the format of their second argument. The utime function is derived from System V versions of UNIX, while utimes is derived from BSD UNIX. SVR4 provides both of them, but Hewlett-Packard has removed utimes from HP-UX 10.x.
Both functions change the access and modification times on the file named by path to the times contained in their second argument. The second argument to utime is a pointer to type struct utimbuf:
    struct utimbuf {
        time_t    actime;
        time_t    modtime;
    };
The actime element of the structure contains the desired new access time in UNIX time format, and modtime contains the desired new modification time. The second argument to utimes is a pointer to an array of two objects of type struct timeval:
    struct timeval {
        long    tv_sec;
        long    tv_usec;
    };
The tv_sec element of the structure contains the desired new time in UNIX time format (the tv_usec element is ignored); the first structure contains the access time, the second contains the modification time. UNIX time format is described in Chapter 7, Time of Day Operations.
In order to change the times on a file, the process must either own the file or be executing with superuser permissions. If the change succeeds, 0 is returned. If it fails, -1 is returned and the reason for failure is stored in the external variable errno. Whenever the access and modification times of a file are changed, the file's inode change time is updated.

Previous SectionNext Section
Books24x7.com, Inc © 2000 –  Feedback