For Loop creating sequential name txt file - c

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.

Related

Weird output from integer array to a file

Hi I am writing a program that generates random ints, put them in an array and save them to a file. Everything seems to work good but after I open this file it has this strange content : ^K^#^#^S^#^#^#^[^#
What have I done wrong?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[]) {
int tab[10];
int fd;
srand(time(0));
int i;
for(i = 0; i < 10; i++)
tab[i] = rand() % 50;
if(argc != 2 || strcmp(argv[1], "--help") == 0)
{
.......
}
fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644);
write(fd, tab, 10);
close(fd);
return 0;
}
The content is wierd because you're writing binary values, random character codes from 0 to 50. But the information is there all right (well, you have to write sizeof(int) times more data to store all the data though, and it can be corrupt on Window because you're missing O_BINARY and some carriage return chars may be inserted at some locations...):
fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644); // add | O_BINARY if you use windows
write(fd, tab, 10 * sizeof(int)); // you can use (fd,tab,sizeof(tab)) too as it's an array, not a pointer
Use a hex editor you'll see the values (with a lot of zeroes since your values can be encoded in a byte). But not with a text editor.
If you want to write formatted integers as strings, use fopen and fprintf on the values, in a text file, not binary. Quick & dirty (and also untested :)):
FILE *f = fopen(argv[1], "w"); // #include <stdio.h> for this
if (f != NULL)
{
int i;
for (i = 0; i < 10; i++)
{
fprintf(f,"%d ",tab[i]);
}
fclose(f);
}

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

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);

open() and write() functions in C

I'm trying to write in a .txt file the content of the variable environ.
int archivo = open(argv[1], "rw");
int i=0;
while(environ[i]!=NULL){
write(archivo, environ[i], 1024);
i++;
}
The file is created but no content is added. Does anyone know why?
consult man 2 open to get the right arguments for open. It should be:
open(argv[1], O_WRONLY | O_CREAT | O_TRUNC);
You should only write ad much as you actually have:
write(archivo, environ[i], strlen(environ[i]));
You have to make sure that what you wrote actually left the buffer:
size_t string_length = strlen(environ[i]);
size_t wrote = 0;
while (wrote < string_length) {
size_t bytes_wrote = write(archivo, environ[i] + wrote, string_length - wrote);
if (bytes_wrote >= 0)
wrote += bytes_wrote;
else {
perror("write");
abort();
}
}
write does not guarantee that all that you submit will be written.
Ideally you should look for the far more programmer friendly stdio calls fopen and fwrite.
FILE * fp = fopen(argv[1], "w");
// loop i
if (!fwrite(environ[i], strlen(environ[i]), 1, fp)) {
perror("fwrite");
abort();
}
I believe you've got to change your flags for opening a file. "rw" isn't for open(), it is for fopen().
open(argv[1], O_WRONLY);
I think is the minimum required for writing to a file using open
EDIT: I found a link http://pubs.opengroup.org/onlinepubs/009696899/functions/open.html

Resources