I tried to use the system call lseek() to get back the beginning of a file or reach the end of the file.
The exact code I used is:
int location = lseek(fd, 0, SEEK_SET) //get back to the beginning
int location = lseek(fd, 0, SEEK_END) //reach to the end
However, after the file location has been reset, whenever I tried to use read(), the return value of read() is always set to -1, which means something was wrong. Furthermore, the errno message I got was Bad file descriptor. Does anyone know what should I do?
PS: I tried to close and reopen the file to help me get back to the beginning of the file and it worked. But I have no ideas on how should I get to the end of the file and read the entire file in the reverse order without using lseek().
Plus: a reproducible example would be:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int fd;
char buffer[1000];
fd = creat("newFile", 0777);
memset(buffer, 'a', 500);
write(fd, buffer, 500); // fill up
int location = lseek(fd, 0, SEEK_SET); //get back to the beginning
int read_bytes = read(fd, buffer, 500);
// this should return the bytes it reads but it actually returns -1
printf("%d\n", read_bytes);
return 0;
}
The creat function does not allow you to read from the file. It only allows you to write to it.
From creat(2):
creat()
A call to creat() is equivalent to calling open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.
The important part here is O_WRONLY. That means "write only".
If you want to open the file (and create it) for reading and writing, then you can use open like so:
int fd = open("newFile", O_CREAT|O_RDWR|O_TRUNC, 0777);
The important part here is O_RDWR. That means "read and write".
If you want to have open give an error if the file already exists, add the O_EXCL flag; this causes -1 to be returned and errno to be set to EEXIST if the file already exists when you try to create it.
The following proposed code:
cleanly compiles
properly declares the variable types
properly creates the file
properly includes the needed header files
properly checks for error indications from C library functions (and properly handles any error)
And now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int fd;
char buffer[1000];
// fd = creat("newFile", 0777);
fd = open("newFile", O_CREAT|O_RDWR|O_TRUNC, 0777);
if( fd < 0 )
{
perror( "open failed" );
exit( EXIT_FAILURE );
}
memset(buffer, 'a', 500);
write(fd, buffer, 500); // fill up
off_t location = lseek(fd, 0, SEEK_SET); //get back to the beginning
printf( "%ld\n", location );
ssize_t read_bytes = read(fd, buffer, 500);
if( read_bytes < 0 )
{
perror( "read failed" );
exit( EXIT_FAILURE );
}
// this should return the bytes it reads but it actually returns -1
printf("%ld\n", read_bytes);
return 0;
}
A run of the program results in:
0
500
Suggest reading/understanding the MAN pages for any C library functions your code uses
Related
I am trying to understand how glib's gzip functions works. So I wrote a small program to simulate what I need.
what I need is:
I need to open and store the file descriptor and when ever I want to just pass the fd and open a gzFile using a dupped fd and then close it. so that my original fd remains open for future read.
I've gone through lib manual here!
It says that:
"If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails."
I am doing the same as part of my below given code, where I am reading one character every time and closing the fd so that I can use it in future.
Here's My Code with gzFile that does not work:
#include <stdio.h>
#include <zlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
int ouFd1;
int inpFd1;
int main( int argc, char ** argv )
{
// Open a file to write the data
inpFd1 = open("temp.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
char* str = (char*)"Anil Prasad.";
gzFile gzfile = gzdopen(inpFd1, "wb9h");
int len = gzwrite(gzfile, &(str[0]), strlen(str));
printf("written length: %d\n", len);
gzclose(gzfile);
// open a file to read the data.
ouFd1 = open("temp.txt", O_RDONLY);
char b[1];
while (len > 0) {
int ouFd1_dup = dup(ouFd1);
gzFile gzFile_2 = gzdopen(ouFd1_dup, "rb");
int r = gzread(gzFile_2, &(b[0]), 1);
printf("Character : %c\n", b[0]);
len--;
gzclose(gzFile_2);
}
fsync(ouFd1);
close(ouFd1);
}
The output of this is:
Character : A
Character : A
Character : A
Character : A
Character : A
Character : A
Character : A
Character : A
Character : A
Character : A
Character : A
Character : A
Can some help me understand why offset is not moving after I do a gzread()?
Or is it getting reset when I am doing gzclose(gzFile_2);?
I've tried moving offset as well like:
while (len > 0) {
int ouFd1_dup = dup(ouFd1);
gzFile gzFile_2 = gzdopen(ouFd1_dup, "rb");
int r = gzread(gzFile_2, &(b[0]), 1);
gzseek(gzFile_2, 1, SEEK_CUR);
printf("Character : %c\n", b[0]);
len--;
gzclose(gzFile_2);
}
But results remains same!
Can someone help me with this?
You are opening and closing the file within the loop - this will reset the file pointer to the beginning on each iteration.
I don't think you need to duplicate the file descriptor for what your doing. You could just use gzopen("temp.txt", "rb") and use the file pointer given.
You are also using a buffer of size 1 - you could get the size of the file first and read into a buffer of appropriate size.
I would do something like this:
// Create buffer
char *buffer = new char[len+1];
memset(buffer, 0, len);
//Open file
gzFile * file = gzopen("temp.txt", "rb");
gzread(file, buffer, len);
printf("%s\n", buffer);
//Close file
gzclose(file);
//Delete buffer
delete [] buffer;
I try to create file using open(), then move 1MB with lseek() and finally need to write 1 byte into that file.
There is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int f_open(const char *name);
int f_open(const char *name){
int dskr;
dskr = open( name, O_CREAT );
if( dskr == -1 ){
perror( name );
exit(1);
}
printf( "dskr = %d\n", dskr );
return dskr;
}
int main( int argc, char *argv[] ){
int d;
int f;
char buf[20];
if( argc != 2 ){
printf( "Naudojimas:\n %s failas_ar_katalogas\n", argv[0] );
exit( 255 );
}
d = f_open( argv[1] );
lseek( d, 1, SEEK_SET );
f = write( d, buf, 1);
return 0;
}
File created correctly, but I am not sure if move 1MB works good and also write not working. I am not sure because program runs correctly but the size of it is 0.
What am I doing wrong?
A few bugs:
dskr = open( name, O_CREAT );
The flags to open() must include one of O_RDONLY, O_WRONLY or O_RDWR. So you probably want O_WRONLY | O_CREAT.
lseek( d, 1, SEEK_SET );
The offset to lseek is in bytes. If you want to seek 1 megabyte, you have to convert that into bytes. A convenient and readable way is to write 1024*1024.
Also, you ought to check the return value of lseek and report any errors appropriately.
f = write( d, buf, 1);
You never initialized buf[0], so you are writing one byte of garbage. (Anyway, there is no point in having buf be 20 bytes if you are never going to use the other 19.)
Also, you ought to check the return value of write and handle errors or short writes appropriately.
I'm new in the area of memory mapped and I was wondering if there is any way I can read a text file using memory mapped to a string. I don't really know how to start to write the code.
The general idea with memory mapped I/O is that you tell the operating system (OS) what file you want, and it (after doing some amount of set-up work) tells you where that file now is in memory.
Once that contract is performed, you should be able to copy things to and from that memory in any way you wish (such as with memcpy), and it will magically handle the I/O for you.
Detail depends on which OS you're using since the ISO C standard doesn't specify this behaviour - it's therefore OS-specific.
For example, Windows uses a file mapping paradigm shown here, while Linux uses mmap to allow you to subject a file you've already opened to memory mapping (via its file descriptor).
By way of example, this Linux program, a little voluminous due mainly to its error checking and progress reports, memory maps the file.txt file and outputs its content:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
// Helper function to minimise error code in main.
static int clean(
int retVal, // value to return.
char *err, // error/NULL, allows optional %s for strerror(errno).
int fd, // fd/-1 to close.
void *filMem, // memory/NULL to unmap.
off_t sz, // size if unmapping.
void *locMem // memory/NULL to free.
) {
if (err) printf (err, strerror(errno));
if (locMem) free(locMem);
if (filMem) munmap(filMem, sz);
if (fd >= 0) close(fd);
return retVal;
}
int main(void) {
int fd = open("file.txt", O_RDONLY);
if (fd < 0) return clean(-1, "Can't open: %s\n", -1, NULL, 0, NULL);
printf("File opened okay, fd = %d.\n", fd);
off_t sz = lseek(fd, 0, SEEK_END);
if (sz == (off_t) -1) return clean(-1, "Can't seek: %s\n", fd, NULL, 0, NULL);
printf("File size is %ld.\n", sz);
void *fileArea = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
if (! fileArea) return clean(-1, "Can't map: %s\n", fd, NULL, 0, NULL);
printf("File mapped to address %p.\n", fileArea);
char *localArea = calloc(1, sz + 1);
if (! localArea) return clean(-1, "Can't allocate\n", fd, fileArea, sz, NULL);
memcpy(localArea, fileArea, sz);
printf("Data copied to %p, result is [\n%s]\n", localArea, localArea);
return clean(0, NULL, fd, fileArea, sz, localArea);
}
Running that on my local system, the results can be seen from the following transcript:
pax$ cat file.txt
...This is the input file content.
pax$ ./testprog
File opened okay, fd = 3.
File size is 35.
File mapped to address 0x7f868a93b000.
Data copied to 0x1756420, result is [
...This is the input file content.
]
I was asked to find the size of the file usjng lseek command (without using stat) and i wrote the following code
int main()
{
char buf[100], fn[10];
int fd, i;
printf("Enter file name\n");
scanf("%s", fn);
fd = open(fn, O_RDONLY);
int size = lseek(fd, 0, SEEK_END);
printf("Size is %d", size);
close(fd);
}
But i am getting -1 as file size, where am i going wrong
From lseek documentation available online:
RETURN VALUE
Upon successful completion, lseek() returns the resulting offset
location as measured in bytes from the beginning of the file. On
error, the value (off_t) -1 is returned and errno is set to indicate
the error.
So you have to check the errno (print it if lseek returns -1):
The list of possible errors from the same link:
ERRORS
EBADF fd is not an open file descriptor.
EINVAL whence is not valid. Or: the resulting file offset would be
negative, or beyond the end of a seekable device.
ENXIO whence is SEEK_DATA or SEEK_HOLE, and the file offset is
beyond the end of the file.
EOVERFLOW The resulting file offset cannot be represented in an off_t.
ESPIPE fd is associated with a pipe, socket, or FIFO.
In your case, it is most likely EBADF.
the following proposed code:
cleanly compiles
properly checks for errors
performs the desired functionality
uses proper variable typing
and now the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main( void )
{
char fn[10];
int fd;
printf("Enter file name\n");
if( scanf("%9s", fn) != 1 )
{
fprintf( stderr, "scanf for file name failed\n" );
exit( EXIT_FAILURE );
}
if( (fd = open(fn, O_RDONLY) ) < 0 )
{
perror( "open failed" );
exit( EXIT_FAILURE );
}
off_t size = lseek(fd, 0, SEEK_END);
printf("Size is %ld", size);
close(fd);
}
I am attempting to open files and append to them using C. I am dynamically naming the directory based on process Id and creating the filenames based on the "room" that has been randomly selected in the loop. My intention is to open the file, append the room name into the file, and then close the file and move to the next room and perform the same function. The issue I am having is with "open". It seems to only be returning -1, which indicates an error. The error message is stating "Permission denied". I am confused by this because I appear to be setting the proper permissions in the open function. I tried using fopen(), but that kept producing a segmentation fault 11. Is there an issue with my roomFilePath declaration and usage or is my usage of open incorrect? Here is the portion of the code that contains the issue. The makeRooms() function is where I check to see if the file was opened correctly. Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#define NUM_ROOMS 10
#define NUM_USED_ROOMS 7
#define MAX_CONNECTIONS 6
time_t t;
char* usedRooms[NUM_USED_ROOMS];
int i;
char directoryName[100];
char* baseDirectory = "walterer.rooms.";
int processId;
char roomFilePath[75];
int adjacencyMatrix[7][7] = {0};
int useableConnections;
int e;
int totConnections = 0;
int openRoom;
int file_descriptor;
char* roomNames[] = {
"cleveland",
"columbus",
"dallas",
"toledo",
"miami",
"sarasota",
"boston",
"chicago",
"denver",
"phoenix"
};
int connections[10] = {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
void makeDirectory() {
processId = getpid();
sprintf(directoryName, "%s%d", baseDirectory,processId);
//printf("%s\n", directoryName);
mkdir(directoryName, 777);
}
void makeRooms() {
/* Initializes random number generator */
srand((unsigned) time(&t));
/* Create 7 rooms */
for(i = 0; i < NUM_USED_ROOMS; ){
/* Generate random number between 0 to 10 */
int randomNumber = rand() % NUM_ROOMS;
/* Loop as long the array does not contain any connections at the index */
while(connections[randomNumber] == 0) {
/* Append the room path to the end of my ONID path */
sprintf(roomFilePath,"%s/%s", directoryName, roomNames[randomNumber]);
printf("%s\n",roomFilePath);
/* Create file */
FILE *filePointer;
/* Open file to append*/
//filePointer = open(roomFilePath, O_WRONLY | O_CREAT, 0600);
//!!!Returning -1
file_descriptor = open(roomFilePath, O_APPEND, 0600);
printf("%d\n",file_descriptor);
if (file_descriptor == -1)
{
printf("open() failed on \"%s\"\n", roomFilePath);
perror("In createRooms()");
exit(1);
}
/*if (filePointer == NULL)
{
fprintf(stderr, "Error Creating File\n");
printf("something went wrong with read()! %s\n", strerror(errno));
}*/
/* Print the room name in the file */
/* SEG FAULT HERE!!!! */
fprintf(filePointer, "ROOM NAME: %s\n", roomNames[randomNumber]);
/* Close the file */
//fclose(filePointer);
usedRooms[i] = roomNames[randomNumber];
connections[randomNumber] = 1;
//printf("Room %d is %s \n", i+1, roomNames[randomNumber]);
i++;
}
}
}
First, you're missing part of the required flags argument to open() in this line:
file_descriptor = open(roomFilePath, O_APPEND, 0600);
The only open() flag you're passing is O_APPEND, but open() also requires at least one of the O_RDONLY, O_WRONLY, O_RDWR, O_EXEC, or O_SEARCH flags. (the last two are rarely used.)
Your code should be something like
file_descriptor = open(roomFilePath, O_RDONLY | O_APPEND, 0600);
Per the POSIX standard for open():
SYNOPSIS
#include <sys/stat.h> #include <fcntl.h>
int open(const char *path, int oflag, ...);
...
Values for oflag are constructed by a bitwise-inclusive OR of flags
from the following list, defined in <fcntl.h>. Applications shall
specify exactly one of the first five values (file access modes) below
in the value of oflag:
O_EXEC
Open for execute only (non-directory files). The result is
unspecified if this flag is applied to a directory.
O_RDONLY
Open for reading only.
O_RDWR
Open for reading and writing. The result is undefined if this flag
is applied to a FIFO.
O_SEARCH
Open directory for search only. The result is unspecified if this
flag is applied to a non-directory file.
O_WRONLY
Open for writing only.
In your posted code, of course you get a segmentation fault at this line:
/* SEG FAULT HERE!!!! */
fprintf(filePointer, "ROOM NAME: %s\n", roomNames[randomNumber]);
The filePointer variable has not been initialized in your posted code, so using the value causes a segmentation fault.