summaryrefslogtreecommitdiff
path: root/tests/stdio_test.cpp
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2019-04-17 13:01:06 -0700
committerElliott Hughes <enh@google.com>2019-08-02 09:09:59 -0700
commit05b675e8bfec6e33138fd2e1b2e0e16afe745b37 (patch)
tree2de2c98f748581531eaa6b0bb92adbe30f891f36 /tests/stdio_test.cpp
parentc2a722f5d77911afd199f452b03d9c15fbe645f8 (diff)
Add renameat2.
Bug: http://b/127675384 Test: new tests Change-Id: Ia2e3d5679180391ca98e62fa429fa11cbf167507
Diffstat (limited to 'tests/stdio_test.cpp')
-rw-r--r--tests/stdio_test.cpp83
1 files changed, 82 insertions, 1 deletions
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 01b4dbab7..a0cda1be0 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -19,7 +19,6 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <linux/fs.h>
#include <math.h>
#include <stdio.h>
#include <sys/types.h>
@@ -34,10 +33,18 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/unique_fd.h>
#include "BionicDeathTest.h"
#include "utils.h"
+// This #include is actually a test too. We have to duplicate the
+// definitions of the RENAME_ constants because <linux/fs.h> also contains
+// pollution such as BLOCK_SIZE which conflicts with lots of user code.
+// Important to check that we have matching definitions.
+// There's no _MAX to test that we have all the constants, sadly.
+#include <linux/fs.h>
+
#if defined(NOFORTIFY)
#define STDIO_TEST stdio_nofortify
#define STDIO_DEATHTEST stdio_nofortify_DeathTest
@@ -2610,3 +2617,77 @@ TEST(STDIO_TEST, SEEK_macros) {
// So we'll notice if Linux grows another constant in <linux/fs.h>...
ASSERT_EQ(SEEK_MAX, SEEK_HOLE);
}
+
+TEST(STDIO_TEST, rename) {
+ TemporaryDir td;
+ std::string old_path = td.path + "/old"s;
+ std::string new_path = td.path + "/new"s;
+
+ // Create the file, check it exists.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+ struct stat sb;
+ ASSERT_EQ(0, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(-1, stat(new_path.c_str(), &sb));
+
+ // Rename and check it moved.
+ ASSERT_EQ(0, rename(old_path.c_str(), new_path.c_str()));
+ ASSERT_EQ(-1, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(0, stat(new_path.c_str(), &sb));
+}
+
+TEST(STDIO_TEST, renameat) {
+ TemporaryDir td;
+ android::base::unique_fd dirfd{open(td.path, O_PATH)};
+ std::string old_path = td.path + "/old"s;
+ std::string new_path = td.path + "/new"s;
+
+ // Create the file, check it exists.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+ struct stat sb;
+ ASSERT_EQ(0, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(-1, stat(new_path.c_str(), &sb));
+
+ // Rename and check it moved.
+ ASSERT_EQ(0, renameat(dirfd, "old", dirfd, "new"));
+ ASSERT_EQ(-1, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(0, stat(new_path.c_str(), &sb));
+}
+
+TEST(STDIO_TEST, renameat2) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "glibc doesn't have renameat2 until 2.28";
+#else
+ TemporaryDir td;
+ android::base::unique_fd dirfd{open(td.path, O_PATH)};
+ std::string old_path = td.path + "/old"s;
+ std::string new_path = td.path + "/new"s;
+
+ // Create the file, check it exists.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+ struct stat sb;
+ ASSERT_EQ(0, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(-1, stat(new_path.c_str(), &sb));
+
+ // Rename and check it moved.
+ ASSERT_EQ(0, renameat2(dirfd, "old", dirfd, "new", 0));
+ ASSERT_EQ(-1, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(0, stat(new_path.c_str(), &sb));
+
+ // After this, both "old" and "new" exist.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+
+ // Rename and check it moved.
+ ASSERT_EQ(-1, renameat2(dirfd, "old", dirfd, "new", RENAME_NOREPLACE));
+ ASSERT_EQ(EEXIST, errno);
+#endif
+}
+
+TEST(STDIO_TEST, renameat2_flags) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "glibc doesn't have renameat2 until 2.28";
+#else
+ ASSERT_NE(0, RENAME_EXCHANGE);
+ ASSERT_NE(0, RENAME_NOREPLACE);
+ ASSERT_NE(0, RENAME_WHITEOUT);
+#endif
+}