فصل ۴ - Uinversal I/O Model

- disk files
- terminal files
- pipe files

----> buffered I/O
----> unbuffered I/O

file descriptors are used to refer to all types of open files, including pipes,
FIFOs, sockets, terminals, devices, and regular files. Each process has its
own set of file descriptors.

I/O redirection

#   POSIX name      stdion stream
----------------------------------
0   STDIN_FILENO    stdin
1   STDOUT_FILENO   stdout
2   STDERR_FILENO   stderr

! freopen() may change the file descriptor underlying the reopened stream

mode_t
-------
S_IRUSR     S_IRGRP     S_IROTH     S_ISUID
S_IWUSR     S_IWGRP     S_IWOTH     S_ISGID
S_IXUSR     S_IXGRP     S_IXOTH     S_ISVTX

S_IRWXU     S_IRWXG     S_IRWXO


mode_t tests
--------------
S_ISREG(m)      S_ISFIFO(m) // named pipe?
S_ISDIR(m)      S_ISLNK(m)
S_ISCHR(m)      S_ISSOCK(m)
S_ISBLK(m)

mode_t ifs (used by mode & S_IFMT=0170000)
----------------------------------
S_IFREG     S_IFIFO
S_IFDIR     S_IFLNK
S_IFCHR     S_IFSOCK
S_IFBLK

when access to specific features of a file system or device is required, a
program can use the catchall ioctl() system call, which provides an interface
to features that fall outside of the universal I/O model.

    ! Universal I/O Model: implementing open(), read(), write(), close()
    ! for all types of the file.


Open or create a file
+-----------------------------------------------------------------------+
| #include <sys/stat.h>                                                 |
| #include <fcntl.h>                                                    |
|                                                                       |
| int open(const char *pathname, int flags, ... /* mode_t mode */);     |
|                                                                       |
|                                          fd or success or -1 on error |
+-----------------------------------------------------------------------+

In code below inline /* comment */ is correctly TRUE.
+-----------------------------------------------------------------------+
| int                                                                   |
| main(void)                                                            |
| {                                                                     |
|    if (1 /* true */)                                                  |
|        return 0;                                                      |
|    return 1;                                                          |
| }                                                                     |
+-----------------------------------------------------------------------+

The mode_t data type is an integer type specified in SUS3. If the open() system
call doesn't specify O_CREAT, mode can be ommitted.

    ? resize array dynamically

    ! C doesn't check array boundaries.

+***************************+
| $ getconf -a              |
| $ getcinf MAX_INT         |
+***************************+


st_mode in OCTAL format
S_IXOTH        000 001
S_IWOTH        000 002
S_IROTH        000 004
S_IRWXO        000 007
S_IXGRP        000 010
S_IWGRP        000 020
S_IRGRP        000 040
S_IRWXG        000 070
S_IXUSR        000 100
S_IWUSR        000 200
S_IRUSR        000 400
S_IRWXU        000 700
S_ISVTX        001 000
S_ISGID        002 000
S_ISUID        004 000
S_IFIFO        010 000
S_IFCHR        020 000
S_IFDIR        040 000
S_IFBLK        060 000
S_IFREG        100 000
S_IFLNK        120 000
S_IFSOCK       140 000
S_IFMT         170 000

open() flags in HEX format
O_RDONLY       00 0000  retrievable and settable
O_LARGEFILE    00 0000
O_WRONLY       00 0001  *
O_RDWR         00 0002  *
O_CREAT        00 0040
O_EXCL         00 0080
O_NOCTTY       00 0100
O_TRUNC        00 0200
O_APPEND       00 0400  *+
O_NONBLOCK     00 0800  *+      /* O_NDELAY */
O_DSYNC        00 1000  *
O_ASYNC        00 2000  *+
O_DIRECT       00 4000   +
O_DIRECTORY    01 0000
O_NOFOLLOW     02 0000
O_NOATIME      04 0000   +
O_CLOEXEC      08 0000
O_SYNC         10 1000  *
O_PATH         20 0000
O_TMPFILE      41 0000

SUSv3 specifies that if open() successed, it is guaranteed to use the lowest
numbered unused file descriptor for the process.

O_APPEND makes that all writes happend at the end of the file. even after
changing file offset with lseek() function.

O_ASYNC (signal driven I/O) flag in linux in open function has no effect.
use fcntl() function with F_SETFL operation.

O_EXEC is used with O_CREAT. if file already exists open will return EERROR.
in other words O_EXEC makes sure that it is the current process that
has created the file. in this case pathname must not be symbolic link.

O_NOATIME is for backup and indexing program beacause they don't need to update
inodes repeatedly. _GNU_SOURCE must be set.

It is not permitted to modify (i.e. open for writting) the executable file
associated with a running program.

+---------------------------------------------------------------------------+
| #include <fcntl.h>                                                        |
|                                                                           |
| int creat(const char *pathname, mode_t mode)                              |
+---------------------------------------------------------------------------+

create(pathname, mode) == open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)

System calls don't allocate memory for buffers that are used to return
information to the caller. Instead we must path a pointer to a previously
allocated memory buffer of the correct size.

ssize_t and size_t both are (long) integer data types

read() doesn't place a terminating null byte at the end of the string that
printf() needs.


+---------------------------------------------------------------------------+
| #include <unistd.h>                                                       |
|                                                                           |
| ssize_t read(int fd, void *buffer, size_t count)                          |
|                                                                           |
|                        return number of nytes read, 0 on EOF, -1 on ERROR |
+---------------------------------------------------------------------------+


+---------------------------------------------------------------------------+
| #include <unistd.h>                                                       |
|                                                                           |
| ssize_t write(int fd, void *buffer, size_t count);                        |
|                                                                           |
|                           returns number of bytes written, or -1 on error |
+---------------------------------------------------------------------------+

Kernel performs buffering of disk I/O in order to reduce disk activity,
therefore successful return from write doesn't guarantee that the data has
been transfered to disk.

+---------------------------------------------------------------------------+
| #include <sys/types.h>                                                    |
| #include <dirent.h>                                                       |
|                                                                           |
| int dirfd(DIR *dirp);                                                     |
|                                                                           |
|                  return directory file descriptor on success, -1 on error |
+---------------------------------------------------------------------------+


+---------------------------------------------------------------------------+
| #include <unistd.h>                                                       |
|                                                                           |
| int close(int fd)                                                         |
|                                                                           |
|                                         retunrs 0 on success, -1 on error |
+---------------------------------------------------------------------------+

+---------------------------------------------------------------------------+
| #include <unistd.h>                                                       |
|                                                                           |
| off_t lseek(int fd, off_t offset, int whence);                            |
|                                                                           |
|                      Returns new file offset if succesful, or -1 on error |
+---------------------------------------------------------------------------+

off_t data type is a signed (long) integer type specified by SUS3.

whence: SEEK_SET, SEEK_CUR, SEEK_END (next byte after the last byte)

calling lseek() simply adjusts the kernels record of the file offset associated
with a file descriptor. It does not cause any physical device access.

linux has not a system call that tell us current file offset!

not all files are seekables. pipe, fifo, socket, or terminals are not seekable.
they return with ESPIPE error.

The null character '\0' is not printable.

File holes don't take up any disk space. The file system doesn't allocate any
disk blocks for a hole until at some later point, data is written into it. core
dump files are common examples of files that conatin large holes.

The existence of holes means that a file's nominal size may be larger than the
amount of disk storage it utilizes.

+---------------------------------------------------------------------------+
| #include <fcntl.h>                                                        |
|                                                                           |
| int posix_fallocate(int fd, off_t offset, off_t len);                     |
|                                                                           |
|                     Returns zero on success or an error number on failure |
+---------------------------------------------------------------------------+

none portable, linux-specific system call:
+---------------------------------------------------------------------------+
| #include <fcntl.h>                                                        |
|                                                                           |
| int fallocate(int fd, int mode, off_t offset, off_t len);                 |
|                                                                           |
|                                          Return 0 on success, -1 on error |
+---------------------------------------------------------------------------+

    ! \n and \t are not printable.
The ioctl() system call is a general purpose mechanism for performing file and
device operations that fall outside the universal I/O model.

+---------------------------------------------------------------------------+
| #include <sys/ioctl.h>                                                    |
|                                                                           |
| int ioctl(int fd, int request, ... /* argp */);                           |
|                                                                           |
|              value returned on success depends on request, or -1 on error |
+---------------------------------------------------------------------------+

device specific header files define constants that can be passed in the
request argument.

question: write a program like cp that, when used to copy a regular file that
contains holes (sequence of null bytes), also creates corresponding holes in
the target file.

مثال‌های این فصل

نوشته شده در: 1405-03-10 (1 هفته 21 ساعت 40 دقیقه پیش)

من محسن هستم؛ برنامه‌نویس تفننی!

برای ارتباط با من یا در همین سایت کامنت بگذارید و یا به dokaj.ir(at)gmail.com ایمیل بزنید.

در مورد این مطلب یادداشتی بنویسید.