Module 2: Unix Files and Api 'S: File Types
Module 2: Unix Files and Api 'S: File Types
Files are the building blocks of any operating system. When you execute a command in UNIX, the UNIX kernel fetches the
corresponding executable file from a file system, loads its instruction text to memory, and creates a process to execute the
command on your behalf. In the course of execution, a process may read from or write to files. All these operations involve files.
Thus, the design of an operating system always begins with an efficient file management system.
File Types
A file in a UNIX or POSIX system may be one of the following types:
regular file
directory file
FIFO file
Character device file
Block device file
Regular file
A regular file may be either a text file or a binary file
These files may be read or written to by users with the appropriate access permission
Regular files may be created, browsed through and modified by various means such as text editors or compilers,
and they can be removed by specific system commands
Directory file
It is like a folder that contains other files, including sub-directory files.
It provides a means for users to organise their files into some hierarchical structure based on file relationship or
uses.
Ex: /bin directory contains all system executable programs, such as cat, rm, sort
A directory may be created in UNIX by the mkdir command
o Ex: mkdir /usr/foo/xyz
A directory may be removed via the rmdir command
o Ex: rmdir /usr/foo/xyz
The content of directory may be displayed by the ls command
Device file
Block device file Character device file
It represents a physical device that transmits data a It represents a physical device that transmits data in a
block at a time. character-based manner.
Ex: hard disk drives and floppy disk drives Ex: line printers, modems, and consoles
A physical device may have both block and character device files representing it for different access methods.
An application program may perform read and write operations on a device file and the OS will automatically
invoke an appropriate device driver function to perform the actual data transfer between the physical device and
the application
An application program in turn may choose to transfer data by either a character-based(via character device file) or
block-based(via block device file)
A device file is created in UNIX via the mknod command
o Ex: mknod /dev/cdsk c 115 5
Page 1
UNIX SYSTEM PROGRAMMING NOTES
o For block device file, use argument ‘b’ instead of ‘c’.
Major device number an index to a kernel table that contains the addresses of all device driver functions known
to the system. Whenever a process reads data from or writes data to a device file, the kernel uses the device file’s
major number to select and invoke a device driver function to carry out actual data transfer with a physical device.
Minor device number an integer value to be passed as an argument to a device driver function when it is called.
It tells the device driver function what actual physical device is talking to and the I/O buffering scheme to be used
for data transfer.
FIFO file
It is a special pipe device file which provides a temporary buffer for two or more processes to communicate by
writing data to and reading data from the buffer.
The size of the buffer is fixed to PIPE_BUF.
Data in the buffer is accessed in a first-in-first-out manner.
The buffer is allocated when the first process opens the FIFO file for read or write
The buffer is discarded when all processes close their references (stream pointers) to the FIFO file.
Data stored in a FIFO buffer is temporary.
A FIFO file may be created via the mkfifo command.
o The following command creates a FIFO file (if it does not exists)
mkfifo /usr/prog/fifo_pipe
o The following command creates a FIFO file (if it does not exists)
mknod /usr/prog/fifo_pipe p
FIFO files can be removed using rm command.
Symbolic link file
BSD UNIX & SV4 defines a symbolic link file.
A symbolic link file contains a path name which references another file in either local or a remote file system.
POSIX.1 does not support symbolic link file type
A symbolic link may be created in UNIX via the ln command
Ex: ln -s /usr/divya/original /usr/raj/slink
It is possible to create a symbolic link to reference another symbolic link.
rm, mv and chmod commands will operate only on the symbolic link arguments directly and not on the files that
they reference.
Page 2
UNIX SYSTEM PROGRAMMING NOTES
/bin Stores all the system programs like cat, rm, cp,etc.
In addition to the above attributes, UNIX systems also store the major and minor device numbers for each device file. All the
above attributes are assigned by the kernel to a file when it is created. The attributes that are constant for any file are:
File type
File inode number
File system ID
Major and minor device number
The other attributes are changed by the following UNIX commands or system calls
Unix System Attributes changed
Command Call
chmod chmod Changes access permission, last change time
chown chown Changes UID, last change time
chgrp chown Changes GID, ast change time
touch utime Changes last access time, modification time
Ln link Increases hard link count
Rm unlink Decreases hard link count. If the hard link count is zero, the file will be
removed from the file system
vi, emac Changes the file size, last access time, last modification time
Page 3
UNIX SYSTEM PROGRAMMING NOTES
Inodes in UNIX System V
In UNIX system V, a file system has an inode table, which keeps tracks of all files. Each entry of the inode table is an
inode record which contains all the attributes of a file, including inode # and the physical disk address where data of the
file is stored
For any operation, if a kernel needs to access information of a file with an inode # 15, it will scan the inode table to find
an entry, which contains an inode # 15 in order to access the necessary data.
An inode # is unique within a file system. A file inode record is identified by a file system ID and an inode #.
Generally an OS does not keep the name of a file in its record, because the mapping of the filenames to inode# is done
via directory files i.e. a directory file contains a list of names of their respective inode # for all file stored in that
directory.
Ex: a sample directory file content
Page 4
APSCE
UNIX SYSTEM PROGRAMMING NOTES
Normally the reference count in the file table entry is 1,if we wish to increase the rc in the file table entry, this can be done using
fork,dup,dup2 system call. When a open system call is succeeded, its return value will be an integer (file
Page 5
UNIX SYSTEM PROGRAMMING NOTES
descriptor). Whenever the process wants to read or write data from the file, it should use the file descriptor as one of its
argument.
The following events will occur whenever a process calls the close function to close the files that are opened.
1. The kernel sets the corresponding file descriptor table entry to be unused.
2. It decrements the rc in the corresponding file table entry by 1, if rc not equal to 0 go to step 6.
3. The file table entry is marked as unused.
4. The rc in the corresponding file inode table entry is decremented by 1, if rc value not equal to 0 go to step 6.
5. If the hard link count of the inode is not zero, it returns to the caller with a success status otherwise it marks the inode table
entry as unused and de-allocates all the physical dusk storage of the file.
6. It returns to the process with a 0 (success) status.
The file descriptor associated with a stream pointer can be extracted by fileno macro, which is declared in the <stdio.h> header.
int fileno(FILE * stream_pointer);
To convert a file descriptor to a stream pointer, we can use fdopen C library function
FILE *fdopen(int file_descriptor, char * open_mode);
The following lists some C library functions and the underlying UNIX APIs theyuse to perform their functions:
Directory Files
It is a record-oriented file
Each record contains the information of a file residing in that directory
The record data type is struct dirent in UNIX System V and POSIX.1 and struct direct in BSD UNIX.
The record content is implementation-dependent
They all contain 2 essential member fields
File name
Page 6
UNIX SYSTEM PROGRAMMING NOTES
o Inode number
Usage is to map file names to corresponding inode number
Both /urs/divya/abc and /usr/raj/xyz refer to the same inode number 201, thus type is no new file created.
Case 2: For the same operation, if ln –s command is used then a new inode will be created.
ln –s /usr/divya/abc /usr/raj/xyz
The content of the directory files divya and raj will be
If cp command was used then the data contents will be identical and the 2 files will be separate objects in the file system,
whereas in ln –s the data will contain only the path name.
Limitations of hard link:
1. User cannot create hard links for directories, unless he has super-user privileges.
2. User cannot create hard link on a file system that references files on a different file system, because inode number is unique
to a file system.
Differences between hard link and symbolic link are listed below:
Page 7
UNIX SYSTEM PROGRAMMING NOTES
Page 8
UNIX SYSTEM PROGRAMMING NOTES
Page 1
UNIX SYSTEM PROGRAMMING NOTES
creat
This system call is used to create new regular files.
The prototype of creat is
#include <sys/types.h>
#include<unistd.h>
int creat(const char *pathname, mode_t mode);
Returns: file descriptor opened for write-only if OK, -1 on error.
The first argument pathname specifies name of the file to be created.
The second argument mode_t, specifies permission of a file to be accessed by owner group and others.
The creat function can be implemented using open function as:
#define creat(path_name, mode)
open (pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
read
The read function fetches a fixed size of block of data from a file referenced by a given file descriptor.
The prototype of read function is:
#include<sys/types.h>
#include<unistd.h>
size_t read(int fdesc, void *buf, size_t nbyte);
If successful, read returns the number of bytes actually read.
If unsuccessful, read returns –1.
The first argument is an integer, fdesc that refers to an opened file.
The second argument, buf is the address of a buffer holding any data read.
The third argument specifies how many bytes of data are to be read from the file.
The size_t data type is defined in the <sys/types.h> header and should be the same as unsigned int.
There are several cases in which the number of bytes actually read is less than the amount requested:
o When reading from a regular file, if the end of file is reached before the requested number of bytes has been
read. For example, if 30 bytes remain until the end of file and we try to read 100 bytes, read
returns 30. The next time we call read, it will return 0 (end of file).
o When reading from a terminal device. Normally, up to one line is read at a time.
o When reading from a network. Buffering within the network may cause less than the requested amount
to be returned.
o When reading from a pipe or FIFO. If the pipe contains fewer bytes than requested, read will return only what is
available.
write
The write system call is used to write data into a file.
The write function puts data to a file in the form of fixed block size referred by a given file descriptor.
Page 2
UNIX SYSTEM PROGRAMMING NOTES
The prototype of write is
#include<sys/types.h>
#include<unistd.h>
ssize_t write(int fdesc, const void *buf, size_t size);
If successful, write returns the number of bytes actually written.
If unsuccessful, write returns –1.
The first argument, fdesc is an integer that refers to an opened file.
The second argument, buf is the address of a buffer that contains data to be written.
The third argument, size specifies how many bytes of data are in the buf argument.
The return value is usually equal to the number of bytes of data successfully written to a file. (size value)
close
The close system call is used to terminate the connection to a file from a process.
The prototype of the close is
#include<unistd.h>
int close(int fdesc);
If successful, close returns 0.
If unsuccessful, close returns –1.
The argument fdesc refers to an opened file.
Close function frees the unused file descriptors so that they can be reused to reference other files. This is important
because a process may open up to OPEN_MAX files at any time and the close function allows a process to reuse file
descriptors to access more than OPEN_MAX files in the course of its execution.
The close function de-allocates system resources like file table entry and memory buffer allocated to hold the
read/write.
fcntl
The fcntl function helps a user to query or set flags and the close-on-exec flag of any file descriptor.
The prototype of fcntl is
#include<fcntl.h>
int fcntl(int fdesc, int cmd, …);
The first argument is the file descriptor.
The second argument cmd specifies what operation has to be performed.
The third argument is dependent on the actual cmd value.
The possible cmd values are defined in <fcntl.h> header.
int cur_flags=fcntl(fdesc,F_GETFL);
int rc=fcntl(fdesc,F_SETFL,cur_flag | O_APPEND | O_NONBLOCK);
Page 3
UNIX SYSTEM PROGRAMMING NOTES
The following example reports the close-on-exec flag of fdesc, sets it to on afterwards:
cout<<fdesc<<”close-on-
exec”<<fcntl(fdesc,F_GETFD)<<endl;
(void)fcntl(fdesc,F_SETFD,1); //turn on close-on-
exec flag
The following statements change the standard input og a process to a file called FOO:
int //open FOO for read
fdesc=open(“FOO”,O_RDONLY); //close standard input
close(0);
if(fcntl(fdesc,F_DUPFD,0)==-1)
perror(“fcntl”); //stdin from FOO now
char buf[256];
int rc=read(0,buf,256); //read data from FOO
The dup and dup2 functions in UNIX perform the same file duplication function as fcntl.
They can be implemented using fcntl as:
lseek
The lseek function is also used to change the file offset to a different value.
Thus lseek allows a process to perform random access of data on any opened file.
The prototype of lseek is
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fdesc, off_t pos, int whence);
On success it returns new file offset, and –1 on error.
The first argument fdesc, is an integer file descriptor that refer to an opened file.
The second argument pos, specifies a byte offset to be added to a reference location in deriving the new file offset
value.
The third argument whence, is the reference location.
link
The link function creates a new link for the existing file.
The prototype of the link function is
#include <unistd.h>
int link(const char *cur_link, const char *new_link);
If successful, the link function returns 0.
If unsuccessful, link returns –1.
The first argument cur_link, is the pathname of existing file.
The second argument new_link is a new pathname to be assigned to the same file.
If this call succeeds, the hard link count will be increased by 1.
The UNIX ln command is implemented using the link API.
Page 4
UNIX SYSTEM PROGRAMMING NOTES
/*test_ln.c*/
#include<iostream.h>
#include<stdio.h>
#include<unistd.h>
unlink
The unlink function deletes a link of an existing file.
This function decreases the hard link count attributes of the named file, and removes the file name entry of the link
from directory file.
A file is removed from the file system when its hard link count is zero and no process has any file descriptor referencing
that file.
The prototype of unlink is
#include <unistd.h>
int unlink(const char * cur_link);
If successful, the unlink function returns 0.
If unsuccessful, unlink returns –1.
The argument cur_link is a path name that references an existing file.
ANSI C defines the rename function which does the similar unlink operation.
The prototype of the rename function is:
#include<stdio.h>
int rename(const char * old_path_name,const char * new_path_name);
The UNIX mv command can be implemented using the link and unlink APIs as shown:
#include <iostream.h>
#include <unistd.h>
#include<string.h>
int main ( int argc, char *argv[ ])
{
if (argc != 3 || strcmp(argv[1],argcv[2]))
cerr<<”usage:”<<argv[0]<<””<old_link><new_lin
k>\n”;
else if(link(argv[1],argv[2]) == 0)
return unlink(argv[1]);
return 1;
}
stat, fstat
The stat and fstat function retrieves the file attributes of a given file.
The only difference between stat and fstat is that the first argument of a stat is a file pathname, where as the first
argument of fstat is file descriptor.
The prototypes of these functions are
#include<sys/stat.h>
#include<unistd.h>
Page 5
UNIX SYSTEM PROGRAMMING NOTES
The second argument to stat and fstat is the address of a struct stat-typed variable which is defined in the <sys/stat.h>
header.
Its declaration is as follows:
struct stat
{
dev_t st_dev; /* file system ID */
ino_t st_ino; /* file inode number */
/* contains file type and
mode_t st_mode; permission */
nlink_t st_nlink; /* hard link count */
uid_t st_uid; /* file user ID */
gid_t st_gid; /* file group ID */
/*contains major and minor
dev_t st_rdev; device#*/
off_t st_size; /* file size in bytes */
time_t st_atime; /* last access time */
time_t st_mtime; /* last modification time */
st_ctime
time_t ; /* last status change time */
};
The return value of both functions is o
0 if they succeed
o -1 if they fail
o errno contains an error status code
The lstat function prototype is the same as that of stat:
int lstat(const char * path_name, struct stat* statv);
We can determine the file type with the macros as shown.
macro Type of file
S_ISREG() regular file
S_ISDIR() directory file
S_ISCHR() character special file
S_ISBLK() block special file
S_ISFIFO() pipe or FIFO
S_ISLNK() symbolic link
S_ISSOCK() socket
Note: refer UNIX lab program 3(b) for example
access
The access system call checks the existence and access permission of user to a named file.
The prototype of access function is:
#include<unistd.h>
int access(const char *path_name, int flag);
On success access returns 0, on failure it returns –1.
The first argument is the pathname of a file.
The second argument flag, contains one or more of the following bit flag .
Bit flag Uses
F_OK Checks whether a named file exist
R_OK Test for read permission
W_OK Test for write permission
X_OK Test for execute permission
The flag argument value to an access call is composed by bitwise-ORing one or more of the above bit flags as shown:
int rc=access(“/usr/divya/usp.txt”,R_OK | W_OK);
example to check whether a file exists:
if(access(“/usr/divya/usp.txt”, F_OK)==-
1) printf(“file does not exists”);
else
printf(“file exists”);
Page 6
UNIX SYSTEM PROGRAMMING NOTES
chmod, fchmod
The chmod and fchmod functions change file access permissions for owner, group & others as well as the set_UID,
set_GID and sticky flags.
A process must have the effective UID of either the super-user/owner of the file.
The prototypes of these functions are
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
chown, fchown, lchown
The chown functions changes the user ID and group ID of files.
The prototypes of these functions are
#include<unistd.h>
#include<sys/types.h>
if (UID == (uid_t)-1)
cerr <<“Invalid user name”;
else for (int i = 2; i < argc ; i++)
if (stat(argv[i], &statv)==0)
{
if (chown(argv[i], UID,statv.st_gid))
perror (“chown”);
else
perror (“stat”);
}
return 0;
}
The above program takes at least two command line arguments: o
The first one is the user name to be assigned to files
o The second and any subsequent arguments are file path names.
The program first converts a given user name to a user ID via getpwuid function. If that succeeds, the program
processes each named file as follows: it calls stat to get the file group ID, then it calls chown to change the file user ID. If
either the stat or chown fails, error is displayed.
utime Function
The utime function modifies the access time and the modification time stamps of a file.
The prototype of utime function is
#include<sys/types.h>
#include<unistd.h>
#include<utime.h>
Page 8
UNIX SYSTEM PROGRAMMING NOTES
So, in order to overcome this drawback UNIX and POSIX standard support file locking mechanism.
File locking is applicable for regular files.
Only a process can impose a write lock or read lock on either a portion of a file or on the entire file.
The differences between the read lock and the write lock is that when write lock is set, it prevents the other process
from setting any over-lapping read or write lock on the locked file.
Similarly when a read lock is set, it prevents other processes from setting any overlapping write locks on the locked
region.
The intension of the write lock is to prevent other processes from both reading and writing the locked region while the
process that sets the lock is modifying the region, so write lock is termed as “Exclusive lock”.
The use of read lock is to prevent other processes from writing to the locked region while the process that sets the lock
is reading data from the region.
Other processes are allowed to lock and read data from the locked regions. Hence a read lock is also called as “shared
lock “.
File lock may be mandatory if they are enforced by an operating system kernel.
If a mandatory exclusive lock is set on a file, no process can use the read or write system calls to access the data on the
locked region.
These mechanisms can be used to synchronize reading and writing of shared files by multiple processes.
If a process locks up a file, other processes that attempt to write to the locked regions are blocked until the former
process releases its lock.
Problem with mandatory lock is – if a runaway process sets a mandatory exclusive lock on a file and never unlocks it,
then, no other process can access the locked region of the file until the runway process is killed or the system has to be
rebooted.
If locks are not mandatory, then it has to be advisory lock.
A kernel at the system call level does not enforce advisory locks.
This means that even though a lock may be set on a file, no other processes can still use the read and write functions to
access the file.
To make use of advisory locks, process that manipulate the same file must co-operate such that they follow
the given below procedure for every read or write operation to the file.
1. Try to set a lock at the region to be accesses. If this fails, a process can either wait for the lock request to
become successful.
2. After a lock is acquired successfully, read or write the locked region.
3. Release the lock.
If a process sets a read lock on a file, for example from address 0 to 256, then sets a write lock on the file from address
0 to 512, the process will own only one write lock on the file from 0 to 512, the previous read lock from 0 to 256 is now
covered by the write lock and the process does not own two locks on the region from 0 to 256. This process is called
“Lock Promotion”.
Furthermore, if a process now unblocks the file from 128 to 480, it will own two write locks on the file: one from 0 to
127 and the other from 481 to 512. This process is called “Lock Splitting”.
UNIX systems provide fcntl function to support file locking. By using fcntl it is possible to impose read or write locks on
either a region or an entire file.
The prototype of fcntl is
#include<fcntl.h>
int fcntl(int fdesc, int cmd_flag, ....);
The first argument specifies the file descriptor.
The second argument cmd_flag specifies what operation has to be performed.
If fcntl is used for file locking then it can values as
F_SETLK sets a file lock, do not block if this cannot succeed immediately.
F_SETLKW sets a file lock and blocks the process until the lock is acquired.
F_GETLK queries as to which process locked a specified region of file.
For file locking purpose, the third argument to fctnl is an address of a struct flock type variable.
This variable specifies a region of a file where lock is to be set, unset or queried.
struct flock
{
Page 9
UNIX SYSTEM PROGRAMMING NOTES
The l_whence, l_start & l_len define a region of a file to be locked or unlocked.
The possible values of l_whence and their uses are
l_whence value Use
SEEK_CUR The l_start value is added to current file pointer address
SEEK_SET The l_start value is added to byte 0 of the file
SEEK_END The l_start value is added to the end of the file
A lock set by the fcntl API is an advisory lock but we can also use fcntl for mandatory locking purpose with the following
attributes set before using fcntl
1. Turn on the set-GID flag of the file.
2. Turn off the group execute right permission of the file.
In the given example program we have performed a read lock on a file “divya” from the 10th byte to 25th byte.
Example Program
#include <unistd.h>
#include<fcntl.h>
int main ( )
{
int fd;
struct flock lock;
fd=open(“divya”,O_RDONLY);
lock.l_type=F_RDLCK;
lock.l_whence=0;
lock.l_start=10;
lock.l_len=15;
fcntl(fd,F_SETLK,&lock);
}
Function Use
telldir Returns the file pointer of a given dir_fdesc
seekdir Changes the file pointer of a given dir_fdesc to a specified address
The following list_dir.C program illustrates the uses of the mkdir, opendir, readdir, closedir and rmdir APIs:
#include<iostream.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#if defined(BSD) && !_POSIX_SOURCE
#include<sys/dir.h>
typedef struct dirent Dirent;
#else
#include<dirent.h>
typedef struct dirent Dirent;
#endif
Page 11
UNIX SYSTEM PROGRAMMING NOTES
for(int cnt=0;dp=readdir(dir_fdesc);)
{
if(i)
cout<<dp->d_name<<endl;
if(strcmp(dp->d_name,".") && strcmp(dp->d_name,".."))
cnt++;
}
if(!cnt)
{
rmdir(*argv);
break;
}
rewinddir(dir_fdesc);
}
closedir(dir_fdesc);
}
}
Page 12
UNIX SYSTEM PROGRAMMING NOTES
else if(rc)
cout<<buf<<endl;
close(fd);
}
Page 13
UNIX SYSTEM PROGRAMMING NOTES
Page 14
UNIX SYSTEM PROGRAMMING NOTES
/* filebase.h */
#define FILEBASE_H
#ifndef FILEBASE_H
#include<fstream.h>
#include<iostream.h>
#include<sys/types.h>
#include<string.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<utime.h>
typedef enum
{
REG_FILE=‟r‟, DIR_FILE=‟d‟, CHAR_FILE=‟c‟ PIPE_FILE=‟p‟,
SYM_FILE = „s‟, BLK_FILE = „b‟, UNKNOWN_FILE = „?‟
}
FILE_TYPE_ENUM;
class filebase : public fstream
{
protected:
char *filename;
friend ostream& operator<<(ostream& os,filebase& fobj)
{return os;};
public :
file base() {filename =0:};
file base(const char *fn, int flags, int prot = filebuf :: openprot)
ifstream(fn, flags, prot)
{
filename = newchar[strlen(fn) + 1];
strcpy(filename, fn);
};
virtual ~filebase() {delete filename;};
virtual int create(const char *fn, mode_t mode)
{
return :: create(fn, mode);
};
int fileno()
{
return rdbuf()->fd();
};
int chmod(mode_t mode)
{
return :: chmod(filename, mode);
};
int chown(uid_t uid, gid_t gid)
{
return :: chown(filename, uid, gid);
};
int link (const char *new_link)
{
return :: link (filename, new_link);
};
int utime (const struct utim buf *timbuf_ptr)
{
return :: utime (filename, timbuf_ptr);
};
virtual int remove()
Page 15
UNIX SYSTEM PROGRAMMING NOTES
{
return :: unlink(filename );
};
FILE_TYPE_ENUM file_type()
{
struct stat statv;
if (stat(filename, &statv)==0)
switch (statv.st_mode & S_IFMT)
{
case S_IFREG : return REG_FILE : /* Regular file */
case S_IFIFO : return PIPE_FILE; /* block device file */
case S_IFCHR : return CHAR_FILE ; /* character device file */
case S_IFDIR : return DIR_FILE ; /* Directory file */
case S_IFLNK : return SYM_FILE ; /* Symbolic link file */
}
return UNKNOWN_FILE;
};
};
#endif /*filebase.h*/
Page 17
UNIX SYSTEM PROGRAMMING NOTES
Page 18
UNIX SYSTEM PROGRAMMING NOTES
Device File Class
A device file object has most of the properties of a regular file object except in the way that the device file object is created. Also
the tellg, seekg, lock, lockw, unlock and getlock functions are invalid for any character-based device file objects.
/*devfile.h*/
#define DEVFILE_H
#ifndef DEVFILE_H
#include “regfile.h”
class devfile : public regfile
{
public :
devfile(const char *fn, int flags, int prot): regfile(fn, flags, prot)
{};
int create (const char *fn, mode_t prot, int major_no, int minor_no, char type=‟c‟)
{
if (type ==‟c‟)
return mknod(fn, S_IFCHR | prot, (major_no <<8) |minor_no);
else
return mknod(fn, S_IFBLK | prot, (major_no << 8) | minor_no);
};
streampos tellg()
{
if (file_type() == CHAR_FILE)
return (streampos)-1;
else
return fstream :: tellg();
};
istream seekg(streampos ofs, seek_dir d)
{
if (file_type() ! = CHAR_FILE)
fstream :: seekg(ofs, d);
return *this :
};
int lock (int lck_type, off_t len, int cmd = F_SETLK)
{
if (file_type() != CHAR_FILE)
return regfile :: lock(lck_type, len, cmd);
else return -1;
};
int lockw(int lck_type, off_t len)
{
if (file_type() ! = CHAR_FILE)
return regfile :: lockw(lck_type, len);
else return-1;
};
int unlockw(off_t len)
{
if(file_type() ! = CHAR_FILE)
return regfile :: unlock(len);
else return -1;
};
int getlock(int lck_type, off_t len, struct flock &flck)
{
if (file_type()! = CHAR_FILE)
return regfile :: getlock(lck_type, len, flck);
else return -1;
};
};
#end if
#end if
#include “filebase.h”
#include “dirfile.h”
#include “symfile.h”
void show_list(ostream &ofs, const char *fname, int
deep); extern void long_list (ostream &ofs, char
*fn); void show_dir(ostream &ofs, const char *fname)
{
dirfile dirobj(fname);
char buf[256];
ofs <<“Directory :” << fname;
while (dirobj.read(buf, 256))
{
filebase fobj(buf, ios :: in, O755);
if(fobj.file_type==DIR_FILE)
Page 20
UNIX SYSTEM PROGRAMMING NOTES
show_dir(ofs, buf);
fobj.close();
}
dirobj.close();
}
void show_list(ostream &ofs, const char *fname, int deep)
{
long_list(ofs, fname);
filebase fobj(fname, ios::n, O755);
if (fobj.file_type()==SYM_FILE)
{
Symfile *symobj = (symfile *) fobj;
ofs << “->” << symobj -> ref_path()<<endl;
}
else if (fobj.file_type() == DIR_FILE && deep)
Show_dir(ofs, fname);
}
int main(int argc, char *argv[])
{
while (- -argc >0) show_list(cout, *++argv, 1);
return 0;
}
Summary
The inheritance hierarchy of all the file classes defined in the chapter is:
Page 21