why SEEK_SET flag is not working as expected - c

I tried to do lseek() on a file which is opened in write mode as below. But it is not working as expected.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
int fd = open("/local/sandbox/.C/mytest", O_WRONLY | O_APPEND);
if(fd == -1)
{
printf("\nFailed to opne file in write mode\n");
return -1;
}
lseek(fd, 2, SEEK_SET);
write(fd, "OK", 2);
write(fd, "AAAAAAAA", 3);
close(fd);
}
'mytest' file is already existed with the content "Hi, How are you". I thought after executing the program, my test will contain 'HiOKAAA, How are you". But instead it is writing "OKAAA" at the end. Is it because of O_APPEND flag? But even, I am using lseek() to change the file offset to '2' only. Can any one please let me know why it is failing?

Yes, the O_APPEND option is causing this. From the POSIX specification of open:
O_APPEND
If set, the file offset shall be set to the end of the file prior to each write.
If you want to be able to write to arbitrary locations in the file, don't use O_APPEND mode.

Related

why if I redirect the STD_OUT on a file and write to STD_OUT the file remains empty?

I can't solve a problem with standard output laugh, I'm on Unix operating system, so the file-descriptor of STD_IN = 0, STD_OUT = 1, STD_ERR = 2, basically I tried to close the descriptor associated with the standard output, and then overwrite it with that of the file I want to write to, but when I open the file it is empty.
CODE:
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
/*special file's descriptor --use it or constants in unistd.h-- */
#define STD_IN 0 /*standard input stream*/
#define STD_OUT 1 /*standard output stream*/
#define STD_ERR 2 /*standard output-error stream*/
int main(unsigned int num_of_args, char** args)
{
if(num_of_args != 3)
{
write(STD_ERR, "Few argouments.\nThe use = ./executable <message> <file>\n", 69);
return -1;
}
int file_des= open(args[2], O_CREAT, 0640);
if(file_des < 0)
{
write(STD_ERR, "Error, we couldn't open file.\n", 31);
return -1;
}
//I close the descriptor associated with STD_OUT
close(STD_OUT);
//I copy the descriptor associated with fil_des on the first available descriptor(so STD_OUT)
dup(file_des);
write(STD_OUT, args[1], sizeof(args[1]));
close(file_des);
return 0;
}
It should be fine, I don't see any errors, but when I open the file I don't find the message written.
Because? help me
This code is incorrect:
int file_des= open(args[2], O_CREAT, 0640);
Per the POSIX documentation for open() (note the bolded portion - my bolding):
SYNOPSIS
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag, ...);
int openat(int fd, const char *path, int oflag, ...);
DESCRIPTION ...
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.
Your open() call needs to include either O_WRONLY or O_RDWR as you are writing to the file:
int file_des= open(args[2], O_CREAT | O_WRONLY, 0640);
The Problem
The problem here is that the file descriptor which is being assigned to file_des isn't really 1.
int test = dup(file_des);
fprintf(stderr, "%d", test);
3
Now, what could the reason be?
The problem is with how you are opening your file. O_CREAT creates a file if it does not exist.
There is no specification whether you are opening the file for read, write, or read/write.
Since you are associating your file to the file descriptor of stdout, you must use the O_WRONLY flag as well.
int file_des = open(args[2], O_CREAT | O_WRONLY, 0640);

Duplicating file descriptor and seeking through both of them independently

I have an open file descriptor which I want to duplicate in order to perform reading and seeking through both of them independently. I looked at the
int dup(int old_fd)
syscall. The problem is it does not really fit here. Man page states the following
http://man7.org/linux/man-pages/man2/dup.2.html :
After a successful return, the old and new file descriptors
may be used interchangeably. They refer to the same
open file description (see open(2)) and thus share file
offset and file status flags; for example, if the file offset is
modified by using lseek(2) on one of the file descriptors,
the offset is also changed for the other.
Is there a way to duplicate a file descriptor so they are completely independent?
In Linux, opening /proc/<pid>/fd/<n> opens the file that's currently open at fd N, but this is a new copy, not a linked duplicate like the one you get with dup() and friends.
This should create a file that contains bar, a bunch of zero bytes, then foo. Contrast with the version using dup().
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd1, fd2;
char buffer[50];
fd1 = open("testfile", O_CREAT | O_TRUNC | O_RDWR, 0600);
sprintf(buffer, "/proc/self/fd/%d", fd1);
#ifndef USE_DUP
fd2 = open(buffer, O_RDWR);
if (fd2 == -1) {
perror("open");
}
#else
fd2 = dup(fd1);
#endif
if (lseek(fd1, 16, SEEK_SET) == -1) {
perror("lseek");
}
if (write(fd1, "foo", 3) == -1) {
perror("write(fd1)");
}
if (write(fd2, "bar", 3) == -1) {
perror("write(fd2)");
}
}
No — at least, not in POSIX-defined mechanisms.
If you want complete independence of the file descriptors, you need to avoid the shared open file description, which means an independent open() or equivalent.
There's a chance that there's a Linux-specific mechanism that does the job that I've not heard of. However, looking through the system calls for Linux at http://man7.org/linux/man-pages/man2/ didn't provide enlightenment.

C open() function fails. Are my parameters wrong?

This function fails to open the file. Are my parameters wrong or what could be causing this problem?
int CreateFile(const char *filename){
char filepath[strlen(filename) + 3];
sprintf(filepath, "./%s", filename);
int fd = open(filepath, O_CREAT, O_APPEND, S_IWGRP);
if(fd == -1) printf("file read failed\n");
return fd;
}
Xcode prints only "file read failed" to the console. I tried to run this via Terminal aswell but that didn't help either.
I fixed an issue pointed by NetMage:
int CreateFile(const char *filename){
char filepath[strlen(filename) + 3];
sprintf(filepath, "./%s", filename);
int fd = open(filepath, O_CREAT|O_APPEND, S_IWGRP);
if(fd == -1) printf("file read failed\n");
return fd;
}
Unfortunately that didn't fix the issue
Step 1 - Verify that filepath is being set correctly, either by printing it to the terminal or examining it in a debugger.
Step 2 - Verify that the file exists in that path, and that its permissions are set so that you can open it. If filepath is "./foo", then a file named foo had better exist in the current working directory (the directory from which you ran the program), and it needs to have at least read permission.
Step 3 - If the file does not exist, verify that you have permission to create new files in the current working directory.
Step 4 - If after doing all of that you still get an error, check errno. It will give you some additional information beyond "it didn't work."
#include <errno.h>
...
if(fd == -1)
{
switch( errno )
{
case EACCESS: // permission issues
handle_permission_issue();
break;
case EEXIST: // file already exists and you used O_CREAT and O_EXCL
handle_already_exists_issue();
break;
case EFAULT: // bad path
handle_bad_path_issue()
break;
...
}
printf("file read failed\n");
}
NetMage has pointed out one problem - your flags need to be bitwise-OR'd together, rather than listed as separate arguments. Surprised the compiler didn't yell at you over that.
The open function takes only one parameter for oflags, which must be bit-ored together:
#include <errno.h>
#include <string.h>
int fd = open(filepath, O_CREAT|O_APPEND, S_IWGRP);
if (fd == -1) printf("file read failed: %s\n", strerror(errno));
Per the POSIX documentation for open() (somewhat reformatted, and note the bolded text):
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.
...
You need to include at least one of those five flags, perhaps like:
int fd = open(filepath, O_WRONLY|O_CREAT|O_APPEND, S_IWGRP);
Note that other failures may still occur. As noted in the comments, you're prepending "./" to the file name, which may cause problems if, for example, you get passed "/tmp/filename" and the tmp directory doesn't exist in your current working directory, as open() will not create missing directories in any path.

Is it possible to use write() in file opened with O_APPEND mode?

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(){
FILE * fp;
char buf[128];
int fd = open("/home/pdave/Downloads/ccode/fileout1",O_CREAT);
printf("fd after creat:%d",fd);
close(fd);
fd = open("/home/pdave/Downloads/ccode/fileout1",O_APPEND);
printf("fd after append:%d",fd);
int more=1;
int ret=0;
while(more){
puts("enter text:");
scanf("%s",buf);
puts(buf);
ret=write(fd,buf,128);
printf("ret:%d",ret);
puts("more?");
scanf("%d",&more);
}
}
The above tries to write characters to a file opened with the open function in O_APPEND mode. It works when it is opened with O_WRONLY mode but not when it is opened in O_APPEND. How can I append to it without opening with "w" and then using seek to SEEK_END and then fputs to the file or something like that?
Use O_WRONLY | O_APPEND, you still need the file access mode. (For some [most?] compilers, not including a file access flag will cause the file to be treated as read-only, and if not then you'd have an EINVAL error.)

execution of files from shell execlp

I have an exercise that asks me to complement the code , so that his execution obtained as a result equivalent to $ date> out.txt
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define NEWFILE (O_WRONLY | O_CREAT)
#define MODE644 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main() {
int fd;
if (fork() == 0) {
//// Code Here for add/// Result
fd=open("out.txt",NEWFILE,MODE644);
dup2(fd,1);
close(fd);
execlp("date",NULL);
exit(0);
}
wait(NULL);
}
I can not understand the three lines that have been added:
fd=open("out.txt",NEWFILE,MODE644);
dup2(fd,1);
close(fd);
The tricky bit is dup2.
int dup2(int fildes, int fildes2);
It closes filedes2 and makes it a clone of filedes. Which means, from now on when you refer to filedes2 it's as if you referred to filedes. Back to your code, you should know that STDOUT_FILENO is 1.
So your code means:
Open a file (descriptor filedes)
Close STDOUT_FILENO and make it refer to filedes
open opens the file and returns a file descriptor. dup2(fildes, fildes2) "shall cause the file descriptor fildes2 to refer to the same open file description as the file descriptor fildes", i.e. it closes standard output (if it's open) and makes stdout a copy of your new file descriptor. close then closes fd as it's no longer needed, since stdout is now the file you just opened.

Resources