...
In this example, an attempt is made to check whether a file exists before opening it for writing by trying to open the file for reading.
Code Block |
---|
|
char *file_name;
FILE *fp;
/* initialize file_name */
fp = fopen(file_name,"r");
if (!fp) { /* file does not exist */
fp = fopen(file_name,"w");
/* ... */
fclose(fp);
} else {
/* file exists */
fclose(fp);
}
|
...
The fopen_s()
function defined in ISO/IEC TR 24731-1:2007 is designed to improve the security of the fopen()
function. However, like fopen()
, fopen_s()
provides no mechanism to determine if an existing file has been opened for writing or a new file has been created. The code below contains the same TOCTOU race condition as the first non-compliant code example using fopen()
.
Code Block |
---|
|
char *file_name;
FILE *fptr;fp;
/* initialize file_name */
errno_t res = fopen_s(&fptrfp, file_name, "r");
if (res != 0) { /* file does not exist */
res = fopen_s(&fptrfp, file_name, "w");
/* ... */
fclose(fptrfp);
} else {
fclose(fptrfp);
}
|
Compliant Solution: open()
(POSIX)
Wiki Markup |
---|
The {{open()}} function as defined in the Open Group Base Specifications Issue 6 \[[Open Group 04|AA. C References#Open Group 04]\] is available on many platforms and provides the control that {{fopen()}} does not provide. If the {{O_CREAT}} and {{O_EXCL}} flags are used together, the {{open()}} function fails if the file specified by {{file_name}} already exists. |
Code Block |
---|
|
char *file_name;
int new_file_mode;
/* initialize file_name and new_file_mode */
int fd = open(file_name, O_CREAT | O_EXCL | O_WRONLY, new_file_mode);
if (fd == -1) {
/* Handle Error */
}
|
...
The GNU C library defines one additional character for use in opentype
: the character 'x
' insists on creating a new fileâ”if a file filename
already exists, fopen
fails rather than opening it. If you use 'x
' you are guaranteed that you will not clobber an existing file. This is equivalent to the O_EXCL
option to the open
function.
Code Block |
---|
|
char *file_name;
/* initialize file_name */
FILE *fp = fopen(file_name,"wx");
if (!fp) {
/* Handle Error */
}
|
...
Wiki Markup |
---|
For code that operates on {{FILE}} pointers and not file descriptors, the POSIX {{fdopen()}} function \[[Open Group 04|AA. C References#Open Group 05]\] can be used to associate an open stream with the file descriptor returned by {{open()}}, as shown in this compliant solution. |
Code Block |
---|
|
char *file_name;
int new_file_mode;
FILE *fp;
int fd;
/* initialize file_name and new_file_mode */
fd = open(file_name, O_CREAT | O_EXCL | O_WRONLY, new_file_mode);
if (fd == -1) {
/* Handle Error */
}
fp = fdopen(fd, "w");
if (fp == NULL) {
/* Handle Error */
}
|
...