How can I read a file in reverse using read, write, and open only no fwrite or any other f- related methods? Thanks in advance
I do not know where to begin with this. I have tried to look online but they use fopen or fprint or fgets, etc. I only know how to read and write a file.
CodePudding user response:
This should do, if you're using linux:
#include <fcntl.h> /* open() */
#include <unistd.h> /* close(), read(), lseek */
#include <stdio.h>
#define FILE_PATH "/path/to/the/file/to/print"
static void goToPositionInFile(int fileDescriptor, int position)
{
lseek(fileDescriptor, position, SEEK_SET);
}
static void goToEndOfFile(int fileDescriptor)
{
lseek(fileDescriptor, -1, SEEK_END);
}
static int positionInFile(int fileDescriptor)
{
return lseek(fileDescriptor, 0, SEEK_CUR);
}
static void printFileBackwards(int fileDescriptor)
{
char character;
int position;
goToEndOfFile(fileDescriptor);
do
{
position = positionInFile(fileDescriptor);
read(fileDescriptor, & character, 1);
write(1, & character, 1); /* first argument: target file (stdout) */
goToPositionInFile(fileDescriptor, position - 1);
} while (position > 0);
}
static void openAndPrintFileBackwards(char const * const filePath)
{
int fileDescriptor = open(filePath, 0);
printFileBackwards(fileDescriptor);
close(fileDescriptor);
}
int main(void)
{
openAndPrintFileBackwards(FILE_PATH);
return 0;
}
gcc -ansi -Wall -Wextra -Werror foo.c -o foo
./foo
If you want to buffer the file, you'll need an array, to get the required size:
#include <sys/stat.h>
static long fileSizeInBytes(int fileDescriptor)
{
struct stat fileStats;
fstat(fileDescriptor, & fileStats);
return fileStats.st_size;
}
Manuals, if something doesn't work on your system:
man 2 open
man 2 close
man 2 read
man 2 write
man fstat
CodePudding user response:
First, there will always be a TOCTOU bug potential present when reading a file backwards - there's no atomic "read the last byte of the file" functionality. Seeking to the end and then reading is not atomic, nor is using [f]stat()
or any other method to get the size of the file and then reading from offsets based on that number.
When you read a file from the start using a known-unique file descriptor with a known-unique associated file description, simply repeatedly calling read()
until read()
fails to return any data will not suffer from a TOCTOU bug.
With that caveat out of the way, as mentioned in the comments, this is one way to read a file backwards using pread()
(proper headers and error checking omitted to prevent creation of a vertical scroll bar):
ssize_t readBackwards( const char *filename )
{
int fd = open( filename, O_RDONLY );
struct stat sb;
fstat( fd, &sb );
off_t offsetToRead = sb.st_size;
ssize_t totalRead = 0;
while ( offsetToRead > 0 )
{
offsetToRead--;
char c;
ssize_t result = pread( fd, &c, 1, offsetToRead );
totalRead ;
}
close( fd );
return( totalRead );
}