I am creating a file in read/write mode and writing a string into it. Then I am trying to read it into a buffer where I get read error.
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd,count,fd1;
char buf[10];
fd=creat("./smarak",S_IRWXU);
if(fd<0)
{
perror("creat");
}
count=write(fd,"Hello smarak",7);
printf("count=%d\n",count);
count=read(fd,buf,7);
printf("buf=%s\n",buf);
printf("%d\n",count);
}
I get nothing in buf and also count is -1 which is read error. Why this error? Isn't it possible to read a file created by creat() system call?
You need to reposition between writing and reading:
count=write(fd,"Hello smarak",7);
printf("count=%d\n",count);
// added:
if ( lseek( fd, 0, SEEK_SET ) < 0 )
{
perror("lseek");
}
count=read(fd,buf,7);
printf("buf=%s\n",buf);
printf("%d\n",count);
After your write, the current position in the file is right after what you have written. If you want to read that back in, you have to "rewind" the current position to the beginning of the file.
Check man lseek for details.
And I don't know how Unix calls handle this, but the C standard (C99, 7.19.5.3 The fopen function, section 6) has this to say:
[...] output shall not be directly followed by input without an
intervening call to the fflush function or to a file positioning
function (fseek, fsetpos, or rewind), and input shall not be directly
followed by output without an intervening call to a file positioning
function, unless the input operation encounters end-of-file.
So you might be looking at undefined behaviour in your code sample.
use lseek() function to set the position to the specified.
Try to use open() system call instead of creat() system call.
When you use creat() it will open the process as
root#Lenovo-G585:/proc/6988/fd$ ls -la
total 0
dr-x------ 2 root root 0 Sep 18 16:20 .
dr-xr-xr-x 8 root root 0 Sep 18 16:20 ..
lrwx------ 1 root root 64 Sep 18 16:20 0 -> /dev/pts/4
lrwx------ 1 root root 64 Sep 18 16:20 1 -> /dev/pts/4
lrwx------ 1 root root 64 Sep 18 16:20 2 -> /dev/pts/4
l-wx------ 1 root root 64 Sep 18 16:20 3 -> /tmp/smarak
^
Look ^ here.
The read permission is missing so you cannot able to read from that file.
If you use open() system call like
fd=open("./smarak",O_CREAT|O_RDWR);
O_CREAT - Which is used to create a new file if doesn't exist.
O_RDWR - Which is used to open a file for read and write mode.
By using open with the given argument, you can do your requirement.
When using creat() it will open the file in O_CREAT|O_WRONLY|O_TRUNC.
O_TRUNC - Which is used to truncate remove the file content and keep
the cursor position in start of file.
Note: While using creat() it will truncate the file if already exist.
Related
This question already has answers here:
Writing to stdin and reading from stdout (UNIX/LINUX/C Programming)
(5 answers)
Closed 10 months ago.
In order to understand the workings of C and linux, I was doing the pwnable.kr challenges, but there is something in the first challenge that doesn't quite add to me.
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
To my understanding, the 0 fd is for stdin, and the 1 and 2 fd are for stdout, yet all three of them allow me to solve the challenge. I understand the first one, but wouldn't the other 2 file descriptors just read what I print on my promt, and not allow me to write anything after?
Let's take a look at what /proc says:
$ ls -al /proc/self/fd
total 0
dr-x------. 2 mrsam mrsam 0 Apr 23 15:25 .
dr-xr-xr-x. 9 mrsam mrsam 0 Apr 23 15:25 ..
lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 0 -> /dev/pts/1
lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 1 -> /dev/pts/1
lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 2 -> /dev/pts/1
For an interactive terminal all three file descriptors are, basically the same. All three are connected to the terminal device, after all, why won't they be? Input and output goes to the same screen.
And, for simplicity, you can think of them as dup()s of each other. So, as a side effect, all three file descriptors are read/write.
Now, of course, this is only true for programs launched from an interactive terminal. In an arbitrary program, launched in an unknown environment you can only rely on being able to read from 0 and write to 1 and 2.
I am facing this very strange issue.
I wrote a C-function to read value from path "/sys/kernel/debug/irq_domain_mapping" on my linux runing board. Although the that file has "read" permission for all user/group/other, but my function was still not able to read its content.
Would you please help me with some possibilities for this issue. It 's quite strange and this is the first time I got it.
Thanks in advance.
/* Define the file path */
#define HAL_IRQ_DOMAIN_MAP_FILE "/sys/kernel/debug/irq_domain_mapping" /**< irq map file location and mapping */
/* Open the file with permission read */
FILE *fp = NULL;
fp = fopen(HAL_IRQ_DOMAIN_MAP_FILE, "r");
if (fp == NULL) {
tpLOG_osErr("fopen", HAL_IRQ_DOMAIN_MAP_FILE);
return errno;
}
But can not read the file
Oct 3 01:12:59 fopen /sys/kernel/debug/irq_domain_mapping failed: 'Permission denied'
Although the file has read permission for all
[root#]#ls -la /sys/kernel/debug/irq_domain_mapping
ls -la /sys/kernel/debug/irq_domain_mapping
**-r--r--r-- 1 root root 0 Jan 1 1970 /sys/kernel/debug/irq_domain_mapping**
I got confused about lseek()'s return value(which is new file offset)
I have the text file (Its name is prwtest). Its contents are written to a to z.
And, the code what I wrote is following,
1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 #define BUF 50
8
9 int main(void)
10 {
11 char buf1[]="abcdefghijklmnopqrstuvwxyz";
12 char buf2[BUF];
13 int fd;
14 int read_cnt;
15 off_t cur_offset;
16
17 fd=openat(AT_FDCWD, "prwtest", O_CREAT | O_RDWR | O_APPEND);
18 cur_offset=lseek(fd, 0, SEEK_CUR);
19 //pwrite(fd, buf1, strlen(buf1), 0);
20 //write(fd, buf1, strlen(buf1));
21 //cur_offset=lseek(fd, 0, SEEK_END);
22
23 printf("current offset of file prwtest: %d \n", cur_offset);
24
25 exit(0);
26 }
On the line number 17, I use flag O_APPEND, so the prwtest's current file offset is taken from i-node's current file size. (It's 26).
On the line number 18, I use lseek() which is used by SEEK_CUR, and the offset is 0.
But the result value cur_offset is 0. (I assume that it must be 26, because SEEK_CUR indicates current file offset.)
However, SEEK_END gives me what I thought, cur_offset is 26.
Why the lseek(fd, 0, SEEK_CUR); gives me return value 0, not 26?
O_APPEND takes effect before each write to the file, not when opening file.
Therefore right after the open the position remains 0 but if you invoke write, the lseek on SEEK_CUR will return correct value.
Your issue is with open() / openat(), not lseek().
From the open() manpage, emphasis mine:
O_APPEND
The file is opened in append mode. Before each write(2), the file offset is positioned at the end of the file, as if with lseek(2).
Since you don't write to the file, the offset is never repositioned to the end of the file.
While we're at it, you should be closing the file before ending the program...
Actually, while we're really at it, if you do #include <stdio.h> already, why not use the standard's file I/O (fopen() / fseek() / fwrite()) instead of the POSIX-specific stuff? ;-)
Also, on Linux, your commented-out code won't work as you expect. This code:
17 fd=openat(AT_FDCWD, "prwtest", O_CREAT | O_RDWR | O_APPEND);
18 cur_offset=lseek(fd, 0, SEEK_CUR);
19 pwrite(fd, buf1, strlen(buf1), 0);
will fail to write the contents of buf1 at the beginning of the file (unless the file is empty).
pwrite on Linux is buggy:
BUGS
POSIX requires that opening a file with the O_APPEND flag should
have no effect on the location at which pwrite() writes data.
However, on Linux, if a file is opened with O_APPEND, pwrite()
appends data to the end of the file, regardless of the value of
offset.
I wonder if there is any way to lock and unlock a file in Linux when I open a file using fopen (not open)?
Based on Stack Overflow question C fopen vs open, fopen is preferred over open.
How can I implement my own file lock (if possible) by creating and deleting lock files?
I would strongly disagree with the claim that fopen is prefered over open. It's impossible to use fopen safely when writing a file in a directory that's writable by other users due to symlink vulnerabilities/race conditions, since there is no O_EXCL option. If you need to use stdio on POSIX systems, it's best to use open and fdopen rather than calling fopen directly.
Now, as for locking it depends on what you want to do. POSIX does not have mandatory locking like Windows, but if you just want to ensure you're working with a new file and not clobbering an existing file or following a symlink, use the O_EXCL and O_NOFOLLOW options, as appropriate. If you want to do cooperative locking beyond the initial open, use fcntl locks.
In Linux, if you need a file descriptor (e.g., to pass to a file-locking primitive), you can use fileno(FILE*) to retrieve it. After retrieving the file descriptor, you can use it as if it had been returned by open.
For example, instead of
int fd = open("myfile.txt", flags);
int result = flock(fd, LOCK_SH);
you could equally well do this:
FILE* f = fopen("myfile.txt", "r");
int result = flock(fileno(f)), LOCK_SH);
Note that fileno is defined in the POSIX standard, but not in C or C++ standards.
As for your second question, the Linux open() man page has this to say:
The solution for performing atomic file locking using a lockfile is to
create a unique file on the same file system (e.g., incorporating
hostname and pid), use link(2) to make a link to the lockfile. If
link() returns 0, the lock is successful. Otherwise, use stat(2) on
the unique file to check if its link count has increased to 2, in
which case the lock is also successful.
Files can be locked by using flock(). Its syntax is
#include <sys/file.h>
#define LOCK_SH 1 /* shared lock */
#define LOCK_EX 2 /* exclusive lock */
#define LOCK_NB 4 /* don't block when locking */
#define LOCK_UN 8 /* unlock */
int flock(int fd, int operation);
First file is opened using fopen() or open(). Then this opened file is locked using flock() as given below
int fd = open("test.txt","r");
int lock = flock(fd, LOCK_SH); // Lock the file . . .
// . . . .
// Locked file in use
// . . . .
int release = flock(fd, LOCK_UN); // Unlock the file . . .
Note that in below code fopen will fail (and return NULL) if the lock file /var/lock/my.lock doesn't exist.
FILE* f = fopen("/var/lock/my.lock", "r");
int result = flock(fileno(f)), LOCK_SH);
Use fopen with w+ if you need the lockfile to be created if it doesn't exist.
FILE* f = fopen("/var/lock/my.lock", "w+");
int result = flock(fileno(f)), LOCK_SH);
If you wish to implement your own lock simply, I suggest Rob's answer of using flock. If you wish to implement it in a complex manner, such as for high availability, you can try something like using a thread to touch a file at a regular interval. All other programs wanting to lock the file should also check the file to see if its update time has been updated in at another fixed, but larger interval (the larger part is important). This is probably overkill for most applications, but it handles things such as crashes, freezes, etc. much better than flock.
There is another way with open() function, but I'm not sure about this called locked file. I am using file permissions to open a file.
The code is here:
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#define FILE_NAME "hello.txt"
int main()
{
int fd;
fd = open(FILE_NAME, O_CREAT, S_IRWXU);
// Error checking
if(fd == -1){
perror("[error]\n");
}
else{
printf("[file is opened]\n");
}
return 0;
}
I used a flag for permissions (third argument). This flag gives read, write and execute permissions to the user.
$ls -alh
total 24K
drwxrwxr-x 2 arien arien 4.0K Dec 28 20:56 .
drwxrwxr-x 18 arien arien 4.0K Dec 27 22:20 ..
-rwxrwxr-x 1 arien arien 8.5K Dec 28 20:56 fopen
-rw-rw-r-- 1 arien arien 290 Dec 28 20:56 fopen.c
-rwx------ 1 arien arien 0 Dec 28 20:55 hello.txt
A little tip: If you are using Ubuntu or Debian, you can see the description of functions with man [function_name] man pages of open() function.
The below code is not letting me lock the file using lockf,
flock works fine though
#include <iostream>
#include <unistd.h>
#include<thread>
#include <vector>
#include <sys/file.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
void append()
{
FILE *fp=fopen("a.txt","a");
if(fp)
{
cout<<lockf(fileno(fp),F_LOCK,0)<<endl;
//flock(fileno(fp), LOCK_EX);
fprintf(fp,"abcdefghijklmnopqrstuvwxyz\n");fflush(fp);
sleep(1);
fprintf(fp,"^$^&%&*&^&*(*)_*)_()_*&***&(\n");fflush(fp);
fclose(fp);
}
else {
printf("null\n");
}
}
int main()
{
fclose(fopen("a.txt","w"));
//return 0;
vector<thread*> v;
//#pragma omp parallel for
for(int i=0;i<1000;++i)
{
v.push_back(new thread(append));
//append();
}
for(auto y:v)
{
y->join();
delete y;
}
return 0;
}
I am trying to read some text from a file and write it to another using open(), read() and write().
This is my open() for the file-to-write-to (I want to create a new file and write into it):
fOut = open ("test-1", O_RDWR | O_CREAT | O_SYNC);
This is setting file-permissions to something I don't understand at all. This is the output of ls -l:
---------T 1 chaitanya chaitanya 0 2010-02-11 09:38 test-1
Even the read permission is locked. I tried searching for this, but could not find ANYTHING.
Strangely, write() still successfully writes data to the file.
Also, if I do a 'chmod 777 test-1', things start working properly again.
Could someone please let me know where I am going wrong in my open call?
Thanks!
For your reference, I have pasted the complete program below:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main () {
char buffer[512], ch;
int fIn, fOut, i;
ssize_t bytes;
FILE *fp = NULL;
//open a file
fIn = open ("test", O_RDONLY);
if (fIn == -1) {
printf("\nfailed to open file.");
return 1;
}
//read from file
bytes = read (fIn, buffer, sizeof(buffer));
//and close it
close (fIn);
printf("\nSuccessfully read %d bytes.\n", bytes);
//Create a new file
fOut = open ("test-1", O_RDWR | O_CREAT | O_SYNC);
printf("\nThese are the permissions for test-1\n");
fflush(stdout);
system("ls -l test-1");
//write to it and close it.
write (fOut, buffer, bytes);
close (fOut);
//write is somehow locking even the read permission to the file. Change it.
system("chmod 777 test-1");
fp = fopen ("test-1", "r");
if (fp == NULL) {
printf("\nCan't open test-1");
return 1;
}
while (1)
{
ch = fgetc(fp);
if (ch == EOF)
break;
printf("\n%c", ch);
}
fclose (fp);
return 0;
}
open() takes a third argument which is the set of permissions, i.e.
open(filename, O_RDWR|O_CREAT, 0666)
0666 is an octal number, i.e. every one of the 6's corresponds to three permission bits
6 = rw
7 = rwx
first three bits for owner permission, next three bits for group permission and next is for the world
the first digit - represents that is file or directory. (0 - file, d - directory)
here we used 0 means file
It's a typical pitfall. The compiler allows you to leave the permission argument away because when you open an existing file the permission bits don't make sense. But when you forget the argument when you create a file, you get a random set of permissions, e.g. 0000 in your case (---).
Reading http://linux.die.net/man/2/open it seems you missed the mode parameter for open:
mode must be specified when O_CREAT is in the flags, and is ignored otherwise.
The argument mode specifies the permissions to use in case a new file is created.
This question recently helped me out, so I wanted to do my part to add a bit more depth as to what's going on. Like it was stated before, you were missing the third argument to open(). However, the permissions you see aren't random; they're coming from the stack. Look at the following code snippet:
asm("push $0");
asm("push $0");
asm("push $0");
fd = open("base", O_RDWR|O_CREAT);
Note the following result:
----------. 1 user user 4 Feb 26 08:21 base
Let's change the first push to 1, i.e. execute permission:
asm("push $1;push $0;push $0");
fd = open("base", O_RDWR|O_CREAT);
and we get:
---------x. 1 user user 4 Feb 26 08:25 base
Change the push to 4, i.e. read permission, and mess with the other two values:
asm("push $4;push $5;push $6");
fd = open("base", O_RDWR|O_CREAT);
and we get:
-------r--. 1 user user 4 Feb 26 08:27 base
Thus we can see the third value popped off the stack (first pushed) is what really matters. Finally for fun we can try 5 and then 50, which respectively result in:
-------r-x. 1 user user 4 Feb 26 08:27 base
----rw----. 1 user user 4 Feb 26 08:28 base
Hope this adds some clarity!
Actually umask() only filters permissions and does not set them. The typical umask() value is 0002 ("don't give away write permission to the world") and if your mode value in the open( "file", O_CREAT, 0777) gave all permissions, the resulting file would have 775 as its permssions.
Not strictly relevant to the question, but the accepted answer could use this clarifying point:
There is a relationship between rwx and its numerical representation that can be seen by treating the presence of a letter as a binary 1, and its absence as a binary 0.
e.g.
rwx <--> 111 (binary) <--> 7 (octal)
r-- <--> 100 (binary) <--> 4 (octal)
-wx <--> 011 (binary) <--> 3 (octal)
As a further addendum, you may now consider the chmod command:
chmod 777 filename.extension --> rwxrwxrwx permissions
777 <--> 111 111 111 <--> rwx rwx rwx
or: chmod 654 filename.extension --> rw-r-x-r--
654 <--> 110 101 100 <--> rw- r-x r--
Hope this is informative!
you can call umask(0); system call before using open(); system call to set your choices permissions to file correctly.
This is kind of an old thread, but I think people should be aware of the "sys/stat.h" library. This includes a bunch of symbolic constants for setting permission bits.
For example: To open a file with Read/Write permissions enabled for the user
#include <fcntl.h>
#include <sys/stat.h>
open("Your/File/Path", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
where:
S_IWUSR // Sets the Users Write bit
S_IRUSR // Sets the Users Read bit
This library includes a bunch of others, I won't list them all here but you can read up on it all here.
Of course you can put in the octal values to set these bits, however some may argue that it is poor coding practice.