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


on screen.                                               */
if (stat("foo.txt", &file_status) == 0) {
    if (S_ISDIR(file_status.st_mode))
        printf("foo.txt is a directory\n");
    if (S_ISLNK(file_status.st_mode))
        printf("foo.txt is a symbolic link\n");
    if (S_ISCHR(file_status.st_mode))
        printf("foo.txt is a character special file\n");
    if (S_ISBLK(file_status.st_mode))
        printf("foo.txt is a block special file\n");
    if (S_ISFIFO(file_status.st_mode))
        printf("foo.txt is a FIFO (named pipe)\n");
    if (S_ISSOCK(file_status.st_mode))
        printf("foo.txt is a (Unix domain) socket file\n");
    if (S_ISREG(file_status.st_mode))
        printf("foo.txt is a normal file\n");
}
else { /* stat() call failed and returned '-1'. */
    perror("stat");
}

/* add the write permission to the group owner of file "/tmp/parlevouz", */
/* without overriding any of the previous access permission flags.       */
if (stat("/tmp/parlevouz", &file_status) == -1) {
    perror("stat");
    exit(1);
}
if (!S_IWGRP(file_status.st_mode)) { /* the group has no write permission */
    umode_t curr_mode = file_status.st_mode & ~S_IFMT
    umode_t new_mode = curr_mode | S_IWGRP;

    if (chmod("/tmp/parlevouz", new_mode) == -1) {
        perror("chmod");
        exit(1);
    }
}



The last item should be explained better. For some reason, the 'stat' structure uses the same bit field to contain file type information and access permission flags. Thus, to get only the access permissions, we need to mask off the file type bits. The mask for the file type bits is 'S_IFMT', and thus the mask for the permission modes is its logical negation, or '~S_IFMT'. By logically "and"-ing this value with the 'st_mode' field of the 'stat' structure, we get the current access permission modes. We can add new modes using the logical or ('|') operator, and remove modes using the logical and ('&') operator. After we create the new modes, we use chmod() to set the new permission flags for the file.
Note that this operation will also implicitly modify the 'ctime' (change time) of the file, but that won't be reflected in our 'stat' structure, unless we stat() the file again.




Renaming A File
The rename() system call may be used to change the name (and possibly the directory) of an existing file. It gets two parameters: the path to the old location of the file (including the file name), and a path to the new location of the file (including the new file name). If the new name points to a an already existing file, that file is deleted first. We are allowed to name either a file or a directory. Here are a few examples:


/* rename the file 'logme' to 'logme.1' */
if (rename("logme", "logme1") == -1) {
    perror("rename (1):");
    exit(1);
}

/* move the file 'data' from the current directory to directory "/old/info" */
if (rename("data", "/old/info/data") == -1) {
    perror("rename (2):");
    exit(1);
}


Note: If the file we are renaming is a symbolic link, then the symbolic link will be renamed, not the file it is pointing to. Also, if the new path points to an existing symbolic link, this symbolic link will be erased, not the file it is pointing to.




Deleting A File
Deleting a file is done using the unlink() system call. This one is very simple:

/* remove the file "/tmp/data" */
if (unlink("/tmp/data") == -1) {
    perror("unlink");
    exit(1);
}


The file will be removed from the directory in which it resides, and all the disk blocks is occupied will be marked as free for re-use by the system. However, if any process currently has this file open, the file won't be actually erased until the last process holding it open erases it. This could explain why often erasing a log file from the system does not increase the amount of free disk space - it might be that the system logger process (syslogd) holds this file open, and thus the system won't really erase it until syslogd closes it. Until then, it will be removed from the directory (i.e. 'ls' won't show it), but not from the disk.




Creating A Symbolic Link
We have encountered symbolic links earlier. lets see how to create them, with the symlink() system call:



/* create a symbolic link named "link" in the current directory, */
/* that points to the file "/usr/local/data/datafile".           */
if (symlink("/usr/local/data/datafile", "link") == -1) {
    perror("symlink");
    exit(1);
}

/* create a symbolic link whose full path is "/var/adm/log",     */
/* that points to the file "/usr/adm/log".                       */
if (symlink("/usr/adm/log", "/var/adm/log") == -1) {
    perror("symlink");
    exit(1);
}


So the first parameter is the file being pointer to, and the second parameter is the file that will be the symbolic link. Note that the first file does not need to exist at all - we can create a symbolic link that points nowhere. If we later create the file this link points to, accessing the file via the symbolic link will work properly.





The Mysterious Mode Mask
If you created files with open() or fopen(), and you did not supply the mode for the newly created file, you might wonder how does the system assign access permission flags for the newly created file. You will also note that these "default" flags are different on different computers or different account setups. This mysteriousness is due to the usage of the umask() system call, or its equivalent umask shell command.

The umask() system call sets a mask for the permission flags the system will assign to newly created files. By default, newly created files will have read and write permissions to everyone (i.e. rw-rw-rw- , in the format reported by 'ls -l'). Using umask(), we can denote which flags will be turned off for newly created files. For example, if we set the mask to 077 (a leading 0 denotes an octal value), newly created files will get access permission flags of 0600 (i.e. rw-------). If we set the mask to 027, newly created files will get flags of 0640 (i.e. rw-r-----). Try translating these values to binary format in order to see what is going on here.

Here is how to mess with the umask() system call in a program:

/* set the file permissions mask to '077'. save the original mask */
/* in 'old_mask'.                                                 */
int old_mask = umask(077);

/* newly created files will now be readable only by the creating user. */
FILE* f_write = fopen("my_file", "w");
if (f_write) {
    fprintf(f_write, "My name is pit stanman.\n");
    fprintf(f_write, "My voice is my pass code. Verify me.\n");
    fclose(f_write);
}

/* restore the original umask. */
umask(old_mask);



Note: the permissions mask affects also calls to open() that specify an exact permissions mask. If we want to create a file whose permission are less restrictive the the current mask, we need to use umaks() to lighten these restrictions, before calling open() to create the file.

Note 2: on most systems you will find that the mask is different then the default. This is because the system administrator has set the default mask in the system-wide shell startup files, using the shell's umask command. You may set a different default mask for your own account by placing a proper umask command in your shell's starup file ("~/.profile" if you're using "sh" or "bash". "~/.cshrc" if you are using "csh" or "tcsh").




A Complete Example
As an example to the usage of the system calls interface for manipulating files, we will show a program that handles simple log file rotation. The program gets one argument - the name of a log file, and assumes it resides in a given directory ("/tmp/var/log"). If the size of the log file is more then 1024KB, it renames it to have a ".old" suffix, and creates a new (empty) log file with the same name as the original file, and the same access permissions. This

Page : << Previous 5  Next >>