Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: changed titles & wording to indicate that target file is being protected or erased

...

Code Block
int rename(char const *oldsrc_file, char const *newdest_file);

If the file referenced by newdest_file exists prior to calling rename(), the behavior is implementation-defined. On POSIX systems, the file is removed. On Windows systems, the rename() fails.

This creates issues when trying to write portable code, or when trying to implement alternative behavior.

New File Removed

Protect Pre-existing dest_file

Occasionally, a programmer might want to implement a behavior other than the implementation-defined behavior for rename() on that platform. If the desired behavior is to ensure that any file referenced by newdest_file is removed, Windows not erased or overwritten, POSIX programmers must write implement additional codesafeguards.

Non-Compliant Code Example (

...

POSIX)

This If the intent of the programmer is to remove the file referenced by new_file if it exists prior to calling rename(), this code example is non-compliant on Windows platforms because because if dest_file exists it is removed by rename() will fail.

Code Block
bgColor#ffcccc
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;
if (rename(oldsrc_file, newdest_file) != 0) {
  /* Handle Error */
}

Compliant Solution (

...

POSIX)

Wiki Markup
If the intent of the programmer is to not remove the file referenced by {{dest_file}} if it exists prior to calling {{rename()}}, the POSIX {{access()}} function can be used to check for the existence of a file explicitly \[[Open Group 04|AA. C References#Open Group 04]\]. This compliant solution only renames the file referenced by {{src_file}} if the file referenced by {{dest_file}} does not exist
On Windows systems, it is necessary to explicitly remove the file referenced by new_file before calling rename(), if you want the file to be overwritten and the rename() operation to succeed
.

Code Block
bgColor#ccccff
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;

if (_access_s(newdest_file,0 F_OK) =!= 0) {
  if (remove(newrename(src_file, dest_file) != 0) {
    /* Handle error condition */
  }
}

if (rename(old_file, new_file) != 0)  
else {
  /* Handle errorfile-exists condition */
}

This code contains an unavoidable race conditions condition between the calls call to _access_s(), remove() and and the call to rename() and can consequently only be safely executed within a secure directory (see FIO17-A. Ensure that file operations are performed in a secure directory).

On file systems where the program does not have sufficient permissions in the directory to view the file, access() may return -1 even when the file exists. In such cases, rename() would also fail because the program lacks adequate permissions to perform the operation.

Compliant Solution (

...

Windows)

Wiki Markup
On Windows, the [{{rename()}}|http://msdn.microsoft.com/en-us/library/zw5t957f(VS.80).aspx] function fails if \[[MSDN|AA. C References#MSDN]\]:

File or directory specified by newname already exists or could not be created (invalid path)

Consequently, it is unnecessary to explicitly check for the existence of On POSIX systems, if the file referenced by newdest_file exists prior to before calling rename(), the file is automatically removed.

Code Block
bgColor#ccccff
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;
if (rename(oldsrc_file, newdest_file) != 0) {
  /* Handle error conditionError */
}

...

Erase Pre-existing dest_file

If the desired behavior is to ensure that any file referenced by newdest_file is not removed, POSIX erased by the rename() operation, Windows programmers must implement write additional safe guardscode.

Non-Compliant Code Example (

...

Windows)

If the intent of the programmer is to remove the file referenced by dest_file if it exists prior to calling rename(), this This code example is non-compliant because if new_file exists it is removed by on Windows platforms because rename() will fail.

Code Block
bgColor#ffcccc
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;
if (rename(oldsrc_file, newdest_file) != 0) {
  /* Handle Error */
}

Compliant Solution (

...

Windows)

On Windows systems, it is necessary to explicitly remove the file referenced by dest_file before calling rename(), if you want the file to be overwritten and the rename() operation to succeed. Wiki MarkupIf the intent of the programmer is to not remove the file referenced by {{new_file}} if it exists prior to calling {{rename()}}, the POSIX {{access()}} function can be used to check for the existence of a file explicitly \[[Open Group 04|AA. C References#Open Group 04]\]. This compliant solution only renames the file referenced by {{old_file}} if the file referenced by {{new_file}} does not exist.

Code Block
bgColor#ccccff
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;

if (_access_s(newdest_file, F_OK0) !== 0) {
  if (rename(old_file, newremove(dest_file) != 0) {
    /* Handle error condition */
  }
} 
else

if (rename(src_file, dest_file) != 0) {
  /* Handle file-existserror condition */
}

This code contains an unavoidable race condition conditions between the call calls to _access_s() and the call to , remove() and rename() and can consequently only be safely executed within a secure directory (see FIO17-A. Ensure that file operations are performed in a secure directory).On file systems where the program does not have sufficient permissions in the directory to view the file, access() may return -1 even when the file exists. In such cases, rename() would also fail because the program lacks adequate permissions to perform the operation.

Compliant Solution (

...

POSIX)

On Windows, the [{{rename()}}|http://msdn.microsoft.com/en-us/library/zw5t957f(VS.80).aspx] function fails if \[[MSDN|AA. C References#MSDN]\]:

File or directory specified by newname already exists or could not be created (invalid path)

Consequently, it is unnecessary to explicitly check for the existence of POSIX systems, if the file referenced by newdest_file before exists prior to calling rename(), the file is automatically removed.

Code Block
bgColor#ccccff
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;
if (rename(oldsrc_file, newdest_file) != 0) {
  /* Handle error Errorcondition */
}

Portable Behavior

A programmer that wants an application to behave the same on any C99 implementation must first determine what behavior to implement.

Compliant Solution (

...

Erase Pre-existing dest_file)

This compliant solution ensures that any file referenced by newdest_file is portably removed.

Code Block
bgColor#ccccff
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;

(void)remove(newdest_file);

if (rename(oldsrc_file, newdest_file) != 0) {
  /* Handle error condition */
}

...

The return value of remove() is deliberately not checked, because it is expected to fail in the case where the file does not exist. If the file exists but cannot be removed, the rename() call will also fail and the error will be detected at that point.

Compliant Solution (

...

Protect Pre-existing dest_file)

This compliant solution only renames the file referenced by oldsrc_file if the file referenced by newdest_file does not exist.

Code Block
bgColor#ccccff
char const *oldsrc_file = /* ... */;
char const *newdest_file = /* ... */;

if (!file_exists(newdest_file)) {
  if (rename(oldsrc_file, newdest_file) != 0) {
    /* Handle error condition */
  }
} 
else {
  /* Handle file-exists condition */
}

...