LIP Unit III.ppt

  

Unit III

FILES

FILE TYPES

  

Regular file

  

Directory file

  

Character device file

  

Block device file

   FIFO file

Regular file

  

  It may be text or binary file

  

  Both the files are executable provided execution rights are set

  

  They can be read or written by users with appropriate permissions

  

  To remove regular files use rm command

Directory file

  

  Folder that contains other files and subdirectories

  

  Provides a means to organize files in hierarchical structure

  

  To create : mkdir command

  

  To remove : rmdir command

   Block device file : Physical device which

  transmits data a block at a time EX: hard disk drive, floppy disk drive

   Character device file : Physical device

  which transmits data in a character-based manner EX: line printers, modems, consoles

   To create : mknod command mknod filename type major minor mknod /dev/cdsk c 115 5 /dev/cdsk : name of the device c -- character device b -- block device 115 — major device number 5 — minor device number

  

Major device number : an index to the kernel’s

file table that contains address of all device drivers Minor device number : indicates the type of physical file and I/O buffering scheme used for data transfer

  

FIFO file

  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 Max size of bufferPIPE_BUF The storage is temporary The file exists as long as there is one process in direct connection to the FIFO for data access To create : mkfifo OR mknod mkfifo /usr/prog/fifo_pipe mknod /usr/prog/fifo_pipe p

A FIFO file can be removed like any other regular file.

  

Symbolic link file

  A symbolic link file contains a pathname which references another file in either the local or a remote file system

  

  To create : ln command with –s option

  ln –s /usr/abc/original /usr/xyz/slink cat /usr/xyz/slink /*will print contents of /usr/abc/original file*/

The File System Structure

  

/

etc bin usr1 faculty dev tmp date cal . . .

  . . .

  . . . . . .

mj

File systems

  

  They have a tree-like hierarchical file system

   “/” – denotes the root

   “.” – current directory

   “..” – parent directory

   NAME_MAX – max number of characters

  in a file name

   PATH_MAX -- max number of characters

  in a path name

  

Common UNIX files

  

/etc : Stores system administrative files

& programs

   /etc/passwd : Stores all user information

   /etc/shadow : Stores user passwords

   /etc/group : Stores all group information

   /bin : Stores all system programs

   /dev : Stores all character and block device files

   /usr/include : Stores standard header files

   /usr/lib : Stores standard libraries

   tmp : Stores all temporary files created by programs

  

File attributes

File type : type of file Access permission : the file access permission for owner group and others Hard link count : number of hard links of a file UID

  : the file owner user ID GID : the file group ID File size : the file size in bytes Last access time : time the file was last accessed Last modify time : the time the file was last modified Last change time : the time the file access permission UID ,GID or hard link count was last changed

Inode number : system inode number of the file

  File system ID : the file system ID where the file is stored

Attributes of a file that remain unchanged

   File type

   File inode number

   File system ID

   Major and minor device number

   Other attributes are changed using UNIX commands or system calls

  UNIX System call Attributes changed command chmod chmod Changes access permission, last change time

chown chown Changes UID, last

change time

chgrp chown Changes GID, last

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 file size,last access time, last modification time

  

Inodes

  

UNIX system V has an inode table which keeps track

of all files Each entry in inode table is an inode record

Inode record contains all attributes of file including

inode number and physical address of file Information of a file is accessed using its inode number Inode number is unique within a file system

  A file record is identified by a file system ID and inode number Inode record doesnot contain the name of the file

The mapping of filenames to inode number is done

via directory files

  112

  67 ..

  97 abc 234 a.out To access a file for example /usr/abc , the

kernel knows ”/” directory inode number of

any process, it will scan “/” directory to

find inode number of “usr” directory it then

checks for inode number of abc in usr .

  The entire process in carried out taking into account the permissions of calling process

INTERFACE TO FILES

  

  Files are indentified by path names

  

  Files must must be created before they can be used.

  

  Files must be opened before they can be accessed by application programs .open system call is for this purpose, which returns a file descriptor, which is a file handle used in other system calls to manipulate the open file

  

  A process can may open at most

  OPEN_MAX number of files

  The read and write system calls can be used to read and write data to opened files

  

  File attributes are queried using stat or

  fstat system calls

  File attributes are changed using chmod,

  chown, utime and link system calls

  Hard links are removed by unlink system call

   struct stat

   { dev_ts t_dev; ino_t st_ino;

mode_t st_mode;

nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; time_t st_atime;

time_t st_mtime

time_t st_ctime };

Low Level File Access

  

We can access & control files and directories

using a small number of function known as system calls.

  

The low level functions used to access file or

device drivers are open : Open a file or device. read : Read from an open file or device write : Write to a file or device. close : Close the file or device ioctl : Pass Control information to a device driver.

   Each running program, called a process, has a number of file descriptors associated with it.

  

These are small integers that we can use to

access open files or devices.

   When a program starts, it has three descriptors already opened. These are 0 : Standard Input 1 : Standard Output

  2 : Standard Error

  

We can associate other file descriptors with

file and devices using open system call.

Library Functions

  The using low level system call directly is inefficient due to

  

  There’s a performance penalty in making a system call. System calls are therefore expensive compared to function calls because Linux has to switch from running your program code to executing its own kernel code and back again.

  

  The hardware has limitations that can impose restrictions on the size of data blocks that can be read or written by the low-level system call at any one time.

  

To provide a higher-level interface to devices

and disk files, a Linux distribution (and UNIX)

provides a number of standard libraries.

   These are collections of functions that you can include in your own programs to handle these problems.

   A good example is the standard I/O library that

provides buffered output. You can effectively

write data blocks of varying sizes

   This dramatically reduces the system call overhead.

Low Level File Access cont.. write

   The write system call writes the first nbytes bytes from buf to the file associated with the file descriptor fildes.

   It returns the number of bytes actually written. If the function returns 0, it means no data was

written; if it returns –1, there has been an error

in the write call, and the error will be specified in the errno global variable.

   syntax:

  #include <unistd.h> size_t write(int fildes, const void *buf, size_t nbytes);

  read

  The read system call reads up to nbytes bytes of data from the file associated with the file descriptor fildes and places them in the data area buf.

   It returns the number of data bytes actually read, which may be less than the number requested. If a read call returns 0, it had nothing to read.

   An error on the call will cause it to return –1.

  Syntax :- #include <unistd.h> size_t read(int fildes, void *buf, size_t nbytes);

   open

To create a new file descriptor, use the open system call.

  #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> int open(const char *path, int oflags);

int open(const char *path, int oflags, mode_t mode);

If successful, it returns a file descriptor (always a

nonnegative integer) that can be used in read, write, and

other system calls or –1 if it fails.

  The file descriptor is unique and isn’t shared by any other processes that may be running.

  The name of the file or device to be opened is passed as a

parameter, path; the oflags parameter is used to specify

actions to be taken on opening the file.

   The oflags are specified as a combination of a mandatory file access mode and other optional modes. Mandatory modes are O_RDONLY Open for read-only O_WRONLY Open for write-only

  O_RDWR Open for reading and writing 

  

The call may also include a combination (using a

bitwise OR) of the following optional modes in the oflags parameter: O_APPEND: Place written data at the end of the file.

  O_TRUNC: Set the length of the file to zero, discarding existing contents.

  O_CREAT: Creates the file, if necessary, with permissions given in mode.

  O_EXCL: Used with O_CREAT, ensures that the caller creates the file.

   Initial Permissions When we create a file using the O_CREAT flag with open, we must use the three-parameter form. mode, the third parameter, is made from a bitwise OR of the flags defined in the header file sys/stat.h. These are: S_IRUSR : Read permission, owner S_IWUSR : Write permission, owner S_IXUSR : Execute permission, owner S_IRGRP : Read permission, group S_IWGRP : Write permission, group S_IXGRP : Execute permission, group S_IROTH : Read permission, others S_IWOTH : Write permission, others S_IXOTH : Execute permission, others

  close

  We use close to terminate the association between a file descriptor, fildes, and its file.

  The file.

  

descriptor becomes available for reuse. It

returns 0 if successful and –1 on error.

  #include <unistd.h> int close(int fildes);

  File Copy Program #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> int main() { char block[1024]; int in, out; int nread; in = open(“file.in”, O_RDONLY);

out = open(“file.out”, O_WRONLY|O_CREAT,

  S_IRUSR|S_IWUSR);

while((nread = read(in,block,sizeof(block))) > 0)

write(out,block,nread); exit(0); }

   ioctl It provides an interface for controlling the behavior of devices and their descriptors and configuring underlying services.

  

Terminals, file descriptors, sockets, and even tape

drives may have ioctl calls defined for them and we

need to refer to the specific device’s man page for

details. Here’s the syntax:

  #include <unistd.h> int ioctl(int fildes, int cmd, ...);

ioctl performs the function indicated by cmd on the

object referenced by the descriptor fildes. It may take an optional third argument, depending on the functions supported by a particular device.

The Standard I/O Library

   The standard I/O library (stdio) and its header file, stdio.h, provide a versatile interface to low-level I/O system calls.

   we look at the following functions: ❑ fopen, fclose ❑ fread, fwrite ❑ fflush ❑ fseek ❑ fgetc, getc, getchar ❑ fputc, putc, putchar ❑ fgets, gets

  fopen #include <stdio.h>

FILE *fopen(const char *filename, const char

*mode); fopen opens the file named by the filename parameter and associates a stream with it. The mode parameter specifies how the file is to be opened. It’s one of the following strings: “r” or “rb” : Open for reading only “w” or “wb” : Open for writing, truncate to zero length “a” or “ab” : Open for writing, append to end of file “r+” or “rb+” or “r+b” : Open for update (reading and writing) “w+” or “wb+” or “w+b”: Open for update, truncate to zero length “a+” or “ab+” or “a+b”: Open for update, append to end of file

If successful, fopen returns a non-null FILE * pointer. If it

fails, it returns the value NULL.

   fread

  

The fread library function is used to read data from a

file stream.

  Data is read into a data buffer given by ptr from the stream, stream. Both fread and fwrite deal with data records. These are specified by a record size, size, and a count, nitems, of records to transfer. The function returns the number of items (rather than the number of bytes) successfully read into the data buffer.

  At the end of a file, fewer than nitems may be returned, including zero. Here’s the syntax: #include <stdio.h> size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

  fwrite

  The fwrite library call has a similar interface to fread.

  

  It takes data records from the specified data buffer and writes them to the output stream. It returns the number of records successfully written.

  

  Here’s the syntax:

  #include <stdio.h> size_t fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream);

  fclose

  The fclose library function closes the specified stream, causing any unwritten data to be written.

  

  It’s important to use fclose because the stdio library will buffer data. If the program needs to be sure that data has been completely written, it should call fclose. Here’s the syntax:

  #include <stdio.h> int fclose(FILE *stream);

  fflush

  The fflush library function causes all outstanding data on a file stream to be written immediately.

  

  You can use this to ensure that, for example, an interactive prompt has been sent to a terminal before any attempt to read a response. It’s also useful for ensuring that important data has been committed to disk before continuing.

  

  Here’s the syntax:

  #include <stdio.h> int fflush(FILE *stream);

  fseek

  The fseek function sets the position in the stream for the next read or write on that stream.

  

  Here’s the syntax:

  #include <stdio.h> int fseek(FILE *stream, long int offset, int whence);

  The offset parameter is used to specify the position, and the whence parameter specifies how the offset is used. whence can be one of the following: SEEK_SET: offset is an absolute position

  • SEEK_CUR: offset is relative to the current position
  • >SEEK_END: offset is relative to the end of the

  fgetc, getc, and getchar

  The fgetc function returns the next byte, as a character, from a file stream. When it reaches the end of the file or there is an error, it returns EOF.

  

  The getc function is equivalent to fgetc, except that it may be implemented as a macro.

  

  The getchar function is equivalent to getc(stdin) and reads the next character from the standard input. Here’s the syntax:

  #include <stdio.h> int fgetc(FILE *stream); int getc(FILE *stream); int getchar();

  fputc, putc, and putchar

  The fputc function writes a character to an output file stream. It returns the value it has written, or EOF on failure.

  #include <stdio.h> int fputc(int c, FILE *stream); int putc(int c, FILE *stream); int putchar(int c);

  fgets and gets

  The fgets function reads a string from an input file stream.

  #include <stdio.h> char *fgets(char *s, int n, FILE *stream); char *gets(char *s);  fgets writes characters to the string pointed to by s

until a newline is encountered, n-1 characters have

been transferred, or the end of file is reached, whichever occurs first.

   The gets function is similar to fgets, except that it reads from the standard input and discards any newline encountered. It adds a trailing null byte to the receiving string.

  

Formatted Input and Output

printf, fprintf, and sprintf

   scanf, fscanf, and sscanf

  printf, fprintf, and sprintf

  The printf family of functions format and output a variable number of arguments of different types.

  

  The way each is represented in the output stream is controlled by the format parameter, which is a string that contains ordinary characters to be printed and codes called conversion specifiers,

  which indicate how and where the remaining arguments are to be printed.

  #include <stdio.h> int printf(const char *format, ...); int sprintf(char *s, const char *format, ...); int fprintf(FILE *stream, const char *format, ...);

  

  The printf function produces its output on the standard output.

  

  The fprintf function produces its output on a specified stream.

  

  The sprintf function writes its output and a terminating null character into the string s passed as a parameter.

  

  Here are some of the most commonly used conversion specifiers:

  ❑ %d, %i : Print an integer in decimal ❑ %o, %x : Print an integer in octal, hexadecimal : Print a character ❑ %c : Print a string ❑ %s

  ❑ %f : Print a floating-point (single precision) number ❑ %e : Print a double precision number, in fixed format ❑ %g : Print a double in a general format.

  Format Argument |Output|

  %10s “Hello” | Hello| %-10s “Hello” |Hello | %10d 1234 |

  1234| %-10d 1234 |1234 |

%010d 1234 |0000001234 |

  %10.4f 12.34 | 12.3400| %*s 10,”Hello” | Hello|

%10s “HelloTherePeeps” | HelloTherePeeps|

  scanf, fscanf, and sscanf

  The scanf family of functions works in a way similar to the printf group, except that these functions read items from a stream and place values into variables at the addresses they’re passed as pointer parameters.

  

  They use a format string to control the input conversion in the same way, and many of the conversion specifiers are the same.

  #include <stdio.h> int scanf(const char *format, ...);

int fscanf(FILE *stream, const char *format, ...);

int sscanf(const char *s, const char *format, ...);

  

  The conversion specifiers are

  : Scan a decimal integer ❑ %d : Scan an octal, hexadecimal integer ❑ %o, %x

  ❑ %f, %e, %g : Scan a floating-point number ❑ %c : Scan a character (whitespace not skipped) ❑ %s : Scan a string : Scan a set of characters ❑ %[]

: Scan a % character

❑ %%

  

  Use the %[] specifier to read a string composed of

  %[A-Z]

  characters from a set. The format will read a string of capital letters. If the first character in the

  ^

  set is a caret, , the specifier reads a string that consists of characters not in the set. So, to read a string with spaces in it, but stopping at the first

Stream Errors

   To indicate an error, many stdio library functions return out-of-range values, such as null pointers or the constant EOF.

  

In these cases, the error is indicated in the

external variable errno:

  #include <errno.h> extern int errno;

   We can also interrogate the state of a file stream to determine whether an error has occurred, or the end of file has been reached.

  #include <stdio.h> int ferror(FILE *stream); int feof(FILE *stream); void clearerr(FILE *stream); The ferror function tests the error indicator for a stream and returns nonzero if it’s set, but zero otherwise.

  The feof function tests the end-of-file indicator within a

stream and returns nonzero if it is set, zero otherwise.

  The clearerr function clears the end-of-file and error indicators for the stream to which stream points.

  

File Copy Program

  #include <stdio.h> #include <stdlib.h> int main() { int c; FILE *in, *out; in = fopen(“file.in”,”r”); out = fopen(“file.out”,”w”); while((c = fgetc(in)) != EOF) fputc(c,out); exit(0); }

  

The kernel has a file table that keeps the track

of all opened files in the system.

   There is also an inode table that contains a

copy of the file inodes most recently accessed.

   Whenever a user executes a command, a process is created by the kernel to carry out the command execution.

  

Each process has its own data structures: file

descriptor table is one among them

   File descriptor table has OPEN_MAX entries,

and it records all files opened by the process

  

Kernel support : open system call

  

Whenever an open function is called the kernel

will resolve the pathname to file inode

  Open call fails and returns -1 if the file inode does not exist or the process lacks appropriate permissions

  Else a series of steps follow

  

1. The kernel will search the file descriptor table and

look for first unused entry, which is returned as file descriptor of the opened file

  

2. The kernel will scan the file table in its kernel space

to find an unused entry that can be assigned to reference the file. If an unused entry is found then

  

a) The process’s file descriptor table entry will be

set to point to file table entry b)The file table entry will be set to point to inode table entry where the inode record of file is present

  c) The file table entry will contain the current file pointer of the open file d)The file table entry will contain an open mode which specifies the file is opened for read-only, write-only etc.

  e) Reference count of file table is set to 1.

  

f) The reference count of the in-memory inode of

file is increased by 1.

  Inode table File table

  File descriptor table rc=1 r rc=1

rw

rc=2 rc=1

w

  Data Structure for rc=1 File Manipulation

   Kernel support : read system call The kernel will use the file descriptor to index the process’s file descriptor table to find file table entry to opened file It checks the file table entry to make sure that the file is opened with appropriate mode The kernel will use the file pointer used in file table entry to determine where the read operation should occur in file The kernel will check the type of file in the inode record

and invokes an appropriate driver function to initiate

the actual data transfer with a physical file

If the process calls lseek function then the changes

are made provided the file is not a character device file,

a FIFO file, or a symbolic link file as they follow only

sequential read and write operations

Kernel support : close system call When a process calls the close function to close an opened file, the sequence of events are as follows:

  1.The kernel will set the corresponding descriptor table entry to unused

  

2.It decrements the reference count in file table entry

by 1. If reference count !=0 then go to 6

  3.File table entry is marked unused 4.The reference count in file inode table entry by 1. If reference count !=0 then go to 6

  5.If hard link count is non zero, it returns a success status, otherwise marks the inode table entry as unused and deallocates all the physical disk storage 6.It returns the process with a 0 (success) status.

Hard and symbolic links

  

  A hard link is a UNIX path name for a file

  

  To create hard link ln command is used

  ln /usr/abc/old.c /usr/xyz/new.c

  Symbolic link is also a means of referencing a file

  

  To create symbolic link ln command is used with option –s

  ln –s /usr/abc/old.c /usr/xyz/new.c

  

Difference : cp and ln command

  Cp command creates a duplicated copy of file to another file with a different path name

  

  Where as ln command saves space by not duplicating the copy here the new file will have same inode number as original file.

  

Difference : hard link and symbolic

link

Hard link

  Symbolic link Does not create a new inode Create a new inode Cannot link directories unless it is done by root Can link directories Cannot link files across file systems Can link files across file system Increase hard link count of the linked inode Does not change hard link count of the linked inode

   open Opens a file for data access read Reads data from file write Writes data into file lseek Allows random access of data in a file close Terminates connection to a file stat,fstat Queries attributes of a file chmod Changes access permissions of a file chown Changes UID and/or GID of a file Utime Changes last modification time and access time stamps of a file link creates a hard link to a file ulink Deletes a hard link to a file umask Sets default file creation mask

  File structure related system calls General file APIs

  

Open

  The function establishes connection

between process and a file or to create a

  new file.

   The prototype of the function

  #include <sys/types.h> #include <fcntl.h> int open (const char *pathname, int access mode, mode_t permission);

Pathname : It can be absolute path name or a relative

path name

   Access_mode : An integer which specifies how file is to be accessed by calling process, use one of these flag  O_RDONLY Opens file for read-onlyO_WRONLY Opens file for write only O_RDWR Opens file for read & write

   One or more Access modifier flag can be used with these  O_APPEND Appends data to the end of the fileO_CREAT Create the file if doesn’t exists.

   O_EXCL This causes open to fail, if file already exist.O_TRUNC If file exists, set file size to zero.

O_NONBLOCK Any subsequent read/write on file should be

nonblocking

   O_NOCTTY Specifies not to use the named terminal device file as calling process control terminal.

   Permission required only if O_CREAT flag is set.

  (Example:- S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH to specify 0764 permissions on the file)

  

Umask

  It specifies some access rights to be masked off

  

  Prototype:

  mode_t umask ( mode_t new_umask); mode_t old_mask = umask(S_IXGRP|S_IWOTH);

/*removes execute permission from others and write

permission from group*/ 

  Actual_permission = permission & ~umask_value

  

Creat

  It is used to create new regular files #include <sys/types.h> #include <unistd.h> Int creat (const char* pathname,mode_t mode)

Read

   This function fetches a fixed size block of data from a file referenced by a given file descriptor

  #include <sys/types.h> #include <unistd.h> ssize_t read (int fdesc ,void* buf, size_t size);

  

Write

  The write function puts a fixed size block of data to a file referenced by a file descriptor

  #include <sys/types.h> #include <unistd.h> ssize_t read (int fdesc ,void* buf, size_t size);

Close

  

  Disconnects a file from a process

  #include <unistd.h> int close (int fdesc);  Close function frees unused file descriptors. 

  Close function will deallocate system resources

  

  It a process terminates without closing all the files it has opened, the kernel will close those files for the process.

  fcntl

  The fcntl function helps to query or set access control flags and the close-on-exec flag of any file descriptor.

  

  We can also use fcntl to assign multiple file descriptors to reference the same file

  #include <fcntl.h> Int fcntl (int fdesc ,int cmd, … );

  cmd argument specifies which operation to perform on a file referenced by the fdesc argument.

  

  The third argument value is dependent on the actual cmd value.

   Following are the cmd values that can be used.

  F_GETFL : returns the access control flags of a file descriptor fdesc F_SETFL : sets or clears control flags that are specified in the third argument. The allowed flags are O_APPEND & O_NONBLOCK F_GETFD : returns the close-on-exec flag of a file referenced by fdesc. If return value is 0, flag is off, otherwise if nonzero flag is on.

  F_SETFD : sets or clears close-on-exec flag of a file descriptor fdesc. The third argument is 0 to clear the flag or 1 to set the flag.

  F_DUPFD : duplicates the file descriptor fdesc with

another file descriptor. The argument is an integer that

specifies the duplicated file descriptor must be greater

than or equal to that value.

  lseek  the lseek system call is used to change the file offset to a different value

   Prototype :

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

off_t sleek (int fdesc , off_t pos, int whence)

   Pos :

  

  specifies a byte offset to be added to a reference location in deriving the new file offset value

   Whence location reference

  

  SEEK_CUR current file pointer address

  

  SEEK_SET the beginning of a file

  

  SEEK_END the end of a file link 

  The link function creates a new link for existing file

  

  Prototype :

  #include <unistd.h> int link (const char* cur_link ,const char*

new_link)

  

  Cannot link a directory unless the calling function has the superuser privilege

  unlink

  Deletes link of an existing file

  #include <unistd.h> int unlink (const char* cur_link );

Stat fstat

  

  Stat and fstat retrieve arguments of a given file

  #include <sys/types.h> #include <unistd.h> int stat (const char* path_name,struct

stat* statv)

int fstat (const int fdesc,struct stat* statv)

   Struct stat { dev_ts t_dev; ino_t st_ino;

mode_t st_mode;

nlink_t st_nlink;

uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size;

time_t st_mtime

time_t st_ctime };

  

  If pathname specified in stast is a symbolic link then the attributes of the non-symbolic file is obtained

  

  To avoid this lstat system call is used

  

  It is used to obtain attribites of the symbolic link file

  

int lstat (const char* path_name , struct stat*

statv);

  /* Program to emulate the UNIX ls -l command */ #include <iostream.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <pwd.h> #include <grp.h> static char xtbl[10] = "rwxrwxrwx"; #ifndef MAJOR #define MINOR_BITS 8

#define MAJOR(dev) ((unsigned)dev >> MINOR_BITS)

#define MINOR(dev) ( dev & MINOR_BITS) #endif

  

/* Show file type at column 1 of an output line */

static void display_file_type ( ostream& ofs, int

st_mode )

{ switch (st_mode &S_IFMT) {

case S_IFDIR: ofs << 'd'; return;

  

/* directory file */

case S_IFCHR:ofs << 'c'; return;

  /* character device file */

case S_IFBLK: ofs << 'b'; return;

  /* block device file */

case S_IFREG: ofs << ' '; return;

  /* regular file */

case S_IFLNK: ofs << 'l'; return;

  /* symbolic link file */

case S_IFIFO: ofs << 'p'; return;

  /* FIFO file */ } }

  /* Show access permission for owner, group, others, and any special flags */ static void display_access_perm ( ostream& ofs, int st_mode ) { char amode[10]; for (int i=0, j= (1 << 8); i < 9; i++, j>>=1) amode[i] = (st_mode&j) ? xtbl[i] : '-'; /* set access permission */ if (st_mode&S_ISUID) amode[2] = (amode[2]=='x') ? 'S' : 's'; if (st_mode&S_ISGID) amode[5] = (amode[5]=='x') ? 'G' : 'g'; if (st_mode&S_ISVTX) amode[8] = (amode[8]=='x') ? 'T' : 't'; ofs << amode << ' '; }

  /* List attributes of one file */ static void long_list (ostream& ofs, char* path_name) { struct stat statv; struct group *gr_p; struct passwd *pw_p; if (stat (path_name, &statv)) { perror( path_name ); return; } display_file_type( ofs, statv.st_mode ); display_access_perm( ofs, statv.st_mode ); ofs << statv.st_nlink; /* display hard link count */ gr_p = getgrgid(statv.st_gid); /* convert GID to group name */ pw_p = getpwuid(statv.st_uid); / *convert UID to user name */ ofs << ' ' << pw_p->pw_name << ' ' << gr_p->gr_name << ' ';

  if ((statv.st_mode&S_IFMT) == S_IFCHR || (statv.st_mode&S_IFMT)==S_IFBLK) ofs << MAJOR(statv.st_rdev) << ',' << MINOR(statv.st_rdev); else ofs << statv.st_size; /* show file size or major/minor no. */ ofs << ' ' << ctime (&statv.st_mtime);/* print last modification time */ ofs << ' ' << path_name << endl; /* show file name */ } /* Main loop to display file attributes one file at a time */ int main (int argc, char* argv[]) { if (argc==1)

cerr << "usage: " << argv[0] << " <file path name> ...\n";

else while (--argc >= 1) long_list( cout, *++argv); return 0; }