The rename()
function has the following prototype:
Code Block |
---|
int rename(const char *src_file, const char *dest_file);
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
/* Handle Error */
}
|
...
If the programmer's intent is to not remove to remove an existing destination file, the POSIX access()
function can be used to check for the existence of a file [Open Group 2004]. This compliant solution renames the source file only if the destination file does not exist.
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (access(dest_file, F_OK) != 0) {
if (rename(src_file, dest_file) != 0) {
/* Handle error condition */
}
}
else {
/* Handle file-exists condition */
}
|
This code contains an unavoidable race condition between the call to access()
and the call to rename()
and can consequently be safely executed only when the destination file is located within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)
...
In situations where the source file is supposed not to be a directory or symbolic link, an alternative solution is to use link()
to link the source file to the destination file and then use unlink()
(or remove()
) to delete the source file. Since link()
fails if the destination file exists, this avoids the need for calling access()
is avoided. However, this solution has two race conditions related to the source file. First, before calling link()
, the program must use lstat()
to check that the source file is not a directory or symbolic link. Second, there is the time the source file could change during time window between the link()
and the unlink()
during which the source file could change. Consequently, this alternative solution can be safely executed only when the source file is located within a secure directory.
...
On Windows, the rename()
function fails if [MSDN]a
File file or directory specified by
newname
already exists or could not be created (invalid path) [MSDN].
Consequently, it is unnecessary to explicitly check for the existence of the destination file before calling rename()
.
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
/* Handle Error */
}
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
/* Handle error */
}
|
...
On Windows systems, it is necessary to explicitly remove the destination file before calling rename()
, if you want the file to be overwritten and the rename()
operation to succeed.
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (_access_s(dest_file, 0) == 0) {
if (remove(dest_file) != 0) {
/* Handle error condition */
}
}
if (rename(src_file, dest_file) != 0) {
/* Handle error condition */
}
|
This code contains unavoidable race conditions between the calls to _access_s()
, remove()
, and rename()
and can consequently be safely executed only within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)
...
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
/* Handle error condition */
}
|
...
A programmer who wants an application to behave the same on any C99 C implementation must first determine what behavior to implement.
...
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
(void)remove(dest_file);
if (rename(src_file, dest_file) != 0) {
/* Handle error condition */
}
|
This code contains an unavoidable race condition between the call to remove()
and the call to rename()
and , consequently , can be safely executed only within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)
The return value of remove()
is deliberately not checked because it is expected to fail in the case where fail if 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. This is a valid exception (EXP12-EX1) to recommendation EXP12-C. Do not ignore values returned by functions.
...
Code Block | ||||
---|---|---|---|---|
| ||||
const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (!file_exists(dest_file)) {
if (rename(src_file, dest_file) != 0) {
/* Handle error condition */
}
}
else {
/* Handle file-exists condition */
}
|
This code contains an unavoidable race condition between the call to file_exists()
and the call to rename()
and can consequently be safely executed only within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)
...
CERT C++ Secure Coding Standard: FIO10-CPP. Take care when using the rename() function
ISO/IEC 9899:1999 Section 2011 Section 7.921.4.2, "The rename
function"
...