Appending to existing file from resource file in Linux C Program - c

i've trying to perform appending to an existing file from resource file using the C programming in Linux. However, my code doesn't work for that, can any1 do tell me what's wrong with the code and also how O_APPEND is working? thanks :)
char ifile[150];
char tfile[150];
char cc;
system("clear");
printf("Please enter your resource file name : ");
gets(ifile);
printf("Please enter your destination file name : ");
gets(tfile);
int in, out;
in = open(ifile, O_RDONLY);
int size = lseek(in,0L,SEEK_END);
out = open(tfile, O_WRONLY |O_APPEND);
char block[size];
int pdf;
while(read(in,&block,size) == size)
pdf = write(out,&block,size);
close(in);close(out);
if(pdf != -1)
printf("Successfully copy!");
else
perror("Failed to append! Error : ");
printf("Press enter to exit...");
do
{
cc = getchar();
} while(cc != '\n');

The problem here is that you deplace the reading cursor at the end of the file in order to know its size, but you don't rewind to the start of the file to be able to read. So read() reads EOF, and returns 0.
int size = lseek(in, 0L, SEEK_END);
out = open(tfile, O_WRONLY | O_APPEND);
should be
int size = lseek(in, 0L, SEEK_END);
lseek(in, 0L, SEEK_SET);
out = open(tfile, O_WRONLY | O_APPEND);
In addition, when you read and write, you should use block and not &block, since block is already a pointer (or an address).
Oh, and also... When you open the file out for writing... It will fail if the file does not exist already.
Here how to create it with rights set to 644:
out = open(tfile, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
(This won't have any effect if the file already exists)

Related

For Loop creating sequential name txt file

I want to create N files in a for loop under Linux as O.S.;
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *ptr;
char name[25];
for (int i = 0; i < 10; i++) {
snprintf(name, sizeof(name), "File_Nr%d.txt", i);
ptr = fopen(name, "w");
if( ptr == NULL ){
perror("Error creating file!");
}
fclose(ptr);
}
return 0;
}
It works and creates File_Nr0.txt to File_Nr9.txt.
Question: is this code "safe"?
Perhaps since you want to only create the files, you can directly use the open() system call, which has more options and more readable way of expressing options IMO.
int fd = open(name, O_WRONLY|O_CREAT|O_TRUNC,
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
or
int fd = creat(name, 0644) // consider it to be an alias for above.
if you want to fail when the file exists already,
int fd = open(name, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
in fopen() you can achieve this by using the 'x' in mode param.
ptr = fopen(name, "wx");
And as #xception mentioned, you should return a non-zero error code when something goes wrong.
if (NULL == ptr) {
perror("...");
return -1; // or better the errno which was set by open() call..
}
And in your code, you attempt to close the ptr even in failure case, that is gonna give you a crash. So, you need to handle that.

create new file with system calls

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.

What is the default mode for open() calls with O_CREAT and how to properly set it while opening/creating files

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!
$

Copying certain contents of a file to another

I am trying to limit the amount of lines I copy over to a file to x amount. I know how to copy the files, but how would I limit it, for example, 10 lines.
Code:
char buf[BUFSIZ];
int outft, inft,fileread;
if((outft = open("TMPFILE3", O_CREAT | O_APPEND | O_RDWR, 0644))==-1){
perror("open");
}
inft = open("TMPFILE", O_RDONLY);
if(inft >0){
fileread = read(inft, buf, sizeof(buf));
printf("%s\n", buf);
write(outft, buf, fileread);
close(inft);
}
close(outft);

Named pipes and background process

I'm trying to make a background process named server that uses a named pipe to receive data from a "client" program, and the process saves that data in a file called log. My code is as follows:
server:
main(){
int fd2,fd_log;
char *fifo ="/home/me/fifo";
char c;
mkfifo(fifo, 0666);
int x;
while(fd2 = open(fifo, O_RDONLY)>=0){
fd_log=open("/home/me/log.txt",O_WRONLY | O_CREAT | O_APPEND);
while(read(fd2,&c,1)>=0){
write(fd_log,&c,1);
}
close(fd2);
close(fd_log);
}
}
client:
main(){
int fd1;
char *fifo ="/home/me/fifo";
char c;
fd1 = open(fifo, O_WRONLY);
while(read(0, &c, 1)>=0){
write(fd1,&c,1);
}
close(fd1);
}
However, this doesn't seem to work. There is no action in the log file, and I think the read call in the server file it's not done. Any suggestions?
The problem is in your line here:
while(fd2 = open(fifo, O_RDONLY)>=0){
Due to C operator precedence, this is really evaluated as:
while((fd2 = (open(fifo, O_RDONLY)>=0)) != 0){
I.e. call open(), check if it's return value is greater than 0, then assign that boolean result to fd2, then check if it is zero or not.
That way you are then reading from file no. 1, which is stdout and that surely blocks indefinitely.
Change it to this and everything starts working of course:
while((fd2 = open(fifo, O_RDONLY)) >=0){
Also you are opening the log file without any permissions, you should specify some so that you can access it afterwards somehow, e.g:
fd_log=open("/home/me/log.txt",O_WRONLY | O_CREAT | O_APPEND, 0600);

Resources