...
If the file referenced by new
exists prior to calling rename()
, the behavior is implementation-defined. For portability, you must ensure that the file referenced by new
does not exist when rename()
is invoked.
Non-Compliant Code Example
In this non-compliant code example, a file is moved using rename()
.
Code Block | ||
---|---|---|
| ||
char const *old = /* ... */;
char const *new = /* ... */;
if (rename(old, new) != 0) {
/* Handle Error */
}
|
If the file named by new
exists at the time of the call to rename()
, the result is implementation-defined.
Compliant Solution
This compliant solution checks for the existence of the new file before callling rename()
. This code contains an unavoidable race condition between the call to fopen()
and the call to rename()
. Consequently, this code can only be safely executed within a secure directory.
Code Block | ||
---|---|---|
| ||
char const *old = /* ... */;
char const *new = /* ... */;
FILE *file = fopen(new, "r");
if (!file) {
if (rename(old, new) != 0) {
/* Handle Error */
}
} else {
fclose(file);
/* handle Error */
}
|
Unfortunately, fopen()
may fail on many file systems when the file exists but the program does not have sufficient permissions to read it.
Compliant Solution (POSIX)
Wiki Markup |
---|
A somewhat better solution involves using the The POSIX {{access()}} function which can check for the existence of a file explicitly \[[Open Group 04|AA. C References#Open Group 04]\]. As with the {{fopen()}} solution, this code contains an unavoidable race condition and consequently can only be safely executed within a secure directory. In fact the existence check is not really needed on POSIX systems, because POSIX specifies the behavior of {{rename()}} when the file referenced by {{new}} exists. |
...
Wiki Markup |
---|
On Windows, [{{_access_srename()}}|http://msdn.microsoft.com/en-us/library/a2xs1dtszw5t957f(VS.80).aspx] allowsis already onedefined to checkreturn for the existence of a filenonzero if: \[[MSDN|AA. C References#MSDN]\]. As with the {{fopen()}} solution, this code contains an unavoidable race condition and consequently can only be safely executed within a secure directory. |
Code Block | ||
---|---|---|
| ||
char const *old = /* ... */;
char const *new = /* ... */;
if (_access_s(new,0) != 0) {
if (rename(old, new) != 0) {
/* Handle Error */
}
} else {
/* Handle Error */
}
|
File or directory specified by
newname
already exists or could not be created (invalid path)
So it is not necessary to explicitly check for the existence of new
before calling rename()
This _access_s()
example shares many of the same problems as the POSIX access()
example above.
Risk Assessment
Calling rename()
has implementation-defined behavior when the new file name refers to an existing file. Incorrect use of rename()
can result in a file being unexpectedly overwritten or other unexpected behavior.
...
Wiki Markup |
---|
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.9.4.2, "The {{rename}} function" \[[MSDN|AA. C References#MSDN]\] [{{_access_s, _waccess_srename()}}|http://msdn.microsoft.com/en-us/library/a2xs1dtszw5t957f(VS.80).aspx] \[[Open Group 04|AA. C References#Open Group 04]\] [{{access()}}|http://www.opengroup.org/onlinepubs/009695399/functions/access.html] |
...