Im trying to create a new file / overwrite an existing file using systemcalls , but for some reason I have two problems:
1. When I'm first running the program it exits with value 0, so it seems like it created the file successfully, but I can't see anything in my project directory.
then when I secondly running the program the file is created, but an error message is printed on the screen.
2. Also after the first iteration of the program, I can't see the prinf message at the end of the main function.
Thanks for helping.
int readFileDesc = 0, writeFiledesc = 0;
int sourceFile = 1, destFile = 2, bufferSize = 3, isOverwrite;
if (argc != 4 && argc != 5) {
printf("Invalid number of arguments\n");
printf("Usage:\n");
printf(" ex1 [-f] SOURCE DEST BUFFER_SIZE");
exit(EXIT_FAILURE);
}
//Checking if -f [OP] is activated.
isOverwrite = (strcmp(argv[1], "-f") == 0);
if (isOverwrite) {
sourceFile++;
destFile++;
bufferSize++;
}
//Opening the source file
readFileDesc = open(argv[sourceFile], O_RDONLY);
if (readFileDesc < 0) {
perror("Unable to open source file for reading: ");
exit(EXIT_FAILURE);
}
//opening the destination file
if (!isOverwrite) {
//Case we dont have the -f [op] so we create the file.
writeFiledesc = open(argv[destFile],
O_CREAT | O_EXCL | O_WRONLY ,
S_IRUSR | S_IWUSR);
if (writeFiledesc < 0) {
perror("Unable to open destination file for reading: ");
exit(EXIT_FAILURE);
}
} else {
//Case we have the -f [op] so we override existing file.
writeFiledesc = open(argv[destFile], O_RDONLY | O_WRONLY | O_TRUNC);
if (writeFiledesc < 0) {
perror("Unable to open destination file for writing: ");
exit(EXIT_FAILURE);
}
}
//Assume the buffersize is legal.
bufferSize = atoi(argv[bufferSize]);
char data[bufferSize];
int nread, nwrite;
while ((nread = read(readFileDesc, data, bufferSize)) > 0) {
if ((nwrite = write(writeFiledesc, data, nread)) != nread) {
printf("write problem: ");
}
}
// cant see this!
printf("File %s was copied to %s" , argv[sourceFile] , argv[destFile]);
//handling errors
close(sourceFile);
close(destFile);
return EXIT_SUCCESS;
}
This is wrong:
writeFiledesc = open(argv[destFile], O_RDONLY | O_WRONLY | O_TRUNC);
Using both O_RDONLY and O_WRONLY is wrong. You need to use O_RDWR.
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 . 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.
Any combination of the following may be used:
...
Also, read() and write() return ssize_t, not int.
Related
This question already has an answer here:
Using open(), read() and write() system calls to copy a file
(1 answer)
Closed last year.
I am trying to implement the cp command only using read/write system calls.
Here is my code:
/**
* cp file1 file 2
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int errsv;
char contents[1024];
int fd_read, fd_write;
fd_read = open(argv[1], O_RDONLY);
if (fd_read == -1)
{
errsv = errno;
printf("Error occured: %d\n", errsv);
}
read(fd_read, contents, sizeof(contents));
fd_write = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0744);
if (fd_write == -1)
{
errsv = errno;
printf("Error occured: %d\n", errsv);
}
write(fd_write, contents, sizeof(contents));
close(fd_read);
close(fd_write);
return 0;
}
I tested the code using the commands:
cc test.c
./a.out file1 file2
Here is my file1:
dummy text
dummy text
After running the code, although file2 contains the text from file1, it also has some gibberish characters. [not keeping this here.]
Why is this so?
You need to call read() and write() in a loop to copy the entire file. read() returns 0 when you reach EOF, or a negative result if there's an error, then you can end the loop.
read() returns the number of bytes that were read, which may be less than the size of the buffer. You need to use that number when calling write(), otherwise you'll write extra characters to the output file. These will be unitialized characters on the first iteration, and on other iterations they'll be left over characters from previous iterations.
int main(int argc, char *argv[])
{
char contents[1024];
int fd_read, fd_write;
fd_read = open(argv[1], O_RDONLY);
if (fd_read == -1)
{
perror("open input file");
exit(1);
}
fd_write = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0744);
if (fd_write == -1)
{
perror("open output file");
exit(1)
}
int n_read;
while ((n_read = read(fd_read, contents, sizeof(contents))) > 0) {
write(fd_write, contents, n_read);
}
close(fd_read);
close(fd_write);
return 0;
}
write(fd_write, contents, strlen(contents));
Strlen returns the filled entries number but sizeof returns the buffer size which is 1024
I've written a simplified "cat" function in C. It is working fine, except when one of my argument is the name of a directory.
As it is an assignement, I'm only allowed to use "open", "read" and "close" functions in my code.
When "-1" is returned by function open(file, O_RDONLY), I call function ft_display_error to display error messages such as "No such file or directory".
Yet it doesn't work when "file" is a directory: in this case open will not return "-1". It will go on some kind of infinite loop.
void ft_display_file(char *file)
{
int fd;
char buf[BUF_SIZE + 1];
int ret;
fd = open(file, O_RDONLY);
if (fd == -1)
ft_display_error(file);
else
{
ret = read(fd, buf, BUF_SIZE);
while(ret)
{
buf[ret] = 0;
write(1, buf, ret);
ret = read(fd, buf, BUF_SIZE);
}
}
close(fd);
}
int main(int ac, char **av)
{
int i;
i = 1;
while (i < ac)
{
ft_display_file(av[i]);
i++;
}
}
Instead, I would like my program to identify that my argument is a directory, and then display the following message "cat: file: Is a directory.
Opening a directory for reading with open is the low level way of accessing its contents. Not very useful for you, but it doesn't allow to test for a directory.
If you cannot use stat (which is the best option) there seems to be another trick:
According to the documentation of open
The open() function shall fail if:
...
EISDIR
The named file is a directory and oflag includes O_WRONLY or O_RDWR.
So first try to open your file with O_RDWR (read-write) and if it fails, check if errno is equal to EISDIR
Code (untested)
fd = open(file, O_RDWR);
if ((fd == -1) && (errno == EISDIR))
{
// this is a directory
}
I am trying to recreate the basic functionality of fopen() using the I/O system calls. I am somehow suppose to "set the default mode for open() calls with O_CREAT" however am unsure how to go about this. It's not perfect but this is what I've got so far.
MYFILE * myfopen(const char * path, const char * mode){
MYFILE *fp = (MYFILE *)malloc(sizeof(MYFILE)); //EDITED
int fd;
switch(mode[0]){
case 'r':
fd=open(path, O_RDONLY | O_CREAT, 0440);
break;
case 'w':
fd=open(path, O_WRONLY | O_CREAT | O_TRUNC, 0220);
break;
default:
fd=open(path, O_RDWR | O_CREAT | O_TRUNC, 0660);
}
if(fd < 0){
return NULL;
}
fp->fileD=fd;
fp->offset=0;
return fp;
}
fileD will be the file descriptor returned by the open call. I think the rest is self-explanatory.
It compiles but I'm getting a "segmentation fault" error when I try to run it. This function also fails to open a new file and associate a file descriptor to it.
I think the segmentation error might be somewhere in here:
int myfputc(int c, MYFILE * fp){
if(write(fp->fileD, &c, 1) == -1){
return 1;
}
++fp->offset; //how to gain access to the current offset of the stream?
return 0;
}
Where I'm trying to recreate fputc.
Here is the MYFILE struct:
typedef struct {
int fileD; // descriptor
int bufferSz; // buffer size
int bufferCh; // # of bytes in stream
int offset; //current offset position
int errorF; // error flag
int EOFF; // EOF flag
} MYFILE;
The file permissions should probably be 0644, or maybe 0666 (or maybe 0640/0660 to deny others access while allowing your group access), regardless of whether you're creating the file for reading or writing. You should not normally include execute permission (and you don't). I'd be willing to support fewer permissions for group (no write for group seems good to me). You can even make a file readonly for every other process while the current process has write permission with 0444 or tighter permissions. But the standard will use 0666 and let the umask remove permissions.
You might note that your code leaks if you fail to open the file. You should free(fp); before the return on the error path.
Note that you have not set all the fields in your structure, and neither has malloc(), so you have random junk in those fields. Curiously, there isn't a buffer in sight, even though there's a buffer size.
This code works for me. It cleans up, marginally, your myfopen() function, but otherwise, it runs without crashing. I think your problem is in other code.
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
typedef struct
{
int fileD; // descriptor
int bufferSz; // buffer size
int bufferCh; // # of bytes in stream
int offset; // current offset position
int errorF; // error flag
int EOFF; // EOF flag
} MYFILE;
static
MYFILE *myfopen(const char *path, const char *mode)
{
MYFILE *fp = (MYFILE *)malloc(sizeof(*fp));
int fd;
switch (mode[0])
{
case 'r':
fd = open(path, O_RDONLY | O_CREAT, 0640);
break;
case 'w':
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
break;
default:
fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0640);
break;
}
if (fd < 0)
{
free(fp);
return NULL;
}
fp->fileD = fd;
fp->offset = 0;
fp->bufferSz = 0;
fp->bufferCh = 0;
fp->errorF = 0;
fp->EOFF = 0;
return fp;
}
static
int myfputc(int c, MYFILE *fp)
{
if (write(fp->fileD, &c, 1) == -1)
{
return 1;
}
++fp->offset; // how to gain access to the current offset of the stream?
return 0;
}
int main(void)
{
MYFILE *fp = myfopen("./test.txt", "w");
if (fp != 0)
{
const char *src = "The text!\n";
while (*src != '\0')
myfputc(*src++, fp);
}
return 0;
}
Result:
$ ls -l test.txt
-rw-r----- 1 jleffler staff 10 Feb 15 19:11 test.txt
$ cat test.txt
The text!
$
I have this function that utilizes open to set i/o redirection:
void setOutput(char * buffer){
int file = open(buffer, O_WRONLY || O_CREAT, S_IWUSR);
if(file < 0){ printf("error opening %s for output\n", buffer); }
if(dup2(file, 1) < 0){ printf("error with dup2 opening %s for output\n", buffer); }
}
When I run it, it works fine for files that are already defined but returns -1 when it receives a non-created file. Not sure why
You need to change the following
int file = open(buffer, O_WRONLY || O_CREAT, S_IWUSR);
To
int file = open(buffer, O_WRONLY | O_CREAT, S_IWUSR);
Format :
int open( char *filename, int access, int permission );
access : Should be provided as a bit wise OR operator, that means using | not || which is logical OR
I have written the following code to simulate the write() system call in C.
The program executes without errors, but the new content is not written to myfile.
What is the problem?
#include<stdio.h>
int main(int ac, char* av[])
{
int fd;
int i = 1;
char *sep = "";
if(ac < 1)
{
printf("Insuff arguments\n");
exit(1);
}
if((fd = open("myfile", 0660)) == -1)
{
printf("Cannot open file");
exit(1);
}
while(i<ac)
{
write(fd, av[i], strlen(av[i]));
write(fd, sep, strlen(sep));
i++;
}
close (fd);
}
you should check the return value of write and see what's going on with perror (for exemple),
anyway you are not calling open in the correct way
try
if ((fd=open("myfile", O_WRONLY | O_CREAT, 0660))==-1)
{
printf("Cannot open file");
exit(1);
}
while(i<ac)
{
write(fd,av[i],strlen(av[i])); //check the return value of write
write(fd,sep,strlen(sep));
perror("write");
i++;
}
close (fd);
and include unistd.h fcntl.h
You need to specify mode(read or write) of the open when you are opening a file. In your open call you didn't specify any mode and you are giving file permission flags. For more information refer manual page of open system call.
You can try this in open call
fd=open("myfile", O_WRONLY | O_CREAT, 0660);
check return value of your write call, it is failing because you didn't specify any mode and you are trying to write data in to that file.