Skip to content

Instantly share code, notes, and snippets.

@caiorss
Created June 19, 2020 23:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caiorss/05fbba6475cca1dbdd50bbb2bd5ac8ae to your computer and use it in GitHub Desktop.
Save caiorss/05fbba6475cca1dbdd50bbb2bd5ac8ae to your computer and use it in GitHub Desktop.
Unix low level IO - file descriptor syscalls
#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