diff --git a/chp2/fopenflags.c b/chp2/fopenflags.c new file mode 100644 index 0000000..bae1670 --- /dev/null +++ b/chp2/fopenflags.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +int main(void) +{ + int fd; + fd = open("test.txt", O_CREAT | O_EXCL); + if (fd == -1) + perror("First open"); + close(fd); + + fd = open("test.txt", O_CREAT | O_EXCL); + if (fd == -1) + perror("Second open"); + close(fd); + + fd = open("test.txt", O_CREAT | O_EXCL); + if (fd == -1) + perror("Third open"); + close(fd); + + fd = open("test.txt", O_CREAT); + if (fd == -1) + perror("Fourth open"); + close(fd); + + return 0; +} diff --git a/chp2/fopenmode.c b/chp2/fopenmode.c new file mode 100644 index 0000000..4ab2c14 --- /dev/null +++ b/chp2/fopenmode.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +int main(void) +{ + int fd; + fd = open("test.txt", O_CREAT | O_EXCL, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); + if (fd == -1) + perror("open"); + close(fd); + + return 0; +} diff --git a/chp2/fpread.c b/chp2/fpread.c new file mode 100644 index 0000000..66621dd --- /dev/null +++ b/chp2/fpread.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#define _XOPEN_SOURCE 500 +#include + +int main(void) { + printf("Try to open file read.txt\n"); + int fd = open("read.txt", O_RDONLY); + if (fd == -1) { + perror("Failed to open read.txt"); + return -1; + } + printf("Open file success\n"); + + int len; + // move file's cursor at the end of file and return bytes + if ((len = lseek(fd, 0, SEEK_END)) == -1) { + perror("Failed to move cursor at end of read.txt file"); + return -1; + } + + // cannot rewind cursor at the start file because pread use "bytes_read_total" for position + + printf("File size of %d bytes\n", len); + + printf("Reading file read.txt\n"); + char buf[len + 1]; + memset(buf, 0, sizeof(buf)); + + size_t bytes_read_total = 0; + ssize_t ret; + while (bytes_read_total < len && (ret = pread(fd, buf, len - bytes_read_total, bytes_read_total)) != -1) { + if (ret == -1) { + if (errno == EINTR) continue; + perror("Failed to read read.txt"); + break; + } + bytes_read_total += ret; + } + + buf[bytes_read_total] = '\0'; + + printf("File text is:\n\"%s\"\n", buf); + + printf("Close file read.txt\n"); + + if (close(fd) == -1) { + perror("Failed to close read.txt"); + return -1; + } + + return 0; +} diff --git a/chp2/fread.c b/chp2/fread.c new file mode 100644 index 0000000..e15d2ba --- /dev/null +++ b/chp2/fread.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +int main(void) { + printf("Try to open file read.txt\n"); + int fd = open("read.txt", O_RDONLY); + if (fd == -1) { + perror("Failed to open read.txt"); + return -1; + } + printf("Open file success\n"); + + int len; + if ((len = lseek(fd, 0, SEEK_END)) == -1) { + perror("Failed to move cursor at end of read.txt file"); + return -1; + } + printf("File size of %d bytes\n", len); + if (lseek(fd, 0, SEEK_SET) == -1) { + perror("Failed to move cursor at start of read.txt file"); + return -1; + } + + printf("Reading file read.txt\n"); + char buf[len + 1]; + memset(buf, 0, sizeof(buf)); + + size_t bytes_read_total = 0; + ssize_t ret; + while (bytes_read_total < len && (ret = read(fd, buf + bytes_read_total, len - bytes_read_total)) != 0) { + if (ret == -1) { + if (errno == EINTR) continue; + perror("Failed to read read.txt"); + break; + } + bytes_read_total += ret; + } + + buf[bytes_read_total] = '\0'; + + printf("File text is:\n\"%s\"\n", buf); + + printf("Close file read.txt\n"); + + if (close(fd) == -1) { + perror("Failed to close read.txt"); + return -1; + } + + return 0; +} diff --git a/chp2/ftruncate.c b/chp2/ftruncate.c new file mode 100644 index 0000000..b80f90e --- /dev/null +++ b/chp2/ftruncate.c @@ -0,0 +1,13 @@ +#include +#include + +int main(void) { + int ret; + + ret = truncate("./pirate.txt", 45); + if (ret == -1) { + perror("truncate"); + return -1; + } + return 0; +} diff --git a/chp2/pirate.txt b/chp2/pirate.txt new file mode 100644 index 0000000..3c2bedc --- /dev/null +++ b/chp2/pirate.txt @@ -0,0 +1,2 @@ +Edward Teach was a notorious English pirate. +He was nicknamed Blackbeard. diff --git a/chp2/poll.c b/chp2/poll.c new file mode 100644 index 0000000..2c8ebfa --- /dev/null +++ b/chp2/poll.c @@ -0,0 +1,38 @@ +#include +#include +#include + +#define TIMEOUT 5 /* poll timeout, in seconds */ + +int main(void) { + struct pollfd fds[2]; + int ret; + + /* watch stdin for input */ + fds[0].fd = STDIN_FILENO; + fds[0].events = POLLIN; + + /* watch stdout for ability to write (almost always true) */ + fds[1].fd = STDOUT_FILENO; + fds[1].events = POLLOUT; + + /* All set, block! */ + ret = poll(fds, 2, TIMEOUT * 1000); + if (ret == -1) { + perror("poll"); + return 1; + } + + if (!ret) { + printf("%d seconds elapsed.\n", TIMEOUT); + return 0; + } + + if (fds[0].revents & POLLIN) + printf("stdin is readable\n"); + + if (fds[1].revents & POLLOUT) + printf("stdout is writable\n"); + + return 0; +} diff --git a/chp2/read.txt b/chp2/read.txt new file mode 100644 index 0000000..8ab686e --- /dev/null +++ b/chp2/read.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/chp2/select.c b/chp2/select.c new file mode 100644 index 0000000..0a5c021 --- /dev/null +++ b/chp2/select.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +#define TIMEOUT 5 +#define BUF_LEN 1024 + +int main(void) { + struct timeval tv; + fd_set readfds; + int ret; + + /* Wait on stdin for intput. */ + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + + /* Wait up to file seconds */ + tv.tv_sec = TIMEOUT; + tv.tv_usec = 0; + + /* All right, now block! */ + ret = select( + STDIN_FILENO + 1, + &readfds, + NULL, + NULL, + &tv + ); + if (ret == -1) { + perror("select"); + return 1; + } else if (!ret) { + printf("%d seconds elapsed.\n", TIMEOUT); + return 0; + } + + /* + * Is our file descriptor ready to read? + * (It must be, as it was the only fd that + * we provided and the call returned + * nonzero, but we will humor ourselves.) + */ + if (FD_ISSET(STDIN_FILENO, &readfds)) { + char buf[BUF_LEN+1]; + int len; + + /* guaranteed to not block */ + len = read(STDIN_FILENO, buf, BUF_LEN); + if (len == -1) { + perror("read"); + return 1; + } + + if (len) { + buf[len] = '\0'; + printf("read: %s\n", buf); + } + + return 0; + } + + fprintf(stderr, "This should not happen!\n"); + return 1; +} diff --git a/chp2/select_regular_files.c b/chp2/select_regular_files.c new file mode 100644 index 0000000..42a0039 --- /dev/null +++ b/chp2/select_regular_files.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define FILE_NUMBER 3 +#define FILENAME_MAX_LEN 10 +#define TIMEOUT 10 +#define BUF_LEN 1024 + +int create_tmp_file(char *filename); +void cleanup(char *filenames[]); + +int main(void) { + int exit_code = 0; + char *filename_template = "test%d.txt"; + char *filenames[FILE_NUMBER] = {NULL}; + int fds[FILE_NUMBER] = {0}; + + // Create a bunch of number ephemeral files + for (int i = 0; i < FILE_NUMBER; i++) { + char *filename = (char *)malloc(FILENAME_MAX_LEN*sizeof(char)); + if (!filename) { + perror("malloc failed"); + exit_code = -1; + goto exit; + } + snprintf(filename, FILENAME_MAX_LEN, filename_template, i+1); + filenames[i] = filename; + printf("Opening file %s...\n", filename); + fds[i] = create_tmp_file(filename); + if (fds[i] == -1) { + fprintf(stderr, "Error to open file %s: %s\n", filename, strerror(errno)); + exit_code = -1; + goto exit; + } + printf("Open file %s with file descriptor %d\n", filename, fds[i]); + + // write something in the files + dprintf(fds[i], "Hello I am %s\n", filename); + } + + fd_set readfds; + FD_ZERO(&readfds); + for (int i = 0; i < FILE_NUMBER; i++) { + FD_SET(fds[i], &readfds); + } + + struct timeval *timeout = (struct timeval *)malloc(sizeof(struct timeval)); + timeout->tv_sec = TIMEOUT; + timeout->tv_usec = 0; + + /* This function do not work with regular files because for the operating system, + * a regular file is ready always. + * This example is wrong the best way to use select() is with socket, pipe or other channel types. + */ + int ret = select( + FILE_NUMBER + 1, + &readfds, + NULL, + NULL, + timeout + ); + + if (ret == -1) { + fprintf(stderr, "Error to select: %s\n", strerror(errno)); + exit_code = 1; + goto exit; + } else if (!ret) { + fprintf(stderr, "%d seconds elapsed.\n", TIMEOUT); + exit_code = 1; + goto exit; + } + + for (int i = 0; i < FILE_NUMBER; i++) { + int fd = fds[i]; + if (FD_ISSET(fd, &readfds)) { + char buf[BUF_LEN+1]; + int len = read(fd, buf, BUF_LEN); + if (len == -1) { + fprintf(stderr, "Error reading file %s: %s\n", filenames[i], strerror(errno)); + exit_code = 1; + goto exit; + } + if (len) { + buf[len] = '\0'; + printf("%s:\n%s\n", filenames[i], buf); + } + } + } + +exit: + // Closing and remove all creating files + for (int i = 0; i < FILE_NUMBER; i++) { + int fd = fds[i]; + printf("Close file with file descriptor %d\n", fd); + if (close(fd) == -1) { + fprintf(stderr, "Error to close file %d: %s\n", fd, strerror(errno)); + } + } + + free(timeout); + timeout = NULL; + + printf("Cleanup files\n"); + cleanup(filenames); + + return exit_code; +} + +int create_tmp_file(char *filename) { + int fd = open(filename, O_CREAT | O_EXCL | O_RDWR, 0644); + if (fd == -1) { + return -1; + } + return fd; +} + +void cleanup(char *filenames[]) { + for (int j = 0; j < FILE_NUMBER; j++) { + if (filenames[j] != NULL) { + if (remove(filenames[j]) == -1) + fprintf(stderr, "Failed to remove %s: %s\n", filenames[j], strerror(errno)); + free(filenames[j]); + filenames[j] = NULL; + } + } +}