Chapter 5 File I/O
File I/O
- All system calls are atomic in nature, all steps in that system call either complete or fail
- open takes a flag
O_EXCLwhich means to create the file exclusively when it does not exists.Kernel guarantees that no other process will succed in creating file if this one fails. - Similar things can happen while writing in files that support lseek. Two processes can overwrite data on each other.
fcntl
Signature
1
2
3
#include <fcntl.h>
int fnctl(int fd, int cmd, ...)
- one example is that of
GET_FL. This flag as 2nd arg fetches the FLAG that was used to open the file. - In case one wants to access access bits ,AND with O_ACCMODE . O_ACCMODE is 000000011 that means last two bits only represnt the access bits of read and write
- Kernel maintaisn 3 data structures
- per process file descriptors
- system wide table of open file descriptors
- file system i-node table
- two processes can share file descriptor to same file and sometimes same offset,
dupanddup2can also be used to share.1 2
#include <unistd.h> int dup(int old)
./myscript > results.log 2>&1this would mean redirect both std output and error to log filr, 2 is stderr, 1 is stdoutnewfd = fcntl(oldfd, F_DUPFD, startfd);can also be used to duplicate fd
pread
1
2
3
4
5
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
Returns number of bytes read, 0 on EOF, or –1 on error
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
Returns number of bytes written, or –1 on error
The pread() and pwrite() system calls operate just like read() and write(), except that the file I/O is performed at the location specified by offset This is performed atomically instead of at separatly
readv and writev
1
2
3
4
5
#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
Returns number of bytes read, 0 on EOF, or –1 on error
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
Returns number of bytes written, or –1 on error
- reads from different inuts and populates different buffers, all atomically
preadvandpwritevperforms reads and writes at different positions in buffer.
1
2
3
#include <unistd.h>
int truncate(const char *pathname, off_t length); int ftruncate(int fd, off_t length);
Nonblocking mode can be used with devices (e.g., terminals and pseudoterminals), pipes, FIFOs, and sockets. (Because file descriptors for pipes and sockets are not obtained using open(), we must enable this flag using the fcntl() F_SETFL operation described in Section 5.3.) O_NONBLOCK is generally ignored for regular files, because the kernel buffer cache ensures that I/O on regular files does not block, as described in Section 13.1. How- ever, O_NONBLOCK does have an effect for regular files when mandatory file locking is employed (Section 55.4).
If the file can’t be opened immediately, then open() returns an error instead of blocking. One case where open() can block is with FIFOs (Section 44.7).
After a successful open(), subsequent I/O operations are also nonblocking. If an I/O system call can’t complete immediately, then either a partial data trans- fer is performed or the system call fails with one of the errors EAGAIN or EWOULDBLOCK. Which error is returned depends on the system call. On Linux, as on many UNIX implementations, these two error constants are synonymous.
Large file support
off_tgenerally denotes offset and was limited to maximum of 2GB- since there are large files, LFS was implemented and supported .
We can write applications requiring LFS functionality in one of two ways: - Use an alternative API that supports large files. This API was designed by the LFS as a “transitional extension” to the Single UNIX Specification. Thus, this API is not required to be present on systems conforming to SUSv2 or SUSv3, but many conforming systems do provide it. This approach is now obsolete. - Define the _FILE_OFFSET_BITS macro with the value 64 when compiling our pro- grams. This is the preferred approach, because it allows conforming applica- tions to obtain LFS functionality without making any source code changes.
$ cc -D_FILE_OFFSET_BITS=64 prog.c like so or #define _FILE_OFFSET_BITS 64
/dev/fd
- /dev/fd/{pid} is the file for process
1 2
fd = open("/dev/fd/1", O_WRONLY); fd = dup(1); /* Duplicate standard output */ - As a convenience, the names /dev/stdin, /dev/stdout, and /dev/stderr are provided as symbolic links to, respectively, /dev/fd/0, /dev/fd/1, and /dev/fd/2.
temp files
1
2
#include <stdlib.h>
int mkstemp(char *temp
The template argument takes the form of a pathname in which the last 6 characters must be XXXXXX. char template[] = "/tmp/somestringXXXXXX";
1
2
#include <stdio.h>
FILE *tmpfile(void)