t_union.c revision 1.1 1 /* $NetBSD: t_union.c,v 1.1 2011/01/12 21:13:27 pooka Exp $ */
2
3 #include <sys/types.h>
4 #include <sys/mount.h>
5
6 #include <atf-c.h>
7 #include <err.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <stdlib.h>
14
15 #include <rump/rump.h>
16 #include <rump/rump_syscalls.h>
17
18 #include <miscfs/union/union.h>
19
20 #include "../../h_macros.h"
21 #include "../common/h_fsmacros.h"
22
23 #define MSTR "magic bus"
24
25 #define HAS_WHITEOUT (FSTYPE_FFS(tc) || FSTYPE_FFSLOG(tc) || \
26 FSTYPE_LFS(tc) || FSTYPE_RUMPFS(tc))
27
28 static void
29 xput_tfile(const char *mp, const char *path)
30 {
31 char pathb[MAXPATHLEN];
32 int fd;
33
34 strcpy(pathb, mp);
35 strcat(pathb, "/");
36 strcat(pathb, path);
37
38 RL(fd = rump_sys_open(pathb, O_CREAT | O_RDWR, 0777));
39 if (rump_sys_write(fd, MSTR, sizeof(MSTR)) != sizeof(MSTR))
40 atf_tc_fail_errno("write to testfile");
41 RL(rump_sys_close(fd));
42 }
43
44 static int
45 xread_tfile(const char *mp, const char *path)
46 {
47 char pathb[MAXPATHLEN];
48 char buf[128];
49 int fd;
50
51 strcpy(pathb, mp);
52 strcat(pathb, "/");
53 strcat(pathb, path);
54
55 fd = rump_sys_open(pathb, O_RDONLY);
56 if (fd == -1)
57 return errno;
58 if (rump_sys_read(fd, buf, sizeof(buf)) == -1)
59 atf_tc_fail_errno("read tfile");
60 RL(rump_sys_close(fd));
61 if (strcmp(buf, MSTR) == 0)
62 return 0;
63 return EPROGMISMATCH;
64 }
65
66 #define TFILE "tensti"
67 static void
68 basic(const atf_tc_t *tc, const char *mp)
69 {
70 char lowerpath[MAXPATHLEN];
71 char dbuf[8192];
72 struct union_args unionargs;
73 struct stat sb;
74 struct dirent *dp;
75 int error, fd, dsize;
76
77 if (!HAS_WHITEOUT) {
78 atf_tc_skip("file system does not support VOP_WHITEOUT");
79 }
80
81 snprintf(lowerpath, sizeof(lowerpath), "%s.lower", mp);
82
83 RL(rump_sys_mkdir(lowerpath, 0777));
84
85 /* create a file in the lower layer */
86 xput_tfile(lowerpath, TFILE);
87
88 /* mount the union with our testfs as the upper layer */
89 memset(&unionargs, 0, sizeof(unionargs));
90 unionargs.target = lowerpath;
91 unionargs.mntflags = UNMNT_BELOW;
92
93 if (rump_sys_mount(MOUNT_UNION, mp, 0,
94 &unionargs, sizeof(unionargs)) == -1)
95 atf_tc_fail_errno("union mount");
96
97 /* first, test we can read the old file from the new namespace */
98 error = xread_tfile(mp, TFILE);
99 if (error != 0)
100 atf_tc_fail("union compare failed: %d (%s)",
101 error, strerror(error));
102
103 /* then, test upper layer writes don't affect the lower layer */
104 xput_tfile(mp, "kiekko");
105 if ((error = xread_tfile(lowerpath, "kiekko")) != ENOENT)
106 atf_tc_fail("invisibility failed: %d (%s)",
107 error, strerror(error));
108
109 /* check that we can whiteout stuff in the upper layer */
110 FSTEST_ENTER();
111 RL(rump_sys_unlink(TFILE));
112 ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TFILE, &sb) == -1);
113 FSTEST_EXIT();
114
115 /* check that the removed node is not in the directory listing */
116 RL(fd = rump_sys_open(mp, O_RDONLY));
117 RL(dsize = rump_sys_getdents(fd, dbuf, sizeof(dbuf)));
118 for (dp = (struct dirent *)dbuf;
119 (char *)dp < dbuf + dsize;
120 dp = _DIRENT_NEXT(dp)) {
121 if (strcmp(dp->d_name, TFILE) == 0 && dp->d_type != DT_WHT)
122 atf_tc_fail("removed file non-white-outed");
123 }
124 RL(rump_sys_close(fd));
125
126 RL(rump_sys_unmount(mp, 0));
127 }
128
129 ATF_TC_FSAPPLY(basic, "check basic union functionality");
130
131 ATF_TP_ADD_TCS(tp)
132 {
133
134 ATF_TP_FSAPPLY(basic);
135 return atf_no_error();
136 }
137