fcntl not working - c

I have a small program that tires to change the files access mode after it has been opened.
int main(int argc, char* argv[])
{
int fd;
char *filename = argv[1];
char data[1];
int curval; //current flag value
int newval; //new flag value
fd = open(filename, O_RDONLY);
while(read(fd, data, 1)>0)
{
write(STDOUT_FILENO, data, 1);
}
lseek(fd, 0, SEEK_SET);
if((curval = fcntl(fd, F_GETFL, 0))<0)
{
perror("file flag get failed");
}
printf("%d\n", curval);
newval = curval | O_WRONLY | O_APPEND;
printf("%d\n", newval);
if(fcntl(fd, F_SETFL, newval)<0)
{
perror("file flag set failed");
}
if(write(fd, argv[2], strlen(argv[2]))<0) //appending more data to the file
{
perror("write failed");
}
lseek(fd, 0, SEEK_SET);
while(read(fd, data, 1)>0)
{
write(STDOUT_FILENO, data, 1);
}
close (fd);
return 0;
}
Here is the output when i run this program with a text file as input.
$ cat input
this is the inital data
$ ./a.out input newdata
this is the inital data
0
1025
write failed: Bad file descriptor
this is the inital data
Why is the write in the program failing? Also I'm not able to find where the file status flag constants are defined. I checked in usr/include/

The behavior you are trying to perform is not allowed. From the fcntl(2) man page:
F_SETFL (long)
Set the file status flags to the value specified by arg. File
access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags
(i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored.
On Linux this command can only change the O_APPEND, O_ASYNC,
O_DIRECT, O_NOATIME, and O_NONBLOCK flags.

If you read Linux manpage, you will see that fcntl cannot change file access modes (e.g., from read-only to read-write).

Related

How can I detect that I open()ed a directory in C, without using stat()?

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
}

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.

Linux C write buffer to file from a while loop issue

I have the following function (that dumps a process memory region). If I write to stdout write(STDOUT_FILENO, buf, rd); it outputs the buffer correctly, the problem rises when I want to write the buffer to a file, the file gets written but with the same date over and over:
void dump_region(int fd, off64_t start, off64_t end)
{
char buf[4096];
int fdo;
fdo = open("memdump_log", O_WRONLY | O_CREAT, 0644);
if (fdo == -1) {
fprintf(stderr, "open failed: %m\n");
close(fd);
exit(1);
}
lseek64(fd, start, SEEK_SET);
while(start < end) {
int rd;
rd = read(fd, buf, 4096);
write(fdo, buf, rd);
//write(STDOUT_FILENO, buf, rd);
start += 4096;
}
close(fdo);
}
The function is accessed from main() like this:
if(maps && mem != -1) {
char buf[BUFSIZ + 1];
while(fgets(buf, BUFSIZ, maps)) {
off64_t start, end;
sscanf(buf, "%llx-%llx", &start, &end);
dump_region(mem, start, end);
}
}
Any idea where am I wrong?
Modify
fdo = open("memdump_log", O_WRONLY | O_CREAT, 0644);
into
fdo = open("memdump_log", O_WRONLY | O_CREAT | O_APPEND, 0644);
You need to seek to the end of your output file, or passing the O_APPEND to open
You keep reopening the output file on every call to dump_region. When opening a file it will always start writing at the start. Either keep the file open all the time, seek to the end, or try the O_APPEND flag.

How to rewrite full content of a file in C

I have text file which uses for ajax source. Every 1 sec browser sends ajax request to read actual data from this file.
Also I have deamon written on C which writes actual data to that file. Look at the following code:
static void writeToFile_withLock(const char * file_path, const char * str)
{
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
int fd;
const char * begin = str;
const char * const end = begin + strlen(str);
fl.l_pid = getpid();
if ((fd = open(file_path, O_CREAT | O_WRONLY)) == -1) {
perror("open");
exit(1);
}
printf("Trying to get lock...\n");
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
printf("got lock\n");
printf("Try to write %s\n", str);
while (begin < end)
{
size_t remaining = end - begin;
ssize_t res = write(fd, begin, remaining);
if (res >= 0)
{
begin += res;
continue; // Let's send the remaining part of this message
}
if (EINTR == errno)
{
continue; // It's just a signal, try again
}
// It's a real error
perror("Write to file");
break;
}
fl.l_type = F_UNLCK; /* set to unlock same region */
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
printf("Unlocked.\n");
close(fd);
}
The problem: If former data was > the new data then old several symbols keeped at the end of the file.
How I can rewrite full file content?
Thanks in advance.
Add O_TRUNC to the open() call...
O_TRUNC
If the file already exists and is a regular file and the open mode
allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to
length 0. If the file is a FIFO or terminal device file, the O_TRUNC
flag is ignored. Otherwise the effect of O_TRUNC is unspecified.
You basically have two options. Either set the O_TRUNC bit of the 2nd parameter of open to discard all content when you open the file, or call ftruncate when you are finished to discard the content of the file that you do not want. (Or use truncate, but since you already have an open file descriptor, there's no advantage to doing that.)

FIFOs in C (Named-pipes)

I'm getting permission errors when trying to mkfifo() in the current directory. I definitely have permission to create files here. Any idea what the problem could be?
char dir[FILENAME_MAX];
getcwd(dir, sizeof(dir));
for(i = 0; i<num_nodes; i++)
{
char path[FILENAME_MAX];
sprintf(path, "%s/%d",dir, i);
printf("%s\n", path);
fifoArray[i] = mkfifo(path, O_WRONLY);
if(fifoArray[i] < 0)
{
printf("Couldn't create fifo\n");
perror(NULL);
}
}
You're creating it with an oflag not a mode_t.
mkfifo takes a second parameter of type mode_t
In other words something like: 0666. You're trying to feed it an oflag as defined in fcntl.h, this is normally like:
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
Hence, Invalid argument. Here's a way to open the fifo:
char * myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666);
if((fd = open(myfifo, O_RDONLY | O_NONBLOCK)) < 0){
printf("Couldn't open the FIFO for reading!\n");
return 0;
}
else {
//do stuff with the fifo
If you are relying on the output of perror to tell you that you are getting permission errors, you are likely mistaken. The call to printf is very likely changing errno, so that information is bogus. Do not call printf. Just write:
perror( path );
and see if the error messages change.

Resources