Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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
bgColor#FFCCCC
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
bgColor#FFCCCC
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
bgColor#ccccff
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
bgColor#ccccff
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
bgColor#ccccff
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 */
}

...