File: test_rename.c

package info (click to toggle)
emscripten 3.1.6~dfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 114,112 kB
  • sloc: ansic: 583,052; cpp: 391,943; javascript: 79,361; python: 54,180; sh: 49,997; pascal: 4,658; makefile: 3,426; asm: 2,191; lisp: 1,869; ruby: 488; cs: 142
file content (261 lines) | stat: -rw-r--r-- 7,233 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*
 * 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 <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

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.
#ifdef WASMFS
  mkdir("dir-readonly2", 0555);
#else
  mkdir("dir-readonly2", 0777);
#endif
  mkdir("dir-readonly2/somename", 0777);
#ifndef WASMFS
  chmod("dir-readonly2", 0555);
#endif
  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 cleanup() {
  // we're hulk-smashing and removing original + renamed files to
  // make sure we get it all regardless of anything failing
  unlink("file");
  unlink("dir/file");
  unlink("dir/file1");
  unlink("dir/file2");
  rmdir("dir/subdir/subsubdir");
  rmdir("dir/subdir");
  rmdir("dir/subdir1");
  rmdir("dir/subdir2");
  rmdir("dir/subdir3/subdir3_1/subdir1 renamed");
  rmdir("dir/subdir3/subdir3_1");
  rmdir("dir/subdir3");
  rmdir("dir/subdir4/");
  rmdir("dir/subdir5/");
  rmdir("dir/b/c");
  rmdir("dir/b");
  rmdir("dir/rename-dir/subdir/subsubdir");
  rmdir("dir/rename-dir/subdir");
  rmdir("dir/rename-dir");
  rmdir("dir");
#ifndef WASMFS
  chmod("dir-readonly2", 0777);
#endif
  rmdir("dir-readonly2/somename");
  rmdir("dir-readonly2");
  rmdir("new-dir");
  rmdir("dir-readonly");
  unlink("dir-nonempty/file");
  rmdir("dir-nonempty");
}

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);

  // 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.
  // TODO: WasmFS needs to traverse up the directory tree from the target to
  // detect this case. To do that safely, we will need to globally lock the
  // directory structure to prevent concurrent modifications during the
  // traversal. In this test, providing the new path as a relative path from the
  // cwd means the ancestor will not be encountered during traversal from root.
  // As a result, this ancestor is unlinked and forms a cycle which is no longer
  // reachable from root.
  chdir("dir/rename-dir/subdir");
  err = rename("/dir/rename-dir", "subsubdir");
#ifdef WASMFS
  assert(err == 0);
#else
  assert(err == -1);
  assert(errno == EINVAL);
#endif
  chdir("/");

  err = rename("dir", "dir/somename/noexist");
  assert(err == -1);
  // In the JS file system, this returns ENOENT rather than detecting that dir
  // is an ancestor.
#ifdef WASMFS
  assert(errno == EINVAL);
#else
  assert(errno == ENOENT);
#endif

  err = rename("dir", "dir/subdir");
  assert(err == -1);
  assert(errno == EINVAL);

  // 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-existant 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);
  assert(errno == ENOTEMPTY);

  puts("success");
}

int main() {
  atexit(cleanup);
  signal(SIGABRT, cleanup);
  setup();
  test();
  return EXIT_SUCCESS;
}