1 /*
2  * ProFTPD - FTP server testsuite
3  * Copyright (c) 2008-2021 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* FSIO API tests */
26 
27 #include "tests.h"
28 
29 #ifdef PR_USE_XATTR
30 /* Handle the case where ENOATTR may not be defined. */
31 # ifndef ENOATTR
32 #  define ENOATTR ENODATA
33 # endif
34 #endif
35 
36 static pool *p = NULL;
37 
38 static char *fsio_cwd = NULL;
39 static const char *fsio_test_path = "/tmp/prt-foo.bar.baz";
40 static const char *fsio_test2_path = "/tmp/prt-foo.bar.baz.quxx.quzz";
41 static const char *fsio_unlink_path = "/tmp/prt-fsio-link.dat";
42 static const char *fsio_link_path = "/tmp/prt-fsio-symlink.lnk";
43 static const char *fsio_testdir_path = "/tmp/prt-fsio-test.d";
44 static const char *fsio_copy_src_path = "/tmp/prt-fs-src.dat";
45 static const char *fsio_copy_dst_path = "/tmp/prt-fs-dst.dat";
46 
47 /* Fixtures */
48 
set_up(void)49 static void set_up(void) {
50   (void) unlink(fsio_test_path);
51   (void) unlink(fsio_test2_path);
52   (void) unlink(fsio_link_path);
53   (void) unlink(fsio_unlink_path);
54   (void) rmdir(fsio_testdir_path);
55 
56   if (fsio_cwd != NULL) {
57     free(fsio_cwd);
58   }
59 
60   fsio_cwd = getcwd(NULL, 0);
61 
62   if (p == NULL) {
63     p = permanent_pool = make_sub_pool(NULL);
64   }
65 
66   init_fs();
67   pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE,
68     PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0);
69 
70   if (getenv("TEST_VERBOSE") != NULL) {
71     pr_trace_set_levels("error", 1, 20);
72     pr_trace_set_levels("fsio", 1, 20);
73     pr_trace_set_levels("fs.statcache", 1, 20);
74   }
75 }
76 
tear_down(void)77 static void tear_down(void) {
78   if (fsio_cwd != NULL) {
79     free(fsio_cwd);
80     fsio_cwd = NULL;
81   }
82 
83   (void) pr_fsio_guard_chroot(FALSE);
84   pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE,
85     PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0);
86 
87   pr_unregister_fs("/testuite");
88 
89   if (getenv("TEST_VERBOSE") != NULL) {
90     pr_trace_set_levels("error", 0, 0);
91     pr_trace_set_levels("fsio", 0, 0);
92     pr_trace_set_levels("fs.statcache", 0, 0);
93   }
94 
95   (void) unlink(fsio_test_path);
96   (void) unlink(fsio_test2_path);
97   (void) unlink(fsio_link_path);
98   (void) unlink(fsio_unlink_path);
99   (void) rmdir(fsio_testdir_path);
100 
101   if (p) {
102     destroy_pool(p);
103     p = permanent_pool = NULL;
104   }
105 }
106 
get_errnum(pool * err_pool,int xerrno)107 static const char *get_errnum(pool *err_pool, int xerrno) {
108   char errnum[32];
109   memset(errnum, '\0', sizeof(errnum));
110   snprintf(errnum, sizeof(errnum)-1, "%d", xerrno);
111   return pstrdup(err_pool, errnum);
112 }
113 
114 /* Tests */
115 
START_TEST(fsio_sys_open_test)116 START_TEST (fsio_sys_open_test) {
117   int flags;
118   pr_fh_t *fh;
119 
120   mark_point();
121   flags = O_CREAT|O_EXCL|O_RDONLY;
122   fh = pr_fsio_open(NULL, flags);
123   fail_unless(fh == NULL, "Failed to handle null arguments");
124   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
125     strerror(errno), errno);
126 
127   mark_point();
128   flags = O_RDONLY;
129   fh = pr_fsio_open(fsio_test_path, flags);
130   fail_unless(fh == NULL, "Failed to handle non-existent file '%s'",
131     fsio_test_path);
132   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
133     strerror(errno), errno);
134 
135   mark_point();
136   flags = O_RDONLY;
137   fh = pr_fsio_open("/etc/hosts", flags);
138   fail_unless(fh != NULL, "Failed to open /etc/hosts: %s", strerror(errno));
139 
140   (void) pr_fsio_close(fh);
141 }
142 END_TEST
143 
START_TEST(fsio_sys_open_canon_test)144 START_TEST (fsio_sys_open_canon_test) {
145   int flags;
146   pr_fh_t *fh;
147 
148   flags = O_CREAT|O_EXCL|O_RDONLY;
149   fh = pr_fsio_open_canon(NULL, flags);
150   fail_unless(fh == NULL, "Failed to handle null arguments");
151   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
152     strerror(errno), errno);
153 
154   flags = O_RDONLY;
155   fh = pr_fsio_open_canon(fsio_test_path, flags);
156   fail_unless(fh == NULL, "Failed to handle non-existent file '%s'",
157     fsio_test_path);
158   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
159     strerror(errno), errno);
160 
161   flags = O_RDONLY;
162   fh = pr_fsio_open_canon("/etc/hosts", flags);
163   fail_unless(fh != NULL, "Failed to open /etc/hosts: %s", strerror(errno));
164 
165   (void) pr_fsio_close(fh);
166 }
167 END_TEST
168 
START_TEST(fsio_sys_open_chroot_guard_test)169 START_TEST (fsio_sys_open_chroot_guard_test) {
170   int flags, res;
171   pr_fh_t *fh;
172   const char *path;
173 
174   res = pr_fsio_guard_chroot(TRUE);
175   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
176 
177   path = "/etc/hosts";
178   flags = O_CREAT|O_RDONLY;
179   fh = pr_fsio_open(path, flags);
180   if (fh != NULL) {
181     (void) pr_fsio_close(fh);
182     fail("open(2) of %s succeeded unexpectedly", path);
183   }
184 
185   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
186     strerror(errno), errno);
187 
188   path = "/&Z";
189   flags = O_WRONLY;
190   fh = pr_fsio_open(path, flags);
191   if (fh != NULL) {
192     (void) pr_fsio_close(fh);
193     fail("open(2) of %s succeeded unexpectedly", path);
194   }
195 
196   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
197     strerror(errno));
198 
199   path = "/etc";
200   fh = pr_fsio_open(path, flags);
201   if (fh != NULL) {
202     (void) pr_fsio_close(fh);
203     fail("open(2) of %s succeeded unexpectedly", path);
204   }
205 
206   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
207     strerror(errno));
208 
209   path = "/lib";
210   fh = pr_fsio_open(path, flags);
211   if (fh != NULL) {
212     (void) pr_fsio_close(fh);
213     fail("open(2) of %s succeeded unexpectedly", path);
214   }
215 
216   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
217     strerror(errno));
218 
219   (void) pr_fsio_guard_chroot(FALSE);
220 
221   path = "/etc/hosts";
222   flags = O_RDONLY;
223   fh = pr_fsio_open(path, flags);
224   fail_unless(fh != NULL, "Failed to open '%s': %s", path, strerror(errno));
225   (void) pr_fsio_close(fh);
226 }
227 END_TEST
228 
START_TEST(fsio_sys_close_test)229 START_TEST (fsio_sys_close_test) {
230   int res;
231   pr_fh_t *fh;
232 
233   res = pr_fsio_close(NULL);
234   fail_unless(res < 0, "Failed to handle null arguments");
235   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s %d", EINVAL,
236     strerror(errno), errno);
237 
238   fh = pr_fsio_open("/etc/hosts", O_RDONLY);
239   fail_unless(fh != NULL, "Failed to open /etc/hosts: %s",
240     strerror(errno));
241 
242   res = pr_fsio_close(fh);
243   fail_unless(res == 0, "Failed to close file handle: %s", strerror(errno));
244 }
245 END_TEST
246 
START_TEST(fsio_sys_unlink_test)247 START_TEST (fsio_sys_unlink_test) {
248   int res;
249   pr_fh_t *fh;
250 
251   res = pr_fsio_unlink(NULL);
252   fail_unless(res < 0, "Failed to handle null arguments");
253   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
254     strerror(errno), errno);
255 
256   fh = pr_fsio_open(fsio_unlink_path, O_CREAT|O_EXCL|O_WRONLY);
257   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_unlink_path,
258     strerror(errno));
259   (void) pr_fsio_close(fh);
260 
261   res = pr_fsio_unlink(fsio_unlink_path);
262   fail_unless(res == 0, "Failed to unlink '%s': %s", fsio_unlink_path,
263     strerror(errno));
264 }
265 END_TEST
266 
START_TEST(fsio_sys_unlink_chroot_guard_test)267 START_TEST (fsio_sys_unlink_chroot_guard_test) {
268   int res;
269 
270   res = pr_fsio_guard_chroot(TRUE);
271   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
272 
273   res = pr_fsio_unlink("/etc/hosts");
274   fail_unless(res < 0, "Deleted /etc/hosts unexpectedly");
275   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
276     strerror(errno), errno);
277 
278   (void) pr_fsio_guard_chroot(FALSE);
279 
280   res = pr_fsio_unlink("/lib/foo.bar.baz");
281   fail_unless(res < 0, "Deleted /lib/foo.bar.baz unexpectedly");
282   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
283     strerror(errno), errno);
284 }
285 END_TEST
286 
START_TEST(fsio_sys_stat_test)287 START_TEST (fsio_sys_stat_test) {
288   int res;
289   struct stat st;
290   unsigned int cache_size = 3, max_age = 1, policy_flags = 0;
291 
292   res = pr_fsio_stat(NULL, &st);
293   fail_unless(res < 0, "Failed to handle null path");
294   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
295     errno);
296 
297   res = pr_fsio_stat("/", NULL);
298   fail_unless(res < 0, "Failed to handle null struct stat");
299   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
300     errno);
301 
302   res = pr_fsio_stat("/", &st);
303   fail_unless(res == 0, "Unexpected stat(2) error on '/': %s",
304     strerror(errno));
305   fail_unless(S_ISDIR(st.st_mode), "'/' is not a directory as expected");
306 
307   /* Now, do the stat(2) again, and make sure we get the same information
308    * from the cache.
309    */
310   res = pr_fsio_stat("/", &st);
311   fail_unless(res == 0, "Unexpected stat(2) error on '/': %s",
312     strerror(errno));
313   fail_unless(S_ISDIR(st.st_mode), "'/' is not a directory as expected");
314 
315   pr_fs_statcache_reset();
316   res = pr_fs_statcache_set_policy(cache_size, max_age, policy_flags);
317   fail_unless(res == 0, "Failed to set statcache policy: %s", strerror(errno));
318 
319   res = pr_fsio_stat("/foo/bar/baz/quxx", &st);
320   fail_unless(res < 0, "Failed to handle nonexistent path");
321   fail_unless(errno == ENOENT, "Expected ENOENT, got %s (%d)", strerror(errno),
322     errno);
323 
324   res = pr_fsio_stat("/foo/bar/baz/quxx", &st);
325   fail_unless(res < 0, "Failed to handle nonexistent path");
326   fail_unless(errno == ENOENT, "Expected ENOENT, got %s (%d)", strerror(errno),
327     errno);
328 
329   /* Now wait for longer than 1 second (our configured max age) */
330   sleep(max_age + 1);
331 
332   res = pr_fsio_stat("/foo/bar/baz/quxx", &st);
333   fail_unless(res < 0, "Failed to handle nonexistent path");
334   fail_unless(errno == ENOENT, "Expected ENOENT, got %s (%d)", strerror(errno),
335     errno);
336 
337   /* Stat a symlink path */
338   res = pr_fsio_symlink("/tmp", fsio_link_path);
339   fail_unless(res == 0, "Failed to create symlink to '%s': %s", fsio_link_path,
340     strerror(errno));
341 
342   res = pr_fsio_stat(fsio_link_path, &st);
343   fail_unless(res == 0, "Failed to stat '%s': %s", fsio_link_path,
344     strerror(errno));
345 
346   (void) unlink(fsio_link_path);
347 }
348 END_TEST
349 
START_TEST(fsio_sys_fstat_test)350 START_TEST (fsio_sys_fstat_test) {
351   int res;
352   pr_fh_t *fh;
353   struct stat st;
354 
355   res = pr_fsio_fstat(NULL, NULL);
356   fail_unless(res < 0, "Failed to handle null arguments");
357   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
358     strerror(errno), errno);
359 
360   fh = pr_fsio_open("/etc/hosts", O_RDONLY);
361   fail_unless(fh != NULL, "Failed to open /etc/hosts: %s",
362     strerror(errno));
363 
364   res = pr_fsio_fstat(fh, &st);
365   fail_unless(res == 0, "Failed to fstat /etc/hosts: %s",
366     strerror(errno));
367   (void) pr_fsio_close(fh);
368 }
369 END_TEST
370 
START_TEST(fsio_sys_read_test)371 START_TEST (fsio_sys_read_test) {
372   int res;
373   pr_fh_t *fh;
374   char *buf;
375   size_t buflen;
376 
377   res = pr_fsio_read(NULL, NULL, 0);
378   fail_unless(res < 0, "Failed to handle null arguments");
379   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
380     strerror(errno), errno);
381 
382   fh = pr_fsio_open("/etc/hosts", O_RDONLY);
383   fail_unless(fh != NULL, "Failed to open /etc/hosts: %s",
384     strerror(errno));
385 
386   res = pr_fsio_read(fh, NULL, 0);
387   fail_unless(res < 0, "Failed to handle null buffer");
388   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
389     strerror(errno), errno);
390 
391   buflen = 32;
392   buf = palloc(p, buflen);
393 
394   res = pr_fsio_read(fh, buf, 0);
395   fail_unless(res < 0, "Failed to handle zero buffer length");
396   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
397     strerror(errno), errno);
398 
399   res = pr_fsio_read(fh, buf, 1);
400   fail_unless(res == 1, "Failed to read 1 byte: %s", strerror(errno));
401 
402   (void) pr_fsio_close(fh);
403 }
404 END_TEST
405 
START_TEST(fsio_sys_pread_test)406 START_TEST (fsio_sys_pread_test) {
407   ssize_t res;
408   pr_fh_t *fh;
409   char *buf;
410   size_t buflen;
411 
412   res = pr_fsio_pread(NULL, NULL, 0, 0);
413   fail_unless(res < 0, "Failed to handle null arguments");
414   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
415     strerror(errno), errno);
416 
417   fh = pr_fsio_open("/etc/hosts", O_RDONLY);
418   fail_unless(fh != NULL, "Failed to open /etc/hosts: %s",
419     strerror(errno));
420 
421   res = pr_fsio_pread(fh, NULL, 0, 0);
422   fail_unless(res < 0, "Failed to handle null buffer");
423   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
424     strerror(errno), errno);
425 
426   buflen = 32;
427   buf = palloc(p, buflen);
428 
429   res = pr_fsio_pread(fh, buf, 0, 0);
430   fail_unless(res < 0, "Failed to handle zero buffer length");
431   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
432     strerror(errno), errno);
433 
434   res = pr_fsio_pread(fh, buf, 1, 0);
435   fail_unless(res == 1, "Failed to read 1 byte: %s", strerror(errno));
436 
437   (void) pr_fsio_close(fh);
438 }
439 END_TEST
440 
START_TEST(fsio_sys_write_test)441 START_TEST (fsio_sys_write_test) {
442   int res;
443   pr_fh_t *fh;
444   char *buf;
445   size_t buflen;
446 
447   res = pr_fsio_write(NULL, NULL, 0);
448   fail_unless(res < 0, "Failed to handle null arguments");
449   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
450     strerror(errno), errno);
451 
452   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
453   fail_unless(fh != NULL, "Failed to open '%s': %s", strerror(errno));
454 
455   /* XXX What happens if we use NULL buffer, zero length? */
456   res = pr_fsio_write(fh, NULL, 0);
457   fail_unless(res < 0, "Failed to handle null buffer");
458   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
459     strerror(errno), errno);
460 
461   buflen = 32;
462   buf = palloc(p, buflen);
463   memset(buf, 'c', buflen);
464 
465   res = pr_fsio_write(fh, buf, 0);
466   fail_unless(res == 0, "Failed to handle zero buffer length");
467 
468   res = pr_fsio_write(fh, buf, buflen);
469   fail_unless((size_t) res == buflen, "Failed to write %lu bytes: %s",
470     (unsigned long) buflen, strerror(errno));
471 
472   (void) pr_fsio_close(fh);
473   (void) pr_fsio_unlink(fsio_test_path);
474 }
475 END_TEST
476 
START_TEST(fsio_sys_pwrite_test)477 START_TEST (fsio_sys_pwrite_test) {
478   ssize_t res;
479   pr_fh_t *fh;
480   char *buf;
481   size_t buflen;
482 
483   res = pr_fsio_pwrite(NULL, NULL, 0, 0);
484   fail_unless(res < 0, "Failed to handle null arguments");
485   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
486     strerror(errno), errno);
487 
488   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
489   fail_unless(fh != NULL, "Failed to open '%s': %s", strerror(errno));
490 
491   /* XXX What happens if we use NULL buffer, zero length? */
492   res = pr_fsio_pwrite(fh, NULL, 0, 0);
493   fail_unless(res < 0, "Failed to handle null buffer");
494   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
495     strerror(errno), errno);
496 
497   buflen = 32;
498   buf = palloc(p, buflen);
499   memset(buf, 'c', buflen);
500 
501   res = pr_fsio_pwrite(fh, buf, 0, 0);
502   fail_unless(res == 0, "Failed to handle zero buffer length");
503 
504   res = pr_fsio_pwrite(fh, buf, buflen, 0);
505   fail_unless((size_t) res == buflen, "Failed to write %lu bytes: %s",
506     (unsigned long) buflen, strerror(errno));
507 
508   (void) pr_fsio_close(fh);
509   (void) pr_fsio_unlink(fsio_test_path);
510 }
511 END_TEST
512 
START_TEST(fsio_sys_lseek_test)513 START_TEST (fsio_sys_lseek_test) {
514   int res;
515   pr_fh_t *fh;
516 
517   res = pr_fsio_lseek(NULL, 0, 0);
518   fail_unless(res < 0, "Failed to handle null arguments");
519   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
520     strerror(errno), errno);
521 
522   fh = pr_fsio_open("/etc/hosts", O_RDONLY);
523   fail_unless(fh != NULL, "Failed to open /etc/hosts: %s",
524     strerror(errno));
525 
526   res = pr_fsio_lseek(fh, 0, 0);
527   fail_unless(res == 0, "Failed to seek to byte 0: %s", strerror(errno));
528 
529   (void) pr_fsio_close(fh);
530 }
531 END_TEST
532 
START_TEST(fsio_sys_link_test)533 START_TEST (fsio_sys_link_test) {
534   int res;
535   const char *target_path, *link_path;
536   pr_fh_t *fh;
537 
538   target_path = link_path = NULL;
539   res = pr_fsio_link(target_path, link_path);
540   fail_unless(res < 0, "Failed to handle null arguments");
541   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
542     errno);
543 
544   target_path = fsio_test_path;
545   link_path = NULL;
546   res = pr_fsio_link(target_path, link_path);
547   fail_unless(res < 0, "Failed to handle null link_path argument");
548   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
549     errno);
550 
551   target_path = NULL;
552   link_path = fsio_link_path;
553   res = pr_fsio_link(target_path, link_path);
554   fail_unless(res < 0, "Failed to handle null target_path argument");
555   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
556     errno);
557 
558   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
559   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
560     strerror(errno));
561   (void) pr_fsio_close(fh);
562 
563   /* Link a file (that exists) to itself */
564   link_path = target_path = fsio_test_path;
565   res = pr_fsio_link(target_path, link_path);
566   fail_unless(res < 0, "Failed to handle same existing source/destination");
567   fail_unless(errno == EEXIST, "Expected EEXIST, got %s (%d)", strerror(errno),
568     errno);
569 
570   /* Create expected link */
571   link_path = fsio_link_path;
572   target_path = fsio_test_path;
573   res = pr_fsio_link(target_path, link_path);
574   fail_unless(res == 0, "Failed to create link from '%s' to '%s': %s",
575     link_path, target_path, strerror(errno));
576   (void) unlink(link_path);
577   (void) pr_fsio_unlink(fsio_test_path);
578 }
579 END_TEST
580 
START_TEST(fsio_sys_link_chroot_guard_test)581 START_TEST (fsio_sys_link_chroot_guard_test) {
582   int res;
583 
584   res = pr_fsio_guard_chroot(TRUE);
585   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
586 
587   res = pr_fsio_link(fsio_link_path, "/etc/foo.bar.baz");
588   fail_unless(res < 0, "Linked /etc/foo.bar.baz unexpectedly");
589   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
590     strerror(errno), errno);
591 
592   (void) pr_fsio_guard_chroot(FALSE);
593 
594   (void) pr_fsio_unlink(fsio_link_path);
595   res = pr_fsio_link(fsio_link_path, "/lib/foo/bar/baz");
596   fail_unless(res < 0, "Linked /lib/foo/bar/baz unexpectedly");
597   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
598     strerror(errno), errno);
599 }
600 END_TEST
601 
START_TEST(fsio_sys_symlink_test)602 START_TEST (fsio_sys_symlink_test) {
603   int res;
604   const char *target_path, *link_path;
605 
606   target_path = link_path = NULL;
607   res = pr_fsio_symlink(target_path, link_path);
608   fail_unless(res < 0, "Failed to handle null arguments");
609   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
610     errno);
611 
612   target_path = "/tmp";
613   link_path = NULL;
614   res = pr_fsio_symlink(target_path, link_path);
615   fail_unless(res < 0, "Failed to handle null link_path argument");
616   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
617     errno);
618 
619   target_path = NULL;
620   link_path = fsio_link_path;
621   res = pr_fsio_symlink(target_path, link_path);
622   fail_unless(res < 0, "Failed to handle null target_path argument");
623   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
624     errno);
625 
626   /* Symlink a file (that exists) to itself */
627   link_path = target_path = "/tmp";
628   res = pr_fsio_symlink(target_path, link_path);
629   fail_unless(res < 0, "Failed to handle same existing source/destination");
630   fail_unless(errno == EEXIST, "Expected EEXIST, got %s (%d)", strerror(errno),
631     errno);
632 
633   /* Create expected symlink */
634   link_path = fsio_link_path;
635   target_path = "/tmp";
636   res = pr_fsio_symlink(target_path, link_path);
637   fail_unless(res == 0, "Failed to create symlink from '%s' to '%s': %s",
638     link_path, target_path, strerror(errno));
639   (void) unlink(link_path);
640 }
641 END_TEST
642 
START_TEST(fsio_sys_symlink_chroot_guard_test)643 START_TEST (fsio_sys_symlink_chroot_guard_test) {
644   int res;
645 
646   res = pr_fsio_guard_chroot(TRUE);
647   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
648 
649   res = pr_fsio_symlink(fsio_link_path, "/etc/foo.bar.baz");
650   fail_unless(res < 0, "Symlinked /etc/foo.bar.baz unexpectedly");
651   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
652     strerror(errno), errno);
653 
654   (void) pr_fsio_guard_chroot(FALSE);
655   (void) pr_fsio_unlink(fsio_link_path);
656 
657   res = pr_fsio_symlink(fsio_link_path, "/lib/foo/bar/baz");
658   fail_unless(res < 0, "Symlinked /lib/foo/bar/baz unexpectedly");
659   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
660     strerror(errno), errno);
661 }
662 END_TEST
663 
START_TEST(fsio_sys_readlink_test)664 START_TEST (fsio_sys_readlink_test) {
665   int res;
666   char buf[PR_TUNABLE_BUFFER_SIZE];
667   const char *link_path, *target_path, *path;
668 
669   res = pr_fsio_readlink(NULL, NULL, 0);
670   fail_unless(res < 0, "Failed to handle null arguments");
671   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
672     errno);
673 
674   /* Read a non-symlink file */
675   path = "/";
676   res = pr_fsio_readlink(path, buf, sizeof(buf)-1);
677   fail_unless(res < 0, "Failed to handle non-symlink path");
678   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
679     errno);
680 
681   /* Read a symlink file */
682   target_path = "/tmp";
683   link_path = fsio_link_path;
684   res = pr_fsio_symlink(target_path, link_path);
685   fail_unless(res == 0, "Failed to create symlink from '%s' to '%s': %s",
686     link_path, target_path, strerror(errno));
687 
688   memset(buf, '\0', sizeof(buf));
689   res = pr_fsio_readlink(link_path, buf, sizeof(buf)-1);
690   fail_unless(res > 0, "Failed to read symlink '%s': %s", link_path,
691     strerror(errno));
692   buf[res] = '\0';
693   fail_unless(strcmp(buf, target_path) == 0, "Expected '%s', got '%s'",
694     target_path, buf);
695 
696   /* Read a symlink file using a zero-length buffer */
697   res = pr_fsio_readlink(link_path, buf, 0);
698   fail_unless(res <= 0, "Expected length <= 0, got %d", res);
699 
700   (void) unlink(link_path);
701 }
702 END_TEST
703 
START_TEST(fsio_sys_lstat_test)704 START_TEST (fsio_sys_lstat_test) {
705   int res;
706   struct stat st;
707   unsigned int cache_size = 3, max_age = 1, policy_flags = 0;
708 
709   res = pr_fsio_lstat(NULL, &st);
710   fail_unless(res < 0, "Failed to handle null path");
711   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
712     errno);
713 
714   res = pr_fsio_lstat("/", NULL);
715   fail_unless(res < 0, "Failed to handle null struct stat");
716   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
717     errno);
718 
719   res = pr_fsio_lstat("/", &st);
720   fail_unless(res == 0, "Unexpected lstat(2) error on '/': %s",
721     strerror(errno));
722   fail_unless(S_ISDIR(st.st_mode), "'/' is not a directory as expected");
723 
724   /* Now, do the lstat(2) again, and make sure we get the same information
725    * from the cache.
726    */
727   res = pr_fsio_lstat("/", &st);
728   fail_unless(res == 0, "Unexpected lstat(2) error on '/': %s",
729     strerror(errno));
730   fail_unless(S_ISDIR(st.st_mode), "'/' is not a directory as expected");
731 
732   pr_fs_statcache_reset();
733   res = pr_fs_statcache_set_policy(cache_size, max_age, policy_flags);
734   fail_unless(res == 0, "Failed to set statcache policy: %s", strerror(errno));
735 
736   res = pr_fsio_lstat("/foo/bar/baz/quxx", &st);
737   fail_unless(res < 0, "Failed to handle nonexistent path");
738   fail_unless(errno == ENOENT, "Expected ENOENT, got %s (%d)", strerror(errno),
739     errno);
740 
741   res = pr_fsio_lstat("/foo/bar/baz/quxx", &st);
742   fail_unless(res < 0, "Failed to handle nonexistent path");
743   fail_unless(errno == ENOENT, "Expected ENOENT, got %s (%d)", strerror(errno),
744     errno);
745 
746   /* Now wait for longer than 1 second (our configured max age) */
747   sleep(max_age + 1);
748 
749   res = pr_fsio_lstat("/foo/bar/baz/quxx", &st);
750   fail_unless(res < 0, "Failed to handle nonexistent path");
751   fail_unless(errno == ENOENT, "Expected ENOENT, got %s (%d)", strerror(errno),
752     errno);
753 
754   /* lstat a symlink path */
755   res = pr_fsio_symlink("/tmp", fsio_link_path);
756   fail_unless(res == 0, "Failed to create symlink to '%s': %s", fsio_link_path,
757     strerror(errno));
758 
759   res = pr_fsio_lstat(fsio_link_path, &st);
760   fail_unless(res == 0, "Failed to lstat '%s': %s", fsio_link_path,
761     strerror(errno));
762 
763   (void) unlink(fsio_link_path);
764 }
765 END_TEST
766 
START_TEST(fsio_sys_access_dir_test)767 START_TEST (fsio_sys_access_dir_test) {
768   int res;
769   uid_t uid = getuid();
770   gid_t gid = getgid();
771   mode_t perms;
772   array_header *suppl_gids;
773 
774   res = pr_fsio_access(NULL, X_OK, uid, gid, NULL);
775   fail_unless(res < 0, "Failed to handle null path");
776   fail_unless(errno == EINVAL, "Expected EINVAL, got %s (%d)", strerror(errno),
777     errno);
778 
779   res = pr_fsio_access("/baz/bar/foo", X_OK, uid, gid, NULL);
780   fail_unless(res < 0, "Failed to handle nonexistent path");
781   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
782     strerror(errno), errno);
783 
784   /* Make the directory to check; we want it to have perms 771.*/
785   perms = (mode_t) 0771;
786   res = mkdir(fsio_testdir_path, perms);
787   fail_if(res < 0, "Unable to create directory '%s': %s", fsio_testdir_path,
788     strerror(errno));
789 
790   /* Use chmod(2) to ensure that the directory has the perms we want,
791    * regardless of any umask settings.
792    */
793   res = chmod(fsio_testdir_path, perms);
794   fail_if(res < 0, "Unable to set perms %04o on directory '%s': %s", perms,
795     fsio_testdir_path, strerror(errno));
796 
797   /* First, check that we ourselves can access our own directory. */
798 
799   pr_fs_clear_cache2(fsio_testdir_path);
800   res = pr_fsio_access(fsio_testdir_path, F_OK, uid, gid, NULL);
801   fail_unless(res == 0, "Failed to check for file access on directory: %s",
802     strerror(errno));
803 
804   pr_fs_clear_cache2(fsio_testdir_path);
805   res = pr_fsio_access(fsio_testdir_path, R_OK, uid, gid, NULL);
806   fail_unless(res == 0, "Failed to check for read access on directory: %s",
807     strerror(errno));
808 
809   pr_fs_clear_cache2(fsio_testdir_path);
810   res = pr_fsio_access(fsio_testdir_path, W_OK, uid, gid, NULL);
811   fail_unless(res == 0, "Failed to check for write access on directory: %s",
812     strerror(errno));
813 
814   pr_fs_clear_cache2(fsio_testdir_path);
815   res = pr_fsio_access(fsio_testdir_path, X_OK, uid, gid, NULL);
816   fail_unless(res == 0, "Failed to check for execute access on directory: %s",
817     strerror(errno));
818 
819   suppl_gids = make_array(p, 1, sizeof(gid_t));
820   *((gid_t *) push_array(suppl_gids)) = gid;
821 
822   pr_fs_clear_cache2(fsio_testdir_path);
823   res = pr_fsio_access(fsio_testdir_path, X_OK, uid, gid, suppl_gids);
824   fail_unless(res == 0, "Failed to check for execute access on directory: %s",
825     strerror(errno));
826 
827   pr_fs_clear_cache2(fsio_testdir_path);
828   res = pr_fsio_access(fsio_testdir_path, R_OK, uid, gid, suppl_gids);
829   fail_unless(res == 0, "Failed to check for read access on directory: %s",
830     strerror(errno));
831 
832   pr_fs_clear_cache2(fsio_testdir_path);
833   res = pr_fsio_access(fsio_testdir_path, W_OK, uid, gid, suppl_gids);
834   fail_unless(res == 0, "Failed to check for write access on directory: %s",
835     strerror(errno));
836 
837   if (getenv("CI") == NULL &&
838       getenv("CIRRUS_CLONE_DEPTH") == NULL &&
839       getenv("TRAVIS") == NULL) {
840     uid_t other_uid;
841     gid_t other_gid;
842 
843     /* Deliberately use IDs other than the current ones. */
844     other_uid = uid - 1;
845     other_gid = gid - 1;
846 
847     /* Next, check that others can access the directory. */
848     pr_fs_clear_cache2(fsio_testdir_path);
849     res = pr_fsio_access(fsio_testdir_path, F_OK, other_uid, other_gid,
850       NULL);
851     fail_unless(res == 0,
852       "Failed to check for other file access on directory: %s",
853       strerror(errno));
854 
855     pr_fs_clear_cache2(fsio_testdir_path);
856     res = pr_fsio_access(fsio_testdir_path, R_OK, other_uid, other_gid,
857       NULL);
858     fail_unless(res < 0,
859       "other read access on directory succeeded unexpectedly");
860     fail_unless(errno == EACCES, "Expected EACCES, got %s (%d)",
861       strerror(errno), errno);
862 
863     pr_fs_clear_cache2(fsio_testdir_path);
864     res = pr_fsio_access(fsio_testdir_path, W_OK, other_uid, other_gid,
865       NULL);
866     fail_unless(res < 0,
867       "other write access on directory succeeded unexpectedly");
868     fail_unless(errno == EACCES, "Expected EACCES, got %s (%d)",
869       strerror(errno), errno);
870 
871     pr_fs_clear_cache2(fsio_testdir_path);
872     res = pr_fsio_access(fsio_testdir_path, X_OK, other_uid, other_gid,
873       NULL);
874     fail_unless(res == 0, "Failed to check for execute access on directory: %s",
875       strerror(errno));
876   }
877 
878   (void) rmdir(fsio_testdir_path);
879 }
880 END_TEST
881 
START_TEST(fsio_sys_access_file_test)882 START_TEST (fsio_sys_access_file_test) {
883   int fd, res;
884   uid_t uid = getuid();
885   gid_t gid = getgid();
886   mode_t perms = 0665;
887   array_header *suppl_gids;
888 
889   /* Make the file to check; we want it to have perms 664.*/
890   fd = open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
891   fail_if(fd < 0, "Unable to create file '%s': %s", fsio_test_path,
892     strerror(errno));
893 
894   /* Use chmod(2) to ensure that the file has the perms we want,
895    * regardless of any umask settings.
896    */
897   res = chmod(fsio_test_path, perms);
898   fail_if(res < 0, "Unable to set perms %04o on file '%s': %s", perms,
899     fsio_test_path, strerror(errno));
900 
901   /* First, check that we ourselves can access our own file. */
902 
903   pr_fs_clear_cache2(fsio_test_path);
904   res = pr_fsio_access(fsio_test_path, F_OK, uid, gid, NULL);
905   fail_unless(res == 0, "Failed to check for file access on '%s': %s",
906     fsio_test_path, strerror(errno));
907 
908   pr_fs_clear_cache2(fsio_test_path);
909   res = pr_fsio_access(fsio_test_path, R_OK, uid, gid, NULL);
910   fail_unless(res == 0, "Failed to check for read access on '%s': %s",
911     fsio_test_path, strerror(errno));
912 
913   pr_fs_clear_cache2(fsio_test_path);
914   res = pr_fsio_access(fsio_test_path, W_OK, uid, gid, NULL);
915   fail_unless(res == 0, "Failed to check for write access on '%s': %s",
916     fsio_test_path, strerror(errno));
917 
918   pr_fs_clear_cache2(fsio_test_path);
919   res = pr_fsio_access(fsio_test_path, X_OK, uid, gid, NULL);
920   fail_unless(res == 0, "Failed to check for execute access on '%s': %s",
921     fsio_test_path, strerror(errno));
922 
923   suppl_gids = make_array(p, 1, sizeof(gid_t));
924   *((gid_t *) push_array(suppl_gids)) = gid;
925 
926   pr_fs_clear_cache2(fsio_test_path);
927   res = pr_fsio_access(fsio_test_path, X_OK, uid, gid, suppl_gids);
928   fail_unless(res == 0, "Failed to check for execute access on '%s': %s",
929     fsio_test_path, strerror(errno));
930 
931   pr_fs_clear_cache2(fsio_test_path);
932   res = pr_fsio_access(fsio_test_path, R_OK, uid, gid, suppl_gids);
933   fail_unless(res == 0, "Failed to check for read access on '%s': %s",
934     fsio_test_path, strerror(errno));
935 
936   pr_fs_clear_cache2(fsio_test_path);
937   res = pr_fsio_access(fsio_test_path, W_OK, uid, gid, suppl_gids);
938   fail_unless(res == 0, "Failed to check for write access on '%s': %s",
939     fsio_test_path, strerror(errno));
940 
941   (void) unlink(fsio_test_path);
942 }
943 END_TEST
944 
START_TEST(fsio_sys_faccess_test)945 START_TEST (fsio_sys_faccess_test) {
946   int res;
947   uid_t uid = getuid();
948   gid_t gid = getgid();
949   mode_t perms = 0664;
950   pr_fh_t *fh;
951 
952   res = pr_fsio_faccess(NULL, F_OK, uid, gid, NULL);
953   fail_unless(res < 0, "Failed to handle null arguments");
954   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
955     strerror(errno), errno);
956 
957   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
958   fail_unless(fh != NULL, "Unable to create file '%s': %s", fsio_test_path,
959     strerror(errno));
960 
961   /* Use chmod(2) to ensure that the file has the perms we want,
962    * regardless of any umask settings.
963    */
964   res = chmod(fsio_test_path, perms);
965   fail_if(res < 0, "Unable to set perms %04o on file '%s': %s", perms,
966     fsio_test_path, strerror(errno));
967 
968   /* First, check that we ourselves can access our own file. */
969 
970   pr_fs_clear_cache2(fsio_test_path);
971   res = pr_fsio_faccess(fh, F_OK, uid, gid, NULL);
972   fail_unless(res == 0, "Failed to check for file access on '%s': %s",
973     fsio_test_path, strerror(errno));
974 
975   pr_fs_clear_cache2(fsio_test_path);
976   res = pr_fsio_faccess(fh, R_OK, uid, gid, NULL);
977   fail_unless(res == 0, "Failed to check for read access on '%s': %s",
978     fsio_test_path, strerror(errno));
979 
980   pr_fs_clear_cache2(fsio_test_path);
981   res = pr_fsio_faccess(fh, W_OK, uid, gid, NULL);
982   fail_unless(res == 0, "Failed to check for write access on '%s': %s",
983     fsio_test_path, strerror(errno));
984 
985   pr_fs_clear_cache2(fsio_test_path);
986   res = pr_fsio_faccess(fh, X_OK, uid, gid, NULL);
987   fail_unless(res < 0,
988     "Check for execute access on '%s' succeeded unexpectedly", fsio_test_path);
989 
990   (void) pr_fsio_close(fh);
991   (void) pr_fsio_unlink(fsio_test_path);
992 }
993 END_TEST
994 
START_TEST(fsio_sys_truncate_test)995 START_TEST (fsio_sys_truncate_test) {
996   int res;
997   off_t len = 0;
998   pr_fh_t *fh;
999 
1000   res = pr_fsio_truncate(NULL, 0);
1001   fail_unless(res < 0, "Failed to handle null arguments");
1002   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1003     strerror(errno), errno);
1004 
1005   res = pr_fsio_truncate(fsio_test_path, 0);
1006   fail_unless(res < 0, "Truncated '%s' unexpectedly", fsio_test_path);
1007   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1008     strerror(errno), errno);
1009 
1010   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1011   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1012     strerror(errno));
1013 
1014   res = pr_fsio_truncate(fsio_test_path, len);
1015   fail_unless(res == 0, "Failed to truncate '%s': %s", fsio_test_path,
1016     strerror(errno));
1017 
1018   (void) pr_fsio_close(fh);
1019   (void) pr_fsio_unlink(fsio_test_path);
1020 }
1021 END_TEST
1022 
START_TEST(fsio_sys_truncate_chroot_guard_test)1023 START_TEST (fsio_sys_truncate_chroot_guard_test) {
1024   int res;
1025 
1026   res = pr_fsio_guard_chroot(TRUE);
1027   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
1028 
1029   res = pr_fsio_truncate("/etc/foo.bar.baz", 0);
1030   fail_unless(res < 0, "Truncated /etc/foo.bar.baz unexpectedly");
1031   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
1032     strerror(errno), errno);
1033 
1034   (void) pr_fsio_guard_chroot(FALSE);
1035 
1036   res = pr_fsio_truncate("/lib/foo/bar/baz", 0);
1037   fail_unless(res < 0, "Truncated /lib/foo/bar/baz unexpectedly");
1038   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
1039     strerror(errno), errno);
1040 }
1041 END_TEST
1042 
START_TEST(fsio_sys_ftruncate_test)1043 START_TEST (fsio_sys_ftruncate_test) {
1044   int res;
1045   off_t len = 0;
1046   pr_fh_t *fh;
1047   pr_buffer_t *buf;
1048 
1049   res = pr_fsio_ftruncate(NULL, 0);
1050   fail_unless(res < 0, "Failed to handle null arguments");
1051   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1052     strerror(errno), errno);
1053 
1054   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1055   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1056     strerror(errno));
1057 
1058   mark_point();
1059   res = pr_fsio_ftruncate(fh, len);
1060   fail_unless(res == 0, "Failed to truncate '%s': %s", fsio_test_path,
1061     strerror(errno));
1062 
1063   /* Attach a read buffer to the handle, make sure it is cleared. */
1064   buf = pcalloc(fh->fh_pool, sizeof(pr_buffer_t));
1065   buf->buflen = 100;
1066   buf->remaining = 1;
1067 
1068   fh->fh_buf = buf;
1069 
1070   mark_point();
1071   res = pr_fsio_ftruncate(fh, len);
1072   fail_unless(res == 0, "Failed to truncate '%s': %s", fsio_test_path,
1073     strerror(errno));
1074   fail_unless(buf->remaining == buf->buflen,
1075     "Expected %lu, got %lu", (unsigned long) buf->buflen,
1076     (unsigned long) buf->remaining);
1077 
1078   (void) pr_fsio_close(fh);
1079   (void) pr_fsio_unlink(fsio_test_path);
1080 }
1081 END_TEST
1082 
START_TEST(fsio_sys_chmod_test)1083 START_TEST (fsio_sys_chmod_test) {
1084   int res;
1085   mode_t mode = 0644;
1086   pr_fh_t *fh;
1087 
1088   res = pr_fsio_chmod(NULL, mode);
1089   fail_unless(res < 0, "Failed to handle null arguments");
1090   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1091     strerror(errno), errno);
1092 
1093   res = pr_fsio_chmod(fsio_test_path, 0);
1094   fail_unless(res < 0, "Changed perms of '%s' unexpectedly", fsio_test_path);
1095   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1096     strerror(errno), errno);
1097 
1098   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1099   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1100     strerror(errno));
1101 
1102   res = pr_fsio_chmod(fsio_test_path, mode);
1103   fail_unless(res == 0, "Failed to set perms of '%s': %s", fsio_test_path,
1104     strerror(errno));
1105 
1106   (void) pr_fsio_close(fh);
1107   (void) pr_fsio_unlink(fsio_test_path);
1108 }
1109 END_TEST
1110 
START_TEST(fsio_sys_chmod_chroot_guard_test)1111 START_TEST (fsio_sys_chmod_chroot_guard_test) {
1112   int res;
1113   mode_t mode = 0644;
1114 
1115   res = pr_fsio_guard_chroot(TRUE);
1116   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
1117 
1118   res = pr_fsio_chmod("/etc/foo.bar.baz", mode);
1119   fail_unless(res < 0, "Set mode on /etc/foo.bar.baz unexpectedly");
1120   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
1121     strerror(errno), errno);
1122 
1123   (void) pr_fsio_guard_chroot(FALSE);
1124 
1125   res = pr_fsio_chmod("/lib/foo/bar/baz", mode);
1126   fail_unless(res < 0, "Set mode on /lib/foo/bar/baz unexpectedly");
1127   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
1128     strerror(errno), errno);
1129 }
1130 END_TEST
1131 
START_TEST(fsio_sys_fchmod_test)1132 START_TEST (fsio_sys_fchmod_test) {
1133   int res;
1134   mode_t mode = 0644;
1135   pr_fh_t *fh;
1136 
1137   res = pr_fsio_fchmod(NULL, mode);
1138   fail_unless(res < 0, "Failed to handle null arguments");
1139   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1140     strerror(errno), errno);
1141 
1142   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1143   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1144     strerror(errno));
1145 
1146   res = pr_fsio_fchmod(fh, mode);
1147   fail_unless(res == 0, "Failed to set perms of '%s': %s", fsio_test_path,
1148     strerror(errno));
1149 
1150   (void) pr_fsio_close(fh);
1151   (void) pr_fsio_unlink(fsio_test_path);
1152 }
1153 END_TEST
1154 
START_TEST(fsio_sys_chown_test)1155 START_TEST (fsio_sys_chown_test) {
1156   int res;
1157   uid_t uid = getuid();
1158   gid_t gid = getgid();
1159   pr_fh_t *fh;
1160 
1161   res = pr_fsio_chown(NULL, uid, gid);
1162   fail_unless(res < 0, "Failed to handle null arguments");
1163   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1164     strerror(errno), errno);
1165 
1166   res = pr_fsio_chown(fsio_test_path, uid, gid);
1167   fail_unless(res < 0, "Changed ownership of '%s' unexpectedly",
1168     fsio_test_path);
1169   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1170     strerror(errno), errno);
1171 
1172   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1173   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1174     strerror(errno));
1175 
1176   res = pr_fsio_chown(fsio_test_path, uid, gid);
1177   fail_unless(res == 0, "Failed to set ownership of '%s': %s", fsio_test_path,
1178     strerror(errno));
1179 
1180   (void) pr_fsio_close(fh);
1181   (void) pr_fsio_unlink(fsio_test_path);
1182 }
1183 END_TEST
1184 
START_TEST(fsio_sys_chown_chroot_guard_test)1185 START_TEST (fsio_sys_chown_chroot_guard_test) {
1186   int res;
1187   uid_t uid = getuid();
1188   gid_t gid = getgid();
1189 
1190   res = pr_fsio_guard_chroot(TRUE);
1191   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
1192 
1193   res = pr_fsio_chown("/etc/foo.bar.baz", uid, gid);
1194   fail_unless(res < 0, "Set ownership on /etc/foo.bar.baz unexpectedly");
1195   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
1196     strerror(errno), errno);
1197 
1198   (void) pr_fsio_guard_chroot(FALSE);
1199 
1200   res = pr_fsio_chown("/lib/foo/bar/baz", uid, gid);
1201   fail_unless(res < 0, "Set ownership on /lib/foo/bar/baz unexpectedly");
1202   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
1203     strerror(errno), errno);
1204 }
1205 END_TEST
1206 
START_TEST(fsio_sys_fchown_test)1207 START_TEST (fsio_sys_fchown_test) {
1208   int res;
1209   uid_t uid = getuid();
1210   gid_t gid = getgid();
1211   pr_fh_t *fh;
1212 
1213   res = pr_fsio_fchown(NULL, uid, gid);
1214   fail_unless(res < 0, "Failed to handle null arguments");
1215   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1216     strerror(errno), errno);
1217 
1218   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1219   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1220     strerror(errno));
1221 
1222   res = pr_fsio_fchown(fh, uid, gid);
1223   fail_unless(res == 0, "Failed to set ownership of '%s': %s", fsio_test_path,
1224     strerror(errno));
1225 
1226   (void) pr_fsio_close(fh);
1227   (void) pr_fsio_unlink(fsio_test_path);
1228 }
1229 END_TEST
1230 
START_TEST(fsio_sys_lchown_test)1231 START_TEST (fsio_sys_lchown_test) {
1232   int res;
1233   uid_t uid = getuid();
1234   gid_t gid = getgid();
1235   pr_fh_t *fh;
1236 
1237   res = pr_fsio_lchown(NULL, uid, gid);
1238   fail_unless(res < 0, "Failed to handle null arguments");
1239   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1240     strerror(errno), errno);
1241 
1242   res = pr_fsio_lchown(fsio_test_path, uid, gid);
1243   fail_unless(res < 0, "Changed ownership of '%s' unexpectedly",
1244     fsio_test_path);
1245   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1246     strerror(errno), errno);
1247 
1248   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1249   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1250     strerror(errno));
1251 
1252   res = pr_fsio_lchown(fsio_test_path, uid, gid);
1253   fail_unless(res == 0, "Failed to set ownership of '%s': %s", fsio_test_path,
1254     strerror(errno));
1255 
1256   (void) pr_fsio_close(fh);
1257   (void) pr_fsio_unlink(fsio_test_path);
1258 }
1259 END_TEST
1260 
START_TEST(fsio_sys_lchown_chroot_guard_test)1261 START_TEST (fsio_sys_lchown_chroot_guard_test) {
1262   int res;
1263   uid_t uid = getuid();
1264   gid_t gid = getgid();
1265 
1266   res = pr_fsio_guard_chroot(TRUE);
1267   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
1268 
1269   res = pr_fsio_lchown("/etc/foo.bar.baz", uid, gid);
1270   fail_unless(res < 0, "Set ownership on /etc/foo.bar.baz unexpectedly");
1271   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
1272     strerror(errno), errno);
1273 
1274   (void) pr_fsio_guard_chroot(FALSE);
1275 
1276   res = pr_fsio_lchown("/lib/foo/bar/baz", uid, gid);
1277   fail_unless(res < 0, "Set ownership on /lib/foo/bar/baz unexpectedly");
1278   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
1279     strerror(errno), errno);
1280 }
1281 END_TEST
1282 
START_TEST(fsio_sys_rename_test)1283 START_TEST (fsio_sys_rename_test) {
1284   int res;
1285   pr_fh_t *fh;
1286 
1287   res = pr_fsio_rename(NULL, NULL);
1288   fail_unless(res < 0, "Failed to handle null arguments");
1289   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1290     strerror(errno), errno);
1291 
1292   res = pr_fsio_rename(fsio_test_path, NULL);
1293   fail_unless(res < 0, "Failed to handle null dst argument");
1294   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1295     strerror(errno), errno);
1296 
1297   res = pr_fsio_rename(fsio_test_path, fsio_test2_path);
1298   fail_unless(res < 0, "Failed to handle non-existent files");
1299   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1300     strerror(errno), errno);
1301 
1302   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1303   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1304     strerror(errno));
1305   (void) pr_fsio_close(fh);
1306 
1307   res = pr_fsio_rename(fsio_test_path, fsio_test2_path);
1308   fail_unless(res == 0, "Failed to rename '%s' to '%s': %s", fsio_test_path,
1309     fsio_test2_path, strerror(errno));
1310 
1311   (void) pr_fsio_unlink(fsio_test_path);
1312   (void) pr_fsio_unlink(fsio_test2_path);
1313 }
1314 END_TEST
1315 
START_TEST(fsio_sys_rename_chroot_guard_test)1316 START_TEST (fsio_sys_rename_chroot_guard_test) {
1317   int res;
1318   pr_fh_t *fh;
1319 
1320   res = pr_fsio_guard_chroot(TRUE);
1321   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
1322 
1323   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1324   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1325     strerror(errno));
1326   (void) pr_fsio_close(fh);
1327 
1328   res = pr_fsio_rename(fsio_test_path, "/etc/foo.bar.baz");
1329   fail_unless(res < 0, "Renamed '%s' unexpectedly", fsio_test_path);
1330   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
1331     strerror(errno), errno);
1332 
1333   res = pr_fsio_rename("/etc/foo.bar.baz", fsio_test_path);
1334   fail_unless(res < 0, "Renamed '/etc/foo.bar.baz' unexpectedly");
1335   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
1336     strerror(errno), errno);
1337 
1338   (void) pr_fsio_guard_chroot(FALSE);
1339 
1340   res = pr_fsio_rename("/etc/foo/bar/baz", "/lib/quxx/quzz");
1341   fail_unless(res < 0, "Renamed '/etc/foo/bar/baz' unexpectedly");
1342   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1343     strerror(errno), errno);
1344 
1345   (void) pr_fsio_unlink(fsio_test_path);
1346 }
1347 END_TEST
1348 
START_TEST(fsio_sys_utimes_test)1349 START_TEST (fsio_sys_utimes_test) {
1350   int res;
1351   struct timeval tvs[3];
1352   pr_fh_t *fh;
1353 
1354   memset(tvs, 0, sizeof(tvs));
1355 
1356   res = pr_fsio_utimes(NULL, NULL);
1357   fail_unless(res < 0, "Failed to handle null arguments");
1358   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1359     strerror(errno), errno);
1360 
1361   res = pr_fsio_utimes(fsio_test_path, (struct timeval *) &tvs);
1362   fail_unless(res < 0, "Changed times of '%s' unexpectedly", fsio_test_path);
1363   fail_unless(errno == ENOENT || errno == EINVAL,
1364     "Expected ENOENT (%d) or EINVAL (%d), got %s (%d)", ENOENT, EINVAL,
1365     strerror(errno), errno);
1366 
1367   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1368   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1369     strerror(errno));
1370 
1371   memset(&tvs, 0, sizeof(tvs));
1372   res = pr_fsio_utimes(fsio_test_path, (struct timeval *) &tvs);
1373   fail_unless(res == 0, "Failed to set times of '%s': %s", fsio_test_path,
1374     strerror(errno));
1375 
1376   (void) pr_fsio_close(fh);
1377   (void) pr_fsio_unlink(fsio_test_path);
1378 }
1379 END_TEST
1380 
START_TEST(fsio_sys_utimes_chroot_guard_test)1381 START_TEST (fsio_sys_utimes_chroot_guard_test) {
1382   int res;
1383   struct timeval tvs[3];
1384 
1385   memset(tvs, 0, sizeof(tvs));
1386 
1387   res = pr_fsio_guard_chroot(TRUE);
1388   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
1389 
1390   res = pr_fsio_utimes("/etc/foo.bar.baz", (struct timeval *) &tvs);
1391   fail_unless(res < 0, "Set times on /etc/foo.bar.baz unexpectedly");
1392   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
1393     strerror(errno), errno);
1394 
1395   (void) pr_fsio_guard_chroot(FALSE);
1396 
1397   res = pr_fsio_utimes("/lib/foo/bar/baz", (struct timeval *) &tvs);
1398   fail_unless(res < 0, "Set times on /lib/foo/bar/baz unexpectedly");
1399   fail_unless(errno == ENOENT || errno == EINVAL,
1400     "Expected ENOENT (%d) or EINVAL (%d), got %s %d", ENOENT, EINVAL,
1401     strerror(errno), errno);
1402 }
1403 END_TEST
1404 
START_TEST(fsio_sys_futimes_test)1405 START_TEST (fsio_sys_futimes_test) {
1406   int res;
1407   struct timeval tvs[3];
1408   pr_fh_t *fh;
1409 
1410   memset(tvs, 0, sizeof(tvs));
1411 
1412   res = pr_fsio_futimes(NULL, NULL);
1413   fail_unless(res < 0, "Failed to handle null arguments");
1414   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1415     strerror(errno), errno);
1416 
1417   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1418   fail_unless(fh != NULL, "Failed to create '%s': %s", fsio_test_path,
1419     strerror(errno));
1420 
1421   memset(&tvs, 0, sizeof(tvs));
1422   res = pr_fsio_futimes(fh, (struct timeval *) &tvs);
1423   fail_unless(res == 0, "Failed to set times of '%s': %s", fsio_test_path,
1424     strerror(errno));
1425 
1426   (void) pr_fsio_close(fh);
1427   (void) pr_fsio_unlink(fsio_test_path);
1428 }
1429 END_TEST
1430 
START_TEST(fsio_sys_fsync_test)1431 START_TEST (fsio_sys_fsync_test) {
1432   int res;
1433   pr_fh_t *fh;
1434 
1435   res = pr_fsio_fsync(NULL);
1436   fail_unless(res < 0, "Failed to handle null arguments");
1437   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1438     strerror(errno), errno);
1439 
1440   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1441   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
1442     strerror(errno));
1443 
1444   res = pr_fsio_fsync(fh);
1445 #ifdef HAVE_FSYNC
1446   fail_unless(res == 0, "fsync of '%s' failed: %s", fsio_test_path,
1447     strerror(errno));
1448 #else
1449   fail_unless(res < 0, "fsync of '%s' succeeded unexpectedly", fsio_test_path);
1450   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1451     strerror(errno), errno);
1452 #endif /* HAVE_FSYNC */
1453 
1454   (void) pr_fsio_close(fh);
1455   (void) pr_fsio_unlink(fsio_test_path);
1456 }
1457 END_TEST
1458 
START_TEST(fsio_sys_getxattr_test)1459 START_TEST (fsio_sys_getxattr_test) {
1460   ssize_t res;
1461   const char *path, *name;
1462   unsigned long fsio_opts;
1463 
1464   res = pr_fsio_getxattr(NULL, NULL, NULL, NULL, 0);
1465   fail_unless(res < 0, "Failed to handle null arguments");
1466   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1467     strerror(errno), errno);
1468 
1469   res = pr_fsio_getxattr(p, NULL, NULL, NULL, 0);
1470   fail_unless(res < 0, "Failed to handle null path");
1471   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1472     strerror(errno), errno);
1473 
1474   path = fsio_test_path;
1475   res = pr_fsio_getxattr(p, path, NULL, NULL, 0);
1476   fail_unless(res < 0, "Failed to handle null arguments");
1477   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1478     strerror(errno), errno);
1479 
1480   name = "foo.bar";
1481 
1482   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1483   res = pr_fsio_getxattr(p, path, name, NULL, 0);
1484   fail_unless(res < 0, "Failed to handle disabled xattr");
1485   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1486     strerror(errno), errno);
1487 
1488   (void) pr_fsio_set_options(fsio_opts);
1489   res = pr_fsio_getxattr(p, path, name, NULL, 0);
1490 #ifdef PR_USE_XATTR
1491   fail_unless(res < 0, "Failed to handle nonexist attribute '%s'", name);
1492   fail_unless(errno == ENOENT || errno == ENOATTR || errno == ENOTSUP,
1493     "Expected ENOENT (%d), ENOATTR (%d) or ENOTSUP (%d), got %s (%d)",
1494     ENOENT, ENOATTR, ENOTSUP, strerror(errno), errno);
1495 
1496 #else
1497   fail_unless(res < 0, "Failed to handle --disable-xattr");
1498   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1499     strerror(errno), errno);
1500 #endif /* PR_USE_XATTR */
1501 }
1502 END_TEST
1503 
START_TEST(fsio_sys_lgetxattr_test)1504 START_TEST (fsio_sys_lgetxattr_test) {
1505   ssize_t res;
1506   const char *path, *name;
1507   unsigned long fsio_opts;
1508 
1509   res = pr_fsio_lgetxattr(NULL, NULL, NULL, NULL, 0);
1510   fail_unless(res < 0, "Failed to handle null arguments");
1511   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1512     strerror(errno), errno);
1513 
1514   res = pr_fsio_lgetxattr(p, NULL, NULL, NULL, 0);
1515   fail_unless(res < 0, "Failed to handle null path");
1516   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1517     strerror(errno), errno);
1518 
1519   path = fsio_test_path;
1520   res = pr_fsio_lgetxattr(p, path, NULL, NULL, 0);
1521   fail_unless(res < 0, "Failed to handle null xattr name");
1522   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1523     strerror(errno), errno);
1524 
1525   name = "foo.bar";
1526 
1527   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1528   res = pr_fsio_lgetxattr(p, path, name, NULL, 0);
1529   fail_unless(res < 0, "Failed to handle disabled xattr");
1530   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1531     strerror(errno), errno);
1532 
1533   pr_fsio_set_options(fsio_opts);
1534   res = pr_fsio_lgetxattr(p, path, name, NULL, 0);
1535 #ifdef PR_USE_XATTR
1536   fail_unless(res < 0, "Failed to handle nonexist attribute '%s'", name);
1537   fail_unless(errno == ENOENT || errno == ENOATTR || errno == ENOTSUP,
1538     "Expected ENOENT (%d), ENOATTR (%d) or ENOTSUP (%d), got %s (%d)",
1539     ENOENT, ENOATTR, ENOTSUP, strerror(errno), errno);
1540 
1541 #else
1542   fail_unless(res < 0, "Failed to handle --disable-xattr");
1543   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1544     strerror(errno), errno);
1545 #endif /* PR_USE_XATTR */
1546 }
1547 END_TEST
1548 
START_TEST(fsio_sys_fgetxattr_test)1549 START_TEST (fsio_sys_fgetxattr_test) {
1550   ssize_t res;
1551   pr_fh_t *fh;
1552   const char *name;
1553   unsigned long fsio_opts;
1554 
1555   res = pr_fsio_fgetxattr(NULL, NULL, NULL, NULL, 0);
1556   fail_unless(res < 0, "Failed to handle null arguments");
1557   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1558     strerror(errno), errno);
1559 
1560   res = pr_fsio_fgetxattr(p, NULL, NULL, NULL, 0);
1561   fail_unless(res < 0, "Failed to handle null file handle");
1562   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1563     strerror(errno), errno);
1564 
1565   (void) unlink(fsio_test_path);
1566   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_RDWR);
1567   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
1568     strerror(errno));
1569 
1570   res = pr_fsio_fgetxattr(p, fh, NULL, NULL, 0);
1571   fail_unless(res < 0, "Failed to handle null xattr name");
1572   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1573     strerror(errno), errno);
1574 
1575   name = "foo.bar";
1576 
1577   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1578   res = pr_fsio_fgetxattr(p, fh, name, NULL, 0);
1579   fail_unless(res < 0, "Failed to handle disabled xattr");
1580   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1581     strerror(errno), errno);
1582 
1583   pr_fsio_set_options(fsio_opts);
1584   res = pr_fsio_fgetxattr(p, fh, name, NULL, 0);
1585 #ifdef PR_USE_XATTR
1586   fail_unless(res < 0, "Failed to handle nonexist attribute '%s'", name);
1587   fail_unless(errno == ENOENT || errno == ENOATTR || errno == ENOTSUP,
1588     "Expected ENOENT (%d), ENOATTR (%d) or ENOTSUP (%d), got %s (%d)",
1589     ENOENT, ENOATTR, ENOTSUP, strerror(errno), errno);
1590 
1591 #else
1592   fail_unless(res < 0, "Failed to handle --disable-xattr");
1593   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1594     strerror(errno), errno);
1595 #endif /* PR_USE_XATTR */
1596 
1597   pr_fsio_close(fh);
1598   (void) unlink(fsio_test_path);
1599 }
1600 END_TEST
1601 
START_TEST(fsio_sys_listxattr_test)1602 START_TEST (fsio_sys_listxattr_test) {
1603   int res;
1604   const char *path;
1605   pr_fh_t *fh = NULL;
1606   array_header *names = NULL;
1607   unsigned long fsio_opts;
1608 
1609   res = pr_fsio_listxattr(NULL, NULL, NULL);
1610   fail_unless(res < 0, "Failed to handle null arguments");
1611   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1612     strerror(errno), errno);
1613 
1614   res = pr_fsio_listxattr(p, NULL, NULL);
1615   fail_unless(res < 0, "Failed to handle null path");
1616   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1617     strerror(errno), errno);
1618 
1619   path = fsio_test_path;
1620   res = pr_fsio_listxattr(p, path, NULL);
1621   fail_unless(res < 0, "Failed to handle null array");
1622   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1623     strerror(errno), errno);
1624 
1625   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1626   res = pr_fsio_listxattr(p, path, &names);
1627   fail_unless(res < 0, "Failed to handle disabled xattr");
1628   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1629     strerror(errno), errno);
1630 
1631   pr_fsio_set_options(fsio_opts);
1632   res = pr_fsio_listxattr(p, path, &names);
1633 #ifdef PR_USE_XATTR
1634   fail_unless(res < 0, "Failed to handle nonexistent path '%s'", path);
1635   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1636     strerror(errno), errno);
1637 
1638   (void) unlink(fsio_test_path);
1639   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1640   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
1641     strerror(errno));
1642   pr_fsio_close(fh);
1643 
1644   res = pr_fsio_listxattr(p, path, &names);
1645   fail_if(res < 0, "Failed to list xattrs for '%s': %s", path, strerror(errno));
1646 
1647   (void) unlink(fsio_test_path);
1648 #else
1649   (void) fh;
1650   fail_unless(res < 0, "Failed to handle --disable-xattr");
1651   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1652     strerror(errno), errno);
1653 #endif /* PR_USE_XATTR */
1654 }
1655 END_TEST
1656 
START_TEST(fsio_sys_llistxattr_test)1657 START_TEST (fsio_sys_llistxattr_test) {
1658   int res;
1659   const char *path;
1660   pr_fh_t *fh = NULL;
1661   array_header *names = NULL;
1662   unsigned long fsio_opts;
1663 
1664   res = pr_fsio_llistxattr(NULL, NULL, NULL);
1665   fail_unless(res < 0, "Failed to handle null arguments");
1666   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1667     strerror(errno), errno);
1668 
1669   res = pr_fsio_llistxattr(p, NULL, NULL);
1670   fail_unless(res < 0, "Failed to handle null path");
1671   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1672     strerror(errno), errno);
1673 
1674   path = fsio_test_path;
1675   res = pr_fsio_llistxattr(p, path, NULL);
1676   fail_unless(res < 0, "Failed to handle null array");
1677   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1678     strerror(errno), errno);
1679 
1680   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1681   res = pr_fsio_llistxattr(p, path, &names);
1682   fail_unless(res < 0, "Failed to handle disabled xattr");
1683   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1684     strerror(errno), errno);
1685 
1686   pr_fsio_set_options(fsio_opts);
1687   res = pr_fsio_llistxattr(p, path, &names);
1688 #ifdef PR_USE_XATTR
1689   fail_unless(res < 0, "Failed to handle nonexistent path '%s'", path);
1690   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1691     strerror(errno), errno);
1692 
1693   (void) unlink(fsio_test_path);
1694   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1695   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
1696     strerror(errno));
1697   pr_fsio_close(fh);
1698 
1699   res = pr_fsio_listxattr(p, path, &names);
1700   fail_if(res < 0, "Failed to list xattrs for '%s': %s", path, strerror(errno));
1701 
1702   (void) unlink(fsio_test_path);
1703 #else
1704   (void) fh;
1705   fail_unless(res < 0, "Failed to handle --disable-xattr");
1706   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1707     strerror(errno), errno);
1708 #endif /* PR_USE_XATTR */
1709 }
1710 END_TEST
1711 
START_TEST(fsio_sys_flistxattr_test)1712 START_TEST (fsio_sys_flistxattr_test) {
1713   int res;
1714   pr_fh_t *fh;
1715   array_header *names = NULL;
1716   unsigned long fsio_opts;
1717 
1718   res = pr_fsio_flistxattr(NULL, NULL, NULL);
1719   fail_unless(res < 0, "Failed to handle null arguments");
1720   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1721     strerror(errno), errno);
1722 
1723   res = pr_fsio_flistxattr(p, NULL, NULL);
1724   fail_unless(res < 0, "Failed to handle null file handle");
1725   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1726     strerror(errno), errno);
1727 
1728   (void) unlink(fsio_test_path);
1729   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_RDWR);
1730   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
1731     strerror(errno));
1732 
1733   res = pr_fsio_flistxattr(p, fh, NULL);
1734   fail_unless(res < 0, "Failed to handle null array");
1735   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1736     strerror(errno), errno);
1737 
1738   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1739   res = pr_fsio_flistxattr(p, fh, &names);
1740   fail_unless(res < 0, "Failed to handle disabled xattr");
1741   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1742     strerror(errno), errno);
1743 
1744   pr_fsio_set_options(fsio_opts);
1745   res = pr_fsio_flistxattr(p, fh, &names);
1746 #ifdef PR_USE_XATTR
1747   fail_if(res < 0, "Failed to list xattrs for '%s': %s", fsio_test_path,
1748     strerror(errno));
1749 
1750 #else
1751   fail_unless(res < 0, "Failed to handle --disable-xattr");
1752   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1753     strerror(errno), errno);
1754 #endif /* PR_USE_XATTR */
1755 
1756   pr_fsio_close(fh);
1757   (void) unlink(fsio_test_path);
1758 }
1759 END_TEST
1760 
START_TEST(fsio_sys_removexattr_test)1761 START_TEST (fsio_sys_removexattr_test) {
1762   int res;
1763   const char *path, *name;
1764   unsigned long fsio_opts;
1765 
1766   res = pr_fsio_removexattr(NULL, NULL, NULL);
1767   fail_unless(res < 0, "Failed to handle null arguments");
1768   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1769     strerror(errno), errno);
1770 
1771   res = pr_fsio_removexattr(p, NULL, NULL);
1772   fail_unless(res < 0, "Failed to handle null path");
1773   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1774     strerror(errno), errno);
1775 
1776   path = fsio_test_path;
1777   res = pr_fsio_removexattr(p, path, NULL);
1778   fail_unless(res < 0, "Failed to handle null attribute name");
1779   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1780     strerror(errno), errno);
1781 
1782   name = "foo.bar";
1783 
1784   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1785   res = pr_fsio_removexattr(p, path, name);
1786   fail_unless(res < 0, "Failed to handle disabled xattr");
1787   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1788     strerror(errno), errno);
1789 
1790   pr_fsio_set_options(fsio_opts);
1791   res = pr_fsio_removexattr(p, path, name);
1792 #ifdef PR_USE_XATTR
1793   fail_unless(res < 0, "Failed to handle nonexistent attribute '%s'", name);
1794   fail_unless(errno == ENOENT || errno == ENOATTR || errno == ENOTSUP,
1795     "Expected ENOENT (%d), ENOATTR (%d) or ENOTSUP (%d), got %s (%d)",
1796     ENOENT, ENOATTR, ENOTSUP, strerror(errno), errno);
1797 
1798 #else
1799   fail_unless(res < 0, "Failed to handle --disable-xattr");
1800   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1801     strerror(errno), errno);
1802 #endif /* PR_USE_XATTR */
1803 }
1804 END_TEST
1805 
START_TEST(fsio_sys_lremovexattr_test)1806 START_TEST (fsio_sys_lremovexattr_test) {
1807   int res;
1808   const char *path, *name;
1809   unsigned long fsio_opts;
1810 
1811   res = pr_fsio_lremovexattr(NULL, NULL, NULL);
1812   fail_unless(res < 0, "Failed to handle null arguments");
1813   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1814     strerror(errno), errno);
1815 
1816   res = pr_fsio_lremovexattr(p, NULL, NULL);
1817   fail_unless(res < 0, "Failed to handle null path");
1818   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1819     strerror(errno), errno);
1820 
1821   path = fsio_test_path;
1822   res = pr_fsio_lremovexattr(p, path, NULL);
1823   fail_unless(res < 0, "Failed to handle null attribute name");
1824   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1825     strerror(errno), errno);
1826 
1827   name = "foo.bar";
1828 
1829   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1830   res = pr_fsio_lremovexattr(p, path, name);
1831   fail_unless(res < 0, "Failed to handle disabled xattr");
1832   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1833     strerror(errno), errno);
1834 
1835   pr_fsio_set_options(fsio_opts);
1836   res = pr_fsio_lremovexattr(p, path, name);
1837 #ifdef PR_USE_XATTR
1838   fail_unless(res < 0, "Failed to handle nonexistent attribute '%s'", name);
1839   fail_unless(errno == ENOENT || errno == ENOATTR || errno == ENOTSUP,
1840     "Expected ENOENT (%d), ENOATTR (%d) or ENOTSUP (%d), got %s (%d)",
1841     ENOENT, ENOATTR, ENOTSUP, strerror(errno), errno);
1842 
1843 #else
1844   fail_unless(res < 0, "Failed to handle --disable-xattr");
1845   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1846     strerror(errno), errno);
1847 #endif /* PR_USE_XATTR */
1848 }
1849 END_TEST
1850 
START_TEST(fsio_sys_fremovexattr_test)1851 START_TEST (fsio_sys_fremovexattr_test) {
1852   int res;
1853   pr_fh_t *fh;
1854   const char *name;
1855   unsigned long fsio_opts;
1856 
1857   res = pr_fsio_fremovexattr(NULL, NULL, NULL);
1858   fail_unless(res < 0, "Failed to handle null arguments");
1859   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1860     strerror(errno), errno);
1861 
1862   res = pr_fsio_fremovexattr(p, NULL, NULL);
1863   fail_unless(res < 0, "Failed to handle null arguments");
1864   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1865     strerror(errno), errno);
1866 
1867   (void) unlink(fsio_test_path);
1868   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_RDWR);
1869   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
1870     strerror(errno));
1871 
1872   res = pr_fsio_fremovexattr(p, fh, NULL);
1873   fail_unless(res < 0, "Failed to handle null attribute name");
1874   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1875     strerror(errno), errno);
1876 
1877   name = "foo.bar";
1878 
1879   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1880   res = pr_fsio_fremovexattr(p, fh, name);
1881   fail_unless(res < 0, "Failed to handle disabled xattr");
1882   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1883     strerror(errno), errno);
1884 
1885   pr_fsio_set_options(fsio_opts);
1886   res = pr_fsio_fremovexattr(p, fh, name);
1887 #ifdef PR_USE_XATTR
1888   fail_unless(res < 0, "Failed to handle nonexistent attribute '%s'", name);
1889   fail_unless(errno == ENOENT || errno == ENOATTR || errno == ENOTSUP,
1890     "Expected ENOENT (%d), ENOATTR (%d) or ENOTSUP (%d), got %s (%d)",
1891     ENOENT, ENOATTR, ENOTSUP, strerror(errno), errno);
1892 
1893 #else
1894   fail_unless(res < 0, "Failed to handle --disable-xattr");
1895   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1896     strerror(errno), errno);
1897 #endif /* PR_USE_XATTR */
1898 
1899   pr_fsio_close(fh);
1900   (void) unlink(fsio_test_path);
1901 }
1902 END_TEST
1903 
START_TEST(fsio_sys_setxattr_test)1904 START_TEST (fsio_sys_setxattr_test) {
1905   int res, flags;
1906   const char *path, *name;
1907   pr_fh_t *fh;
1908   unsigned long fsio_opts;
1909 
1910   res = pr_fsio_setxattr(NULL, NULL, NULL, NULL, 0, 0);
1911   fail_unless(res < 0, "Failed to handle null arguments");
1912   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1913     strerror(errno), errno);
1914 
1915   res = pr_fsio_setxattr(p, NULL, NULL, NULL, 0, 0);
1916   fail_unless(res < 0, "Failed to handle null path");
1917   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1918     strerror(errno), errno);
1919 
1920   path = fsio_test_path;
1921   res = pr_fsio_setxattr(p, path, NULL, NULL, 0, 0);
1922   fail_unless(res < 0, "Failed to handle null attribute name");
1923   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1924     strerror(errno), errno);
1925 
1926   name = "foo.bar";
1927   flags = PR_FSIO_XATTR_FL_CREATE;
1928 
1929   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1930   res = pr_fsio_setxattr(p, path, name, NULL, 0, flags);
1931   fail_unless(res < 0, "Failed to handle disabled xattr");
1932   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1933     strerror(errno), errno);
1934 
1935   pr_fsio_set_options(fsio_opts);
1936   res = pr_fsio_setxattr(p, path, name, NULL, 0, flags);
1937 #ifdef PR_USE_XATTR
1938   fail_unless(res < 0, "Failed to handle nonexistent file '%s'", path);
1939   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1940     strerror(errno), errno);
1941 
1942   (void) unlink(fsio_test_path);
1943   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
1944   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
1945     strerror(errno));
1946   pr_fsio_close(fh);
1947 
1948   res = pr_fsio_setxattr(p, path, name, NULL, 0, flags);
1949   if (res < 0) {
1950     fail_unless(errno == ENOTSUP, "Expected ENOTSUP (%d), got %s (%d)", ENOTSUP,
1951       strerror(errno), errno);
1952   }
1953 
1954   (void) unlink(fsio_test_path);
1955 #else
1956   (void) fh;
1957   fail_unless(res < 0, "Failed to handle --disable-xattr");
1958   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1959     strerror(errno), errno);
1960 #endif /* PR_USE_XATTR */
1961 }
1962 END_TEST
1963 
START_TEST(fsio_sys_lsetxattr_test)1964 START_TEST (fsio_sys_lsetxattr_test) {
1965   int res, flags;
1966   const char *path, *name;
1967   pr_fh_t *fh;
1968   unsigned long fsio_opts;
1969 
1970   res = pr_fsio_lsetxattr(NULL, NULL, NULL, NULL, 0, 0);
1971   fail_unless(res < 0, "Failed to handle null arguments");
1972   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1973     strerror(errno), errno);
1974 
1975   res = pr_fsio_lsetxattr(p, NULL, NULL, NULL, 0, 0);
1976   fail_unless(res < 0, "Failed to handle null path");
1977   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1978     strerror(errno), errno);
1979 
1980   path = fsio_test_path;
1981   res = pr_fsio_lsetxattr(p, path, NULL, NULL, 0, 0);
1982   fail_unless(res < 0, "Failed to handle null attribute name");
1983   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1984     strerror(errno), errno);
1985 
1986   name = "foo.bar";
1987   flags = PR_FSIO_XATTR_FL_CREATE;
1988 
1989   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
1990   res = pr_fsio_lsetxattr(p, path, name, NULL, 0, flags);
1991   fail_unless(res < 0, "Failed to handle disabled xattr");
1992   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
1993     strerror(errno), errno);
1994 
1995   pr_fsio_set_options(fsio_opts);
1996   res = pr_fsio_lsetxattr(p, path, name, NULL, 0, flags);
1997 #ifdef PR_USE_XATTR
1998   fail_unless(res < 0, "Failed to handle nonexistent file '%s'", path);
1999   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2000     strerror(errno), errno);
2001 
2002   (void) unlink(fsio_test_path);
2003   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
2004   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
2005     strerror(errno));
2006   pr_fsio_close(fh);
2007 
2008   res = pr_fsio_lsetxattr(p, path, name, NULL, 0, flags);
2009   if (res < 0) {
2010     fail_unless(errno == ENOTSUP, "Expected ENOTSUP (%d), got %s (%d)", ENOTSUP,
2011       strerror(errno), errno);
2012   }
2013 
2014   (void) unlink(fsio_test_path);
2015 #else
2016   (void) fh;
2017   fail_unless(res < 0, "Failed to handle --disable-xattr");
2018   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
2019     strerror(errno), errno);
2020 #endif /* PR_USE_XATTR */
2021 }
2022 END_TEST
2023 
START_TEST(fsio_sys_fsetxattr_test)2024 START_TEST (fsio_sys_fsetxattr_test) {
2025   int res, flags;
2026   pr_fh_t *fh;
2027   const char *name;
2028   unsigned long fsio_opts;
2029 
2030   res = pr_fsio_fsetxattr(NULL, NULL, NULL, NULL, 0, 0);
2031   fail_unless(res < 0, "Failed to handle null arguments");
2032   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2033     strerror(errno), errno);
2034 
2035   res = pr_fsio_fsetxattr(p, NULL, NULL, NULL, 0, 0);
2036   fail_unless(res < 0, "Failed to handle null file handle");
2037   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2038     strerror(errno), errno);
2039 
2040   (void) unlink(fsio_test_path);
2041   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_RDWR);
2042   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
2043     strerror(errno));
2044 
2045   res = pr_fsio_fsetxattr(p, fh, NULL, NULL, 0, 0);
2046   fail_unless(res < 0, "Failed to handle null attribute name");
2047   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2048     strerror(errno), errno);
2049 
2050   name = "foo.bar";
2051   flags = PR_FSIO_XATTR_FL_CREATE;
2052 
2053   fsio_opts = pr_fsio_set_options(PR_FSIO_OPT_IGNORE_XATTR);
2054   res = pr_fsio_fsetxattr(p, fh, name, NULL, 0, flags);
2055   fail_unless(res < 0, "Failed to handle disabled xattr");
2056   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
2057     strerror(errno), errno);
2058 
2059   pr_fsio_set_options(fsio_opts);
2060   res = pr_fsio_fsetxattr(p, fh, name, NULL, 0, flags);
2061 #ifdef PR_USE_XATTR
2062   if (res < 0) {
2063     fail_unless(errno == ENOTSUP, "Expected ENOTSUP (%d), got %s (%d)", ENOTSUP,
2064       strerror(errno), errno);
2065   }
2066 
2067 #else
2068   fail_unless(res < 0, "Failed to handle --disable-xattr");
2069   fail_unless(errno == ENOSYS, "Expected ENOSYS (%d), got %s (%d)", ENOSYS,
2070     strerror(errno), errno);
2071 #endif /* PR_USE_XATTR */
2072 
2073   pr_fsio_close(fh);
2074   (void) unlink(fsio_test_path);
2075 }
2076 END_TEST
2077 
START_TEST(fsio_sys_mkdir_test)2078 START_TEST (fsio_sys_mkdir_test) {
2079   int res;
2080   mode_t mode = 0755;
2081 
2082   res = pr_fsio_mkdir(NULL, mode);
2083   fail_unless(res < 0, "Failed to handle null arguments");
2084   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2085     strerror(errno), errno);
2086 
2087   res = pr_fsio_mkdir(fsio_testdir_path, mode);
2088   fail_unless(res == 0, "Failed to create '%s': %s", fsio_testdir_path,
2089     strerror(errno));
2090 
2091   (void) pr_fsio_rmdir(fsio_testdir_path);
2092 }
2093 END_TEST
2094 
START_TEST(fsio_sys_mkdir_chroot_guard_test)2095 START_TEST (fsio_sys_mkdir_chroot_guard_test) {
2096   int res;
2097   mode_t mode = 0755;
2098 
2099   res = pr_fsio_guard_chroot(TRUE);
2100   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
2101 
2102   res = pr_fsio_mkdir("/etc/foo.bar.baz.d", mode);
2103   fail_unless(res < 0, "Created /etc/foo.bar.baz.d unexpectedly");
2104   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
2105     strerror(errno), errno);
2106 
2107   (void) pr_fsio_guard_chroot(FALSE);
2108 
2109   res = pr_fsio_mkdir("/lib/foo/bar/baz.d", mode);
2110   fail_unless(res < 0, "Created /lib/foo/bar/baz.d unexpectedly");
2111   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
2112     strerror(errno), errno);
2113 }
2114 END_TEST
2115 
START_TEST(fsio_sys_rmdir_test)2116 START_TEST (fsio_sys_rmdir_test) {
2117   int res;
2118   mode_t mode = 0755;
2119 
2120   res = pr_fsio_rmdir(NULL);
2121   fail_unless(res < 0, "Failed to handle null arguments");
2122   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2123     strerror(errno), errno);
2124 
2125   res = pr_fsio_rmdir(fsio_testdir_path);
2126   fail_unless(res < 0, "Failed to handle null arguments");
2127   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2128     strerror(errno), errno);
2129 
2130   res = pr_fsio_mkdir(fsio_testdir_path, mode);
2131   fail_unless(res == 0, "Failed to create '%s': %s", fsio_testdir_path,
2132     strerror(errno));
2133 
2134   res = pr_fsio_rmdir(fsio_testdir_path);
2135   fail_unless(res == 0, "Failed to remove '%s': %s", fsio_testdir_path,
2136     strerror(errno));
2137 }
2138 END_TEST
2139 
START_TEST(fsio_sys_rmdir_chroot_guard_test)2140 START_TEST (fsio_sys_rmdir_chroot_guard_test) {
2141   int res;
2142 
2143   res = pr_fsio_guard_chroot(TRUE);
2144   fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);
2145 
2146   res = pr_fsio_rmdir("/etc/foo.bar.baz.d");
2147   fail_unless(res < 0, "Removed /etc/foo.bar.baz.d unexpectedly");
2148   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s %d", EACCES,
2149     strerror(errno), errno);
2150 
2151   (void) pr_fsio_guard_chroot(FALSE);
2152 
2153   res = pr_fsio_rmdir("/lib/foo/bar/baz.d");
2154   fail_unless(res < 0, "Removed /lib/etc/foo.bar.baz.d unexpectedly");
2155   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s %d", ENOENT,
2156     strerror(errno), errno);
2157 }
2158 END_TEST
2159 
START_TEST(fsio_sys_chdir_test)2160 START_TEST (fsio_sys_chdir_test) {
2161   int res;
2162 
2163   res = pr_fsio_chdir(NULL, FALSE);
2164   fail_unless(res < 0, "Failed to handle null arguments");
2165   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2166     strerror(errno), errno);
2167 
2168   res = pr_fsio_chdir("/etc/hosts", FALSE);
2169   fail_unless(res < 0, "Failed to handle file argument");
2170   fail_unless(errno == EINVAL || errno == ENOTDIR,
2171     "Expected EINVAL (%d) or ENOTDIR (%d), got %s (%d)", EINVAL, ENOTDIR,
2172     strerror(errno), errno);
2173 
2174   res = pr_fsio_chdir("/tmp", FALSE);
2175   fail_unless(res == 0, "Failed to chdir to '%s': %s", fsio_cwd,
2176     strerror(errno));
2177 
2178   res = pr_fsio_chdir(fsio_cwd, FALSE);
2179   fail_unless(res == 0, "Failed to chdir to '%s': %s", fsio_cwd,
2180     strerror(errno));
2181 }
2182 END_TEST
2183 
START_TEST(fsio_sys_chdir_canon_test)2184 START_TEST (fsio_sys_chdir_canon_test) {
2185   int res;
2186 
2187   res = pr_fsio_chdir_canon(NULL, FALSE);
2188   fail_unless(res < 0, "Failed to handle null arguments");
2189   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2190     strerror(errno), errno);
2191 
2192   res = pr_fsio_chdir_canon("/tmp", FALSE);
2193   fail_unless(res == 0, "Failed to chdir to '%s': %s", fsio_cwd,
2194     strerror(errno));
2195 
2196   res = pr_fsio_chdir_canon(fsio_cwd, FALSE);
2197   fail_unless(res == 0, "Failed to chdir to '%s': %s", fsio_cwd,
2198     strerror(errno));
2199 }
2200 END_TEST
2201 
START_TEST(fsio_sys_chroot_test)2202 START_TEST (fsio_sys_chroot_test) {
2203   int res;
2204 
2205   res = pr_fsio_chroot(NULL);
2206   fail_unless(res < 0, "Failed to handle null arguments");
2207   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2208     strerror(errno), errno);
2209 
2210   if (getuid() != 0) {
2211     res = pr_fsio_chroot("/tmp");
2212     fail_unless(res < 0, "Failed to chroot without root privs");
2213     fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
2214       strerror(errno), errno);
2215   }
2216 }
2217 END_TEST
2218 
START_TEST(fsio_sys_opendir_test)2219 START_TEST (fsio_sys_opendir_test) {
2220   void *res = NULL, *res2 = NULL;
2221   const char *path;
2222 
2223   mark_point();
2224   res = pr_fsio_opendir(NULL);
2225   fail_unless(res == NULL, "Failed to handle null arguments");
2226   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2227     strerror(errno), errno);
2228 
2229   mark_point();
2230   path = "/etc/hosts";
2231   res = pr_fsio_opendir(path);
2232   fail_unless(res == NULL, "Failed to handle file argument");
2233   fail_unless(errno == ENOTDIR, "Expected ENOTDIR (%d), got %s (%d)", ENOTDIR,
2234     strerror(errno), errno);
2235 
2236   mark_point();
2237   path = "/tmp/";
2238   res = pr_fsio_opendir(path);
2239   fail_unless(res != NULL, "Failed to open '%s': %s", path, strerror(errno));
2240 
2241   mark_point();
2242   path = "/usr/";
2243   res2 = pr_fsio_opendir(path);
2244   fail_unless(res != NULL, "Failed to open '%s': %s", path, strerror(errno));
2245 
2246   (void) pr_fsio_closedir(res);
2247   (void) pr_fsio_closedir(res2);
2248 }
2249 END_TEST
2250 
START_TEST(fsio_sys_readdir_test)2251 START_TEST (fsio_sys_readdir_test) {
2252   void *dirh;
2253   struct dirent *dent;
2254 
2255   dent = pr_fsio_readdir(NULL);
2256   fail_unless(dent == NULL, "Failed to handle null arguments");
2257   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2258     strerror(errno), errno);
2259 
2260   dent = pr_fsio_readdir("/etc/hosts");
2261   fail_unless(dent == NULL, "Failed to handle file argument");
2262   fail_unless(errno == ENOTDIR, "Expected ENOTDIR (%d), got %s (%d)", ENOTDIR,
2263     strerror(errno), errno);
2264 
2265   mark_point();
2266   dirh = pr_fsio_opendir("/tmp/");
2267   fail_unless(dirh != NULL, "Failed to open '/tmp/': %s", strerror(errno));
2268 
2269   dent = pr_fsio_readdir(dirh);
2270   fail_unless(dent != NULL, "Failed to read directory entry: %s",
2271     strerror(errno));
2272 
2273   (void) pr_fsio_closedir(dirh);
2274 }
2275 END_TEST
2276 
START_TEST(fsio_sys_closedir_test)2277 START_TEST (fsio_sys_closedir_test) {
2278   void *dirh;
2279   int res;
2280 
2281   res = pr_fsio_closedir(NULL);
2282   fail_unless(res < 0, "Failed to handle null arguments");
2283   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2284     strerror(errno), errno);
2285 
2286   dirh = pr_fsio_opendir("/tmp/");
2287   fail_unless(dirh != NULL, "Failed to open '/tmp/': %s", strerror(errno));
2288 
2289   res = pr_fsio_closedir(dirh);
2290   fail_unless(res == 0, "Failed to close '/tmp/': %s", strerror(errno));
2291 
2292   /* Closing an already-closed directory descriptor should fail. */
2293   res = pr_fsio_closedir(dirh);
2294   fail_unless(res < 0, "Failed to handle already-closed directory handle");
2295   fail_unless(errno == ENOTDIR, "Expected ENOTDIR (%d), got %s (%d)", ENOTDIR,
2296     strerror(errno), errno);
2297 }
2298 END_TEST
2299 
test_chmod_explainer(pool * err_pool,int xerrno,const char * path,mode_t mode,const char ** args)2300 static const char *test_chmod_explainer(pool *err_pool, int xerrno,
2301     const char *path, mode_t mode, const char **args) {
2302   *args = pstrdup(err_pool, "fake args");
2303   return pstrdup(err_pool, "test mode is not real");
2304 }
2305 
START_TEST(fsio_sys_chmod_with_error_test)2306 START_TEST (fsio_sys_chmod_with_error_test) {
2307   int res;
2308   pr_error_t *err = NULL;
2309   const char *errstr, *expected;
2310   module m;
2311   pr_error_explainer_t *explainer;
2312 
2313   mark_point();
2314   res = pr_fsio_chmod_with_error(NULL, fsio_test_path, 0755, NULL);
2315   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2316     fsio_test_path);
2317   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2318     strerror(errno), errno);
2319 
2320   mark_point();
2321   res = pr_fsio_chmod_with_error(p, fsio_test_path, 0755, &err);
2322   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2323     fsio_test_path);
2324   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2325     strerror(errno), errno);
2326   fail_unless(err == NULL, "Unexpectedly populated error");
2327 
2328   memset(&m, 0, sizeof(m));
2329   m.name = "error";
2330 
2331   explainer = pr_error_register_explainer(p, &m, "error");
2332   explainer->explain_chmod = test_chmod_explainer;
2333 
2334   mark_point();
2335   res = pr_fsio_chmod_with_error(p, fsio_test_path, 0755, &err);
2336   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2337     fsio_test_path);
2338   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2339     strerror(errno), errno);
2340   fail_unless(err != NULL, "Failed to populate error");
2341 
2342   expected = pstrcat(p,
2343     "chmod() failed with \"No such file or directory [ENOENT (",
2344     get_errnum(p, ENOENT), ")]\"", NULL);
2345   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2346   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2347     expected, errstr);
2348 
2349   (void) pr_error_unregister_explainer(p, &m, NULL);
2350   pr_error_destroy(err);
2351 }
2352 END_TEST
2353 
test_chown_explainer(pool * err_pool,int xerrno,const char * path,uid_t uid,gid_t gid,const char ** args)2354 static const char *test_chown_explainer(pool *err_pool, int xerrno,
2355     const char *path, uid_t uid, gid_t gid, const char **args) {
2356   *args = pstrdup(err_pool, "fake args");
2357   return pstrdup(err_pool, "test mode is not real");
2358 }
2359 
START_TEST(fsio_sys_chown_with_error_test)2360 START_TEST (fsio_sys_chown_with_error_test) {
2361   int res;
2362   pr_error_t *err = NULL;
2363   const char *errstr, *expected;
2364   module m;
2365   pr_error_explainer_t *explainer;
2366 
2367   mark_point();
2368   res = pr_fsio_chown_with_error(NULL, fsio_test_path, 1, 1, NULL);
2369   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2370     fsio_test_path);
2371   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2372     strerror(errno), errno);
2373 
2374   mark_point();
2375   res = pr_fsio_chown_with_error(p, fsio_test_path, 1, 1, &err);
2376   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2377     fsio_test_path);
2378   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2379     strerror(errno), errno);
2380   fail_unless(err == NULL, "Unexpectedly populated error");
2381 
2382   memset(&m, 0, sizeof(m));
2383   m.name = "error";
2384 
2385   explainer = pr_error_register_explainer(p, &m, "error");
2386   explainer->explain_chown = test_chown_explainer;
2387 
2388   mark_point();
2389   res = pr_fsio_chown_with_error(p, fsio_test_path, 1, 1, &err);
2390   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2391     fsio_test_path);
2392   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2393     strerror(errno), errno);
2394   fail_unless(err != NULL, "Failed to populate error");
2395 
2396   expected = pstrcat(p,
2397     "chown() failed with \"No such file or directory [ENOENT (",
2398     get_errnum(p, ENOENT), ")]\"", NULL);
2399   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2400   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2401     expected, errstr);
2402 
2403   (void) pr_error_unregister_explainer(p, &m, NULL);
2404   pr_error_destroy(err);
2405 }
2406 END_TEST
2407 
test_chroot_explainer(pool * err_pool,int xerrno,const char * path,const char ** args)2408 static const char *test_chroot_explainer(pool *err_pool, int xerrno,
2409     const char *path, const char **args) {
2410   *args = pstrdup(err_pool, "fake args");
2411   return pstrdup(err_pool, "test mode is not real");
2412 }
2413 
START_TEST(fsio_sys_chroot_with_error_test)2414 START_TEST (fsio_sys_chroot_with_error_test) {
2415   int res, xerrno = 0;
2416   pr_error_t *err = NULL;
2417   const char *errstr, *expected;
2418   module m;
2419   pr_error_explainer_t *explainer;
2420 
2421   mark_point();
2422   res = pr_fsio_chroot_with_error(NULL, fsio_testdir_path, NULL);
2423   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2424     fsio_testdir_path);
2425   fail_unless(errno == EPERM || errno == ENOENT,
2426     "Expected EPERM (%d) or ENOENT (%d), %s (%d)", EPERM, ENOENT,
2427     strerror(errno), errno);
2428 
2429   mark_point();
2430   res = pr_fsio_chroot_with_error(p, fsio_testdir_path, &err);
2431   xerrno = errno;
2432   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2433     fsio_testdir_path);
2434   fail_unless(errno == EPERM || errno == ENOENT,
2435     "Expected EPERM (%d) or ENOENT (%d), %s (%d)", EPERM, ENOENT,
2436     strerror(errno), errno);
2437   fail_unless(err == NULL, "Unexpectedly populated error");
2438 
2439   memset(&m, 0, sizeof(m));
2440   m.name = "error";
2441 
2442   explainer = pr_error_register_explainer(p, &m, "error");
2443   explainer->explain_chroot = test_chroot_explainer;
2444 
2445   mark_point();
2446   res = pr_fsio_chroot_with_error(p, fsio_testdir_path, &err);
2447   xerrno = errno;
2448   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2449     fsio_testdir_path);
2450   fail_unless(errno == EPERM || errno == ENOENT,
2451     "Expected EPERM (%d) or ENOENT (%d), %s (%d)", EPERM, ENOENT,
2452     strerror(errno), errno);
2453   fail_unless(err != NULL, "Failed to populate error");
2454 
2455   expected = pstrcat(p,
2456     "chroot() failed with \"", strerror(xerrno), " [",
2457     xerrno == ENOENT ? "ENOENT" : "EPERM", " (",
2458     get_errnum(p, xerrno), ")]\"", NULL);
2459   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2460   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2461     expected, errstr);
2462 
2463   (void) pr_error_unregister_explainer(p, &m, NULL);
2464   pr_error_destroy(err);
2465 }
2466 END_TEST
2467 
test_close_explainer(pool * err_pool,int xerrno,int fd,const char ** args)2468 static const char *test_close_explainer(pool *err_pool, int xerrno, int fd,
2469     const char **args) {
2470   *args = pstrdup(err_pool, "fake args");
2471   return pstrdup(err_pool, "test mode is not real");
2472 }
2473 
START_TEST(fsio_sys_close_with_error_test)2474 START_TEST (fsio_sys_close_with_error_test) {
2475   int res;
2476   pr_error_t *err = NULL;
2477   const char *errstr, *expected;
2478   module m;
2479   pr_error_explainer_t *explainer;
2480 
2481   mark_point();
2482   res = pr_fsio_close_with_error(NULL, NULL, NULL);
2483   fail_unless(res < 0, "Failed to handle null fh");
2484   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2485     strerror(errno), errno);
2486 
2487   mark_point();
2488   res = pr_fsio_close_with_error(p, NULL, &err);
2489   fail_unless(res < 0, "Failed to handle null fh");
2490   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2491     strerror(errno), errno);
2492   fail_unless(err == NULL, "Unexpectedly populated error");
2493 
2494   memset(&m, 0, sizeof(m));
2495   m.name = "error";
2496 
2497   explainer = pr_error_register_explainer(p, &m, "error");
2498   explainer->explain_close = test_close_explainer;
2499 
2500   mark_point();
2501   res = pr_fsio_close_with_error(p, NULL, &err);
2502   fail_unless(res < 0, "Failed to handle null fh");
2503   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2504     strerror(errno), errno);
2505   fail_unless(err != NULL, "Failed to populate error");
2506 
2507   expected = pstrcat(p,
2508     "close() failed with \"Invalid argument [EINVAL (",
2509     get_errnum(p, EINVAL), ")]\"", NULL);
2510   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2511   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2512     expected, errstr);
2513 
2514   (void) pr_error_unregister_explainer(p, &m, NULL);
2515   pr_error_destroy(err);
2516 }
2517 END_TEST
2518 
test_fchmod_explainer(pool * err_pool,int xerrno,int fd,mode_t mode,const char ** args)2519 static const char *test_fchmod_explainer(pool *err_pool, int xerrno, int fd,
2520     mode_t mode, const char **args) {
2521   *args = pstrdup(err_pool, "fake args");
2522   return pstrdup(err_pool, "test mode is not real");
2523 }
2524 
START_TEST(fsio_sys_fchmod_with_error_test)2525 START_TEST (fsio_sys_fchmod_with_error_test) {
2526   int res;
2527   pr_error_t *err = NULL;
2528   const char *errstr, *expected;
2529   module m;
2530   pr_error_explainer_t *explainer;
2531 
2532   mark_point();
2533   res = pr_fsio_fchmod_with_error(NULL, NULL, 0755, NULL);
2534   fail_unless(res < 0, "Failed to handle null fh");
2535   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2536     strerror(errno), errno);
2537 
2538   mark_point();
2539   res = pr_fsio_fchmod_with_error(p, NULL, 0755, &err);
2540   fail_unless(res < 0, "Failed to handle null fh");
2541   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2542     strerror(errno), errno);
2543   fail_unless(err == NULL, "Unexpectedly populated error");
2544 
2545   memset(&m, 0, sizeof(m));
2546   m.name = "error";
2547 
2548   explainer = pr_error_register_explainer(p, &m, "error");
2549   explainer->explain_fchmod = test_fchmod_explainer;
2550 
2551   mark_point();
2552   res = pr_fsio_fchmod_with_error(p, NULL, 0755, &err);
2553   fail_unless(res < 0, "Failed to handle null fh");
2554   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2555     strerror(errno), errno);
2556   fail_unless(err != NULL, "Failed to populate error");
2557 
2558   expected = pstrcat(p,
2559     "fchmod() failed with \"Invalid argument [EINVAL (",
2560     get_errnum(p, EINVAL), ")]\"", NULL);
2561   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2562   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2563     expected, errstr);
2564 
2565   (void) pr_error_unregister_explainer(p, &m, NULL);
2566   pr_error_destroy(err);
2567 }
2568 END_TEST
2569 
test_fchown_explainer(pool * err_pool,int xerrno,int fd,uid_t uid,gid_t gid,const char ** args)2570 static const char *test_fchown_explainer(pool *err_pool, int xerrno, int fd,
2571     uid_t uid, gid_t gid, const char **args) {
2572   *args = pstrdup(err_pool, "fake args");
2573   return pstrdup(err_pool, "test mode is not real");
2574 }
2575 
START_TEST(fsio_sys_fchown_with_error_test)2576 START_TEST (fsio_sys_fchown_with_error_test) {
2577   int res;
2578   pr_error_t *err = NULL;
2579   const char *errstr, *expected;
2580   module m;
2581   pr_error_explainer_t *explainer;
2582 
2583   mark_point();
2584   res = pr_fsio_fchown_with_error(NULL, NULL, 1, 1, NULL);
2585   fail_unless(res < 0, "Failed to handle null fh");
2586   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2587     strerror(errno), errno);
2588 
2589   mark_point();
2590   res = pr_fsio_fchown_with_error(p, NULL, 1, 1, &err);
2591   fail_unless(res < 0, "Failed to handle null fh");
2592   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2593     strerror(errno), errno);
2594   fail_unless(err == NULL, "Unexpectedly populated error");
2595 
2596   memset(&m, 0, sizeof(m));
2597   m.name = "error";
2598 
2599   explainer = pr_error_register_explainer(p, &m, "error");
2600   explainer->explain_fchown = test_fchown_explainer;
2601 
2602   mark_point();
2603   res = pr_fsio_fchown_with_error(p, NULL, 1, 1, &err);
2604   fail_unless(res < 0, "Failed to handle null fh");
2605   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2606     strerror(errno), errno);
2607   fail_unless(err != NULL, "Failed to populate error");
2608 
2609   expected = pstrcat(p,
2610     "fchown() failed with \"Invalid argument [EINVAL (",
2611     get_errnum(p, EINVAL), ")]\"", NULL);
2612   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2613   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2614     expected, errstr);
2615 
2616   (void) pr_error_unregister_explainer(p, &m, NULL);
2617   pr_error_destroy(err);
2618 }
2619 END_TEST
2620 
test_lchown_explainer(pool * err_pool,int xerrno,const char * path,uid_t uid,gid_t gid,const char ** args)2621 static const char *test_lchown_explainer(pool *err_pool, int xerrno,
2622     const char *path, uid_t uid, gid_t gid, const char **args) {
2623   *args = pstrdup(err_pool, "fake args");
2624   return pstrdup(err_pool, "test mode is not real");
2625 }
2626 
START_TEST(fsio_sys_lchown_with_error_test)2627 START_TEST (fsio_sys_lchown_with_error_test) {
2628   int res;
2629   pr_error_t *err = NULL;
2630   const char *errstr, *expected;
2631   module m;
2632   pr_error_explainer_t *explainer;
2633 
2634   mark_point();
2635   res = pr_fsio_lchown_with_error(NULL, fsio_test_path, 1, 1, NULL);
2636   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2637     fsio_test_path);
2638   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2639     strerror(errno), errno);
2640 
2641   mark_point();
2642   res = pr_fsio_lchown_with_error(p, fsio_test_path, 1, 1, &err);
2643   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2644     fsio_test_path);
2645   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2646     strerror(errno), errno);
2647   fail_unless(err == NULL, "Unexpectedly populated error");
2648 
2649   memset(&m, 0, sizeof(m));
2650   m.name = "error";
2651 
2652   explainer = pr_error_register_explainer(p, &m, "error");
2653   explainer->explain_lchown = test_lchown_explainer;
2654 
2655   mark_point();
2656   res = pr_fsio_lchown_with_error(p, fsio_test_path, 1, 1, &err);
2657   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2658     fsio_test_path);
2659   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2660     strerror(errno), errno);
2661   fail_unless(err != NULL, "Failed to populate error");
2662 
2663   expected = pstrcat(p,
2664     "lchown() failed with \"No such file or directory [ENOENT (",
2665     get_errnum(p, ENOENT), ")]\"", NULL);
2666   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2667   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2668     expected, errstr);
2669 
2670   (void) pr_error_unregister_explainer(p, &m, NULL);
2671   pr_error_destroy(err);
2672 }
2673 END_TEST
2674 
test_lstat_explainer(pool * err_pool,int xerrno,const char * path,struct stat * st,const char ** args)2675 static const char *test_lstat_explainer(pool *err_pool, int xerrno,
2676     const char *path, struct stat *st, const char **args) {
2677   *args = pstrdup(err_pool, "fake args");
2678   return pstrdup(err_pool, "test mode is not real");
2679 }
2680 
START_TEST(fsio_sys_lstat_with_error_test)2681 START_TEST (fsio_sys_lstat_with_error_test) {
2682   int res;
2683   struct stat st;
2684   pr_error_t *err = NULL;
2685   const char *errstr, *expected;
2686   module m;
2687   pr_error_explainer_t *explainer;
2688 
2689   mark_point();
2690   res = pr_fsio_lstat_with_error(NULL, fsio_test_path, &st, NULL);
2691   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2692     fsio_test_path);
2693   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2694     strerror(errno), errno);
2695 
2696   mark_point();
2697   res = pr_fsio_lstat_with_error(p, fsio_test_path, &st, &err);
2698   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2699     fsio_test_path);
2700   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2701     strerror(errno), errno);
2702   fail_unless(err == NULL, "Unexpectedly populated error");
2703 
2704   memset(&m, 0, sizeof(m));
2705   m.name = "error";
2706 
2707   explainer = pr_error_register_explainer(p, &m, "error");
2708   explainer->explain_lstat = test_lstat_explainer;
2709 
2710   mark_point();
2711   res = pr_fsio_lstat_with_error(p, fsio_test_path, &st, &err);
2712   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2713     fsio_test_path);
2714   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2715     strerror(errno), errno);
2716   fail_unless(err != NULL, "Failed to populate error");
2717 
2718   expected = pstrcat(p,
2719     "lstat() failed with \"No such file or directory [ENOENT (",
2720     get_errnum(p, ENOENT), ")]\"", NULL);
2721   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2722   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2723     expected, errstr);
2724 
2725   (void) pr_error_unregister_explainer(p, &m, NULL);
2726   pr_error_destroy(err);
2727 }
2728 END_TEST
2729 
test_mkdir_explainer(pool * err_pool,int xerrno,const char * path,mode_t mode,const char ** args)2730 static const char *test_mkdir_explainer(pool *err_pool, int xerrno,
2731     const char *path, mode_t mode, const char **args) {
2732   *args = pstrdup(err_pool, "fake args");
2733   return pstrdup(err_pool, "test mode is not real");
2734 }
2735 
START_TEST(fsio_sys_mkdir_with_error_test)2736 START_TEST (fsio_sys_mkdir_with_error_test) {
2737   int res;
2738   pr_error_t *err = NULL;
2739   const char *errstr, *expected, *path;
2740   module m;
2741   pr_error_explainer_t *explainer;
2742 
2743   path = "/tmp/foo/bar/baz/quxx/quzz.d";
2744 
2745   mark_point();
2746   res = pr_fsio_mkdir_with_error(NULL, path, 0755, NULL);
2747   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2748     fsio_testdir_path);
2749   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2750     strerror(errno), errno);
2751 
2752   mark_point();
2753   res = pr_fsio_mkdir_with_error(p, path, 0755, &err);
2754   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2755     fsio_testdir_path);
2756   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2757     strerror(errno), errno);
2758   fail_unless(err == NULL, "Unexpectedly populated error");
2759 
2760   memset(&m, 0, sizeof(m));
2761   m.name = "error";
2762 
2763   explainer = pr_error_register_explainer(p, &m, "error");
2764   explainer->explain_mkdir = test_mkdir_explainer;
2765 
2766   mark_point();
2767   res = pr_fsio_mkdir_with_error(p, path, 0755, &err);
2768   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2769     fsio_testdir_path);
2770   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2771     strerror(errno), errno);
2772   fail_unless(err != NULL, "Failed to populate error");
2773 
2774   expected = pstrcat(p,
2775     "mkdir() failed with \"No such file or directory [ENOENT (",
2776     get_errnum(p, ENOENT), ")]\"", NULL);
2777   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2778   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2779     expected, errstr);
2780 
2781   (void) pr_error_unregister_explainer(p, &m, NULL);
2782   pr_error_destroy(err);
2783 }
2784 END_TEST
2785 
test_open_explainer(pool * err_pool,int xerrno,const char * path,int flags,mode_t mode,const char ** args)2786 static const char *test_open_explainer(pool *err_pool, int xerrno,
2787     const char *path, int flags, mode_t mode, const char **args) {
2788   *args = pstrdup(err_pool, "fake args");
2789   return pstrdup(err_pool, "test mode is not real");
2790 }
2791 
START_TEST(fsio_sys_open_with_error_test)2792 START_TEST (fsio_sys_open_with_error_test) {
2793   pr_fh_t *fh;
2794   pr_error_t *err = NULL;
2795   const char *errstr, *expected;
2796   module m;
2797   pr_error_explainer_t *explainer;
2798 
2799   mark_point();
2800   fh = pr_fsio_open_with_error(NULL, fsio_test_path, O_RDONLY, NULL);
2801   fail_unless(fh == NULL, "Failed to handle non-existent file '%s'",
2802     fsio_test_path);
2803   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2804     strerror(errno), errno);
2805 
2806   mark_point();
2807   fh = pr_fsio_open_with_error(p, fsio_test_path, O_RDONLY, &err);
2808   fail_unless(fh == NULL, "Failed to handle non-existent file '%s'",
2809     fsio_test_path);
2810   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2811     strerror(errno), errno);
2812   fail_unless(err == NULL, "Unexpectedly populated error");
2813 
2814   memset(&m, 0, sizeof(m));
2815   m.name = "error";
2816 
2817   explainer = pr_error_register_explainer(p, &m, "error");
2818   explainer->explain_open = test_open_explainer;
2819 
2820   mark_point();
2821   fh = pr_fsio_open_with_error(p, fsio_test_path, O_RDONLY, &err);
2822   fail_unless(fh == NULL, "Failed to handle non-existent file '%s'",
2823     fsio_test_path);
2824   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2825     strerror(errno), errno);
2826   fail_unless(err != NULL, "Failed to populate error");
2827 
2828   expected = pstrcat(p,
2829     "open() failed with \"No such file or directory [ENOENT (",
2830     get_errnum(p, ENOENT), ")]\"", NULL);
2831   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2832   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2833     expected, errstr);
2834 
2835   (void) pr_error_unregister_explainer(p, &m, NULL);
2836   pr_error_destroy(err);
2837 }
2838 END_TEST
2839 
test_read_explainer(pool * err_pool,int xerrno,int fd,void * buf,size_t sz,const char ** args)2840 static const char *test_read_explainer(pool *err_pool, int xerrno, int fd,
2841     void *buf, size_t sz, const char **args) {
2842   *args = pstrdup(err_pool, "fake args");
2843   return pstrdup(err_pool, "test mode is not real");
2844 }
2845 
START_TEST(fsio_sys_read_with_error_test)2846 START_TEST (fsio_sys_read_with_error_test) {
2847   int res;
2848   pr_error_t *err = NULL;
2849   const char *errstr, *expected;
2850   module m;
2851   pr_error_explainer_t *explainer;
2852 
2853   mark_point();
2854   res = pr_fsio_read_with_error(NULL, NULL, NULL, 0, NULL);
2855   fail_unless(res < 0, "Failed to handle null fh");
2856   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2857     strerror(errno), errno);
2858 
2859   mark_point();
2860   res = pr_fsio_read_with_error(p, NULL, NULL, 0, &err);
2861   fail_unless(res < 0, "Failed to handle null fh");
2862   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2863     strerror(errno), errno);
2864   fail_unless(err == NULL, "Unexpectedly populated error");
2865 
2866   memset(&m, 0, sizeof(m));
2867   m.name = "error";
2868 
2869   explainer = pr_error_register_explainer(p, &m, "error");
2870   explainer->explain_read = test_read_explainer;
2871 
2872   mark_point();
2873   res = pr_fsio_read_with_error(p, NULL, NULL, 0, &err);
2874   fail_unless(res < 0, "Failed to handle null fh");
2875   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
2876     strerror(errno), errno);
2877   fail_unless(err != NULL, "Failed to populate error");
2878 
2879   expected = pstrcat(p,
2880     "read() failed with \"Invalid argument [EINVAL (",
2881     get_errnum(p, EINVAL), ")]\"", NULL);
2882   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2883   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2884     expected, errstr);
2885 
2886   (void) pr_error_unregister_explainer(p, &m, NULL);
2887   pr_error_destroy(err);
2888 }
2889 END_TEST
2890 
test_rename_explainer(pool * err_pool,int xerrno,const char * from,const char * to,const char ** args)2891 static const char *test_rename_explainer(pool *err_pool, int xerrno,
2892     const char *from, const char *to, const char **args) {
2893   *args = pstrdup(err_pool, "fake args");
2894   return pstrdup(err_pool, "test mode is not real");
2895 }
2896 
START_TEST(fsio_sys_rename_with_error_test)2897 START_TEST (fsio_sys_rename_with_error_test) {
2898   int res;
2899   pr_error_t *err = NULL;
2900   const char *errstr, *expected;
2901   module m;
2902   pr_error_explainer_t *explainer;
2903 
2904   mark_point();
2905   res = pr_fsio_rename_with_error(NULL, fsio_test_path, fsio_test2_path, NULL);
2906   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2907     fsio_test_path);
2908   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2909     strerror(errno), errno);
2910 
2911   mark_point();
2912   res = pr_fsio_rename_with_error(p, fsio_test_path, fsio_test2_path, &err);
2913   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2914     fsio_test_path);
2915   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2916     strerror(errno), errno);
2917   fail_unless(err == NULL, "Unexpectedly populated error");
2918 
2919   memset(&m, 0, sizeof(m));
2920   m.name = "error";
2921 
2922   explainer = pr_error_register_explainer(p, &m, "error");
2923   explainer->explain_rename = test_rename_explainer;
2924 
2925   mark_point();
2926   res = pr_fsio_rename_with_error(p, fsio_test_path, fsio_test2_path, &err);
2927   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2928     fsio_test_path);
2929   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2930     strerror(errno), errno);
2931   fail_unless(err != NULL, "Failed to populate error");
2932 
2933   expected = pstrcat(p,
2934     "rename() failed with \"No such file or directory [ENOENT (",
2935     get_errnum(p, ENOENT), ")]\"", NULL);
2936   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2937   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2938     expected, errstr);
2939 
2940   (void) pr_error_unregister_explainer(p, &m, NULL);
2941   pr_error_destroy(err);
2942 }
2943 END_TEST
2944 
test_rmdir_explainer(pool * err_pool,int xerrno,const char * path,const char ** args)2945 static const char *test_rmdir_explainer(pool *err_pool, int xerrno,
2946     const char *path, const char **args) {
2947   *args = pstrdup(err_pool, "fake args");
2948   return pstrdup(err_pool, "test mode is not real");
2949 }
2950 
START_TEST(fsio_sys_rmdir_with_error_test)2951 START_TEST (fsio_sys_rmdir_with_error_test) {
2952   int res;
2953   pr_error_t *err = NULL;
2954   const char *errstr, *expected;
2955   module m;
2956   pr_error_explainer_t *explainer;
2957 
2958   mark_point();
2959   res = pr_fsio_rmdir_with_error(NULL, fsio_testdir_path, NULL);
2960   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2961     fsio_testdir_path);
2962   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2963     strerror(errno), errno);
2964   fail_unless(err == NULL, "Unexpectedly populated error");
2965 
2966   memset(&m, 0, sizeof(m));
2967   m.name = "error";
2968 
2969   explainer = pr_error_register_explainer(p, &m, "error");
2970   explainer->explain_rmdir = test_rmdir_explainer;
2971 
2972   mark_point();
2973   res = pr_fsio_rmdir_with_error(p, fsio_testdir_path, &err);
2974   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
2975     fsio_testdir_path);
2976   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
2977     strerror(errno), errno);
2978   fail_unless(err != NULL, "Failed to populate error");
2979 
2980   expected = pstrcat(p,
2981     "rmdir() failed with \"No such file or directory [ENOENT (",
2982     get_errnum(p, ENOENT), ")]\"", NULL);
2983   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
2984   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
2985     expected, errstr);
2986 
2987   (void) pr_error_unregister_explainer(p, &m, NULL);
2988   pr_error_destroy(err);
2989 }
2990 END_TEST
2991 
test_stat_explainer(pool * err_pool,int xerrno,const char * path,struct stat * st,const char ** args)2992 static const char *test_stat_explainer(pool *err_pool, int xerrno,
2993     const char *path, struct stat *st, const char **args) {
2994   *args = pstrdup(err_pool, "fake args");
2995   return pstrdup(err_pool, "test mode is not real");
2996 }
2997 
START_TEST(fsio_sys_stat_with_error_test)2998 START_TEST (fsio_sys_stat_with_error_test) {
2999   int res;
3000   struct stat st;
3001   pr_error_t *err = NULL;
3002   const char *errstr, *expected;
3003   module m;
3004   pr_error_explainer_t *explainer;
3005 
3006   mark_point();
3007   res = pr_fsio_stat_with_error(NULL, fsio_test_path, &st, NULL);
3008   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
3009     fsio_test_path);
3010   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
3011     strerror(errno), errno);
3012 
3013   mark_point();
3014   res = pr_fsio_stat_with_error(p, fsio_test_path, &st, &err);
3015   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
3016     fsio_test_path);
3017   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
3018     strerror(errno), errno);
3019   fail_unless(err == NULL, "Unexpectedly populated error");
3020 
3021   memset(&m, 0, sizeof(m));
3022   m.name = "error";
3023 
3024   explainer = pr_error_register_explainer(p, &m, "error");
3025   explainer->explain_stat = test_stat_explainer;
3026 
3027   mark_point();
3028   res = pr_fsio_stat_with_error(p, fsio_test_path, &st, &err);
3029   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
3030     fsio_test_path);
3031   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
3032     strerror(errno), errno);
3033   fail_unless(err != NULL, "Failed to populate error");
3034 
3035   expected = pstrcat(p,
3036     "stat() failed with \"No such file or directory [ENOENT (",
3037     get_errnum(p, ENOENT), ")]\"", NULL);
3038   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
3039   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
3040     expected, errstr);
3041 
3042   (void) pr_error_unregister_explainer(p, &m, NULL);
3043   pr_error_destroy(err);
3044 }
3045 END_TEST
3046 
test_unlink_explainer(pool * err_pool,int xerrno,const char * path,const char ** args)3047 static const char *test_unlink_explainer(pool *err_pool, int xerrno,
3048     const char *path, const char **args) {
3049   *args = pstrdup(err_pool, "fake args");
3050   return pstrdup(err_pool, "test mode is not real");
3051 }
3052 
START_TEST(fsio_sys_unlink_with_error_test)3053 START_TEST (fsio_sys_unlink_with_error_test) {
3054   int res;
3055   pr_error_t *err = NULL;
3056   const char *errstr, *expected;
3057   module m;
3058   pr_error_explainer_t *explainer;
3059 
3060   mark_point();
3061   res = pr_fsio_unlink_with_error(NULL, fsio_test_path, NULL);
3062   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
3063     fsio_test_path);
3064   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
3065     strerror(errno), errno);
3066 
3067   mark_point();
3068   res = pr_fsio_unlink_with_error(p, fsio_test_path, &err);
3069   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
3070     fsio_test_path);
3071   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
3072     strerror(errno), errno);
3073   fail_unless(err == NULL, "Unexpectedly populated error");
3074 
3075   memset(&m, 0, sizeof(m));
3076   m.name = "error";
3077 
3078   explainer = pr_error_register_explainer(p, &m, "error");
3079   explainer->explain_unlink = test_unlink_explainer;
3080 
3081   mark_point();
3082   res = pr_fsio_unlink_with_error(p, fsio_test_path, &err);
3083   fail_unless(res < 0, "Failed to handle non-existent file '%s'",
3084     fsio_test_path);
3085   fail_unless(errno == ENOENT, "Expected ENOENT (%d), %s (%d)", ENOENT,
3086     strerror(errno), errno);
3087   fail_unless(err != NULL, "Failed to populate error");
3088 
3089   expected = pstrcat(p,
3090     "unlink() failed with \"No such file or directory [ENOENT (",
3091     get_errnum(p, ENOENT), ")]\"", NULL);
3092   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
3093   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
3094     expected, errstr);
3095 
3096   (void) pr_error_unregister_explainer(p, &m, NULL);
3097   pr_error_destroy(err);
3098 }
3099 END_TEST
3100 
test_write_explainer(pool * err_pool,int xerrno,int fd,const void * buf,size_t sz,const char ** args)3101 static const char *test_write_explainer(pool *err_pool, int xerrno, int fd,
3102     const void *buf, size_t sz, const char **args) {
3103   *args = pstrdup(err_pool, "fake args");
3104   return pstrdup(err_pool, "test mode is not real");
3105 }
3106 
START_TEST(fsio_sys_write_with_error_test)3107 START_TEST (fsio_sys_write_with_error_test) {
3108   int res;
3109   pr_error_t *err = NULL;
3110   const char *errstr, *expected;
3111   module m;
3112   pr_error_explainer_t *explainer;
3113 
3114   mark_point();
3115   res = pr_fsio_write_with_error(NULL, NULL, NULL, 0, NULL);
3116   fail_unless(res < 0, "Failed to handle null pool");
3117   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
3118     strerror(errno), errno);
3119 
3120   mark_point();
3121   res = pr_fsio_write_with_error(p, NULL, NULL, 0, &err);
3122   fail_unless(res < 0, "Failed to handle null fh");
3123   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
3124     strerror(errno), errno);
3125   fail_unless(err == NULL, "Unexpectedly populated error");
3126 
3127   memset(&m, 0, sizeof(m));
3128   m.name = "error";
3129 
3130   explainer = pr_error_register_explainer(p, &m, "error");
3131   explainer->explain_write = test_write_explainer;
3132 
3133   mark_point();
3134   res = pr_fsio_write_with_error(p, NULL, NULL, 0, &err);
3135   fail_unless(res < 0, "Failed to handle null fh");
3136   fail_unless(errno == EINVAL, "Expected EINVAL (%d), %s (%d)", EINVAL,
3137     strerror(errno), errno);
3138   fail_unless(err != NULL, "Failed to populate error");
3139 
3140   expected = pstrcat(p,
3141     "write() failed with \"Invalid argument [EINVAL (",
3142     get_errnum(p, EINVAL), ")]\"", NULL);
3143   expected = "write() failed with \"Invalid argument [EINVAL (22)]\"";
3144   errstr = pr_error_strerror(err, PR_ERROR_FORMAT_USE_MINIMAL);
3145   fail_unless(strcmp(errstr, expected) == 0, "Expected '%s', got '%s'",
3146     expected, errstr);
3147 
3148   (void) pr_error_unregister_explainer(p, &m, NULL);
3149   pr_error_destroy(err);
3150 }
3151 END_TEST
3152 
START_TEST(fsio_statcache_clear_cache_test)3153 START_TEST (fsio_statcache_clear_cache_test) {
3154   int expected, res;
3155   struct stat st;
3156   char *cwd;
3157 
3158   mark_point();
3159   pr_fs_clear_cache();
3160 
3161   res = pr_fs_clear_cache2("/testsuite");
3162   fail_unless(res == 0, "Failed to clear cache: %s", strerror(errno));
3163 
3164   res = pr_fsio_stat("/tmp", &st);
3165   fail_unless(res == 0, "Failed to stat '/tmp': %s", strerror(errno));
3166 
3167   res = pr_fs_clear_cache2("/tmp");
3168   expected = 1;
3169   fail_unless(res == expected, "Expected %d, got %d", expected, res);
3170 
3171   res = pr_fs_clear_cache2("/testsuite");
3172   expected = 0;
3173   fail_unless(res == expected, "Expected %d, got %d", expected, res);
3174 
3175   res = pr_fsio_stat("/tmp", &st);
3176   fail_unless(res == 0, "Failed to stat '/tmp': %s", strerror(errno));
3177 
3178   res = pr_fsio_lstat("/tmp", &st);
3179   fail_unless(res == 0, "Failed to lstat '/tmp': %s", strerror(errno));
3180 
3181   res = pr_fs_clear_cache2("/tmp");
3182   expected = 2;
3183   fail_unless(res == expected, "Expected %d, got %d", expected, res);
3184 
3185   res = pr_fsio_stat("/tmp", &st);
3186   fail_unless(res == 0, "Failed to stat '/tmp': %s", strerror(errno));
3187 
3188   res = pr_fsio_lstat("/tmp", &st);
3189   fail_unless(res == 0, "Failed to lstat '/tmp': %s", strerror(errno));
3190 
3191   cwd = getcwd(NULL, 0);
3192   fail_unless(cwd != NULL, "Failed to get cwd: %s", strerror(errno));
3193 
3194   res = pr_fs_setcwd("/");
3195   fail_unless(res == 0, "Failed to set cwd to '/': %s", strerror(errno));
3196 
3197   res = pr_fs_clear_cache2("tmp");
3198   expected = 2;
3199   fail_unless(res == expected, "Expected %d, got %d", expected, res);
3200 
3201   res = pr_fs_setcwd(cwd);
3202   fail_unless(res == 0, "Failed to set cwd to '%s': %s", cwd, strerror(errno));
3203 
3204   free(cwd);
3205 }
3206 END_TEST
3207 
START_TEST(fsio_statcache_cache_hit_test)3208 START_TEST (fsio_statcache_cache_hit_test) {
3209   int res;
3210   struct stat st;
3211 
3212   /* First is a cache miss...*/
3213   res = pr_fsio_stat("/tmp", &st);
3214   fail_unless(res == 0, "Failed to stat '/tmp': %s", strerror(errno));
3215 
3216   /* This is a cache hit, hopefully. */
3217   res = pr_fsio_stat("/tmp", &st);
3218   fail_unless(res == 0, "Failed to stat '/tmp': %s", strerror(errno));
3219 
3220   pr_fs_clear_cache();
3221 }
3222 END_TEST
3223 
START_TEST(fsio_statcache_negative_cache_test)3224 START_TEST (fsio_statcache_negative_cache_test) {
3225   int res;
3226   struct stat st;
3227 
3228   /* First is a cache miss...*/
3229   res = pr_fsio_stat("/foo.bar.baz.d", &st);
3230   fail_unless(res < 0, "Check of '/foo.bar.baz.d' succeeded unexpectedly");
3231   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3232     strerror(errno), errno);
3233 
3234   /* This is a cache hit, hopefully. */
3235   res = pr_fsio_stat("/foo.bar.baz.d", &st);
3236   fail_unless(res < 0, "Check of '/foo.bar.baz.d' succeeded unexpectedly");
3237   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3238     strerror(errno), errno);
3239 
3240   pr_fs_clear_cache();
3241 }
3242 END_TEST
3243 
START_TEST(fsio_statcache_expired_test)3244 START_TEST (fsio_statcache_expired_test) {
3245   unsigned int cache_size, max_age;
3246   int res;
3247   struct stat st;
3248 
3249   cache_size = max_age = 1;
3250   pr_fs_statcache_set_policy(cache_size, max_age, 0);
3251 
3252   /* First is a cache miss...*/
3253   mark_point();
3254   res = pr_fsio_stat("/tmp", &st);
3255   fail_unless(res == 0, "Failed to stat '/tmp': %s", strerror(errno));
3256 
3257   /* Wait for that cached data to expire...*/
3258   sleep(max_age + 1);
3259 
3260   /* This is another cache miss, hopefully. */
3261   mark_point();
3262   res = pr_fsio_stat("/tmp2", &st);
3263   fail_unless(res < 0, "Check of '/tmp2' succeeded unexpectedly");
3264   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3265     strerror(errno), errno);
3266 
3267   mark_point();
3268   pr_fs_clear_cache();
3269 }
3270 END_TEST
3271 
START_TEST(fsio_statcache_dump_test)3272 START_TEST (fsio_statcache_dump_test) {
3273   mark_point();
3274   pr_fs_statcache_dump();
3275 }
3276 END_TEST
3277 
START_TEST(fs_create_fs_test)3278 START_TEST (fs_create_fs_test) {
3279   pr_fs_t *fs;
3280 
3281   fs = pr_create_fs(NULL, NULL);
3282   fail_unless(fs == NULL, "Failed to handle null arguments");
3283   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3284     strerror(errno), errno);
3285 
3286   fs = pr_create_fs(p, NULL);
3287   fail_unless(fs == NULL, "Failed to handle null name");
3288   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3289     strerror(errno), errno);
3290 
3291   fs = pr_create_fs(p, "testsuite");
3292   fail_unless(fs != NULL, "Failed to create FS: %s", strerror(errno));
3293 }
3294 END_TEST
3295 
START_TEST(fs_insert_fs_test)3296 START_TEST (fs_insert_fs_test) {
3297   pr_fs_t *fs, *fs2;
3298   int res;
3299 
3300   res = pr_insert_fs(NULL, NULL);
3301   fail_unless(res < 0, "Failed to handle null arguments");
3302   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3303     strerror(errno), errno);
3304 
3305   fs = pr_create_fs(p, "testsuite");
3306   fail_unless(fs != NULL, "Failed to create FS: %s", strerror(errno));
3307 
3308   res = pr_insert_fs(fs, NULL);
3309   fail_unless(res < 0, "Failed to handle null path");
3310   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3311     strerror(errno), errno);
3312 
3313   res = pr_insert_fs(fs, "/testsuite");
3314   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3315 
3316   res = pr_insert_fs(fs, "/testsuite");
3317   fail_unless(res == FALSE, "Failed to handle duplicate paths");
3318   fail_unless(errno == EEXIST, "Expected EEXIST (%d), got %s (%d)", EEXIST,
3319     strerror(errno), errno);
3320 
3321   fs2 = pr_create_fs(p, "testsuite2");
3322   fail_unless(fs2 != NULL, "Failed to create FS: %s", strerror(errno));
3323 
3324   res = pr_insert_fs(fs2, "/testsuite2");
3325   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3326 
3327   fs2 = pr_create_fs(p, "testsuite3");
3328   fail_unless(fs2 != NULL, "Failed to create FS: %s", strerror(errno));
3329 
3330   /* Push this FS on top of the previously registered path; FSes can be
3331    * stacked like this.
3332    */
3333   res = pr_insert_fs(fs2, "/testsuite2");
3334   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3335 
3336   (void) pr_remove_fs("/testsuite");
3337   (void) pr_remove_fs("/testsuite2");
3338   (void) pr_remove_fs("/testsuite3");
3339 }
3340 END_TEST
3341 
START_TEST(fs_get_fs_test)3342 START_TEST (fs_get_fs_test) {
3343   pr_fs_t *fs, *fs2, *fs3;
3344   int exact_match = FALSE, res;
3345 
3346   fs = pr_get_fs(NULL, NULL);
3347   fail_unless(fs == NULL, "Failed to handle null arguments");
3348 
3349   fs = pr_get_fs("/testsuite", &exact_match);
3350   fail_unless(fs != NULL, "Failed to get FS: %s", strerror(errno));
3351   fail_unless(exact_match == FALSE, "Expected FALSE, got TRUE");
3352 
3353   fs2 = pr_create_fs(p, "testsuite");
3354   fail_unless(fs2 != NULL, "Failed to create FS: %s", strerror(errno));
3355 
3356   res = pr_insert_fs(fs2, "/testsuite");
3357   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3358 
3359   fs = pr_get_fs("/testsuite", &exact_match);
3360   fail_unless(fs != NULL, "Failed to get FS: %s", strerror(errno));
3361   fail_unless(exact_match == TRUE, "Expected TRUE, got FALSE");
3362 
3363   fs3 = pr_create_fs(p, "testsuite2");
3364   fail_unless(fs3 != NULL, "Failed to create FS: %s", strerror(errno));
3365 
3366   res = pr_insert_fs(fs3, "/testsuite2/");
3367   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3368 
3369   exact_match = FALSE;
3370   fs = pr_get_fs("/testsuite2/foo/bar/baz", &exact_match);
3371   fail_unless(fs != NULL, "Failed to get FS: %s", strerror(errno));
3372   fail_unless(exact_match == FALSE, "Expected FALSE, got TRUE");
3373 
3374   (void) pr_remove_fs("/testsuite2");
3375   (void) pr_remove_fs("/testsuite");
3376 }
3377 END_TEST
3378 
START_TEST(fs_unmount_fs_test)3379 START_TEST (fs_unmount_fs_test) {
3380   pr_fs_t *fs, *fs2;
3381   int res;
3382 
3383   fs = pr_unmount_fs(NULL, NULL);
3384   fail_unless(fs == NULL, "Failed to handle null arguments");
3385   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3386     strerror(errno), errno);
3387 
3388   fs = pr_unmount_fs("/testsuite", NULL);
3389   fail_unless(fs == NULL, "Failed to handle absent FS");
3390   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
3391     strerror(errno), errno);
3392 
3393   fs2 = pr_create_fs(p, "testsuite");
3394   fail_unless(fs2 != NULL, "Failed to create FS: %s", strerror(errno));
3395 
3396   res = pr_insert_fs(fs2, "/testsuite");
3397   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3398 
3399   fs = pr_unmount_fs("/testsuite", "foo bar");
3400   fail_unless(fs == NULL, "Failed to mismatched path AND name");
3401   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3402     strerror(errno), errno);
3403 
3404   fs = pr_unmount_fs("/testsuite2", NULL);
3405   fail_unless(fs == NULL, "Failed to handle nonexistent path");
3406   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3407     strerror(errno), errno);
3408 
3409   fs2 = pr_unmount_fs("/testsuite", NULL);
3410   fail_unless(fs2 != NULL, "Failed to unmount '/testsuite': %s",
3411     strerror(errno));
3412 
3413   fs2 = pr_create_fs(p, "testsuite");
3414   fail_unless(fs2 != NULL, "Failed to create FS: %s", strerror(errno));
3415 
3416   res = pr_insert_fs(fs2, "/testsuite");
3417   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3418 
3419   fs2 = pr_create_fs(p, "testsuite2");
3420   fail_unless(fs2 != NULL, "Failed to create FS: %s", strerror(errno));
3421 
3422   res = pr_insert_fs(fs2, "/testsuite");
3423   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3424 
3425   fs2 = pr_unmount_fs("/testsuite", NULL);
3426   fail_unless(fs2 != NULL, "Failed to unmount '/testsuite': %s",
3427     strerror(errno));
3428 
3429   fs2 = pr_unmount_fs("/testsuite", NULL);
3430   fail_unless(fs2 != NULL, "Failed to unmount '/testsuite': %s",
3431     strerror(errno));
3432 
3433   (void) pr_remove_fs("/testsuite");
3434   (void) pr_remove_fs("/testsuite");
3435 }
3436 END_TEST
3437 
START_TEST(fs_remove_fs_test)3438 START_TEST (fs_remove_fs_test) {
3439   pr_fs_t *fs, *fs2;
3440   int res;
3441 
3442   fs = pr_remove_fs(NULL);
3443   fail_unless(fs == NULL, "Failed to handle null arguments");
3444   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3445     strerror(errno), errno);
3446 
3447   fs = pr_remove_fs("/testsuite");
3448   fail_unless(fs == NULL, "Failed to handle absent FS");
3449   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
3450     strerror(errno), errno);
3451 
3452   fs2 = pr_create_fs(p, "testsuite");
3453   fail_unless(fs2 != NULL, "Failed to create FS: %s", strerror(errno));
3454 
3455   res = pr_insert_fs(fs2, "/testsuite");
3456   fail_unless(res == TRUE, "Failed to insert FS: %s", strerror(errno));
3457 
3458   fs = pr_remove_fs("/testsuite2");
3459   fail_unless(fs == NULL, "Failed to handle nonexistent path");
3460   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3461     strerror(errno), errno);
3462 
3463   fs2 = pr_remove_fs("/testsuite");
3464   fail_unless(fs2 != NULL, "Failed to remove '/testsuite': %s",
3465     strerror(errno));
3466 }
3467 END_TEST
3468 
START_TEST(fs_register_fs_test)3469 START_TEST (fs_register_fs_test) {
3470   pr_fs_t *fs, *fs2;
3471 
3472   fs = pr_register_fs(NULL, NULL, NULL);
3473   fail_unless(fs == NULL, "Failed to handle null arguments");
3474   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3475     strerror(errno), errno);
3476 
3477   fs = pr_register_fs(p, NULL, NULL);
3478   fail_unless(fs == NULL, "Failed to handle null name");
3479   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3480     strerror(errno), errno);
3481 
3482   fs = pr_register_fs(p, "testsuite", NULL);
3483   fail_unless(fs == NULL, "Failed to handle null path");
3484   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3485     strerror(errno), errno);
3486 
3487   fs = pr_register_fs(p, "testsuite", "/testsuite");
3488   fail_unless(fs != NULL, "Failed to register FS: %s", strerror(errno));
3489 
3490   fs2 = pr_register_fs(p, "testsuite", "/testsuite");
3491   fail_unless(fs2 == NULL, "Failed to handle duplicate names");
3492   fail_unless(errno == EEXIST, "Expected EEXIST (%d), got %s (%d)", EEXIST,
3493     strerror(errno), errno);
3494 
3495   (void) pr_remove_fs("/testsuite");
3496 }
3497 END_TEST
3498 
START_TEST(fs_unregister_fs_test)3499 START_TEST (fs_unregister_fs_test) {
3500   pr_fs_t *fs;
3501   int res;
3502 
3503   res = pr_unregister_fs(NULL);
3504   fail_unless(res < 0, "Failed to handle null argument");
3505   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3506     strerror(errno), errno);
3507 
3508   res = pr_unregister_fs("/testsuite");
3509   fail_unless(res < 0, "Failed to handle nonexistent path");
3510   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3511     strerror(errno), errno);
3512 
3513   fs = pr_register_fs(p, "testsuite", "/testsuite");
3514   fail_unless(fs != NULL, "Failed to register FS: %s", strerror(errno));
3515 
3516   res = pr_unregister_fs("/testsuite");
3517   fail_unless(res == 0, "Failed to unregister '/testsuite': %s",
3518     strerror(errno));
3519 }
3520 END_TEST
3521 
START_TEST(fs_resolve_fs_map_test)3522 START_TEST (fs_resolve_fs_map_test) {
3523   pr_fs_t *fs;
3524   int res;
3525 
3526   mark_point();
3527   pr_resolve_fs_map();
3528 
3529   fs = pr_register_fs(p, "testsuite", "/testsuite");
3530   fail_unless(fs != NULL, "Failed to register FS: %s", strerror(errno));
3531 
3532   mark_point();
3533   pr_resolve_fs_map();
3534 
3535   res = pr_unregister_fs("/testsuite");
3536   fail_unless(res == 0, "Failed to unregister '/testsuite': %s",
3537     strerror(errno));
3538 
3539   mark_point();
3540   pr_resolve_fs_map();
3541 }
3542 END_TEST
3543 
3544 #if defined(PR_USE_DEVEL)
START_TEST(fs_dump_fs_test)3545 START_TEST (fs_dump_fs_test) {
3546   pr_fs_t *fs, *root_fs;
3547 
3548   mark_point();
3549   pr_fs_dump(NULL);
3550 
3551   root_fs = pr_get_fs("/", NULL);
3552   fs = pr_register_fs(p, "testsuite", "/testsuite");
3553 
3554   mark_point();
3555   pr_fs_dump(NULL);
3556 
3557   fs->stat = root_fs->stat;
3558   fs->fstat = root_fs->fstat;
3559   fs->lstat = root_fs->lstat;
3560   fs->rename = root_fs->rename;
3561   fs->unlink = root_fs->unlink;
3562   fs->open = root_fs->open;
3563   fs->close = root_fs->close;
3564   fs->read = root_fs->read;
3565   fs->write = root_fs->write;
3566   fs->lseek = root_fs->lseek;
3567   fs->link = root_fs->link;
3568   fs->readlink = root_fs->readlink;
3569   fs->symlink = root_fs->symlink;
3570   fs->ftruncate = root_fs->ftruncate;
3571   fs->truncate = root_fs->truncate;
3572   fs->chmod = root_fs->chmod;
3573   fs->fchmod = root_fs->fchmod;
3574   fs->chown = root_fs->chown;
3575   fs->fchown = root_fs->fchown;
3576   fs->lchown = root_fs->lchown;
3577   fs->access = root_fs->access;
3578   fs->faccess = root_fs->faccess;
3579   fs->utimes = root_fs->utimes;
3580   fs->futimes = root_fs->futimes;
3581   fs->fsync = root_fs->fsync;
3582   fs->chdir = root_fs->chdir;
3583   fs->chroot = root_fs->chroot;
3584   fs->opendir = root_fs->opendir;
3585   fs->closedir = root_fs->closedir;
3586   fs->readdir = root_fs->readdir;
3587   fs->mkdir = root_fs->mkdir;
3588   fs->rmdir = root_fs->rmdir;
3589 
3590   mark_point();
3591   pr_fs_dump(NULL);
3592 
3593   pr_unregister_fs("/testsuite");
3594 }
3595 END_TEST
3596 #endif /* PR_USE_DEVEL */
3597 
fsio_chroot_cb(pr_fs_t * fs,const char * path)3598 static int fsio_chroot_cb(pr_fs_t *fs, const char *path) {
3599   return 0;
3600 }
3601 
START_TEST(fsio_custom_chroot_test)3602 START_TEST (fsio_custom_chroot_test) {
3603   pr_fs_t *fs;
3604   int res;
3605   const char *path;
3606 
3607   fs = pr_register_fs(p, "custom", "/testsuite/");
3608   fail_unless(fs != NULL, "Failed to register custom FS: %s", strerror(errno));
3609 
3610   fs->chroot = fsio_chroot_cb;
3611 
3612   mark_point();
3613   pr_resolve_fs_map();
3614 
3615   path = "/testsuite/foo/bar";
3616   res = pr_fsio_chroot(path);
3617   fail_unless(res == 0, "Failed to chroot (via custom FS) to '%s': %s", path,
3618     strerror(errno));
3619 
3620   pr_unregister_fs("/testsuite");
3621 }
3622 END_TEST
3623 
START_TEST(fs_clean_path_test)3624 START_TEST (fs_clean_path_test) {
3625   char res[PR_TUNABLE_PATH_MAX+1], *path, *expected;
3626 
3627   mark_point();
3628   pr_fs_clean_path(NULL, NULL, 0);
3629   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3630     strerror(errno), errno);
3631 
3632   path = "/";
3633 
3634   mark_point();
3635   pr_fs_clean_path(path, NULL, 0);
3636   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3637     strerror(errno), errno);
3638 
3639   res[sizeof(res)-1] = '\0';
3640 
3641   mark_point();
3642   pr_fs_clean_path(path, res, 0);
3643 
3644   pr_fs_clean_path(path, res, sizeof(res)-1);
3645   fail_unless(strcmp(res, path) == 0, "Expected cleaned path '%s', got '%s'",
3646     path, res);
3647 
3648   res[sizeof(res)-1] = '\0';
3649   path = "/test.txt";
3650   pr_fs_clean_path(path, res, sizeof(res)-1);
3651   fail_unless(strcmp(res, path) == 0, "Expected cleaned path '%s', got '%s'",
3652     path, res);
3653 
3654   res[sizeof(res)-1] = '\0';
3655   path = "/test.txt";
3656   pr_fs_clean_path(path, res, sizeof(res)-1);
3657   fail_unless(strcmp(res, path) == 0, "Expected cleaned path '%s', got '%s'",
3658     path, res);
3659 
3660   res[sizeof(res)-1] = '\0';
3661   path = "/./test.txt";
3662   pr_fs_clean_path(path, res, sizeof(res)-1);
3663   expected = "/test.txt";
3664   fail_unless(strcmp(res, expected) == 0,
3665     "Expected cleaned path '%s', got '%s'", expected, res);
3666 
3667   res[sizeof(res)-1] = '\0';
3668   path = "test.txt";
3669   pr_fs_clean_path(path, res, sizeof(res)-1);
3670   expected = "/test.txt";
3671   fail_unless(strcmp(res, expected) == 0,
3672     "Expected cleaned path '%s', got '%s'", path, res);
3673 }
3674 END_TEST
3675 
START_TEST(fs_clean_path2_test)3676 START_TEST (fs_clean_path2_test) {
3677   char res[PR_TUNABLE_PATH_MAX+1], *path, *expected;
3678   int code;
3679 
3680   mark_point();
3681   code = pr_fs_clean_path2(NULL, NULL, 0, 0);
3682   fail_unless(code < 0, "Failed to handle null path");
3683   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3684     strerror(errno), errno);
3685 
3686   path = "/";
3687 
3688   mark_point();
3689   code = pr_fs_clean_path2(path, NULL, 0, 0);
3690   fail_unless(code < 0, "Failed to handle null buf");
3691   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3692     strerror(errno), errno);
3693 
3694   res[sizeof(res)-1] = '\0';
3695 
3696   mark_point();
3697   code = pr_fs_clean_path2(path, res, 0, 0);
3698   fail_unless(code == 0, "Failed to handle zero length buf: %s",
3699     strerror(errno));
3700 
3701   res[sizeof(res)-1] = '\0';
3702   path = "test.txt";
3703   code = pr_fs_clean_path2(path, res, sizeof(res)-1, 0);
3704   fail_unless(code == 0, "Failed to clean path '%s': %s", path,
3705     strerror(errno));
3706   fail_unless(strcmp(res, path) == 0, "Expected cleaned path '%s', got '%s'",
3707     path, res);
3708 
3709   res[sizeof(res)-1] = '\0';
3710   path = "/./test.txt";
3711   code = pr_fs_clean_path2(path, res, sizeof(res)-1, 0);
3712   fail_unless(code == 0, "Failed to clean path '%s': %s", path,
3713     strerror(errno));
3714   expected = "/test.txt";
3715   fail_unless(strcmp(res, expected) == 0,
3716     "Expected cleaned path '%s', got '%s'", expected, res);
3717 
3718   res[sizeof(res)-1] = '\0';
3719   path = "test.d///test.txt";
3720   code = pr_fs_clean_path2(path, res, sizeof(res)-1, 0);
3721   fail_unless(code == 0, "Failed to clean path '%s': %s", path,
3722     strerror(errno));
3723   expected = "test.d/test.txt";
3724   fail_unless(strcmp(res, expected) == 0,
3725     "Expected cleaned path '%s', got '%s'", expected, res);
3726 
3727   res[sizeof(res)-1] = '\0';
3728   path = "/test.d///test.txt";
3729   code = pr_fs_clean_path2(path, res, sizeof(res)-1,
3730     PR_FSIO_CLEAN_PATH_FL_MAKE_ABS_PATH);
3731   fail_unless(code == 0, "Failed to clean path '%s': %s", path,
3732     strerror(errno));
3733   expected = "/test.d/test.txt";
3734   fail_unless(strcmp(res, expected) == 0,
3735     "Expected cleaned path '%s', got '%s'", expected, res);
3736 }
3737 END_TEST
3738 
START_TEST(fs_dircat_test)3739 START_TEST (fs_dircat_test) {
3740   char buf[PR_TUNABLE_PATH_MAX+1], *a, *b, *ok;
3741   int res;
3742 
3743   res = pr_fs_dircat(NULL, 0, NULL, NULL);
3744   fail_unless(res == -1, "Failed to handle null arguments");
3745   fail_unless(errno == EINVAL,
3746     "Failed to set errno to EINVAL for null arguments");
3747 
3748   res = pr_fs_dircat(buf, 0, "foo", "bar");
3749   fail_unless(res == -1, "Failed to handle zero-length buffer");
3750   fail_unless(errno == EINVAL,
3751     "Failed to set errno to EINVAL for zero-length buffer");
3752 
3753   res = pr_fs_dircat(buf, -1, "foo", "bar");
3754   fail_unless(res == -1, "Failed to handle negative-length buffer");
3755   fail_unless(errno == EINVAL,
3756     "Failed to set errno to EINVAL for negative-length buffer");
3757 
3758   a = pcalloc(p, PR_TUNABLE_PATH_MAX);
3759   memset(a, 'A', PR_TUNABLE_PATH_MAX-1);
3760 
3761   b = "foo";
3762 
3763   res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
3764   fail_unless(res == -1, "Failed to handle too-long paths");
3765   fail_unless(errno == ENAMETOOLONG,
3766     "Failed to set errno to ENAMETOOLONG for too-long paths");
3767 
3768   a = "foo";
3769   b = "/bar";
3770   ok = b;
3771   res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
3772   fail_unless(res == 0, "Failed to concatenate abs-path path second dir");
3773   fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
3774     ok, buf);
3775 
3776   a = "foo";
3777   b = "bar";
3778   ok = "foo/bar";
3779   res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
3780   fail_unless(res == 0, "Failed to concatenate two normal paths");
3781   fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
3782     ok, buf);
3783 
3784   a = "foo/";
3785   b = "bar";
3786   ok = "foo/bar";
3787   res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
3788   fail_unless(res == 0, "Failed to concatenate first dir with trailing slash");
3789   fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
3790     ok, buf);
3791 
3792   a = "";
3793   b = "";
3794   ok = "/";
3795   res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
3796   fail_unless(res == 0, "Failed to concatenate two empty paths");
3797   fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
3798     ok, buf);
3799 
3800   a = "/foo";
3801   b = "";
3802   ok = "/foo/";
3803   res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
3804   fail_unless(res == 0, "Failed to concatenate two empty paths");
3805   fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
3806     ok, buf);
3807 
3808   a = "";
3809   b = "/bar";
3810   ok = "/bar/";
3811   res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
3812   fail_unless(res == 0, "Failed to concatenate two empty paths");
3813   fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
3814     ok, buf);
3815 }
3816 END_TEST
3817 
START_TEST(fs_setcwd_test)3818 START_TEST (fs_setcwd_test) {
3819   int res;
3820   const char *wd;
3821 
3822   /* Make sure that we don't segfault if we call pr_fs_setcwd() on the
3823    * buffer that it is already using.
3824    */
3825   res = pr_fs_setcwd(pr_fs_getcwd());
3826   fail_unless(res == 0, "Failed to set cwd to '%s': %s", pr_fs_getcwd(),
3827     strerror(errno));
3828 
3829   wd = pr_fs_getcwd();
3830   fail_unless(wd != NULL, "Failed to get working directory: %s",
3831     strerror(errno));
3832   fail_unless(strcmp(wd, fsio_cwd) == 0,
3833     "Expected '%s', got '%s'", fsio_cwd, wd);
3834 
3835   wd = pr_fs_getvwd();
3836   fail_unless(wd != NULL, "Failed to get working directory: %s",
3837     strerror(errno));
3838   fail_unless(strcmp(wd, "/") == 0, "Expected '/', got '%s'", wd);
3839 }
3840 END_TEST
3841 
START_TEST(fs_glob_test)3842 START_TEST (fs_glob_test) {
3843   glob_t pglob;
3844   int res;
3845 
3846   res = pr_fs_glob(NULL, 0, NULL, NULL);
3847   fail_unless(res < 0, "Failed to handle null arguments");
3848   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3849     strerror(errno), errno);
3850 
3851   res = pr_fs_glob(NULL, 0, NULL, &pglob);
3852   fail_unless(res < 0, "Failed to handle null arguments");
3853   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3854     strerror(errno), errno);
3855 
3856   memset(&pglob, 0, sizeof(pglob));
3857   res = pr_fs_glob("*", 0, NULL, &pglob);
3858   fail_unless(res == 0, "Failed to glob: glob(3) returned %d: %s", res,
3859     strerror(errno));
3860   fail_unless(pglob.gl_pathc > 0, "Expected >0, got %lu",
3861     (unsigned long) pglob.gl_pathc);
3862 
3863   mark_point();
3864   pr_fs_globfree(NULL);
3865   if (res == 0) {
3866     pr_fs_globfree(&pglob);
3867   }
3868 }
3869 END_TEST
3870 
START_TEST(fs_copy_file_test)3871 START_TEST (fs_copy_file_test) {
3872   int res;
3873   char *src_path = NULL, *dst_path = NULL, *text;
3874   pr_fh_t *fh;
3875 
3876   res = pr_fs_copy_file(NULL, NULL);
3877   fail_unless(res < 0, "Failed to handle null arguments");
3878   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3879     strerror(errno), errno);
3880 
3881   src_path = (char *) fsio_copy_src_path;
3882   res = pr_fs_copy_file(src_path, NULL);
3883   fail_unless(res < 0, "Failed to handle null destination path");
3884   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3885     strerror(errno), errno);
3886 
3887   dst_path = (char *) fsio_copy_dst_path;
3888   res = pr_fs_copy_file(src_path, dst_path);
3889   fail_unless(res < 0, "Failed to handle nonexistent source path");
3890   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3891     strerror(errno), errno);
3892 
3893   res = pr_fs_copy_file("/tmp", dst_path);
3894   fail_unless(res < 0, "Failed to handle directory source path");
3895   fail_unless(errno == EISDIR, "Expected EISDIR (%d), got %s (%d)", EISDIR,
3896     strerror(errno), errno);
3897 
3898   (void) unlink(src_path);
3899   fh = pr_fsio_open(src_path, O_CREAT|O_EXCL|O_WRONLY);
3900   fail_unless(fh != NULL, "Failed to open '%s': %s", src_path, strerror(errno));
3901 
3902   text = "Hello, World!\n";
3903   res = pr_fsio_write(fh, text, strlen(text));
3904   fail_if(res < 0, "Failed to write '%s' to '%s': %s", text, src_path,
3905     strerror(errno));
3906 
3907   res = pr_fsio_close(fh);
3908   fail_unless(res == 0, "Failed to close '%s': %s", src_path, strerror(errno));
3909 
3910   res = pr_fs_copy_file(src_path, "/tmp");
3911   fail_unless(res < 0, "Failed to handle directory destination path");
3912   fail_unless(errno == EISDIR, "Expected EISDIR (%d), got %s (%d)", EISDIR,
3913     strerror(errno), errno);
3914 
3915   res = pr_fs_copy_file(src_path, "/tmp/foo/bar/baz/quxx/quzz.dat");
3916   fail_unless(res < 0, "Failed to handle nonexistent destination path");
3917   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3918     strerror(errno), errno);
3919 
3920   mark_point();
3921   res = pr_fs_copy_file(src_path, src_path);
3922   fail_unless(res == 0, "Failed to copy file to itself: %s", strerror(errno));
3923 
3924   (void) unlink(dst_path);
3925 
3926   mark_point();
3927   res = pr_fs_copy_file(src_path, dst_path);
3928   fail_unless(res == 0, "Failed to copy file: %s", strerror(errno));
3929 
3930   (void) pr_fsio_unlink(src_path);
3931   (void) pr_fsio_unlink(dst_path);
3932 }
3933 END_TEST
3934 
3935 static unsigned int copy_progress_iter = 0;
copy_progress_cb(int nwritten)3936 static void copy_progress_cb(int nwritten) {
3937   copy_progress_iter++;
3938 }
3939 
START_TEST(fs_copy_file2_test)3940 START_TEST (fs_copy_file2_test) {
3941   int res, flags;
3942   char *src_path, *dst_path, *text;
3943   pr_fh_t *fh;
3944 
3945   src_path = (char *) fsio_copy_src_path;
3946   dst_path = (char *) fsio_copy_dst_path;
3947   flags = PR_FSIO_COPY_FILE_FL_NO_DELETE_ON_FAILURE;
3948 
3949   (void) unlink(src_path);
3950   (void) unlink(dst_path);
3951 
3952   fh = pr_fsio_open(src_path, O_CREAT|O_EXCL|O_WRONLY);
3953   fail_unless(fh != NULL, "Failed to open '%s': %s", src_path, strerror(errno));
3954 
3955   text = "Hello, World!\n";
3956   res = pr_fsio_write(fh, text, strlen(text));
3957   fail_if(res < 0, "Failed to write '%s' to '%s': %s", text, src_path,
3958     strerror(errno));
3959 
3960   res = pr_fsio_close(fh);
3961   fail_unless(res == 0, "Failed to close '%s': %s", src_path, strerror(errno));
3962 
3963   copy_progress_iter = 0;
3964 
3965   mark_point();
3966   res = pr_fs_copy_file2(src_path, dst_path, flags, copy_progress_cb);
3967   fail_unless(res == 0, "Failed to copy file: %s", strerror(errno));
3968 
3969   (void) pr_fsio_unlink(src_path);
3970   (void) pr_fsio_unlink(dst_path);
3971 
3972   fail_unless(copy_progress_iter > 0, "Unexpected progress callback count (%u)",
3973     copy_progress_iter);
3974 }
3975 END_TEST
3976 
START_TEST(fs_interpolate_test)3977 START_TEST (fs_interpolate_test) {
3978   int res;
3979   char buf[PR_TUNABLE_PATH_MAX], *path;
3980 
3981   memset(buf, '\0', sizeof(buf));
3982 
3983   res = pr_fs_interpolate(NULL, NULL, 0);
3984   fail_unless(res < 0, "Failed to handle null arguments");
3985   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3986     strerror(errno), errno);
3987 
3988   path = "/tmp";
3989   res = pr_fs_interpolate(path, NULL, 0);
3990   fail_unless(res < 0, "Failed to handle null buffer");
3991   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3992     strerror(errno), errno);
3993 
3994   res = pr_fs_interpolate(path, buf, 0);
3995   fail_unless(res < 0, "Failed to handle zero buffer length");
3996   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3997     strerror(errno), errno);
3998 
3999   res = pr_fs_interpolate(path, buf, sizeof(buf)-1);
4000   fail_unless(res == 1, "Failed to interpolate path '%s': %s", path,
4001     strerror(errno));
4002   fail_unless(strcmp(buf, path) == 0, "Expected '%s', got '%s'", path, buf);
4003 
4004   path = "~/foo/bar/baz/quzz/quzz.d";
4005   res = pr_fs_interpolate(path, buf, sizeof(buf)-1);
4006   fail_unless(res == 1, "Failed to interpolate path '%s': %s", path,
4007     strerror(errno));
4008   fail_unless(strcmp(buf, path+1) == 0, "Expected '%s', got '%s'", path+1, buf);
4009 
4010   path = "~";
4011   res = pr_fs_interpolate(path, buf, sizeof(buf)-1);
4012   fail_unless(res == 1, "Failed to interpolate path '%s': %s", path,
4013     strerror(errno));
4014   fail_unless(strcmp(buf, "/") == 0, "Expected '/', got '%s'", buf);
4015 
4016   session.chroot_path = "/tmp";
4017   res = pr_fs_interpolate(path, buf, sizeof(buf)-1);
4018   fail_unless(res == 1, "Failed to interpolate path '%s': %s", path,
4019     strerror(errno));
4020   fail_unless(strcmp(buf, session.chroot_path) == 0, "Expected '%s', got '%s'",
4021     session.chroot_path, buf);
4022 
4023   session.chroot_path = NULL;
4024 
4025   path = "~foo.bar.baz.quzz";
4026   res = pr_fs_interpolate(path, buf, sizeof(buf)-1);
4027   fail_unless(res < 0, "Interpolated '%s' unexpectedly", path);
4028   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4029     strerror(errno), errno);
4030 
4031   session.user = "testsuite";
4032   path = "~/tmp.d/test.d/foo.d/bar.d";
4033   res = pr_fs_interpolate(path, buf, sizeof(buf)-1);
4034   fail_unless(res < 0, "Interpolated '%s' unexpectedly", path);
4035   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4036     strerror(errno), errno);
4037   session.user = NULL;
4038 }
4039 END_TEST
4040 
START_TEST(fs_resolve_partial_test)4041 START_TEST (fs_resolve_partial_test) {
4042   int op = FSIO_FILE_STAT, res;
4043   char buf[PR_TUNABLE_PATH_MAX], *path;
4044 
4045   res = pr_fs_resolve_partial(NULL, NULL, 0, op);
4046   fail_unless(res < 0, "Failed to handle null arguments");
4047   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4048     strerror(errno), errno);
4049 
4050   path = "/tmp";
4051   res = pr_fs_resolve_partial(path, NULL, 0, op);
4052   fail_unless(res < 0, "Failed to handle null buffer");
4053   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4054     strerror(errno), errno);
4055 
4056   memset(buf, '\0', sizeof(buf));
4057   res = pr_fs_resolve_partial(path, buf, 0, op);
4058   fail_unless(res < 0, "Failed to handle zero buffer length");
4059   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4060     strerror(errno), errno);
4061 
4062   res = pr_fs_resolve_partial(path, buf, sizeof(buf)-1, op);
4063   fail_unless(res == 0, "Failed to resolve '%s': %s", path, strerror(errno));
4064   if (strcmp(buf, path) != 0) {
4065     /* Mac-specific hack */
4066     const char *prefix = "/private";
4067 
4068     if (strncmp(buf, prefix, strlen(prefix)) != 0) {
4069       fail("Expected '%s', got '%s'", path, buf);
4070     }
4071   }
4072 
4073   path = "/tmp/.////./././././.";
4074   res = pr_fs_resolve_partial(path, buf, sizeof(buf)-1, op);
4075   fail_unless(res == 0, "Failed to resolve '%s': %s", path, strerror(errno));
4076   if (strcmp(buf, path) != 0) {
4077     /* Mac-specific hack */
4078     const char *prefix = "/private";
4079 
4080     if (strncmp(buf, prefix, strlen(prefix)) != 0 &&
4081         strcmp(buf, "/tmp/") != 0) {
4082       fail("Expected '%s', got '%s'", path, buf);
4083     }
4084   }
4085 
4086   path = "/../../../.././..///../";
4087   res = pr_fs_resolve_partial(path, buf, sizeof(buf)-1, op);
4088   fail_unless(res == 0, "Failed to resolve '%s': %s", path, strerror(errno));
4089   if (strcmp(buf, "/") != 0) {
4090     /* Mac-specific hack */
4091     const char *prefix = "/private";
4092 
4093     if (strncmp(buf, prefix, strlen(prefix)) != 0) {
4094       fail("Expected '%s', got '%s'", path, buf);
4095     }
4096   }
4097 
4098   path = "/tmp/.///../../..../";
4099   res = pr_fs_resolve_partial(path, buf, sizeof(buf)-1, op);
4100   fail_unless(res < 0, "Resolved '%s' unexpectedly", path);
4101   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4102     strerror(errno), errno);
4103 
4104   path = "~foo/.///../../..../";
4105   res = pr_fs_resolve_partial(path, buf, sizeof(buf)-1, op);
4106   fail_unless(res < 0, "Resolved '%s' unexpectedly", path);
4107   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4108     strerror(errno), errno);
4109 
4110   path = "../../..../";
4111   res = pr_fs_resolve_partial(path, buf, sizeof(buf)-1, op);
4112   fail_unless(res < 0, "Resolved '%s' unexpectedly", path);
4113   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4114     strerror(errno), errno);
4115 
4116   /* Resolve a symlink path */
4117   res = pr_fsio_symlink("/tmp", fsio_link_path);
4118   fail_unless(res == 0, "Failed to create symlink to '%s': %s", fsio_link_path,
4119     strerror(errno));
4120 
4121   res = pr_fs_resolve_partial(fsio_link_path, buf, sizeof(buf)-1, op);
4122   fail_unless(res == 0, "Failed to resolve '%s': %s", fsio_link_path,
4123     strerror(errno));
4124 
4125   (void) unlink(fsio_link_path);
4126 }
4127 END_TEST
4128 
START_TEST(fs_resolve_path_test)4129 START_TEST (fs_resolve_path_test) {
4130   int op = FSIO_FILE_STAT, res;
4131   char buf[PR_TUNABLE_PATH_MAX], *path;
4132 
4133   memset(buf, '\0', sizeof(buf));
4134 
4135   res = pr_fs_resolve_path(NULL, NULL, 0, op);
4136   fail_unless(res < 0, "Failed to handle null arguments");
4137   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4138     strerror(errno), errno);
4139 
4140   path = "/tmp";
4141   res = pr_fs_resolve_path(path, NULL, 0, op);
4142   fail_unless(res < 0, "Failed to handle null buffer");
4143   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4144     strerror(errno), errno);
4145 
4146   res = pr_fs_resolve_path(path, buf, 0, op);
4147   fail_unless(res < 0, "Failed to handle zero buffer length");
4148   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4149     strerror(errno), errno);
4150 
4151   res = pr_fs_resolve_path(path, buf, sizeof(buf)-1, op);
4152   fail_unless(res == 0, "Failed to resolve path '%s': %s", path,
4153     strerror(errno));
4154   if (strcmp(buf, path) != 0) {
4155     /* Mac-specific hack */
4156     const char *prefix = "/private";
4157 
4158     if (strncmp(buf, prefix, strlen(prefix)) != 0) {
4159       fail("Expected '%s', got '%s'", path, buf);
4160     }
4161   }
4162 
4163   /* Resolve a symlink path */
4164   res = pr_fsio_symlink("/tmp", fsio_link_path);
4165   fail_unless(res == 0, "Failed to create symlink to '%s': %s", fsio_link_path,
4166     strerror(errno));
4167 
4168   res = pr_fs_resolve_path(fsio_link_path, buf, sizeof(buf)-1, op);
4169   fail_unless(res == 0, "Failed to resolve '%s': %s", fsio_link_path,
4170     strerror(errno));
4171 
4172   (void) unlink(fsio_link_path);
4173 }
4174 END_TEST
4175 
START_TEST(fs_use_encoding_test)4176 START_TEST (fs_use_encoding_test) {
4177   int res;
4178 
4179   res = pr_fs_use_encoding(-1);
4180   fail_unless(res < 0, "Failed to handle invalid setting");
4181   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4182     strerror(errno), errno);
4183 
4184   res = pr_fs_use_encoding(TRUE);
4185   fail_unless(res == TRUE, "Expected TRUE, got %d", res);
4186 
4187   res = pr_fs_use_encoding(FALSE);
4188   fail_unless(res == TRUE, "Expected TRUE, got %d", res);
4189 
4190   res = pr_fs_use_encoding(TRUE);
4191   fail_unless(res == FALSE, "Expected FALSE, got %d", res);
4192 }
4193 END_TEST
4194 
START_TEST(fs_decode_path2_test)4195 START_TEST (fs_decode_path2_test) {
4196   int flags = 0;
4197   char junk[32], *res;
4198   const char *path;
4199 
4200   res = pr_fs_decode_path(NULL, NULL);
4201   fail_unless(res == NULL, "Failed to handle null arguments");
4202   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4203     strerror(errno), errno);
4204 
4205   res = pr_fs_decode_path(p, NULL);
4206   fail_unless(res == NULL, "Failed to handle null path");
4207   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4208     strerror(errno), errno);
4209 
4210   path = "/tmp";
4211   res = pr_fs_decode_path2(p, path, flags);
4212   fail_unless(res != NULL, "Failed to decode path '%s': %s", path,
4213     strerror(errno));
4214 
4215   path = "/tmp";
4216   res = pr_fs_decode_path2(p, path, flags);
4217   fail_unless(res != NULL, "Failed to decode path '%s': %s", path,
4218     strerror(errno));
4219 
4220   /* Test a path that cannot be decoded, using junk data from the stack */
4221   junk[sizeof(junk)-1] = '\0';
4222   path = junk;
4223   res = pr_fs_decode_path2(p, path, flags);
4224   fail_unless(res != NULL, "Failed to decode path: %s", strerror(errno));
4225 
4226   /* XXX Use the FSIO_DECODE_FL_TELL_ERRORS flags, AND set the encode
4227    * policy to use PR_ENCODE_POLICY_FL_REQUIRE_VALID_ENCODING.
4228    */
4229 }
4230 END_TEST
4231 
START_TEST(fs_encode_path_test)4232 START_TEST (fs_encode_path_test) {
4233   char junk[32], *res;
4234   const char *path;
4235 
4236   res = pr_fs_encode_path(NULL, NULL);
4237   fail_unless(res == NULL, "Failed to handle null arguments");
4238   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4239     strerror(errno), errno);
4240 
4241   res = pr_fs_encode_path(p, NULL);
4242   fail_unless(res == NULL, "Failed to handle null path");
4243   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4244     strerror(errno), errno);
4245 
4246   path = "/tmp";
4247   res = pr_fs_encode_path(p, path);
4248   fail_unless(res != NULL, "Failed to encode path '%s': %s", path,
4249     strerror(errno));
4250 
4251   /* Test a path that cannot be encoded, using junk data from the stack */
4252   junk[sizeof(junk)-1] = '\0';
4253   path = junk;
4254   res = pr_fs_encode_path(p, path);
4255   fail_unless(res != NULL, "Failed to encode path: %s", strerror(errno));
4256 }
4257 END_TEST
4258 
START_TEST(fs_split_path_test)4259 START_TEST (fs_split_path_test) {
4260   array_header *res;
4261   const char *path, *elt;
4262 
4263   mark_point();
4264   res = pr_fs_split_path(NULL, NULL);
4265   fail_unless(res == NULL, "Failed to handle null pool");
4266   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4267     strerror(errno), errno);
4268 
4269   mark_point();
4270   res = pr_fs_split_path(p, NULL);
4271   fail_unless(res == NULL, "Failed to handle null path");
4272   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4273     strerror(errno), errno);
4274 
4275   path = "";
4276 
4277   mark_point();
4278   res = pr_fs_split_path(p, path);
4279   fail_unless(res == NULL, "Failed to handle empty path");
4280   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4281     strerror(errno), errno);
4282 
4283   path = "/";
4284 
4285   mark_point();
4286   res = pr_fs_split_path(p, path);
4287   fail_unless(res != NULL, "Failed to split path '%s': %s", path,
4288     strerror(errno));
4289   fail_unless(res->nelts == 1, "Expected 1, got %u", res->nelts);
4290   elt = ((char **) res->elts)[0];
4291   fail_unless(strcmp(elt, "/") == 0, "Expected '/', got '%s'", elt);
4292 
4293   path = "///";
4294 
4295   mark_point();
4296   res = pr_fs_split_path(p, path);
4297   fail_unless(res != NULL, "Failed to split path '%s': %s", path,
4298     strerror(errno));
4299   fail_unless(res->nelts == 1, "Expected 1, got %u", res->nelts);
4300   elt = ((char **) res->elts)[0];
4301   fail_unless(strcmp(elt, "/") == 0, "Expected '/', got '%s'", elt);
4302 
4303   path = "/foo/bar/baz/";
4304 
4305   mark_point();
4306   res = pr_fs_split_path(p, path);
4307   fail_unless(res != NULL, "Failed to split path '%s': %s", path,
4308     strerror(errno));
4309   fail_unless(res->nelts == 4, "Expected 4, got %u", res->nelts);
4310   elt = ((char **) res->elts)[0];
4311   fail_unless(strcmp(elt, "/") == 0, "Expected '/', got '%s'", elt);
4312   elt = ((char **) res->elts)[1];
4313   fail_unless(strcmp(elt, "foo") == 0, "Expected 'foo', got '%s'", elt);
4314   elt = ((char **) res->elts)[2];
4315   fail_unless(strcmp(elt, "bar") == 0, "Expected 'bar', got '%s'", elt);
4316   elt = ((char **) res->elts)[3];
4317   fail_unless(strcmp(elt, "baz") == 0, "Expected 'baz', got '%s'", elt);
4318 
4319   path = "/foo//bar//baz//";
4320 
4321   mark_point();
4322   res = pr_fs_split_path(p, path);
4323   fail_unless(res != NULL, "Failed to split path '%s': %s", path,
4324     strerror(errno));
4325   fail_unless(res->nelts == 4, "Expected 4, got %u", res->nelts);
4326   elt = ((char **) res->elts)[0];
4327   fail_unless(strcmp(elt, "/") == 0, "Expected '/', got '%s'", elt);
4328   elt = ((char **) res->elts)[1];
4329   fail_unless(strcmp(elt, "foo") == 0, "Expected 'foo', got '%s'", elt);
4330   elt = ((char **) res->elts)[2];
4331   fail_unless(strcmp(elt, "bar") == 0, "Expected 'bar', got '%s'", elt);
4332   elt = ((char **) res->elts)[3];
4333   fail_unless(strcmp(elt, "baz") == 0, "Expected 'baz', got '%s'", elt);
4334 
4335   path = "/foo/bar/baz";
4336 
4337   mark_point();
4338   res = pr_fs_split_path(p, path);
4339   fail_unless(res != NULL, "Failed to split path '%s': %s", path,
4340     strerror(errno));
4341   fail_unless(res->nelts == 4, "Expected 4, got %u", res->nelts);
4342   elt = ((char **) res->elts)[0];
4343   fail_unless(strcmp(elt, "/") == 0, "Expected '/', got '%s'", elt);
4344   elt = ((char **) res->elts)[1];
4345   fail_unless(strcmp(elt, "foo") == 0, "Expected 'foo', got '%s'", elt);
4346   elt = ((char **) res->elts)[2];
4347   fail_unless(strcmp(elt, "bar") == 0, "Expected 'bar', got '%s'", elt);
4348   elt = ((char **) res->elts)[3];
4349   fail_unless(strcmp(elt, "baz") == 0, "Expected 'baz', got '%s'", elt);
4350 
4351   path = "foo/bar/baz";
4352 
4353   mark_point();
4354   res = pr_fs_split_path(p, path);
4355   fail_unless(res != NULL, "Failed to split path '%s': %s", path,
4356     strerror(errno));
4357   fail_unless(res->nelts == 3, "Expected 3, got %u", res->nelts);
4358   elt = ((char **) res->elts)[0];
4359   fail_unless(strcmp(elt, "foo") == 0, "Expected 'foo', got '%s'", elt);
4360   elt = ((char **) res->elts)[1];
4361   fail_unless(strcmp(elt, "bar") == 0, "Expected 'bar', got '%s'", elt);
4362   elt = ((char **) res->elts)[2];
4363   fail_unless(strcmp(elt, "baz") == 0, "Expected 'baz', got '%s'", elt);
4364 }
4365 END_TEST
4366 
START_TEST(fs_join_path_test)4367 START_TEST (fs_join_path_test) {
4368   char *path;
4369   array_header *components;
4370 
4371   mark_point();
4372   path = pr_fs_join_path(NULL, NULL, 0);
4373   fail_unless(path == NULL, "Failed to handle null pool");
4374   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4375     strerror(errno), errno);
4376 
4377   mark_point();
4378   path = pr_fs_join_path(p, NULL, 0);
4379   fail_unless(path == NULL, "Failed to handle null components");
4380   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4381     strerror(errno), errno);
4382 
4383   components = make_array(p, 0, sizeof(char **));
4384 
4385   mark_point();
4386   path = pr_fs_join_path(p, components, 0);
4387   fail_unless(path == NULL, "Failed to handle empty components");
4388   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4389     strerror(errno), errno);
4390 
4391   *((char **) push_array(components)) = pstrdup(p, "/");
4392 
4393   mark_point();
4394   path = pr_fs_join_path(p, components, 0);
4395   fail_unless(path == NULL, "Failed to handle empty count");
4396   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4397     strerror(errno), errno);
4398 
4399   mark_point();
4400   path = pr_fs_join_path(p, components, 3);
4401   fail_unless(path == NULL, "Failed to handle invalid count");
4402   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4403     strerror(errno), errno);
4404 
4405   mark_point();
4406   path = pr_fs_join_path(p, components, 1);
4407   fail_unless(path != NULL, "Failed to join path: %s", strerror(errno));
4408   fail_unless(strcmp(path, "/") == 0, "Expected '/', got '%s'", path);
4409 
4410   *((char **) push_array(components)) = pstrdup(p, "foo");
4411   *((char **) push_array(components)) = pstrdup(p, "bar");
4412   *((char **) push_array(components)) = pstrdup(p, "baz");
4413 
4414   mark_point();
4415   path = pr_fs_join_path(p, components, 4);
4416   fail_unless(path != NULL, "Failed to join path: %s", strerror(errno));
4417   fail_unless(strcmp(path, "/foo/bar/baz") == 0,
4418     "Expected '/foo/bar/baz', got '%s'", path);
4419 
4420   mark_point();
4421   path = pr_fs_join_path(p, components, 3);
4422   fail_unless(path != NULL, "Failed to join path: %s", strerror(errno));
4423   fail_unless(strcmp(path, "/foo/bar") == 0, "Expected '/foo/bar', got '%s'",
4424     path);
4425 }
4426 END_TEST
4427 
START_TEST(fs_virtual_path_test)4428 START_TEST (fs_virtual_path_test) {
4429   const char *path;
4430   char buf[PR_TUNABLE_PATH_MAX];
4431 
4432   mark_point();
4433   pr_fs_virtual_path(NULL, NULL, 0);
4434 
4435   mark_point();
4436   path = "/tmp";
4437   pr_fs_virtual_path(path, NULL, 0);
4438 
4439   mark_point();
4440   memset(buf, '\0', sizeof(buf));
4441   pr_fs_virtual_path(path, buf, 0);
4442   fail_unless(*buf == '\0', "Expected empty buffer, got '%s'", buf);
4443 
4444   mark_point();
4445   memset(buf, '\0', sizeof(buf));
4446   pr_fs_virtual_path(path, buf, sizeof(buf)-1);
4447   fail_unless(strcmp(buf, path) == 0, "Expected '%s', got '%s'", path, buf);
4448 
4449   mark_point();
4450   memset(buf, '\0', sizeof(buf));
4451   path = "tmp";
4452   pr_fs_virtual_path(path, buf, sizeof(buf)-1);
4453   fail_unless(strcmp(buf, "/tmp") == 0, "Expected '/tmp', got '%s'", path, buf);
4454 
4455   mark_point();
4456   memset(buf, '\0', sizeof(buf));
4457   path = "/tmp/././";
4458   pr_fs_virtual_path(path, buf, sizeof(buf)-1);
4459   fail_unless(strcmp(buf, "/tmp") == 0 || strcmp(buf, "/tmp/") == 0,
4460     "Expected '/tmp', got '%s'", path, buf);
4461 
4462   mark_point();
4463   memset(buf, '\0', sizeof(buf));
4464   path = "tmp/../../";
4465   pr_fs_virtual_path(path, buf, sizeof(buf)-1);
4466   fail_unless(strcmp(buf, "/") == 0, "Expected '/', got '%s'", path, buf);
4467 }
4468 END_TEST
4469 
4470 #if 0
4471 /* This test is commented out, since libcheck is very unhappy when we
4472  * close its logging fds out from underneath it.  Thus we keep this
4473  * test here, for any future tinkering, just not enabled by default.
4474  */
4475 START_TEST (fs_close_extra_fds_test) {
4476   mark_point();
4477   pr_fs_close_extra_fds();
4478 }
4479 END_TEST
4480 #endif
4481 
START_TEST(fs_get_usable_fd_test)4482 START_TEST (fs_get_usable_fd_test) {
4483   int fd, res;
4484 
4485   fd = -1;
4486   res = pr_fs_get_usable_fd(fd);
4487   fail_unless(res < 0, "Failed to handle bad fd");
4488   fail_unless(errno == EBADF || errno == EINVAL,
4489     "Expected EBADF (%d) or EINVAL (%d), got %s (%d)", EBADF, EINVAL,
4490     strerror(errno), errno);
4491 
4492   fd = STDERR_FILENO + 1;
4493   res = pr_fs_get_usable_fd(fd);
4494   fail_unless(res == fd, "Expected %d, got %d", fd, res);
4495 
4496   fd = STDERR_FILENO - 1;
4497   res = pr_fs_get_usable_fd(fd);
4498   fail_unless(res > STDERR_FILENO, "Failed to get usable fd for %d: %s", fd,
4499     strerror(errno));
4500   (void) close(res);
4501 }
4502 END_TEST
4503 
START_TEST(fs_get_usable_fd2_test)4504 START_TEST (fs_get_usable_fd2_test) {
4505   int fd, res;
4506 
4507   res = pr_fs_get_usable_fd2(NULL);
4508   fail_unless(res < 0, "Failed to handle null argument");
4509   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4510     strerror(errno), errno);
4511 
4512   fd = -1;
4513   res = pr_fs_get_usable_fd2(&fd);
4514   fail_unless(res < 0, "Failed to handle bad fd");
4515   fail_unless(errno == EBADF || errno == EINVAL,
4516     "Expected EBADF (%d) or EINVAL (%d), got %s (%d)", EBADF, EINVAL,
4517     strerror(errno), errno);
4518 
4519   fd = STDERR_FILENO + 1;
4520   res = pr_fs_get_usable_fd2(&fd);
4521   fail_unless(res == 0, "Failed to handle fd: %s", strerror(errno));
4522   fail_unless(fd == (STDERR_FILENO + 1), "Expected %d, got %d",
4523     STDERR_FILENO + 1, fd);
4524 
4525   fd = STDERR_FILENO - 1;
4526   res = pr_fs_get_usable_fd2(&fd);
4527   fail_unless(res == 0, "Failed to handle fd: %s", strerror(errno));
4528   fail_unless(fd > STDERR_FILENO, "Expected >%d, got %d", STDERR_FILENO, fd);
4529   (void) close(fd);
4530 }
4531 END_TEST
4532 
START_TEST(fs_getsize_test)4533 START_TEST (fs_getsize_test) {
4534   off_t res;
4535   char *path;
4536 
4537   res = pr_fs_getsize(NULL);
4538   fail_unless(res == (off_t) -1, "Failed to handle null argument");
4539   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4540     strerror(errno), errno);
4541 
4542   path = "/tmp";
4543   res = pr_fs_getsize(path);
4544   fail_unless(res != (off_t) -1, "Failed to get fs size for '%s': %s", path,
4545     strerror(errno));
4546 }
4547 END_TEST
4548 
START_TEST(fs_getsize2_test)4549 START_TEST (fs_getsize2_test) {
4550   int res;
4551   char *path;
4552   off_t sz = 0;
4553 
4554   res = pr_fs_getsize2(NULL, NULL);
4555   fail_unless(res < 0, "Failed to handle null arguments");
4556   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4557     strerror(errno), errno);
4558 
4559   path = "/tmp";
4560   res = pr_fs_getsize2(path, NULL);
4561   fail_unless(res < 0, "Failed to handle null size argument");
4562   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4563     strerror(errno), errno);
4564 
4565   res = pr_fs_getsize2(path, &sz);
4566   fail_unless(res == 0, "Failed to get fs size for '%s': %s", path,
4567     strerror(errno));
4568 }
4569 END_TEST
4570 
START_TEST(fs_fgetsize_test)4571 START_TEST (fs_fgetsize_test) {
4572   int fd = -1, res;
4573   off_t fs_sz = 0;
4574 
4575   mark_point();
4576   res = pr_fs_fgetsize(fd, &fs_sz);
4577   fail_unless(res < 0, "Failed to handle bad file descriptor");
4578   fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
4579     strerror(errno), errno);
4580 
4581   mark_point();
4582   fd = 0;
4583   fs_sz = 0;
4584   res = pr_fs_fgetsize(fd, NULL);
4585   fail_unless(res < 0, "Failed to handle null size argument");
4586   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4587     strerror(errno), errno);
4588 
4589   mark_point();
4590   fd = 0;
4591   fs_sz = 0;
4592   res = pr_fs_fgetsize(fd, &fs_sz);
4593   fail_unless(res == 0, "Failed to get fs size for fd %d: %s", fd,
4594     strerror(errno));
4595 }
4596 END_TEST
4597 
START_TEST(fs_fadvise_test)4598 START_TEST (fs_fadvise_test) {
4599   int advice, fd = -1;
4600   off_t off = 0, len = 0;
4601 
4602   /* We make these function calls to exercise the code paths, even
4603    * though there's no good way to verify the behavior changed.
4604    */
4605 
4606   advice = PR_FS_FADVISE_NORMAL;
4607   pr_fs_fadvise(fd, off, len, advice);
4608 
4609   advice = PR_FS_FADVISE_RANDOM;
4610   pr_fs_fadvise(fd, off, len, advice);
4611 
4612   advice = PR_FS_FADVISE_SEQUENTIAL;
4613   pr_fs_fadvise(fd, off, len, advice);
4614 
4615   advice = PR_FS_FADVISE_WILLNEED;
4616   pr_fs_fadvise(fd, off, len, advice);
4617 
4618   advice = PR_FS_FADVISE_DONTNEED;
4619   pr_fs_fadvise(fd, off, len, advice);
4620 
4621   advice = PR_FS_FADVISE_NOREUSE;
4622   pr_fs_fadvise(fd, off, len, advice);
4623 }
4624 END_TEST
4625 
START_TEST(fs_have_access_test)4626 START_TEST (fs_have_access_test) {
4627   int res;
4628   struct stat st;
4629   uid_t uid;
4630   gid_t gid;
4631   array_header *suppl_gids;
4632 
4633   mark_point();
4634   res = pr_fs_have_access(NULL, R_OK, 0, 0, NULL);
4635   fail_unless(res < 0, "Failed to handle null stat");
4636   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4637     strerror(errno), errno);
4638 
4639   memset(&st, 0, sizeof(struct stat));
4640 
4641   mark_point();
4642   res = pr_fs_have_access(&st, R_OK, 0, 0, NULL);
4643   fail_unless(res == 0, "Failed to handle root access: %s", strerror(errno));
4644 
4645   /* Use cases: no matching UID or GID; R_OK, W_OK, X_OK. */
4646   memset(&st, 0, sizeof(struct stat));
4647   uid = 1;
4648   gid = 1;
4649 
4650   mark_point();
4651   res = pr_fs_have_access(&st, R_OK, uid, gid, NULL);
4652   fail_unless(res < 0, "Failed to handle missing other R_OK access");
4653   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4654     strerror(errno), errno);
4655 
4656   mark_point();
4657   res = pr_fs_have_access(&st, W_OK, uid, gid, NULL);
4658   fail_unless(res < 0, "Failed to handle missing other W_OK access");
4659   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4660     strerror(errno), errno);
4661 
4662   mark_point();
4663   res = pr_fs_have_access(&st, X_OK, uid, gid, NULL);
4664   fail_unless(res < 0, "Failed to handle missing other X_OK access");
4665   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4666     strerror(errno), errno);
4667 
4668   st.st_mode = S_IFMT|S_IROTH|S_IWOTH|S_IXOTH;
4669 
4670   mark_point();
4671   res = pr_fs_have_access(&st, R_OK, uid, gid, NULL);
4672   fail_unless(res == 0, "Failed to handle other R_OK access: %s",
4673     strerror(errno));
4674 
4675   mark_point();
4676   res = pr_fs_have_access(&st, W_OK, uid, gid, NULL);
4677   fail_unless(res == 0, "Failed to handle other W_OK access: %s",
4678     strerror(errno));
4679 
4680   mark_point();
4681   res = pr_fs_have_access(&st, X_OK, uid, gid, NULL);
4682   fail_unless(res == 0, "Failed to handle other X_OK access: %s",
4683     strerror(errno));
4684 
4685   /* Use cases: matching UID, not GID; R_OK, W_OK, X_OK. */
4686   memset(&st, 0, sizeof(struct stat));
4687 
4688   st.st_uid = uid;
4689 
4690   mark_point();
4691   res = pr_fs_have_access(&st, R_OK, uid, gid, NULL);
4692   fail_unless(res < 0, "Failed to handle missing user R_OK access");
4693   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4694     strerror(errno), errno);
4695 
4696   mark_point();
4697   res = pr_fs_have_access(&st, W_OK, uid, gid, NULL);
4698   fail_unless(res < 0, "Failed to handle missing user W_OK access");
4699   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4700     strerror(errno), errno);
4701 
4702   mark_point();
4703   res = pr_fs_have_access(&st, X_OK, uid, gid, NULL);
4704   fail_unless(res < 0, "Failed to handle missing user X_OK access");
4705   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4706     strerror(errno), errno);
4707 
4708   st.st_mode = S_IFMT|S_IRUSR|S_IWUSR|S_IXUSR;
4709 
4710   mark_point();
4711   res = pr_fs_have_access(&st, R_OK, uid, gid, NULL);
4712   fail_unless(res == 0, "Failed to handle user R_OK access: %s",
4713     strerror(errno));
4714 
4715   mark_point();
4716   res = pr_fs_have_access(&st, W_OK, uid, gid, NULL);
4717   fail_unless(res == 0, "Failed to handle user W_OK access: %s",
4718     strerror(errno));
4719 
4720   mark_point();
4721   res = pr_fs_have_access(&st, X_OK, uid, gid, NULL);
4722   fail_unless(res == 0, "Failed to handle user X_OK access: %s",
4723     strerror(errno));
4724 
4725   /* Use cases: matching GID, not UID; R_OK, W_OK, X_OK. */
4726   memset(&st, 0, sizeof(struct stat));
4727 
4728   st.st_gid = gid;
4729 
4730   mark_point();
4731   res = pr_fs_have_access(&st, R_OK, uid, gid, NULL);
4732   fail_unless(res < 0, "Failed to handle missing group R_OK access");
4733   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4734     strerror(errno), errno);
4735 
4736   mark_point();
4737   res = pr_fs_have_access(&st, W_OK, uid, gid, NULL);
4738   fail_unless(res < 0, "Failed to handle missing group W_OK access");
4739   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4740     strerror(errno), errno);
4741 
4742   mark_point();
4743   res = pr_fs_have_access(&st, X_OK, uid, gid, NULL);
4744   fail_unless(res < 0, "Failed to handle missing group X_OK access");
4745   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4746     strerror(errno), errno);
4747 
4748   st.st_mode = S_IFMT|S_IRGRP|S_IWGRP|S_IXGRP;
4749 
4750   mark_point();
4751   res = pr_fs_have_access(&st, R_OK, uid, gid, NULL);
4752   fail_unless(res == 0, "Failed to handle group R_OK access: %s",
4753     strerror(errno));
4754 
4755   mark_point();
4756   res = pr_fs_have_access(&st, W_OK, uid, gid, NULL);
4757   fail_unless(res == 0, "Failed to handle group W_OK access: %s",
4758     strerror(errno));
4759 
4760   mark_point();
4761   res = pr_fs_have_access(&st, X_OK, uid, gid, NULL);
4762   fail_unless(res == 0, "Failed to handle group X_OK access: %s",
4763     strerror(errno));
4764 
4765   /* Use cases: matching suppl GID, not UID; R_OK, W_OK, X_OK. */
4766   memset(&st, 0, sizeof(struct stat));
4767 
4768   suppl_gids = make_array(p, 1, sizeof(gid_t));
4769   *((gid_t *) push_array(suppl_gids)) = 100;
4770   *((gid_t *) push_array(suppl_gids)) = gid;
4771   st.st_gid = gid;
4772 
4773   mark_point();
4774   res = pr_fs_have_access(&st, R_OK, uid, 0, suppl_gids);
4775   fail_unless(res < 0, "Failed to handle missing group R_OK access");
4776   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4777     strerror(errno), errno);
4778 
4779   mark_point();
4780   res = pr_fs_have_access(&st, W_OK, uid, 0, suppl_gids);
4781   fail_unless(res < 0, "Failed to handle missing group W_OK access");
4782   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4783     strerror(errno), errno);
4784 
4785   mark_point();
4786   res = pr_fs_have_access(&st, X_OK, uid, 0, suppl_gids);
4787   fail_unless(res < 0, "Failed to handle missing group X_OK access");
4788   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
4789     strerror(errno), errno);
4790 
4791   st.st_mode = S_IFMT|S_IRGRP|S_IWGRP|S_IXGRP;
4792 
4793   mark_point();
4794   res = pr_fs_have_access(&st, R_OK, uid, 0, suppl_gids);
4795   fail_unless(res == 0, "Failed to handle group R_OK access: %s",
4796     strerror(errno));
4797 
4798   mark_point();
4799   res = pr_fs_have_access(&st, W_OK, uid, 0, suppl_gids);
4800   fail_unless(res == 0, "Failed to handle group W_OK access: %s",
4801     strerror(errno));
4802 
4803   mark_point();
4804   res = pr_fs_have_access(&st, X_OK, uid, 0, suppl_gids);
4805   fail_unless(res == 0, "Failed to handle group X_OK access: %s",
4806     strerror(errno));
4807 }
4808 END_TEST
4809 
START_TEST(fs_is_nfs_test)4810 START_TEST (fs_is_nfs_test) {
4811   int res;
4812 
4813   res = pr_fs_is_nfs(NULL);
4814   fail_unless(res < 0, "Failed to handle null argument");
4815   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4816     strerror(errno), errno);
4817 
4818   res = pr_fs_is_nfs("/tmp");
4819   fail_unless(res == FALSE, "Expected FALSE, got %d", res);
4820 }
4821 END_TEST
4822 
START_TEST(fs_valid_path_test)4823 START_TEST (fs_valid_path_test) {
4824   int res;
4825   const char *path;
4826   pr_fs_t *fs;
4827 
4828   res = pr_fs_valid_path(NULL);
4829   fail_unless(res < 0, "Failed to handle null arguments");
4830   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4831     strerror(errno), errno);
4832 
4833   path = "/";
4834   res = pr_fs_valid_path(path);
4835   fail_unless(res == 0, "'%s' is not a valid path: %s", path, strerror(errno));
4836 
4837   path = ":tmp";
4838   res = pr_fs_valid_path(path);
4839   fail_unless(res < 0, "Failed to handle invalid path");
4840   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4841     strerror(errno), errno);
4842 
4843   fs = pr_register_fs(p, "testsuite", "&");
4844   fail_unless(fs != NULL, "Failed to register FS: %s", strerror(errno));
4845 
4846   fs = pr_register_fs(p, "testsuite2", ":");
4847   fail_unless(fs != NULL, "Failed to register FS: %s", strerror(errno));
4848 
4849   res = pr_fs_valid_path(path);
4850   fail_unless(res == 0, "Failed to handle valid path: %s", strerror(errno));
4851 
4852   (void) pr_remove_fs("/testsuite2");
4853   (void) pr_remove_fs("/testsuite");
4854 }
4855 END_TEST
4856 
START_TEST(fsio_smkdir_test)4857 START_TEST (fsio_smkdir_test) {
4858   int res;
4859   const char *path;
4860   mode_t mode = 0755;
4861   uid_t uid = getuid();
4862   gid_t gid = getgid();
4863 
4864   res = pr_fsio_smkdir(NULL, NULL, mode, uid, gid);
4865   fail_unless(res < 0, "Failed to handle null arguments");
4866   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4867     strerror(errno), errno);
4868 
4869   res = pr_fsio_smkdir(p, NULL, mode, uid, gid);
4870   fail_unless(res < 0, "Failed to handle null path");
4871   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4872     strerror(errno), errno);
4873 
4874   path = fsio_testdir_path;
4875   res = pr_fsio_smkdir(p, path, mode, uid, gid);
4876   fail_unless(res == 0, "Failed to securely create '%s': %s", fsio_testdir_path,
4877     strerror(errno));
4878   (void) pr_fsio_rmdir(fsio_testdir_path);
4879 
4880   res = pr_fsio_set_use_mkdtemp(-1);
4881   fail_unless(res < 0, "Failed to handle invalid setting");
4882   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4883     strerror(errno), errno);
4884 
4885 #ifdef HAVE_MKDTEMP
4886   res = pr_fsio_set_use_mkdtemp(FALSE);
4887   fail_unless(res == TRUE, "Expected TRUE, got %d", res);
4888 
4889   res = pr_fsio_smkdir(p, path, mode, uid, gid);
4890   fail_unless(res == 0, "Failed to securely create '%s': %s", fsio_testdir_path,
4891     strerror(errno));
4892   (void) pr_fsio_rmdir(fsio_testdir_path);
4893 
4894   res = pr_fsio_set_use_mkdtemp(TRUE);
4895   fail_unless(res == FALSE, "Expected FALSE, got %d", res);
4896 #else
4897   res = pr_fsio_set_use_mkdtemp(TRUE);
4898   fail_unless(res == FALSE, "Expected FALSE, got %d", res);
4899 
4900   res = pr_fsio_set_use_mkdtemp(FALSE);
4901   fail_unless(res == FALSE, "Expected FALSE, got %d", res);
4902 #endif /* HAVE_MKDTEMP */
4903 
4904   (void) pr_fsio_rmdir(fsio_testdir_path);
4905 }
4906 END_TEST
4907 
START_TEST(fsio_getpipebuf_test)4908 START_TEST (fsio_getpipebuf_test) {
4909   char *res;
4910   int fd = -1;
4911   long bufsz = 0;
4912 
4913   res = pr_fsio_getpipebuf(NULL, fd, NULL);
4914   fail_unless(res == NULL, "Failed to handle null arguments");
4915   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4916     strerror(errno), errno);
4917 
4918   res = pr_fsio_getpipebuf(p, fd, NULL);
4919   fail_unless(res == NULL, "Failed to handle bad file descriptor");
4920   fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
4921     strerror(errno), errno);
4922 
4923   fd = 0;
4924   res = pr_fsio_getpipebuf(p, fd, NULL);
4925   fail_unless(res != NULL, "Failed to get pipebuf for fd %d: %s", fd,
4926     strerror(errno));
4927 
4928   res = pr_fsio_getpipebuf(p, fd, &bufsz);
4929   fail_unless(res != NULL, "Failed to get pipebuf for fd %d: %s", fd,
4930     strerror(errno));
4931   fail_unless(bufsz > 0, "Expected >0, got %ld", bufsz);
4932 }
4933 END_TEST
4934 
START_TEST(fsio_gets_test)4935 START_TEST (fsio_gets_test) {
4936   char buf[PR_TUNABLE_PATH_MAX], *res, *text;
4937   pr_fh_t *fh;
4938   int res2;
4939 
4940   res = pr_fsio_gets(NULL, 0, NULL);
4941   fail_unless(res == NULL, "Failed to handle null arguments");
4942   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4943     strerror(errno), errno);
4944 
4945   res = pr_fsio_gets(buf, 0, NULL);
4946   fail_unless(res == NULL, "Failed to handle null file handle");
4947   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4948     strerror(errno), errno);
4949 
4950   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_RDWR);
4951   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
4952     strerror(errno));
4953 
4954   res = pr_fsio_gets(buf, 0, fh);
4955   fail_unless(res == NULL, "Failed to handle zero buffer length");
4956   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4957     strerror(errno), errno);
4958 
4959   text = "Hello, World!\n";
4960   res2 = pr_fsio_puts(text, fh);
4961   fail_if(res2 < 0, "Error writing to '%s': %s", fsio_test_path,
4962     strerror(errno));
4963   pr_fsio_fsync(fh);
4964   pr_fsio_lseek(fh, 0, SEEK_SET);
4965 
4966   memset(buf, '\0', sizeof(buf));
4967   res = pr_fsio_gets(buf, sizeof(buf)-1, fh);
4968   fail_if(res == NULL, "Failed reading from '%s': %s", fsio_test_path,
4969     strerror(errno));
4970   fail_unless(strcmp(res, text) == 0, "Expected '%s', got '%s'", text, res);
4971 
4972   (void) pr_fsio_close(fh);
4973   (void) pr_fsio_unlink(fsio_test_path);
4974 }
4975 END_TEST
4976 
START_TEST(fsio_getline_test)4977 START_TEST (fsio_getline_test) {
4978   char buf[PR_TUNABLE_PATH_MAX], *res, *text;
4979   pr_fh_t *fh;
4980   unsigned int lineno = 0;
4981   int res2;
4982 
4983   res = pr_fsio_getline(NULL, 0, NULL, NULL);
4984   fail_unless(res == NULL, "Failed to handle null arguments");
4985   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4986     strerror(errno), errno);
4987 
4988   res = pr_fsio_getline(buf, 0, NULL, NULL);
4989   fail_unless(res == NULL, "Failed to handle file handle");
4990   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4991     strerror(errno), errno);
4992 
4993   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_RDWR);
4994   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
4995     strerror(errno));
4996 
4997   res = pr_fsio_getline(buf, 0, fh, NULL);
4998   fail_unless(res == NULL, "Failed to handle zero buffer length");
4999   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
5000     strerror(errno), errno);
5001 
5002   res = pr_fsio_getline(buf, sizeof(buf)-1, fh, &lineno);
5003   fail_unless(res == NULL, "Failed to read empty '%s' file", fsio_test_path);
5004 
5005   text = "Hello, World!\n";
5006   res2 = pr_fsio_puts(text, fh);
5007   fail_if(res2 < 0, "Error writing to '%s': %s", fsio_test_path,
5008     strerror(errno));
5009 
5010   text = "How\\\n are you?\n";
5011   res2 = pr_fsio_puts(text, fh);
5012   fail_if(res2 < 0, "Error writing to '%s': %s", fsio_test_path,
5013     strerror(errno));
5014 
5015   pr_fsio_fsync(fh);
5016   pr_fsio_lseek(fh, 0, SEEK_SET);
5017 
5018   memset(buf, '\0', sizeof(buf));
5019   res = pr_fsio_getline(buf, sizeof(buf)-1, fh, &lineno);
5020   fail_if(res == NULL, "Failed to read line from '%s': %s", fsio_test_path,
5021     strerror(errno));
5022   fail_unless(strcmp(res, "Hello, World!\n") == 0,
5023     "Expected 'Hello, World!\n', got '%s'", res);
5024   fail_unless(lineno == 1, "Expected 1, got %u", lineno);
5025 
5026   memset(buf, '\0', sizeof(buf));
5027   res = pr_fsio_getline(buf, sizeof(buf)-1, fh, &lineno);
5028   fail_if(res == NULL, "Failed to read line from '%s': %s", fsio_test_path,
5029     strerror(errno));
5030   fail_unless(strcmp(res, "How are you?\n") == 0,
5031     "Expected 'How are you?\n', got '%s'", res);
5032   fail_unless(lineno == 3, "Expected 3, got %u", lineno);
5033 
5034   (void) pr_fsio_close(fh);
5035   (void) pr_fsio_unlink(fsio_test_path);
5036 }
5037 END_TEST
5038 
START_TEST(fsio_puts_test)5039 START_TEST (fsio_puts_test) {
5040   int res;
5041   const char *text;
5042   pr_fh_t *fh;
5043 
5044   res = pr_fsio_puts(NULL, NULL);
5045   fail_unless(res < 0, "Failed to handle null arguments");
5046   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
5047     strerror(errno), errno);
5048 
5049   text = "Hello, World!\n";
5050   res = pr_fsio_puts(text, NULL);
5051   fail_unless(res < 0, "Failed to handle null file handle");
5052   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
5053     strerror(errno), errno);
5054 
5055   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
5056   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
5057     strerror(errno));
5058 
5059   res = pr_fsio_puts(NULL, fh);
5060   fail_unless(res < 0, "Failed to handle null buffer");
5061   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
5062     strerror(errno), errno);
5063 
5064   (void) pr_fsio_close(fh);
5065   (void) pr_fsio_unlink(fsio_test_path);
5066 }
5067 END_TEST
5068 
START_TEST(fsio_blocking_test)5069 START_TEST (fsio_blocking_test) {
5070   int fd, res;
5071   pr_fh_t *fh;
5072 
5073   res = pr_fsio_set_block(NULL);
5074   fail_unless(res < 0, "Failed to handle null argument");
5075   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
5076     strerror(errno), errno);
5077 
5078   fh = pr_fsio_open(fsio_test_path, O_CREAT|O_EXCL|O_WRONLY);
5079   fail_unless(fh != NULL, "Failed to open '%s': %s", fsio_test_path,
5080     strerror(errno));
5081 
5082   fd = fh->fh_fd;
5083   fh->fh_fd = -1;
5084 
5085   res = pr_fsio_set_block(fh);
5086   fail_unless(res < 0, "Failed to handle bad file descriptor");
5087   fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
5088     strerror(errno), errno);
5089 
5090   fh->fh_fd = fd;
5091   res = pr_fsio_set_block(fh);
5092   fail_unless(res == 0, "Failed to make '%s' blocking: %s", fsio_test_path,
5093     strerror(errno));
5094 
5095   (void) pr_fsio_close(fh);
5096   (void) pr_fsio_unlink(fsio_test_path);
5097 }
5098 END_TEST
5099 
tests_get_fsio_suite(void)5100 Suite *tests_get_fsio_suite(void) {
5101   Suite *suite;
5102   TCase *testcase;
5103 
5104   suite = suite_create("fsio");
5105 
5106   testcase = tcase_create("base");
5107   tcase_add_checked_fixture(testcase, set_up, tear_down);
5108 
5109   /* Main FSIO API tests */
5110   tcase_add_test(testcase, fsio_sys_open_test);
5111   tcase_add_test(testcase, fsio_sys_open_canon_test);
5112   tcase_add_test(testcase, fsio_sys_open_chroot_guard_test);
5113   tcase_add_test(testcase, fsio_sys_close_test);
5114   tcase_add_test(testcase, fsio_sys_unlink_test);
5115   tcase_add_test(testcase, fsio_sys_unlink_chroot_guard_test);
5116   tcase_add_test(testcase, fsio_sys_stat_test);
5117   tcase_add_test(testcase, fsio_sys_fstat_test);
5118   tcase_add_test(testcase, fsio_sys_read_test);
5119   tcase_add_test(testcase, fsio_sys_pread_test);
5120   tcase_add_test(testcase, fsio_sys_write_test);
5121   tcase_add_test(testcase, fsio_sys_pwrite_test);
5122   tcase_add_test(testcase, fsio_sys_lseek_test);
5123   tcase_add_test(testcase, fsio_sys_link_test);
5124   tcase_add_test(testcase, fsio_sys_link_chroot_guard_test);
5125   tcase_add_test(testcase, fsio_sys_symlink_test);
5126   tcase_add_test(testcase, fsio_sys_symlink_chroot_guard_test);
5127   tcase_add_test(testcase, fsio_sys_readlink_test);
5128   tcase_add_test(testcase, fsio_sys_lstat_test);
5129   tcase_add_test(testcase, fsio_sys_access_dir_test);
5130   tcase_add_test(testcase, fsio_sys_access_file_test);
5131   tcase_add_test(testcase, fsio_sys_faccess_test);
5132   tcase_add_test(testcase, fsio_sys_truncate_test);
5133   tcase_add_test(testcase, fsio_sys_truncate_chroot_guard_test);
5134   tcase_add_test(testcase, fsio_sys_ftruncate_test);
5135   tcase_add_test(testcase, fsio_sys_chmod_test);
5136   tcase_add_test(testcase, fsio_sys_chmod_chroot_guard_test);
5137   tcase_add_test(testcase, fsio_sys_fchmod_test);
5138   tcase_add_test(testcase, fsio_sys_chown_test);
5139   tcase_add_test(testcase, fsio_sys_chown_chroot_guard_test);
5140   tcase_add_test(testcase, fsio_sys_fchown_test);
5141   tcase_add_test(testcase, fsio_sys_lchown_test);
5142   tcase_add_test(testcase, fsio_sys_lchown_chroot_guard_test);
5143   tcase_add_test(testcase, fsio_sys_rename_test);
5144   tcase_add_test(testcase, fsio_sys_rename_chroot_guard_test);
5145   tcase_add_test(testcase, fsio_sys_utimes_test);
5146   tcase_add_test(testcase, fsio_sys_utimes_chroot_guard_test);
5147   tcase_add_test(testcase, fsio_sys_futimes_test);
5148   tcase_add_test(testcase, fsio_sys_fsync_test);
5149 
5150   /* Extended attribute tests */
5151   tcase_add_test(testcase, fsio_sys_getxattr_test);
5152   tcase_add_test(testcase, fsio_sys_lgetxattr_test);
5153   tcase_add_test(testcase, fsio_sys_fgetxattr_test);
5154   tcase_add_test(testcase, fsio_sys_listxattr_test);
5155   tcase_add_test(testcase, fsio_sys_llistxattr_test);
5156   tcase_add_test(testcase, fsio_sys_flistxattr_test);
5157   tcase_add_test(testcase, fsio_sys_removexattr_test);
5158   tcase_add_test(testcase, fsio_sys_lremovexattr_test);
5159   tcase_add_test(testcase, fsio_sys_fremovexattr_test);
5160   tcase_add_test(testcase, fsio_sys_setxattr_test);
5161   tcase_add_test(testcase, fsio_sys_lsetxattr_test);
5162   tcase_add_test(testcase, fsio_sys_fsetxattr_test);
5163 
5164   tcase_add_test(testcase, fsio_sys_mkdir_test);
5165   tcase_add_test(testcase, fsio_sys_mkdir_chroot_guard_test);
5166   tcase_add_test(testcase, fsio_sys_rmdir_test);
5167   tcase_add_test(testcase, fsio_sys_rmdir_chroot_guard_test);
5168   tcase_add_test(testcase, fsio_sys_chdir_test);
5169   tcase_add_test(testcase, fsio_sys_chdir_canon_test);
5170   tcase_add_test(testcase, fsio_sys_chroot_test);
5171   tcase_add_test(testcase, fsio_sys_opendir_test);
5172   tcase_add_test(testcase, fsio_sys_readdir_test);
5173   tcase_add_test(testcase, fsio_sys_closedir_test);
5174 
5175   /* FSIO with error tests */
5176   tcase_add_test(testcase, fsio_sys_chmod_with_error_test);
5177   tcase_add_test(testcase, fsio_sys_chown_with_error_test);
5178   tcase_add_test(testcase, fsio_sys_chroot_with_error_test);
5179   tcase_add_test(testcase, fsio_sys_close_with_error_test);
5180   tcase_add_test(testcase, fsio_sys_fchmod_with_error_test);
5181   tcase_add_test(testcase, fsio_sys_fchown_with_error_test);
5182   tcase_add_test(testcase, fsio_sys_lchown_with_error_test);
5183   tcase_add_test(testcase, fsio_sys_lstat_with_error_test);
5184   tcase_add_test(testcase, fsio_sys_mkdir_with_error_test);
5185   tcase_add_test(testcase, fsio_sys_open_with_error_test);
5186   tcase_add_test(testcase, fsio_sys_read_with_error_test);
5187   tcase_add_test(testcase, fsio_sys_rename_with_error_test);
5188   tcase_add_test(testcase, fsio_sys_rmdir_with_error_test);
5189   tcase_add_test(testcase, fsio_sys_stat_with_error_test);
5190   tcase_add_test(testcase, fsio_sys_unlink_with_error_test);
5191   tcase_add_test(testcase, fsio_sys_write_with_error_test);
5192 
5193   /* FSIO statcache tests */
5194   tcase_add_test(testcase, fsio_statcache_clear_cache_test);
5195   tcase_add_test(testcase, fsio_statcache_cache_hit_test);
5196   tcase_add_test(testcase, fsio_statcache_negative_cache_test);
5197   tcase_add_test(testcase, fsio_statcache_expired_test);
5198   tcase_add_test(testcase, fsio_statcache_dump_test);
5199 
5200   /* Custom FSIO management tests */
5201   tcase_add_test(testcase, fs_create_fs_test);
5202   tcase_add_test(testcase, fs_insert_fs_test);
5203   tcase_add_test(testcase, fs_get_fs_test);
5204   tcase_add_test(testcase, fs_unmount_fs_test);
5205   tcase_add_test(testcase, fs_remove_fs_test);
5206   tcase_add_test(testcase, fs_register_fs_test);
5207   tcase_add_test(testcase, fs_unregister_fs_test);
5208   tcase_add_test(testcase, fs_resolve_fs_map_test);
5209 #if defined(PR_USE_DEVEL)
5210   tcase_add_test(testcase, fs_dump_fs_test);
5211 #endif /* PR_USE_DEVEL */
5212 
5213   /* Custom FSIO tests */
5214   tcase_add_test(testcase, fsio_custom_chroot_test);
5215 
5216   /* Misc */
5217   tcase_add_test(testcase, fs_clean_path_test);
5218   tcase_add_test(testcase, fs_clean_path2_test);
5219 
5220   tcase_add_test(testcase, fs_dircat_test);
5221   tcase_add_test(testcase, fs_setcwd_test);
5222   tcase_add_test(testcase, fs_glob_test);
5223   tcase_add_test(testcase, fs_copy_file_test);
5224   tcase_add_test(testcase, fs_copy_file2_test);
5225   tcase_add_test(testcase, fs_interpolate_test);
5226   tcase_add_test(testcase, fs_resolve_partial_test);
5227   tcase_add_test(testcase, fs_resolve_path_test);
5228   tcase_add_test(testcase, fs_use_encoding_test);
5229   tcase_add_test(testcase, fs_decode_path2_test);
5230   tcase_add_test(testcase, fs_encode_path_test);
5231   tcase_add_test(testcase, fs_split_path_test);
5232   tcase_add_test(testcase, fs_join_path_test);
5233   tcase_add_test(testcase, fs_virtual_path_test);
5234 #if 0
5235   tcase_add_test(testcase, fs_close_extra_fds_test);
5236 #endif
5237   tcase_add_test(testcase, fs_get_usable_fd_test);
5238   tcase_add_test(testcase, fs_get_usable_fd2_test);
5239   tcase_add_test(testcase, fs_getsize_test);
5240   tcase_add_test(testcase, fs_getsize2_test);
5241   tcase_add_test(testcase, fs_fgetsize_test);
5242   tcase_add_test(testcase, fs_fadvise_test);
5243   tcase_add_test(testcase, fs_have_access_test);
5244 #if defined(HAVE_STATFS_F_TYPE) || defined(HAVE_STATFS_F_FSTYPENAME)
5245   tcase_add_test(testcase, fs_is_nfs_test);
5246 #endif
5247   tcase_add_test(testcase, fs_valid_path_test);
5248   tcase_add_test(testcase, fsio_smkdir_test);
5249   tcase_add_test(testcase, fsio_getpipebuf_test);
5250   tcase_add_test(testcase, fsio_gets_test);
5251   tcase_add_test(testcase, fsio_getline_test);
5252   tcase_add_test(testcase, fsio_puts_test);
5253   tcase_add_test(testcase, fsio_blocking_test);
5254 
5255   suite_add_tcase(suite, testcase);
5256   return suite;
5257 }
5258