Topic : Files and Folders
Author : LUPG
Page : << Previous 4  Next >>
Go to page :


last update time, we can use fdatasync() instead. This is more efficient, as it will issue one fewer disk write operation. In applications that need to synchronize data often, this small saving is important.




Seeking In An Open File
Just like we used the fseek() function to move the read/write pointer of the file stream, we can use the lseek() system call to move the read/write pointer for a file descriptor. Assuming you understood the fseek() examples above, here are a few similar examples using lseek(). We assume that 'fd_read' is an integer variable containing a file descriptor to a previously opened file, in read only mode. 'fd_readwrite' is a similar file descriptor, but for a file opened in read/write mode.

/* this variable is used for storing locations returned by       */
/* lseek().                                                      */
off_t location;

/* move the read/write pointer of the file to position '40'      */
/* in the file. Note that the first position in the file is '0', */
/* not '1'.                                                      */
location = lseek(fd_read, 39L, SEEK_START);

/* move the read/write pointer of the file stream 67 characters  */
/* forward from its given location.                              */
location = lseek(fd_read, 67L, SEEK_SET);
printf("read/write pointer location: %ld\n", location);

/* remember the current read/write pointer's position, move it   */
/* to location '664' in the file, write the string "hello world",*/
/* and move the pointer back to the previous location.           */
location = lseek(fd_readwrite, 0L, SEEK_SET);
if (location == -1) {
    perror("lseek");
    exit(0);
}
if (lseek(fd_readwrite, 663L, SEEK_SET) == -1) {
    perror("lseek(fd_readwrite, 663L, SEEK_SET)");
    exit(0);
}
rc = write(fd_readwrite, "hello world\n", strlen("hello world\n"));
if (lseek(fd_readwrite, location, SEEK_SET) == -1) {
    perror("lseek(fd_readwrite, location, SEEK_SET)");
    exit(0);
}


Note that lseek() might not always work for a file descriptor (e.g. if this file descriptor represents the standard input, surely we cannot have random-access to it). You will encounter other similar cases when you deal with network programming and inter-process communications, in the future.




Checking And Setting A File's permission modes
Since Unix supports access permissions for files, we would sometimes need to check these permissions, and perhaps also manipulate them. Two system calls are used in this context, access() and chmod().

The access() system call is for checking access permissions to a file. This system call accepts a path to a file (full or relative), and a mode mask (made of one or more permission modes). It returns '0' if the specified permission modes are granted for the calling process, or '-1' if any of these modes are not granted, the file does not exist, etc. The access is granted or denied based on the permission flags of the file, and the ID of the user running the process. Here are a few examples:

/* check if we have read permission to "/home/choo/my_names".       */
if (access("/home/choo/my_names", R_OK) == 0)
    printf("Read access to file '/home/choo/my_names' granted.\n");
else
    printf("Read access to file '/home/choo/my_names' denied.\n");

/* check if we have both read and write permission to "data.db".     */
if (access("data.db", R_OK | W_OK) == 0)
    printf("Read/Write access to file 'data.db' granted.\n");
else
    printf("Either read or write access to file 'data.db' is denied.\n");

/* check if we may execute the program file "runme".                 */
if (access("runme", X_OK) == 0)
    printf("Execute permission to program 'runme' granted.\n");
else
    printf("Execute permission to program 'runme' denied.\n");

/* check if we may write new files to directory "/etc/config".       */
if (access("/etc/config", W_OK) == 0)
    printf("File creation permission to directory '/etc/sysconfig' granted.\n");
else
    printf("File creation permission to directory '/etc/sysconfig' denied.\n");

/* check if we may read the contents of directory "/etc/config".     */
if (access("/etc/config", R_OK) == 0)
    printf("File listing read permission to directory '/etc/sysconfig' granted.\n");
else
    printf("File listing read permission to directory '/etc/sysconfig' denied.\n");

/* check if the file "hello.world" in the current directory exists. */
if (access("hello world", F_OK) == 0)
    printf("file 'hello world' exists.\n");
else
    printf("file 'hello world' does not exist.\n");


As you can see, we can check for read, write and execute permissions, as well as for the existence of a file, and the same for a directory. As an example, we will see a program that checks out if we have read permission to a file, and notifies us if not - where the problem lies. The full source code for this program is found in file read-access-check.c.

Note that we cannot use access() to check why we got permissions (i.e. if it was due to the given mode granted to us as the owner of the file, or due to its group permissions or its word permissions). For more fine-grained permission tests, see the stat() system call mentioned below.

The chmod() system call is used for changing the access permissions for a file (or a directory). This call accepts two parameters: a path to a file, and a mode to set. The mode can be a combination of read, write and execute permissions for the user, group or others. It may also contain few special flags, such as the set-user-ID flag or the 'sticky' flag. These permissions will completely override the current permissions of the file. See the stat() system call below to see how to make modifications instead of complete replacement. Here are a few examples of using chmod().


/* give the owner read and write permission to the file "blabla", */
/* and deny access to any other user.                             */
if (chmod("blabla", S_IRUSR | S_IWUSR) == -1) {
    perror("chmod");
}

/* give the owner read and write permission to the file "blabla", */
/* and read-only permission to anyone else.                       */
if (chmod("blabla", S_IRUSR | S_IWUSR | S_IRGRP | S_IWOTH) == -1) {
    perror("chmod");
}



For the full list of access permission flags to use with chmod(), please refer to its manual page.




Checking A File's Status
We have seen how to manipulate the file's data (write) and its permission flags (chmod). We saw a primitive way of checking if we may access it (access), but we often need more then that: what are the exact set of permission flags of the file? when was it last changed? which user and group owns the file? how large is the file?
All these questions (and more) are answered by the stat() system call.

stat() takes as arguments the full path to the file, and a pointer to a (how surprising) 'stat' structure. When stat() returns, it populates this structure with a lot of interesting (and boring) stuff about the file. Here are few of the fields found in this structure (for the rest, read the manual page):

umode_t st_mode
Access permission flags of the file, as well as information about the type of file (file? directory? symbolic link? etc).
uid_t st_uid
The ID of the user that owns the file.
gid_t st_gid
The ID of the group that owns the file.
off_t st_size
The size of the file (in bytes).
time_t st_atime
Time when the file was last accessed (read from or written to). Time is given as number of seconds since 1 Jan, 1970.
time_t st_mtime
Time when the file was last modified (created or written to).
time_t st_ctime
Time when the file was last changed (had its permission modes changed, or any of its book-keeping, but NOT a contents change).
Here are a few examples of how stat() can be used:


/* structure passed to the stat() system call, to get its results. */
struct stat file_status;

/* check the status information of file "foo.txt", and print its */
/* type


Page : << Previous 4  Next >>