I want:
file to be created if it does not exist, not overwritten if it does.
to read and write and fseek where ever I want
and I can not find out valid mode — "w+", "rw" "rwb+" "r+b" "w+b" "a+" or what?
The basic level 'open' that performs well is:
int fd =open("fname", O_RDWR | O_CREAT, 0666);
but I would like to know fopen alternative.
Every mode letters [w, r, a, +] combination I tried will either overwrite contents, or fseek-fwrite not write where it should. "a+" will always append no matter what fseek sets... "rw+" works ok, but does not create nonexistent file ...etc.
Update: to clarify why for example "a+" is NOT a solution:
#include <stdio.h>
int main()
{ FILE *fp =fopen("aaa.txt", "a+");
fwrite("aaaaaaaaaaaaaaaaaaa", 1, 10, fp);
fseek(fp, 5, SEEK_SET);
fwrite("AAA", 1, 3, fp);
fclose(fp);
return 0;
}
runned with: $ rm aaa.txt; gcc test.c && ./a.out && cat aaa.txt && echo .
produces wrong result: aaaaaaaaaaAAA.
result should be: aaaaaAAAaa
Update2: summary... minimal functions that i end up with:
FILE *fopenrwc(char*n) {FILE*f=fopen(n,"a");if(f)fclose(f),f=fopen(n,"r+");return f;}
or:
FILE *fopenrwc(char*n) {return fdopen(open(n,O_RDWR|O_CREAT,0666),"r+");}
If you review the manual page for fopen(), none of the standard open mode strings meets your requirements.
If you're on a sufficiently POSIX-like machine to be able to use open(), don't underestimate the benefits of fdopen() which would allow you to use open() with the options you showed and then create a file stream to use that file.
Note that "rw+" is not a valid mode. If you're (un)lucky, it gets treated as r+.
If you can't use fdopen() for some reason, you may be best off trying r+ and if that fails using w+; that opens a small window of vulnerability where someone might create a file that you then clobber with the w+ option — or creates a symlink so you end up creating a file where you didn't intend to do so.
This is the way it used to be necessary to work with open(); originally, you called open() — in the days before there was an O_CREAT — and if that failed, then you used creat() instead. That's a long time ago, though — see 'UNIX Programming' in 7th Edition UNIX Programmer's Manual Vol 2.
In general, testing with access() doesn't help. It leaves open a window of vulnerability because there is a TOCTOU — Time of Check, Time of Use — gap between the use of access() and open() (or fopen()). This is also the trouble with open() and creat(), or two calls to fopen().
If you want the finer controls, such as O_EXCL, or specialized properties such as O_DSYNC or O_NOCTTY, or even control over the permissions on the created file other than the default as modified by umask(), then open() plus fdopen() is practically the only way to go.
There is no direct way to meet your requirement with a simple fopen. IMHO, you best choice is to first use a low level open to create the file, and then use a fdopen (as suggested by Jonathan Leffler) to get a FILE * that can then be used with all the C library IO functions:
int fd =open("fname", O_RDWR | O_CREAT, 0666);
FILE *fp = fdopen(fd, "r+");
/* Ok, you can do what you want with fp */
Related
I fully understand that tmpnam has been deprecated and would like to remove it from a function in an existing file that prevents me from building the project. However, since I am not familiar with it and am unable to experiment with it, I am not sure how best to replicate this functionality.
if ((myfileName = tmpnam(NULL)) == NULL) { return APP_ERROR }
I read the information on tmpnam here but the best I can come up with is to use something like:
if (tmpnam_r == NULL) { return APP_ERROR }
However, since I cannot compile with tmpnam and am unfamiliar with the code in question, I am not confident in properly capturing the original intent.
As best as I can tell, this appears to be testing if the file exists, and if not, simply returns an error, as the next step consists of copying content into myfileName, which should presumably exist following the above check.
The problem with tmpnam() is that it generates a name that is unique and does not exist when it returns, but that name is not guaranteed to be unique by the time you use it in a call to fopen() (or open()).
The key feature of the mkstemp() function is that it creates and opens a file with the new name, so that there isn't a TOCTOU (time of check, time of use) vulnerability. This cuts down the avenues for security risks.
Code designed to use tmpnam() usually needs a file name, so using tmpfile() is usually not an option; it doesn't provide a way to find the file name. If you don't need the file name then using tmpfile() works well and is Standard C, so it is widely available.
The specific case of tmpnam() and tmpnam_s() is interesting. Although tmpnam_s() avoids some string-related problems, it does not change the behaviour of tmpnam() in the way that causes the security problems addressed by mkstemp(). So, independent of the portability issues that arise from attempting to use tmpnam_s() (or any of the other *_s() functions from Annex K of the C11 or C18 standards), it doesn't fix the problem that causes tmpnam() to be deprecated.
You can arrange to use mkstemp() instead of tmpnam() and close the file descriptor before continuing with the other code:
tmpnam(name); // Replace this
int fd = mkstemp(name); // With this…
if (fd >= 0)
close(fd);
It's not great, but it does ensure the file is created, which reduces the security vulnerabilities a bit, but not as much as using the file descriptor directly. You could (should) wrap that into a function.
Note that the mkstemp() returns a file descriptor; if you want a file stream, you can use fdopen() to create a file stream from the file descriptor. And if that fails, you probably want to remove the file (with remove() or unlink()).
So, that gives you a need for fmkstemp():
#include <stdio.h>
#include <stdlib.h> /* mkstemp() */
#include <unistd.h> /* close() */
extern FILE *fmkstemp(char *name); /* Add to a convenient header file */
FILE *fmkstemp(char *name)
{
int fd = mkstemp(name);
FILE *fp = 0;
if (fd >= 0)
{
fp = fdopen(fd, "w+");
if (fp == 0)
{
close(fd);
unlink(name);
}
}
return(fp);
}
Note that after you've used fmkstemp(), you use fclose() to close the file stream (and, behind the scenes, that closes the file descriptor).
Don't forget to remove the temporary file before exit. That's where a function registered with atexit() or one of its variants can be useful.
I'm a beginner in C, have a question about the flags and mode paramaters in open file function in C
so C's open function is :
int open(char *filename, int flags, mode_t mode);
and some macros for the flags are:
O_RDONLY: Reading only
O_WRONLY: Writing only
O_RDWR: Reading and writing
and the mode bit is something like:
What I don't understand is,
let say we have a open function as:
fd = Open("foo.txt", O_RDONLY, S_IWOTH);
so O_RDONLY specifies that we can only read the file, but S_IWOTH specifies that anyone can write this file, isn't that they contradict to each other?
The flags decide the properties to be applied during opening of this file at this time (let's call this the "session") - this affects what you can do with the file while it's open (or, more correctly, what you can do with the file descriptor).
The mode decide the properties of the file should it be created as part of the opening process - this affects how anyone can open the file in future.
Your specific example (albeit with the correct open rather than Open):
fd = open("foo.txt", O_RDONLY, S_IWOTH);
is not really relevant since the file won't be created without the O_CREAT flag(a).
However, had you supplied O_CREAT, it's perfectly acceptable to create the file allowing anyone to write to it, but have it opened for this session in read-only mode.
(a) Some systems have other flags which may create the file under some circumstances. For example, Linux has the O_TMPFILE flag.
I am working on a project for a class and we were given a .c file containing the following code:
int fd = -1;
if (fd < 0)
{
fd = open ("my_dev", O_RDWR);
if (fd < 0)
{
perror ("open");
return -1;
}
...
So I understand that it is trying to open a file "my_dev" with read/write permissions, and then is returning the file descriptor on success or a negative value on failure, but what I dont understand is why it is giving me "permission denied" consistently. I tried to use this code:
int des = open("my_dev", O_CREAT | O_RDWR, 0777);
...
close(des)
to open/create the file (this is called before the other block), but this does not work, and yet if I just use this instead:
FILE* file = fopen("my_dev","w+");
fprintf(file,str);
fclose(file);
I can write to the file, meaning I have write permissions. Now normally, I would just use fopen and fprintf for everything, but for this project, we sort of have to use the teacher's .c file which is going to try to use
open()
which is going to give a "permission denied" error which is in turn going to screw up my code.
I guess my question is how fopen and open relate to each other? Everyone seems to be able to recite that open is a system call whereas fopen is a standard lib function, but I cant seem to find a clear answer for how I can create a file with fopen() that can be opened by open() without a "permission denied" error, or how I can create a file with open() which I can then write to, close and open again with open().
In short, how do I create a file in C that I can write to and open later with open(O_RDWR)?
Sorry if this is a little piecey, im super tired.
PS: It should be noted that I am compiling and running on a university computer, so permissions may be "weird" BUT it should be noted that if I create the file with the terminal command "dd" open() will work, and furthermore, I clearly have SOME write permissions since I can indeed write to the file with fopen and fprintf
fopen is a library function that provided by the standard C runtime, it returns a stream and you can call stream functions on it, like fscanf, fprintf, or fread, fwrite.
open is usually a system call on unix-like systems, provided by the operating system kernel, it returns an file descriptor, you can call IO functions with the fd, like read, write.
Generally fopen is implemented using open underline.
If you want to use standard stream functions on a file descriptor, you can use the posix api, fdopen, which takes a fd, and returns a FILE* stream.
I'm working on improving my C programming knowledge, but I am having trouble understanding the man pages for the following Unix system calls:
open
create
close
unlink
read
write
lseek
The man pages for each of these are, for lack of a better term, completely confusing and unintelligible. For example, here is the man page for open:
"Given a pathname for a file, open() returns a file descriptor, a small, nonnegative integer for use in subsequent system calls (read(2), write(2), lseek(2), fcntl(2), etc.). The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process.
By default, the new file descriptor is set to remain open across an execve(2) (i.e., the FD_CLOEXEC file descriptor flag described in fcntl(2) is initially disabled; the O_CLOEXEC flag, described below, can be used to change this default). The file offset is set to the beginning of the file (see lseek(2)).
A call to open() creates a new open file description, an entry in the system-wide table of open files. This entry records the file offset and the file status flags (modifiable via the fcntl(2) F_SETFL operation). A file descriptor is a reference to one of these entries; this reference is unaffected if pathname is subsequently removed or modified to refer to a different file. The new open file description is initially not shared with any other process, but sharing may arise via fork(2)."
I have no idea what this all means. From my understanding, if open returns a negative integer, an error occurred, and if it returns a positive integer, then that integer can be used in further system calls (???). That is, unfortunately, basically the extent of my knowledge and what I can attempt to parse from the man page. I need some help.
What does it mean that it "returns the lowest-numbered file descriptor not currently open for the process"? What process is it referring to? Why is it the lowest-numbered file descriptor, and why does this matter/how would I use this? I hate to sound like an idiot but I honestly have no clue what it's talking about.
Let's take an example. Let's say I wanted to create a new file in a directory, and open up a file from another directory, and copy the file I opened into the file I created, while checking for errors along the way. This is my attempt:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int XYZ = creat("XYZ.doc", 0 );
if (XYZ < 0)
printf("file creating error");
int file = open("/usr/.../xx.xx", 0);
if(file < 0)
printf("file opening error");
}
How would I copy the file that I opened into the file that I created? That should be easy. But what if I wanted to copy the file that I opened in reverse to the file that I created? (Maybe that example will illuminate how to use the file offset stuff mentioned in the man page, which I don't currently understand...)
I would like to edit this post to write a layman's terms description next to each of these system calls, thus creating a good online resource for people to study from. Also, if anyone has any good references for these system calls in C, that would be much appreciated as well.
Error checking left out for simplicity sake:
char data[1024]; /* size of this chosen more or less on a whim */
ssize_t n;
while ((n = read(file, data, sizeof(data))) > 0) {
write(XYZ, data, n);
}
close(file);
close(XYZ);
I want to truncate the file something like setsizeof() with FILE *
I'm developing vs 2003 windows
#include <unistd.h> there's no such lib
how can I do it freopen() truncates all the data vut doesn't write- getting EINVAL error
some help?????
_chsize function does the job better it get fd ans size to change to
There are a number (roughly 20) of header files in the C standard and unistd is not one of them (it's a POSIX/UNIX95/UNIX98 header). So there's no requirement for a vendor to provide it. Neither C89 nor C99 have unistd as one the the mandated header files.
The easiest way to truncate a file is to reopen it in write mode (assuming you have the file name).
fclose (fh);
fh = fopen ("file_name", "w");
If all you have is the file handle, you need to use freopen(). You will only get EINVAL if the mode is incorrect. You cannot change the mode except accoording to the following table:
r -> r
w a -> a w
r+ w+ a+ -> any mode
See man freopen for further details.