rmdirtest.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
  3. * The President and Fellows of Harvard College.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * rmdirtest.c
  31. *
  32. * Tests file system synchronization and directory implementation by
  33. * removing the current directory under itself and then trying to do
  34. * things. It's ok for most of those things to fail, but the system
  35. * shouldn't crash.
  36. */
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include <unistd.h>
  42. #include <fcntl.h>
  43. #include <errno.h>
  44. #include <limits.h>
  45. #include <err.h>
  46. static const char testdir[] = "testdir";
  47. static char startpoint[PATH_MAX - sizeof(testdir)];
  48. /*
  49. * Create the test directory, and change into it, remembering
  50. * where we came from.
  51. */
  52. static
  53. void
  54. startup(void)
  55. {
  56. if (getcwd(startpoint, sizeof(startpoint))==NULL) {
  57. err(1, "getcwd (not in test dir)");
  58. }
  59. if (mkdir(testdir, 0775) < 0) {
  60. err(1, "%s: mkdir", testdir);
  61. }
  62. if (chdir(testdir) < 0) {
  63. err(1, "%s: chdir", testdir);
  64. }
  65. }
  66. /*
  67. * Remove the test directory.
  68. *
  69. * Note that even though it's the current directory, we can't do it
  70. * with rmdir(".") - what that would try to do is remove the "." entry
  71. * from the current directory, which is justifiably prohibited.
  72. */
  73. static
  74. void
  75. killdir(void)
  76. {
  77. char tmp[PATH_MAX];
  78. snprintf(tmp, sizeof(tmp), "%s/%s", startpoint, testdir);
  79. if (rmdir(tmp)<0) {
  80. err(1, "%s: rmdir", tmp);
  81. }
  82. }
  83. /*
  84. * Leave the test directory and go back to where we came from, so we
  85. * can try again.
  86. */
  87. static
  88. void
  89. finish(void)
  90. {
  91. if (chdir(startpoint)<0) {
  92. err(1, "%s: chdir", startpoint);
  93. }
  94. }
  95. /*************************************************************/
  96. /*
  97. * Basic test - just try removing the directory without doing anything
  98. * evil.
  99. */
  100. static
  101. void
  102. test1(void)
  103. {
  104. printf("Making %s\n", testdir);
  105. startup();
  106. printf("Removing %s while in it\n", testdir);
  107. killdir();
  108. printf("Leaving the test directory\n");
  109. finish();
  110. }
  111. /*
  112. * Now do it while we also have the directory open.
  113. */
  114. static
  115. void
  116. test2(void)
  117. {
  118. int fd;
  119. printf("Now trying with the directory open...\n");
  120. startup();
  121. fd = open(".", O_RDONLY);
  122. if (fd<0) {
  123. err(1, ".: open");
  124. }
  125. killdir();
  126. finish();
  127. /* close *after* leaving, just for excitement */
  128. if (close(fd)<0) {
  129. err(1, "removed %s: close", testdir);
  130. }
  131. }
  132. /*
  133. * Now see if . and .. work after rmdir.
  134. */
  135. static
  136. void
  137. test3(void)
  138. {
  139. char buf[PATH_MAX];
  140. int fd;
  141. printf("Checking if . exists after rmdir\n");
  142. startup();
  143. killdir();
  144. fd = open(".", O_RDONLY);
  145. if (fd<0) {
  146. switch (errno) {
  147. case EINVAL:
  148. case EIO:
  149. case ENOENT:
  150. break;
  151. default:
  152. err(1, ".");
  153. break;
  154. }
  155. }
  156. else {
  157. close(fd);
  158. }
  159. fd = open("..", O_RDONLY);
  160. if (fd<0) {
  161. switch (errno) {
  162. case EINVAL:
  163. case EIO:
  164. case ENOENT:
  165. break;
  166. default:
  167. err(1, "..");
  168. break;
  169. }
  170. }
  171. else {
  172. warnx("..: openable after rmdir - might be bad");
  173. close(fd);
  174. }
  175. snprintf(buf, sizeof(buf), "../%s", testdir);
  176. fd = open(buf, O_RDONLY);
  177. if (fd<0) {
  178. switch (errno) {
  179. case EINVAL:
  180. case EIO:
  181. case ENOENT:
  182. break;
  183. default:
  184. err(1, "%s", buf);
  185. break;
  186. }
  187. }
  188. else {
  189. errx(1, "%s: works after rmdir", buf);
  190. }
  191. finish();
  192. }
  193. /*
  194. * Now try to create files.
  195. */
  196. static
  197. void
  198. test4(void)
  199. {
  200. char buf[4096];
  201. int fd;
  202. printf("Checking if creating files works after rmdir...\n");
  203. startup();
  204. killdir();
  205. fd = open("newfile", O_WRONLY|O_CREAT|O_TRUNC, 0664);
  206. if (fd<0) {
  207. switch (errno) {
  208. case EINVAL:
  209. case EIO:
  210. case ENOENT:
  211. break;
  212. default:
  213. err(1, "%s", buf);
  214. break;
  215. }
  216. }
  217. else {
  218. warnx("newfile: creating files after rmdir works");
  219. warnx("(this is only ok if the space gets reclaimed)");
  220. /*
  221. * Waste a bunch of space so we'll be able to tell
  222. */
  223. memset(buf, 'J', sizeof(buf));
  224. write(fd, buf, sizeof(buf));
  225. write(fd, buf, sizeof(buf));
  226. write(fd, buf, sizeof(buf));
  227. write(fd, buf, sizeof(buf));
  228. close(fd);
  229. }
  230. finish();
  231. }
  232. /*
  233. * Now try to create directories.
  234. */
  235. static
  236. void
  237. test5(void)
  238. {
  239. printf("Checking if creating subdirs works after rmdir...\n");
  240. startup();
  241. killdir();
  242. if (mkdir("newdir", 0775)<0) {
  243. switch (errno) {
  244. case EINVAL:
  245. case EIO:
  246. case ENOENT:
  247. break;
  248. default:
  249. err(1, "mkdir in removed dir");
  250. break;
  251. }
  252. }
  253. else {
  254. warnx("newfile: creating directories after rmdir works");
  255. warnx("(this is only ok if the space gets reclaimed)");
  256. /*
  257. * Waste a bunch of space so we'll be able to tell
  258. */
  259. mkdir("newdir/t0", 0775);
  260. mkdir("newdir/t1", 0775);
  261. mkdir("newdir/t2", 0775);
  262. mkdir("newdir/t3", 0775);
  263. mkdir("newdir/t4", 0775);
  264. mkdir("newdir/t5", 0775);
  265. }
  266. finish();
  267. }
  268. /*
  269. * Now try listing the directory.
  270. */
  271. static
  272. void
  273. test6(void)
  274. {
  275. char buf[PATH_MAX];
  276. int fd, len;
  277. printf("Now trying to list the directory...\n");
  278. startup();
  279. fd = open(".", O_RDONLY);
  280. if (fd<0) {
  281. err(1, ".: open");
  282. }
  283. killdir();
  284. while ((len = getdirentry(fd, buf, sizeof(buf)-1))>0) {
  285. if ((unsigned)len >= sizeof(buf)-1) {
  286. errx(1, ".: getdirentry: returned invalid length");
  287. }
  288. buf[len] = 0;
  289. if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
  290. /* these are allowed to appear */
  291. continue;
  292. }
  293. errx(1, ".: getdirentry: returned unexpected name %s", buf);
  294. }
  295. if (len==0) {
  296. /* EOF - ok */
  297. }
  298. else { /* len < 0 */
  299. switch (errno) {
  300. case EINVAL:
  301. case EIO:
  302. break;
  303. default:
  304. err(1, ".: getdirentry");
  305. break;
  306. }
  307. }
  308. finish();
  309. /* close *after* leaving, just for excitement */
  310. if (close(fd)<0) {
  311. err(1, "removed %s: close", testdir);
  312. }
  313. }
  314. /*
  315. * Try getcwd.
  316. */
  317. static
  318. void
  319. test7(void)
  320. {
  321. char buf[PATH_MAX];
  322. startup();
  323. killdir();
  324. if (getcwd(buf, sizeof(buf))==NULL) {
  325. switch (errno) {
  326. case EINVAL:
  327. case EIO:
  328. case ENOENT:
  329. break;
  330. default:
  331. err(1, "getcwd after removing %s", testdir);
  332. break;
  333. }
  334. }
  335. else {
  336. errx(1, "getcwd after removing %s: succeeded (got %s)",
  337. testdir, buf);
  338. }
  339. finish();
  340. }
  341. /**************************************************************/
  342. int
  343. main(void)
  344. {
  345. test1();
  346. test2();
  347. test3();
  348. test4();
  349. test5();
  350. test6();
  351. test7();
  352. printf("Whew... survived.\n");
  353. return 0;
  354. }