blob: d1aaadf9fb88ef18c3dd89fab48b7516cce762b4 [file]
/*
* Copyright 2013 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#if WASMFS
#include <emscripten/wasmfs.h>
#endif
void create_file(const char *path, const char *buffer, int mode) {
int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
assert(fd >= 0);
int err = write(fd, buffer, sizeof(char) * strlen(buffer));
assert(err == (sizeof(char) * strlen(buffer)));
close(fd);
}
void setup() {
create_file("file", "abcdef", 0777);
mkdir("dir", 0777);
mkdir("new-dir", 0777);
create_file("dir/file", "abcdef", 0777);
mkdir("dir/subdir", 0777);
mkdir("dir/subdir/subsubdir", 0777);
mkdir("dir/rename-dir", 0777);
mkdir("dir/rename-dir/subdir", 0777);
mkdir("dir/rename-dir/subdir/subsubdir", 0777);
mkdir("dir-readonly", 0555);
// TODO: Remove when chmod is implemented in WasmFS.
mkdir("dir-readonly2", 0777);
mkdir("dir-readonly2/somename", 0777);
chmod("dir-readonly2", 0555);
mkdir("dir-nonempty", 0777);
mkdir("dir/subdir3", 0777);
mkdir("dir/subdir3/subdir3_1", 0777);
mkdir("dir/subdir4/", 0777);
mkdir("dir/a/", 0777);
mkdir("dir/b/", 0777);
mkdir("dir/b/c", 0777);
create_file("dir-nonempty/file", "abcdef", 0777);
}
void test() {
int err;
// Can't rename something that doesn't exist
err = rename("noexist", "dir");
assert(err == -1);
assert(errno == ENOENT);
// Can't overwrite a folder with a file
err = rename("file", "dir");
assert(err == -1);
assert(errno == EISDIR);
// Can't overwrite a file with a folder
err = rename("dir", "file");
assert(err == -1);
assert(errno == ENOTDIR);
// Can't overwrite a non-empty folder
err = rename("dir", "dir-nonempty");
assert(err == -1);
assert(errno == ENOTEMPTY);
// Can't create anything in a read-only directory
err = rename("dir", "dir-readonly/dir");
assert(err == -1);
assert(errno == EACCES);
// Can't move from a read-only directory.
err = rename("dir-readonly2/somename", "dir");
assert(err == -1);
assert(errno == EACCES);
// Can't rename a file with a new path name that is longer than WASMFS_NAME_MAX.
#ifdef WASMFS
errno = 0;
rename("dir",
"000000000100000000020000000003000000000400000000050000000006000000000"
"700000000080000000009000000000000000000010000000002000000000300000000"
"040000000005000000000600000000070000000008000000000900000000000000000"
"0010000000002000000000300000000040000000005123456");
assert(errno == ENAMETOOLONG);
#endif
// Can't use an empty path for oldpath.
err = rename("", "test");
assert(err == -1);
assert(errno == ENOENT);
// Can't use an empty path for newpath.
err = rename("dir", "");
assert(err == -1);
assert(errno == ENOENT);
// Source should not be ancestor of target.
err = rename("dir", "dir/somename");
assert(err == -1);
assert(errno == EINVAL);
// Even if it is not a direct ancestor.
err = rename("dir", "dir/subdir/noexist");
assert(err == -1);
assert(errno == EINVAL);
// After changing the current working directory and using a relative path to
// the target, we should still detect that the source is an ancestor of the
// target.
chdir("dir/rename-dir/subdir");
err = rename("/dir/rename-dir", "subsubdir");
assert(err == -1);
assert(errno == EINVAL);
chdir("/");
// Target should not be an ancestor of source
err = rename("dir/subdir", "dir");
assert(err == -1);
assert(errno == ENOTEMPTY);
err = rename("dir/subdir/subsubdir", "dir");
assert(err == -1);
assert(errno == ENOTEMPTY);
// Do some valid renaming
err = rename("dir/file", "dir/file1");
assert(!err);
err = rename("dir/file1", "dir/file2");
assert(!err);
// TODO: Remove when WASMFS implements the access syscall.
#ifndef WASMFS
err = access("dir/file2", F_OK);
#endif
assert(!err);
err = rename("dir/subdir", "dir/subdir1");
assert(!err);
err = rename("dir/subdir1", "dir/subdir2");
assert(!err);
#ifndef WASMFS
err = access("dir/subdir2", F_OK);
#endif
assert(!err);
err = rename("dir/subdir2", "dir/subdir3/subdir3_1/subdir1 renamed");
assert(!err);
#ifndef WASMFS
err = access("dir/subdir3/subdir3_1/subdir1 renamed", F_OK);
#endif
assert(!err);
// Test that non-existent parent during rename generates the correct error
// code.
err = rename("dir/hicsuntdracones/empty", "dir/hicsuntdracones/renamed");
assert(err == -1);
assert(errno == ENOENT);
err = rename("dir/subdir4/", "dir/subdir5/");
assert(!err);
// Test renaming the same directory.
err = rename("dir/file2", "dir/file2");
assert(!err);
// Test renaming a directory with a subdirectory with a common ancestor.
err = rename("dir/a", "dir/b/c");
assert(!err);
// In Linux and WasmFS, renaming the root directory should return EBUSY.
// In the JS file system it reports EINVAL.
err = rename("/", "dir/file2");
assert(err == -1);
#ifdef WASMFS
assert(errno == EBUSY);
#else
assert(errno == EINVAL);
#endif
// Test renaming a directory with root.
err = rename("dir/file2", "/");
assert(err == -1);
#ifdef WASMFS
assert(errno == EBUSY);
#else
assert(errno == ENOTEMPTY);
#endif
#ifdef WASMFS
// Files cannot be renamed between backends.
// Create a new backend (and make sure it is different).
backend_t js_backend = wasmfs_create_js_file_backend();
assert(js_backend != wasmfs_get_backend_by_path("/"));
// Create a directory and a file.
err = wasmfs_create_directory("/js-dir", 0777, js_backend);
assert(err == 0);
create_file("/js-dir/js-file", "foo", 0777);
// Try to move it.
err = rename("/js-dir/js-file", "/moved-js-file");
assert(err == -1);
assert(errno == EXDEV);
#endif
puts("done");
}
int main() {
setup();
test();
return 0;
}