NEXT UP previous
Next: File Hierarchy

Changing File Attributes

Out of all of the information you can collect about a file there is only a relatively small amount of it that you can change. This section looks at most of the things over which you have this control.

chmod and fchmod System Calls

The first thing to look at is the file permission bits. The system calls used to change them are called chmod() and fchmod(). The bits that can be changed by these system calls are exactly the same as those which can be changed by the chmod command. This includes the read, write and execute bits for the owner, group and world user classes. It also includes the setuid bit and the setgid bit. The prototypes for chmod() and fchmod() are:

	#include <sys/types.h>
	#include <sys/stat.h>

	int chmod(char *pathname, mode_t mode); 
	int fchmod(int fd, mode_t mode);

The chmod() call changes the mode bits of the file at the given pathname, while fchmod() changes the mode bits of the file associated with the file descriptor fd.

Notice that the mode parameter has the POSIX data type mode_t and so to be properly portable you should use the symbolic bit mask names for the mode bits from <sys/stat.h> and not the octal number versions. Linux, however, will accept either so that the following two fchmod() system calls perform exactly the same function:

	fchmod(fd, S_ISUID | S_IRWXU | S_IXGRP | S_IXDTH);

	fchmod(fd, 04711);

Both of these system calls return the value 0 if they complete successfully, or -1 on error, with an appropriate error value in errno.

umask System Call

Don't forget when you change the mode bits on a file, that the bits you specify will automatically be modified by the current umask value according to the formula:

	mode & (~umask)

The functionality of the umask command which you have seen previously, is provided at the system programming level by a umask() system call:

	#include <unistd.h>

	mode_t umask(mode_t mask);

The mask parameter is specified using the same set of symbolic bit mask names as chmod().

The return value from umask() is the current value of the umask that your new mask parameter replaces. This allows you to discover the current umask value as follows:

	oldmask = umask(O); 
	(void)umask(oldmask);

The second call to umask() is required to restore the umask value that was discovered.

chown and fchown System Calls

The chown() and fchown() system calls are used to change a file's owner ID or its group ID. The prototype for these calls is:

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

	int chown(char *pathname  uid_t owner, gid_t group); 
	int fchown(int fd, uid_t owner, gid_t group);

The chown() and fchown() system calls assign the new owner and gvoup IDs to a file specified by pathname or file descriptor fd respectively.

Under Linux, only root can make sensible use of the chown() and fchown() system calls.

fcntl System Call

Another thing which can be examined and changed are the flags which were set up for the file by the second parameter to the open() call. The system call to do this is called fcntl(). Obviously, since it is working with the flags set up when the file was opened, fcntl() only has a version that works on a file descriptor, and not one that works from a pathname. The prototype for fcntl() is:

	#include <unistd.h>
	#include <fcntl.h>

	int fcntl(int fd, int cmd);
	int fcntl(int fd, int cmd, long setval);

There is a whole collection of miscellaneous file control facilities which can be provided by the fcntl() call on a file, via the file descriptor fd. Here we shall look at only two of them (we will come back to look at others in later tutorials).

The fcntl() call takes two or three parameters depending on the value of the command (cmd) parameter. In general, commands which get the value of some attribute or flag use the two-parameter version of fcntl() and supply the required value as its return value. Similarly, commands that set the value of some attribute or flag typically use the three-parameter version of fcntl() and set the attribute or flag from the setval parameter.

The two commands required for getting and setting some of the open() flags are:

	F_GETFL return flags and access mode associated with fd; 
	F_SETFL set flags associated with fd.

The F_GETFL command can return any of the flags and access mode values set by open() (such as O_RDONLY, O_WRONLY, O_APPEND, etc.), but the F_SETFL command can only set or reset the O_APPEND and O_NONBLOCK flags.

As the access mode values returned by the O_GETFL command are not single-bit flags, the safest way to test if a particular mode value is set is to use a test of the following form (testing for O_RDONLY in this example):

	if ((fcntl(fd, F_GETFL) & O_ACCMODE) == O_RDONLY)     /* code if fd is open read only */

where O_ACCMODE is specifically designed to mask out the access mode bits from the fcntl() return value.

truncate and ftruncate System Calls

The final system calls in this section can be used to truncate a file to a specified length given either a pathname to the file or a file descriptor associated with the file:

	#include <unistd.h>

	int trumcate(char *pathname, size_t len); 
	int ftruncate(int fd, size_t len);

If the file referred to in these calls is longer than len bytes in length, then it will be truncated to the specified size and the extra bytes will be lost.

In order for ftruncate() to operate successfully fd must be associated with an open file description that is open for writing (i.e either O_WRONLY or O_RDWR).


NEXT UP previous
Next: File Hierarchy