150 likes | 447 Views
File and I/O system calls int open(const char* path, int flags, mode_t modes) int creat(const char *path, mode_t mode) ssize_t read(int fd, void *buf, size_t nbyte) ssize_t write(int fd, const void *buf, size_t nbyte) int close(int fd) off_t lseek(int fd, off_t offset, int reference)
E N D
File and I/O system calls int open(const char* path, int flags, mode_t modes) int creat(const char *path, mode_t mode) ssize_t read(int fd, void *buf, size_t nbyte) ssize_t write(int fd, const void *buf, size_t nbyte) int close(int fd) off_t lseek(int fd, off_t offset, int reference) int stat(const char *file_name, struct stat *buf)
Each process records all the files opened in its context, the file descriptor table in the process table entry. Process context process descriptor file descriptor table 0 1 2 3 4 File info file descriptor table contains all the files opened by the process
open/creat: find the first empty slot in the file descriptor table, use the slot to store a pointer to the file information. • Linear search • close(fd) : among other things, makes the entry fd in the file descriptor table available. • read/write: get the file information (such as current position) through the file descriptor table.
//example1.cpp #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <iostream> using namespace std; main() { int f1, f2, f3, f4, f5, f6; f1 = open(“open.cpp”, O_RDONLY); cout << “f1 = “ << f1 << “\n”; f2 = open(“open.cpp”, O_RDONLY); cout << “f2 = “ << f2 << “\n”; f3 = open(“open.cpp”, O_RDONLY); cout << “f3 = “ << f3 << “\n”; close(f1); f4 = open(“open.cpp”, O_RDONLY); cout << “f4 = “ << f4 << “\n”; } Why f1 = 3, but not 1?
First three slots in the file descriptor table are occupied for standard I/O operation when the process is created. • Slot 0 ==> for standard input. • Slot 1 ==> for standard output. • Slot 2 ==> for standard error. • Every time UNIX searches for an available slot in the open file table, it does a linear search starting from slot 0. • The return of the first open == ?
Slots 0, 1, and 2 in the file descriptor table • used for standard I/O • They can be used just like regular files. Main() { main() { cout << “hello, world!!\n”; ==> write(1, “hello, world!!\n”, } strlen(“hello, world!!\n”); } // example2.cpp • no need to open and close files 0, 1, 2 -- taken care of by the OS when it creates the process.
Let us redo the following program with read calls: main() { int I; cin >> I; cout << I; } See example2a.cpp
What if we close the standard I/O files? • See example2b.cpp. • Lost I/O capability!!
What if we close the standard I/O files and open files again? • What is return value of the open call? • See example4.cpp • Now what happens when you do cout in example4.cpp? • This is called I/O redirection, instead of read from keyboard and print to the screen, cin will read from a file and cout will print to a file!!
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <iostream.h> main() { int f1, f2, f3, f4, f5, f6; f1 = open(“open.cpp”, O_RDONLY); cout << “f1 = “ << f1 << “\n”; f2 = open(“open.cpp”, O_RDONLY); cout << “f2 = “ << f2 << “\n”; close(1); f3 = open(“aaa”, O_RDONLY | O_WRONLY | O_CREAT, 0666); cout << “f3 = “ << f3 << “\n”; cerr << “f3 = “ << f3 << “\n”; } // example4.cpp, Output redirection What happens in This program?
Another way of redirect a file into standard I/O • Duplicate an file descriptor: dup() • #include <unistd.h> • int dup(int fd); • return a new file descriptor having the common open file, file pointer and access mode with fd. • Note: UNIX does a linear search in the file descriptor table for the available slot.
Difference between dup and open/create (Why dup instead of open) • Using dup, the file position of the two duplicated open files is shared. • Using open one file two times, there are two file positions for the two open files (open file != file) • See extra1.cpp and extra2.cpp.
Using dup() to do standard I/O redirection. Implementing I/O redirection #include <fcntl.h> #include <unistd.h> #include <iostream> #include <stdio.h> #include <stdlib.h> main() { char buf[100]; int fd; fd = open(“tmp111”, O_CREAT|O_WRONLY, 00777); close(1); dup(fd); close(fd); cout << “what is going on?\n”; cerr << “1111111\n”; } // example5.cpp
execv system call revisit: • format: int execv(const char *path, char * argv[]) • Wipe out the original process and load the new • executable path into memory and execute path. • When the system call execv is successful, every thing after the execv call in the original program will NOT be executed. • Wipe out everything??? NOT precise!!!!! • The open file descriptor table remains unchanged -->implication? • If you do something to the file descriptor table before you call execv, you can redirect the standard I/O in the command to be executed!!!
void runcommand(char *cmd, char*argv[], char* readfile, char* writefile) { int status; if (fork() == 0) { if (readfile != NULL) { int fd = open(readfile, O_RDONLY); if (fd == -1) {cerr << “error\n”, exit(0);} close(0); dup(fd); close(fd); } if (writefile != NULL) { int fd = open(writefile, O_CREAT | O_WRONLY, 00777); if (fd == -1) {cerr << “error\n”, exit(0);} close(1); dup(fd); close(fd); } int stat = execv(cmd, argv); if (stat == (-1)) {cerr << “error\n”, exit(10);} } int stat = wait(&status); if (stat == -1) {cerr << “error return from wait\n”;} } // example6.cpp Running cmd with I/O redirection