diff options
author | netblue30 <netblue30@yahoo.com> | 2016-11-16 11:10:32 -0500 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2016-11-16 11:10:32 -0500 |
commit | edcd62d7523365165e23695d7daabc94f1e9f48d (patch) | |
tree | 25649c9b73acd260fbafa30ee66cd6f7ceae8f1c | |
parent | Merge pull request #912 from curiosity-seeker/master (diff) | |
download | firejail-edcd62d7523365165e23695d7daabc94f1e9f48d.tar.gz firejail-edcd62d7523365165e23695d7daabc94f1e9f48d.tar.zst firejail-edcd62d7523365165e23695d7daabc94f1e9f48d.zip |
fcopy part 1
-rw-r--r-- | Makefile.in | 13 | ||||
-rwxr-xr-x | configure | 3 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rwxr-xr-x | gcov.sh | 5 | ||||
-rw-r--r-- | src/fcopy/Makefile.in | 45 | ||||
-rw-r--r-- | src/fcopy/main.c | 345 | ||||
-rw-r--r-- | src/firejail/util.c | 1 | ||||
-rw-r--r-- | src/fnet/main.c | 6 | ||||
-rw-r--r-- | src/fseccomp/main.c | 4 | ||||
-rwxr-xr-x | test/fcopy/cmdline.exp | 56 | ||||
-rwxr-xr-x | test/fcopy/dircopy.exp | 86 | ||||
-rwxr-xr-x | test/fcopy/fcopy.sh | 23 | ||||
-rwxr-xr-x | test/fcopy/filecopy.exp | 54 | ||||
-rwxr-xr-x | test/fcopy/linkcopy.exp | 86 | ||||
-rw-r--r-- | test/fcopy/src/a/b/file4 | 11 | ||||
-rw-r--r-- | test/fcopy/src/a/file3 | 0 | ||||
l--------- | test/fcopy/src/dircopy.exp | 1 | ||||
-rwxr-xr-x | test/fcopy/src/file1 | 0 | ||||
-rw-r--r-- | test/fcopy/src/file2 | 0 |
19 files changed, 733 insertions, 11 deletions
diff --git a/Makefile.in b/Makefile.in index 86fd4f4b7..6501989a9 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,6 +1,6 @@ | |||
1 | all: apps man | 1 | all: apps man |
2 | MYLIBS = src/lib | 2 | MYLIBS = src/lib |
3 | APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect src/fnet src/fseccomp | 3 | APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect src/fnet src/fseccomp src/fcopy |
4 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 | 4 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 |
5 | 5 | ||
6 | prefix=@prefix@ | 6 | prefix=@prefix@ |
@@ -78,6 +78,7 @@ realinstall: | |||
78 | install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. | 78 | install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. |
79 | install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/. | 79 | install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/. |
80 | install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/. | 80 | install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/. |
81 | install -c -m 0755 src/fcopy/fcopy $(DESTDIR)/$(libdir)/firejail/. | ||
81 | # documents | 82 | # documents |
82 | install -m 0755 -d $(DESTDIR)/$(DOCDIR) | 83 | install -m 0755 -d $(DESTDIR)/$(DOCDIR) |
83 | install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/. | 84 | install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/. |
@@ -128,6 +129,7 @@ install-strip: all | |||
128 | strip src/faudit/faudit | 129 | strip src/faudit/faudit |
129 | strip src/fnet/fnet | 130 | strip src/fnet/fnet |
130 | strip src/fseccomp/fseccomp | 131 | strip src/fseccomp/fseccomp |
132 | strip src/fcopy/fcopy | ||
131 | $(MAKE) realinstall | 133 | $(MAKE) realinstall |
132 | 134 | ||
133 | uninstall: | 135 | uninstall: |
@@ -145,7 +147,7 @@ uninstall: | |||
145 | rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firecfg | 147 | rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firecfg |
146 | 148 | ||
147 | DISTFILES = "src etc platform configure configure.ac Makefile.in install.sh mkman.sh mketc.sh mkdeb.sh mkuid.sh COPYING README RELNOTES" | 149 | DISTFILES = "src etc platform configure configure.ac Makefile.in install.sh mkman.sh mketc.sh mkdeb.sh mkuid.sh COPYING README RELNOTES" |
148 | DISTFILES_TEST = "test/rlimit test/apps test/apps-x11 test/apps-x11-xorg test/root test/environment test/profiles test/utils test/compile test/filters test/network test/arguments test/fs test/sysutils" | 150 | DISTFILES_TEST = "test/rlimit test/apps test/apps-x11 test/apps-x11-xorg test/root test/fcopy test/environment test/profiles test/utils test/compile test/filters test/network test/arguments test/fs test/sysutils" |
149 | 151 | ||
150 | dist: | 152 | dist: |
151 | mv config.status config.status.old | 153 | mv config.status config.status.old |
@@ -226,7 +228,10 @@ test-fs: | |||
226 | test-rlimit: | 228 | test-rlimit: |
227 | cd test/rlimit; ./rlimit.sh | grep TESTING | 229 | cd test/rlimit; ./rlimit.sh | grep TESTING |
228 | 230 | ||
229 | test: test-profiles test-fs test-utils test-environment test-apps test-apps-x11 test-apps-x11-xorg test-filters test-arguments test-rlimit | 231 | test-fcopy: |
232 | cd test/fcopy; ./fcopy.sh | grep TESTING | ||
233 | |||
234 | test: test-profiles test-fcopy test-fs test-utils test-environment test-apps test-apps-x11 test-apps-x11-xorg test-filters test-arguments test-rlimit | ||
230 | echo "TEST COMPLETE" | 235 | echo "TEST COMPLETE" |
231 | 236 | ||
232 | ########################################## | 237 | ########################################## |
@@ -254,6 +259,6 @@ test-overlay: | |||
254 | 259 | ||
255 | # For testing hidepid system, the command to set it up is "mount -o remount,rw,hidepid=2 /proc" | 260 | # For testing hidepid system, the command to set it up is "mount -o remount,rw,hidepid=2 /proc" |
256 | 261 | ||
257 | test-all: test-root test-network test-appimage test-overlay test | 262 | test-all: test-root test-network test-appimage test-overlay test-fcopy test |
258 | echo "TEST COMPLETE" | 263 | echo "TEST COMPLETE" |
259 | \ No newline at end of file | 264 | \ No newline at end of file |
@@ -3777,7 +3777,7 @@ if test "$prefix" = /usr; then | |||
3777 | sysconfdir="/etc" | 3777 | sysconfdir="/etc" |
3778 | fi | 3778 | fi |
3779 | 3779 | ||
3780 | ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile" | 3780 | ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile" |
3781 | 3781 | ||
3782 | cat >confcache <<\_ACEOF | 3782 | cat >confcache <<\_ACEOF |
3783 | # This file is a shell script that caches the results of configure | 3783 | # This file is a shell script that caches the results of configure |
@@ -4488,6 +4488,7 @@ do | |||
4488 | case $ac_config_target in | 4488 | case $ac_config_target in |
4489 | "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; | 4489 | "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; |
4490 | "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;; | 4490 | "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;; |
4491 | "src/fcopy/Makefile") CONFIG_FILES="$CONFIG_FILES src/fcopy/Makefile" ;; | ||
4491 | "src/fnet/Makefile") CONFIG_FILES="$CONFIG_FILES src/fnet/Makefile" ;; | 4492 | "src/fnet/Makefile") CONFIG_FILES="$CONFIG_FILES src/fnet/Makefile" ;; |
4492 | "src/firejail/Makefile") CONFIG_FILES="$CONFIG_FILES src/firejail/Makefile" ;; | 4493 | "src/firejail/Makefile") CONFIG_FILES="$CONFIG_FILES src/firejail/Makefile" ;; |
4493 | "src/firemon/Makefile") CONFIG_FILES="$CONFIG_FILES src/firemon/Makefile" ;; | 4494 | "src/firemon/Makefile") CONFIG_FILES="$CONFIG_FILES src/firemon/Makefile" ;; |
diff --git a/configure.ac b/configure.ac index 74ba09f43..f3076f2f8 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -158,8 +158,9 @@ if test "$prefix" = /usr; then | |||
158 | sysconfdir="/etc" | 158 | sysconfdir="/etc" |
159 | fi | 159 | fi |
160 | 160 | ||
161 | AC_OUTPUT(Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile \ | 161 | AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \ |
162 | src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile) | 162 | src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \ |
163 | src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile) | ||
163 | 164 | ||
164 | echo | 165 | echo |
165 | echo "Configuration options:" | 166 | echo "Configuration options:" |
@@ -13,6 +13,7 @@ firemon --help | |||
13 | /usr/lib/firejail/fnet --help | 13 | /usr/lib/firejail/fnet --help |
14 | /usr/lib/firejail/fseccomp --help | 14 | /usr/lib/firejail/fseccomp --help |
15 | /usr/lib/firejail/ftee --help | 15 | /usr/lib/firejail/ftee --help |
16 | /usr/lib/firejail/fcopy --help | ||
16 | firecfg --help | 17 | firecfg --help |
17 | sudo chown $USER:$USER `find .` | 18 | sudo chown $USER:$USER `find .` |
18 | generate | 19 | generate |
@@ -34,6 +35,10 @@ make test-overlay | |||
34 | generate | 35 | generate |
35 | sleep 2 | 36 | sleep 2 |
36 | 37 | ||
38 | make test-fcopy | ||
39 | generate | ||
40 | sleep 2 | ||
41 | |||
37 | make test-profiles | 42 | make test-profiles |
38 | generate | 43 | generate |
39 | sleep 2 | 44 | sleep 2 |
diff --git a/src/fcopy/Makefile.in b/src/fcopy/Makefile.in new file mode 100644 index 000000000..278957a4f --- /dev/null +++ b/src/fcopy/Makefile.in | |||
@@ -0,0 +1,45 @@ | |||
1 | all: fcopy | ||
2 | |||
3 | prefix=@prefix@ | ||
4 | exec_prefix=@exec_prefix@ | ||
5 | libdir=@libdir@ | ||
6 | sysconfdir=@sysconfdir@ | ||
7 | |||
8 | VERSION=@PACKAGE_VERSION@ | ||
9 | NAME=@PACKAGE_NAME@ | ||
10 | HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ | ||
11 | HAVE_SECCOMP=@HAVE_SECCOMP@ | ||
12 | HAVE_CHROOT=@HAVE_CHROOT@ | ||
13 | HAVE_BIND=@HAVE_BIND@ | ||
14 | HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ | ||
15 | HAVE_NETWORK=@HAVE_NETWORK@ | ||
16 | HAVE_USERNS=@HAVE_USERNS@ | ||
17 | HAVE_X11=@HAVE_X11@ | ||
18 | HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ | ||
19 | HAVE_WHITELIST=@HAVE_WHITELIST@ | ||
20 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ | ||
21 | HAVE_APPARMOR=@HAVE_APPARMOR@ | ||
22 | HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ | ||
23 | HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ | ||
24 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
25 | HAVE_GCOV=@HAVE_GCOV@ | ||
26 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
27 | |||
28 | H_FILE_LIST = $(sort $(wildcard *.[h])) | ||
29 | C_FILE_LIST = $(sort $(wildcard *.c)) | ||
30 | OBJS = $(C_FILE_LIST:.c=.o) | ||
31 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
32 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security | ||
33 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread | ||
34 | |||
35 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h | ||
36 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
37 | |||
38 | fcopy: $(OBJS) | ||
39 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | ||
40 | |||
41 | clean:; rm -f *.o fcopy *.gcov *.gcda *.gcno | ||
42 | |||
43 | distclean: clean | ||
44 | rm -fr Makefile | ||
45 | |||
diff --git a/src/fcopy/main.c b/src/fcopy/main.c new file mode 100644 index 000000000..4437b90e5 --- /dev/null +++ b/src/fcopy/main.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "../include/common.h" | ||
22 | #include <fcntl.h> | ||
23 | #include <ftw.h> | ||
24 | |||
25 | |||
26 | #define COPY_LIMIT (500 * 1024 *1024) | ||
27 | static int size_limit_reached = 0; | ||
28 | static unsigned file_cnt = 0; | ||
29 | static unsigned size_cnt = 0; | ||
30 | |||
31 | static char *outpath = NULL; | ||
32 | static char *inpath = NULL; | ||
33 | |||
34 | |||
35 | // modified version of the function from util.c | ||
36 | static void copy_file(const char *srcname, const char *destname, mode_t mode, uid_t uid, gid_t gid) { | ||
37 | assert(srcname); | ||
38 | assert(destname); | ||
39 | mode &= 07777; | ||
40 | |||
41 | // open source | ||
42 | int src = open(srcname, O_RDONLY); | ||
43 | if (src < 0) { | ||
44 | fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname); | ||
45 | return; | ||
46 | } | ||
47 | |||
48 | // open destination | ||
49 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, 0755); | ||
50 | if (dst < 0) { | ||
51 | fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", destname); | ||
52 | close(src); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | // copy | ||
57 | ssize_t len; | ||
58 | static const int BUFLEN = 1024; | ||
59 | unsigned char buf[BUFLEN]; | ||
60 | while ((len = read(src, buf, BUFLEN)) > 0) { | ||
61 | int done = 0; | ||
62 | while (done != len) { | ||
63 | int rv = write(dst, buf + done, len - done); | ||
64 | if (rv == -1) | ||
65 | goto errexit; | ||
66 | done += rv; | ||
67 | } | ||
68 | } | ||
69 | fflush(0); | ||
70 | |||
71 | if (fchown(dst, uid, gid) == -1) | ||
72 | goto errexit; | ||
73 | if (fchmod(dst, mode) == -1) | ||
74 | goto errexit; | ||
75 | |||
76 | close(src); | ||
77 | close(dst); | ||
78 | |||
79 | return; | ||
80 | |||
81 | errexit: | ||
82 | close(src); | ||
83 | close(dst); | ||
84 | unlink(destname); | ||
85 | fprintf(stderr, "Warning fcopy: cannot copy %s\n", destname); | ||
86 | } | ||
87 | |||
88 | |||
89 | |||
90 | // modified version of the function in firejail/util.c | ||
91 | static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { | ||
92 | assert(fname); | ||
93 | mode &= 07777; | ||
94 | |||
95 | if (mkdir(fname, mode) == -1 || | ||
96 | chmod(fname, mode) == -1) { | ||
97 | fprintf(stderr, "Error fcopy: failed to create %s directory\n", fname); | ||
98 | errExit("mkdir/chmod"); | ||
99 | } | ||
100 | if (chown(fname, uid, gid)) | ||
101 | fprintf(stderr, "Warning fcopy: failed to change ownership of %s\n", fname); | ||
102 | } | ||
103 | |||
104 | void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { | ||
105 | char *rp = realpath(target, NULL); | ||
106 | if (rp) { | ||
107 | if (symlink(rp, linkpath) == -1) | ||
108 | goto errout; | ||
109 | free(rp); | ||
110 | } | ||
111 | else | ||
112 | goto errout; | ||
113 | |||
114 | return; | ||
115 | errout: | ||
116 | fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", target); | ||
117 | } | ||
118 | |||
119 | static int first = 1; | ||
120 | static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) { | ||
121 | (void) st; | ||
122 | (void) sftw; | ||
123 | assert(infname); | ||
124 | assert(*infname != '\0'); | ||
125 | assert(outpath); | ||
126 | assert(*outpath != '\0'); | ||
127 | assert(inpath); | ||
128 | |||
129 | // check size limit | ||
130 | if (size_limit_reached) | ||
131 | return 0; | ||
132 | |||
133 | char *outfname; | ||
134 | if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1) | ||
135 | errExit("asprintf"); | ||
136 | |||
137 | // don't copy it if we already have the file | ||
138 | struct stat s; | ||
139 | if (stat(outfname, &s) == 0) { | ||
140 | if (first) | ||
141 | first = 0; | ||
142 | else | ||
143 | fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); | ||
144 | free(outfname); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | // extract mode and ownership | ||
149 | if (stat(infname, &s) != 0) { | ||
150 | fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); | ||
151 | free(outfname); | ||
152 | return 0; | ||
153 | } | ||
154 | uid_t uid = s.st_uid; | ||
155 | gid_t gid = s.st_gid; | ||
156 | mode_t mode = s.st_mode; | ||
157 | |||
158 | // recalculate size | ||
159 | if ((s.st_size + size_cnt) > COPY_LIMIT) { | ||
160 | fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024); | ||
161 | size_limit_reached = 1; | ||
162 | free(outfname); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | file_cnt++; | ||
167 | size_cnt += s.st_size; | ||
168 | |||
169 | if(ftype == FTW_F) { | ||
170 | copy_file(infname, outfname, mode, uid, gid); | ||
171 | } | ||
172 | else if (ftype == FTW_D) { | ||
173 | mkdir_attr(outfname, mode, uid, gid); | ||
174 | } | ||
175 | else if (ftype == FTW_SL) { | ||
176 | copy_link(infname, outfname, mode, uid, gid); | ||
177 | } | ||
178 | |||
179 | return(0); | ||
180 | } | ||
181 | |||
182 | static char *check(const char *src) { | ||
183 | struct stat s; | ||
184 | char *rsrc = realpath(src, NULL); | ||
185 | if (!rsrc || stat(rsrc, &s) == -1) { | ||
186 | fprintf(stderr, "Error fcopy: cannot find %s directory\n", src); | ||
187 | exit(1); | ||
188 | } | ||
189 | |||
190 | // check uid | ||
191 | if (s.st_uid != getuid() || s.st_gid != getgid()) { | ||
192 | fprintf(stderr, "Error fcopy: uid/gid mismatch for %s\n", rsrc); | ||
193 | exit(1); | ||
194 | } | ||
195 | |||
196 | // dir, link, regular file | ||
197 | if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || S_ISLNK(s.st_mode)) { | ||
198 | return rsrc; // normal exit from the function | ||
199 | } | ||
200 | fprintf(stderr, "Error fcopy: invalid directory %s\n", rsrc); | ||
201 | exit(1); | ||
202 | } | ||
203 | |||
204 | static void duplicate_dir(const char *src, const char *dest, struct stat *s) { | ||
205 | (void) s; | ||
206 | char *rsrc = check(src); | ||
207 | char *rdest = check(dest); | ||
208 | inpath = rsrc; | ||
209 | outpath = rdest; | ||
210 | |||
211 | // walk | ||
212 | if(nftw(rsrc, fs_copydir, 1, FTW_PHYS) != 0) { | ||
213 | fprintf(stderr, "Error: unable to copy file\n"); | ||
214 | exit(1); | ||
215 | } | ||
216 | |||
217 | free(rsrc); | ||
218 | free(rdest); | ||
219 | } | ||
220 | |||
221 | static void duplicate_file(const char *src, const char *dest, struct stat *s) { | ||
222 | char *rsrc = check(src); | ||
223 | char *rdest = check(dest); | ||
224 | uid_t uid = s->st_uid; | ||
225 | gid_t gid = s->st_gid; | ||
226 | mode_t mode = s->st_mode; | ||
227 | |||
228 | // build destination file name | ||
229 | char *name; | ||
230 | char *ptr = strrchr(rsrc, '/'); | ||
231 | ptr++; | ||
232 | if (asprintf(&name, "%s/%s", rdest, ptr) == -1) | ||
233 | errExit("asprintf"); | ||
234 | |||
235 | // copy | ||
236 | copy_file(rsrc, name, mode, uid, gid); | ||
237 | |||
238 | free(name); | ||
239 | free(rsrc); | ||
240 | free(rdest); | ||
241 | } | ||
242 | |||
243 | static void duplicate_link(const char *src, const char *dest, struct stat *s) { | ||
244 | char *rsrc = check(src); | ||
245 | char *rdest = check(dest); | ||
246 | uid_t uid = s->st_uid; | ||
247 | gid_t gid = s->st_gid; | ||
248 | mode_t mode = s->st_mode; | ||
249 | |||
250 | // build destination file name | ||
251 | char *name; | ||
252 | char *ptr = strrchr(rsrc, '/'); | ||
253 | ptr++; | ||
254 | if (asprintf(&name, "%s/%s", rdest, ptr) == -1) | ||
255 | errExit("asprintf"); | ||
256 | |||
257 | // copy | ||
258 | copy_link(rsrc, name, mode, uid, gid); | ||
259 | |||
260 | free(name); | ||
261 | free(rsrc); | ||
262 | free(rdest); | ||
263 | } | ||
264 | |||
265 | static void usage(void) { | ||
266 | printf("Usage: fcopy src dest\n"); | ||
267 | printf("Copy src file in dest directory. If src is a directory, copy all the files in\n"); | ||
268 | printf("src recoursively\n"); | ||
269 | } | ||
270 | |||
271 | int main(int argc, char **argv) { | ||
272 | #if 0 | ||
273 | { | ||
274 | //system("cat /proc/self/status"); | ||
275 | int i; | ||
276 | for (i = 0; i < argc; i++) | ||
277 | printf("*%s* ", argv[i]); | ||
278 | printf("\n"); | ||
279 | } | ||
280 | #endif | ||
281 | if (argc != 3) { | ||
282 | fprintf(stderr, "Error fcopy: files missing\n"); | ||
283 | usage(); | ||
284 | exit(1); | ||
285 | } | ||
286 | |||
287 | int i; | ||
288 | int index = 1; | ||
289 | for (i = 1; i < (argc - 2); i++) { | ||
290 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | ||
291 | usage(); | ||
292 | return 0; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | // check the two files; remove ending / | ||
297 | char *src = argv[index]; | ||
298 | int len = strlen(src); | ||
299 | if (src[len - 1] == '/') | ||
300 | src[len - 1] = '\0'; | ||
301 | if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != (size_t)len) { | ||
302 | fprintf(stderr, "Error fcopy: invalid file name %s\n", src); | ||
303 | exit(1); | ||
304 | } | ||
305 | |||
306 | char *dest = argv[index + 1]; | ||
307 | len = strlen(dest); | ||
308 | if (dest[len - 1] == '/') | ||
309 | dest[len - 1] = '\0'; | ||
310 | if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != (size_t)len) { | ||
311 | fprintf(stderr, "Error fcopy: invalid file name %s\n", dest); | ||
312 | exit(1); | ||
313 | } | ||
314 | |||
315 | |||
316 | // the destination should be a directory; remove ending / | ||
317 | struct stat s; | ||
318 | if (stat(dest, &s) == -1) { | ||
319 | fprintf(stderr, "Error fcopy: cannot find destination directory\n"); | ||
320 | exit(1); | ||
321 | } | ||
322 | if (S_ISDIR(s.st_mode) == -1) { | ||
323 | fprintf(stderr, "Error fcopy: the destination should be a directory\n"); | ||
324 | exit(1); | ||
325 | } | ||
326 | |||
327 | // copy files | ||
328 | if (lstat(src, &s) == -1) { | ||
329 | fprintf(stderr, "Error fcopy: cannot find source file\n"); | ||
330 | exit(1); | ||
331 | } | ||
332 | |||
333 | if (S_ISDIR(s.st_mode)) | ||
334 | duplicate_dir(src, dest, &s); | ||
335 | else if (S_ISREG(s.st_mode)) | ||
336 | duplicate_file(src, dest, &s); | ||
337 | else if (S_ISLNK(s.st_mode)) | ||
338 | duplicate_link(src, dest, &s); | ||
339 | else { | ||
340 | fprintf(stderr, "Error fcopy: source file unsupported\n"); | ||
341 | exit(1); | ||
342 | } | ||
343 | |||
344 | return 0; | ||
345 | } | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c index d928c6b42..027f1cd47 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -206,6 +206,7 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m | |||
206 | done += rv; | 206 | done += rv; |
207 | } | 207 | } |
208 | } | 208 | } |
209 | fflush(0); | ||
209 | 210 | ||
210 | if (fchown(dst, uid, gid) == -1) | 211 | if (fchown(dst, uid, gid) == -1) |
211 | errExit("fchown"); | 212 | errExit("fchown"); |
diff --git a/src/fnet/main.c b/src/fnet/main.c index 4ae9eb6e3..4e7807d07 100644 --- a/src/fnet/main.c +++ b/src/fnet/main.c | |||
@@ -42,10 +42,10 @@ for (i = 0; i < argc; i++) | |||
42 | printf("\n"); | 42 | printf("\n"); |
43 | } | 43 | } |
44 | #endif | 44 | #endif |
45 | if (argc < 2) | 45 | if (argc < 2) { |
46 | usage(); | ||
46 | return 1; | 47 | return 1; |
47 | 48 | } | |
48 | |||
49 | 49 | ||
50 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | 50 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { |
51 | usage(); | 51 | usage(); |
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 39e72fdf9..2f85a786b 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -47,8 +47,10 @@ for (i = 0; i < argc; i++) | |||
47 | printf("\n"); | 47 | printf("\n"); |
48 | } | 48 | } |
49 | #endif | 49 | #endif |
50 | if (argc < 2) | 50 | if (argc < 2) { |
51 | usage(); | ||
51 | return 1; | 52 | return 1; |
53 | } | ||
52 | 54 | ||
53 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | 55 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { |
54 | usage(); | 56 | usage(); |
diff --git a/test/fcopy/cmdline.exp b/test/fcopy/cmdline.exp new file mode 100755 index 000000000..95e221321 --- /dev/null +++ b/test/fcopy/cmdline.exp | |||
@@ -0,0 +1,56 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "/usr/lib/firejail/fcopy\r" | ||
11 | expect { | ||
12 | timeout {puts "TESTING ERROR 0\n";exit} | ||
13 | "files missing" | ||
14 | } | ||
15 | expect { | ||
16 | timeout {puts "TESTING ERROR 1\n";exit} | ||
17 | "Usage:" | ||
18 | } | ||
19 | after 100 | ||
20 | |||
21 | send -- "/usr/lib/firejail/fcopy foo\r" | ||
22 | expect { | ||
23 | timeout {puts "TESTING ERROR 2\n";exit} | ||
24 | "files missing" | ||
25 | } | ||
26 | expect { | ||
27 | timeout {puts "TESTING ERROR 3\n";exit} | ||
28 | "Usage:" | ||
29 | } | ||
30 | after 100 | ||
31 | |||
32 | send -- "/usr/lib/firejail/fcopy f%oo1 foo2\r" | ||
33 | expect { | ||
34 | timeout {puts "TESTING ERROR 4\n";exit} | ||
35 | "invalid file name" | ||
36 | } | ||
37 | after 100 | ||
38 | |||
39 | send -- "/usr/lib/firejail/fcopy foo1 f,oo2\r" | ||
40 | expect { | ||
41 | timeout {puts "TESTING ERROR 5\n";exit} | ||
42 | "invalid file name" | ||
43 | } | ||
44 | after 100 | ||
45 | |||
46 | send -- "/usr/lib/firejail/fcopy foo1 foo2\r" | ||
47 | expect { | ||
48 | timeout {puts "TESTING ERROR 6\n";exit} | ||
49 | "cannot find destination directory" | ||
50 | } | ||
51 | after 100 | ||
52 | |||
53 | |||
54 | |||
55 | |||
56 | puts "\nall done\n" | ||
diff --git a/test/fcopy/dircopy.exp b/test/fcopy/dircopy.exp new file mode 100755 index 000000000..b87f24a59 --- /dev/null +++ b/test/fcopy/dircopy.exp | |||
@@ -0,0 +1,86 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | # | ||
7 | # copy directory src to dest | ||
8 | # | ||
9 | set timeout 10 | ||
10 | spawn $env(SHELL) | ||
11 | match_max 100000 | ||
12 | |||
13 | send -- "rm -fr dest/*\r" | ||
14 | after 100 | ||
15 | |||
16 | send -- "/usr/lib/firejail/fcopy src dest\r" | ||
17 | after 100 | ||
18 | |||
19 | send -- "find dest\r" | ||
20 | expect { | ||
21 | timeout {puts "TESTING ERROR 0\n";exit} | ||
22 | "dest/" | ||
23 | } | ||
24 | expect { | ||
25 | timeout {puts "TESTING ERROR 1\n";exit} | ||
26 | "dest/a" | ||
27 | } | ||
28 | expect { | ||
29 | timeout {puts "TESTING ERROR 2\n";exit} | ||
30 | "dest/a/b" | ||
31 | } | ||
32 | expect { | ||
33 | timeout {puts "TESTING ERROR 3\n";exit} | ||
34 | "dest/a/b/file4" | ||
35 | } | ||
36 | expect { | ||
37 | timeout {puts "TESTING ERROR 4\n";exit} | ||
38 | "dest/a/file3" | ||
39 | } | ||
40 | expect { | ||
41 | timeout {puts "TESTING ERROR 5\n";exit} | ||
42 | "dest/dircopy.exp" | ||
43 | } | ||
44 | expect { | ||
45 | timeout {puts "TESTING ERROR 6\n";exit} | ||
46 | "dest/file2" | ||
47 | } | ||
48 | expect { | ||
49 | timeout {puts "TESTING ERROR 7\n";exit} | ||
50 | "dest/file1" | ||
51 | } | ||
52 | after 100 | ||
53 | |||
54 | |||
55 | send -- "ls -al dest\r" | ||
56 | expect { | ||
57 | timeout {puts "TESTING ERROR 8\n";exit} | ||
58 | "drwx--x--x" | ||
59 | } | ||
60 | expect { | ||
61 | timeout {puts "TESTING ERROR 9\n";exit} | ||
62 | "rwxrwxrwx" | ||
63 | } | ||
64 | expect { | ||
65 | timeout {puts "TESTING ERROR 10\n";exit} | ||
66 | "rw-r--r--" | ||
67 | } | ||
68 | after 100 | ||
69 | |||
70 | send -- "diff -q src/a/b/file4 dest/a/b/file4; echo done\r" | ||
71 | expect { | ||
72 | timeout {puts "TESTING ERROR 11\n";exit} | ||
73 | "differ" {puts "TESTING ERROR 12\n";exit} | ||
74 | "done" | ||
75 | } | ||
76 | |||
77 | send -- "file dest/dircopy.exp\r" | ||
78 | expect { | ||
79 | timeout {puts "TESTING ERROR 13\n";exit} | ||
80 | "symbolic link" | ||
81 | } | ||
82 | |||
83 | send -- "rm -fr dest/*\r" | ||
84 | after 100 | ||
85 | |||
86 | puts "\nall done\n" | ||
diff --git a/test/fcopy/fcopy.sh b/test/fcopy/fcopy.sh new file mode 100755 index 000000000..9961d6317 --- /dev/null +++ b/test/fcopy/fcopy.sh | |||
@@ -0,0 +1,23 @@ | |||
1 | #!/bin/bash | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | export MALLOC_CHECK_=3 | ||
7 | export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) | ||
8 | |||
9 | rm -fr dest/* | ||
10 | |||
11 | echo "TESTING: fcopy cmdline (test/fcopy/cmdline.exp)" | ||
12 | ./cmdline.exp | ||
13 | |||
14 | echo "TESTING: fcopy directory (test/fcopy/dircopy.exp)" | ||
15 | ./dircopy.exp | ||
16 | |||
17 | echo "TESTING: fcopy file (test/fcopy/filecopy.exp)" | ||
18 | ./filecopy.exp | ||
19 | |||
20 | echo "TESTING: fcopy link (test/fcopy/linkcopy.exp)" | ||
21 | ./linkcopy.exp | ||
22 | |||
23 | rm -fr dest/* | ||
diff --git a/test/fcopy/filecopy.exp b/test/fcopy/filecopy.exp new file mode 100755 index 000000000..9927e18fe --- /dev/null +++ b/test/fcopy/filecopy.exp | |||
@@ -0,0 +1,54 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | # | ||
7 | # copy directory src to dest | ||
8 | # | ||
9 | set timeout 10 | ||
10 | spawn $env(SHELL) | ||
11 | match_max 100000 | ||
12 | |||
13 | send -- "rm -fr dest/*\r" | ||
14 | after 100 | ||
15 | |||
16 | send -- "/usr/lib/firejail/fcopy src/dircopy.exp dest\r" | ||
17 | after 100 | ||
18 | |||
19 | send -- "find dest\r" | ||
20 | expect { | ||
21 | timeout {puts "TESTING ERROR 0\n";exit} | ||
22 | "dest/" | ||
23 | } | ||
24 | expect { | ||
25 | timeout {puts "TESTING ERROR 1\n";exit} | ||
26 | "dest/dircopy.exp" | ||
27 | } | ||
28 | after 100 | ||
29 | |||
30 | |||
31 | send -- "ls -al dest\r" | ||
32 | expect { | ||
33 | timeout {puts "TESTING ERROR 2\n";exit} | ||
34 | "lrwxrwxrwx" | ||
35 | } | ||
36 | after 100 | ||
37 | |||
38 | send -- "diff -q dircopy.exp dest/dircopy.exp; echo done\r" | ||
39 | expect { | ||
40 | timeout {puts "TESTING ERROR 3\n";exit} | ||
41 | "differ" {puts "TESTING ERROR 4\n";exit} | ||
42 | "done" | ||
43 | } | ||
44 | |||
45 | send -- "file dest/dircopy.exp\r" | ||
46 | expect { | ||
47 | timeout {puts "TESTING ERROR 5\n";exit} | ||
48 | "symbolic link" | ||
49 | } | ||
50 | |||
51 | send -- "rm -fr dest/*\r" | ||
52 | after 100 | ||
53 | |||
54 | puts "\nall done\n" | ||
diff --git a/test/fcopy/linkcopy.exp b/test/fcopy/linkcopy.exp new file mode 100755 index 000000000..b87f24a59 --- /dev/null +++ b/test/fcopy/linkcopy.exp | |||
@@ -0,0 +1,86 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | # | ||
7 | # copy directory src to dest | ||
8 | # | ||
9 | set timeout 10 | ||
10 | spawn $env(SHELL) | ||
11 | match_max 100000 | ||
12 | |||
13 | send -- "rm -fr dest/*\r" | ||
14 | after 100 | ||
15 | |||
16 | send -- "/usr/lib/firejail/fcopy src dest\r" | ||
17 | after 100 | ||
18 | |||
19 | send -- "find dest\r" | ||
20 | expect { | ||
21 | timeout {puts "TESTING ERROR 0\n";exit} | ||
22 | "dest/" | ||
23 | } | ||
24 | expect { | ||
25 | timeout {puts "TESTING ERROR 1\n";exit} | ||
26 | "dest/a" | ||
27 | } | ||
28 | expect { | ||
29 | timeout {puts "TESTING ERROR 2\n";exit} | ||
30 | "dest/a/b" | ||
31 | } | ||
32 | expect { | ||
33 | timeout {puts "TESTING ERROR 3\n";exit} | ||
34 | "dest/a/b/file4" | ||
35 | } | ||
36 | expect { | ||
37 | timeout {puts "TESTING ERROR 4\n";exit} | ||
38 | "dest/a/file3" | ||
39 | } | ||
40 | expect { | ||
41 | timeout {puts "TESTING ERROR 5\n";exit} | ||
42 | "dest/dircopy.exp" | ||
43 | } | ||
44 | expect { | ||
45 | timeout {puts "TESTING ERROR 6\n";exit} | ||
46 | "dest/file2" | ||
47 | } | ||
48 | expect { | ||
49 | timeout {puts "TESTING ERROR 7\n";exit} | ||
50 | "dest/file1" | ||
51 | } | ||
52 | after 100 | ||
53 | |||
54 | |||
55 | send -- "ls -al dest\r" | ||
56 | expect { | ||
57 | timeout {puts "TESTING ERROR 8\n";exit} | ||
58 | "drwx--x--x" | ||
59 | } | ||
60 | expect { | ||
61 | timeout {puts "TESTING ERROR 9\n";exit} | ||
62 | "rwxrwxrwx" | ||
63 | } | ||
64 | expect { | ||
65 | timeout {puts "TESTING ERROR 10\n";exit} | ||
66 | "rw-r--r--" | ||
67 | } | ||
68 | after 100 | ||
69 | |||
70 | send -- "diff -q src/a/b/file4 dest/a/b/file4; echo done\r" | ||
71 | expect { | ||
72 | timeout {puts "TESTING ERROR 11\n";exit} | ||
73 | "differ" {puts "TESTING ERROR 12\n";exit} | ||
74 | "done" | ||
75 | } | ||
76 | |||
77 | send -- "file dest/dircopy.exp\r" | ||
78 | expect { | ||
79 | timeout {puts "TESTING ERROR 13\n";exit} | ||
80 | "symbolic link" | ||
81 | } | ||
82 | |||
83 | send -- "rm -fr dest/*\r" | ||
84 | after 100 | ||
85 | |||
86 | puts "\nall done\n" | ||
diff --git a/test/fcopy/src/a/b/file4 b/test/fcopy/src/a/b/file4 new file mode 100644 index 000000000..ac318d7ab --- /dev/null +++ b/test/fcopy/src/a/b/file4 | |||
@@ -0,0 +1,11 @@ | |||
1 | |||
2 | |||
3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam interdum at massa non aliquam. Maecenas molestie id orci volutpat porta. Praesent aliquam nunc quis mi tristique, ac feugiat enim rutrum. Nulla vitae metus sodales, pellentesque risus sit amet, volutpat nisl. Curabitur accumsan arcu congue lacus porta laoreet. Nulla facilisi. Integer nec augue id magna gravida tincidunt id vitae lorem. Curabitur facilisis, tellus vel pellentesque pretium, odio dolor efficitur lorem, et tincidunt dui enim cursus lacus. Cras a orci ac magna semper dapibus nec et velit. Nullam aliquam sollicitudin auctor. | ||
4 | |||
5 | Mauris ac quam vel purus volutpat semper eget a ante. Curabitur arcu nisl, dapibus ac lectus ac, porttitor fermentum metus. Aliquam et sem aliquam magna interdum ultricies at eu orci. Aenean tortor augue, volutpat nec magna nec, rutrum bibendum justo. Vivamus ex quam, auctor ut pellentesque mattis, aliquet a eros. Etiam ac lacus ac ante ullamcorper sollicitudin a quis orci. Suspendisse quis justo ac mauris cursus finibus quis at elit. Vestibulum elementum finibus diam, eget convallis purus aliquet et. Fusce fermentum ornare urna, non ornare nisl tincidunt consectetur. Donec et lacus vitae ex eleifend porttitor id ut odio. Quisque luctus eget lorem et sollicitudin. | ||
6 | |||
7 | Aliquam libero elit, finibus a nisl a, commodo viverra turpis. Nam pulvinar in est sit amet fermentum. Praesent scelerisque tempus lectus, ac porta elit sodales rutrum. Duis faucibus faucibus urna eget accumsan. Vivamus in turpis ut massa rhoncus pretium nec et lorem. Aenean at tellus eget metus porta ornare. Aliquam erat volutpat. Donec hendrerit a massa vel malesuada. Integer varius sapien et orci viverra pretium. In at velit aliquet, vulputate nisi lobortis, aliquam augue. | ||
8 | |||
9 | Ut aliquam turpis ut lorem aliquam, in faucibus elit pulvinar. Vivamus viverra tortor ornare, lacinia leo sit amet, auctor arcu. Sed erat leo, pellentesque vel nibh a, malesuada vehicula purus. Vivamus est dolor, aliquet quis facilisis fermentum, varius in dolor. Nunc quis libero feugiat, imperdiet est vitae, mollis risus. Vestibulum elementum mattis lorem vitae gravida. Nullam id tellus interdum, aliquam erat eu, laoreet nunc. Aliquam ut felis vel mauris maximus pellentesque. | ||
10 | |||
11 | Vestibulum tempus mauris eget ex interdum, vitae vehicula tortor sollicitudin. Pellentesque et dolor cursus dui vulputate laoreet. Morbi eu bibendum quam, at ultrices elit. Vestibulum dictum enim sit amet ultricies imperdiet. Praesent congue magna ac mauris mattis, a iaculis ante aliquet. Vivamus at egestas ex. Suspendisse orci dolor, pharetra at aliquam a, faucibus facilisis leo. Quisque semper lorem eget elit commodo pretium. Aenean posuere augue quis arcu finibus, sit amet fringilla risus congue. Pellentesque rutrum nunc leo, aliquam lobortis lacus molestie nec. Donec convallis congue diam, ullamcorper vestibulum dui varius nec. Praesent pellentesque nisi risus. In aliquam molestie malesuada. Nulla facilisis a risus eu tristique. Morbi molestie et arcu quis efficitur. Curabitur cursus vestibulum luctus. | ||
diff --git a/test/fcopy/src/a/file3 b/test/fcopy/src/a/file3 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/fcopy/src/a/file3 | |||
diff --git a/test/fcopy/src/dircopy.exp b/test/fcopy/src/dircopy.exp new file mode 120000 index 000000000..2acf88f7b --- /dev/null +++ b/test/fcopy/src/dircopy.exp | |||
@@ -0,0 +1 @@ | |||
../dircopy.exp \ No newline at end of file | |||
diff --git a/test/fcopy/src/file1 b/test/fcopy/src/file1 new file mode 100755 index 000000000..e69de29bb --- /dev/null +++ b/test/fcopy/src/file1 | |||
diff --git a/test/fcopy/src/file2 b/test/fcopy/src/file2 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/fcopy/src/file2 | |||