Created
June 19, 2020 23:08
-
-
Save caiorss/05fbba6475cca1dbdd50bbb2bd5ac8ae to your computer and use it in GitHub Desktop.
Unix low level IO - file descriptor syscalls
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <cstring> // Import: char* strerror(in errnum); | |
const char* | |
errno_to_cstring(int err) | |
{ | |
// No such file or directory | |
if(err == ENOENT) return "ENOENT"; | |
// Operation not permitted | |
if(err == EPERM) return "EPERM"; | |
// Onput/Output error | |
if(err == EIO) return "EIO"; | |
if(err == EAGAIN) return "EAGAIN"; | |
if(err == EPERM) return "EPERM"; | |
if(err == EPIPE) return "EPIPE"; | |
return "<UNKNOWN>"; | |
} | |
/** Check whether file descriptor is regular file */ | |
bool fd_is_regular_file(int fd) | |
{ | |
struct stat fd_info; | |
// int fstat(int fd, struct stat *statbuf); | |
int r = fstat(fd, &fd_info); | |
return S_ISREG(fd_info.st_mode); | |
} | |
bool fd_is_directory(int fd) | |
{ | |
struct stat fd_info; | |
// int fstat(int fd, struct stat *statbuf); | |
int r = fstat(fd, &fd_info); | |
return S_ISDIR(fd_info.st_mode); | |
} | |
void print_errno_details(int err) | |
{ | |
std::fprintf(stderr , "\n => errno(int) = %d" | |
"\n => errno(str) = %s" | |
"\n => errno message = %s \n" | |
, err, errno_to_cstring(err), strerror(err)); | |
std::fflush(stderr); | |
} | |
int main(int argc, char** argv) | |
{ | |
std::puts(" [INFO] Program started. "); | |
if(argc < 3){ | |
std::fprintf(stderr, " Usage: \n"); | |
std::fprintf(stderr, " => To read a file: \n"); | |
std::fprintf(stderr, " $ %s file <FILE> \n", argv[0]); | |
std::fprintf(stderr, " => To read stdin (console input): \n"); | |
std::fprintf(stderr, " $ %s file -stdin \n", argv[0]); | |
return 0; | |
} | |
// Compare two c-strings return 0 (zero) when they are equal. | |
// int strcmp(const char *s1, const char *s2) | |
if( strcmp(argv[1], "file") != 0 ) | |
{ | |
std::fprintf(stderr, " [ERROR] Expected command file. \n"); | |
return EXIT_FAILURE; | |
} | |
// Variable for holding a file descriptor | |
int fd; | |
// The library-call open() attempts to open a file and returns a "file-descriptor" | |
// (integer number ) when the operation is successful. The library-call | |
// returns (-1) when the operation fails. | |
// Note: It encapsulates the 'open' system call. | |
// | |
if( strcmp(argv[2], "-stdin") == 0) | |
fd = STDIN_FILENO; | |
else | |
fd = open(argv[2], O_RDONLY); | |
if(fd == -1){ | |
// Get error flag 'errno' to get more details about current error. | |
int err = errno; | |
std::fprintf(stderr ," [ERROR] Failed to open file. "); | |
print_errno_details(err); | |
return EXIT_FAILURE; | |
} | |
std::fprintf(stdout, " [INFO] ?? File is regular file = %s \n" | |
, fd_is_regular_file(fd) ? "TRUE" : "FALSE" ); | |
std::fprintf(stdout, " [INFO] ?? File is directory file = %s \n" | |
, fd_is_directory(fd) ? "TRUE" : "FALSE" ); | |
// Flush file => Force changes to be immeditely written. | |
std::fflush(stdout); | |
// Buffer maximum size in bytes | |
constexpr size_t BUFFER_MAX_SIZE = 200; | |
char buffer[BUFFER_MAX_SIZE]; | |
// Stream BUFFER_MAX_SIZE bytes from file descriptor | |
// to STDOUT_FILENO (file descriptor). | |
//--------------------------------------------------- | |
ssize_t ret; | |
do { | |
ret = read(fd, buffer, BUFFER_MAX_SIZE); | |
if(ret == -1) { | |
int err = errno; | |
std::fprintf(stderr, " [ERROR] An error has happened => "); | |
print_errno_details(err); | |
close(fd); | |
return EXIT_FAILURE; | |
} | |
::write(STDOUT_FILENO, buffer, ret); | |
} while( ret != 0); | |
// Always close the file descriptor. | |
close(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment