1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <fcntl.h>
6 #include <limits.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12
13 #include <zircon/syscalls.h>
14 #include <unittest/unittest.h>
15
16 #include "filesystems.h"
17
TestFcntlAppend(void)18 bool TestFcntlAppend(void) {
19 BEGIN_TEST;
20
21 int fd = open("::file", O_APPEND | O_RDWR | O_CREAT, 0644);
22 ASSERT_GT(fd, 0);
23
24 // Do a quick check that O_APPEND is appending
25 char buf[5];
26 memset(buf, 'a', sizeof(buf));
27 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
28 ASSERT_EQ(write(fd, buf, sizeof(buf)), sizeof(buf));
29 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
30 ASSERT_EQ(write(fd, buf, sizeof(buf)), sizeof(buf));
31 struct stat sb;
32 ASSERT_EQ(fstat(fd, &sb), 0);
33 ASSERT_EQ(sb.st_size, sizeof(buf) * 2);
34
35 // Use F_GETFL; observe O_APPEND
36 int flags = fcntl(fd, F_GETFL);
37 ASSERT_GT(flags, -1, "Fcntl failed");
38 ASSERT_EQ(flags & O_ACCMODE, O_RDWR, "Access mode flags did not match");
39 ASSERT_EQ(flags & ~O_ACCMODE, O_APPEND, "Status flags did not match");
40
41 // Use F_SETFL; turn off O_APPEND
42 ASSERT_EQ(fcntl(fd, F_SETFL, flags & ~O_APPEND), 0, "Fcntl failed");
43
44 // Use F_GETFL; observe O_APPEND has been turned off
45 flags = fcntl(fd, F_GETFL);
46 ASSERT_GT(flags, -1, "Fcntl failed");
47 ASSERT_EQ(flags & O_ACCMODE, O_RDWR, "Access mode flags did not match");
48 ASSERT_EQ(flags & ~O_ACCMODE, 0, "Status flags did not match");
49
50 // Write to the file, verify it is no longer appending.
51 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
52 ASSERT_EQ(write(fd, buf, sizeof(buf)), sizeof(buf));
53 ASSERT_EQ(fstat(fd, &sb), 0);
54 ASSERT_EQ(sb.st_size, sizeof(buf) * 2);
55
56 // Clean up
57 ASSERT_EQ(close(fd), 0);
58 ASSERT_EQ(unlink("::file"), 0);
59 END_TEST;
60 }
61
TestFcntlAccessBits(void)62 bool TestFcntlAccessBits(void) {
63 BEGIN_TEST;
64
65 int fd = open("::file", O_APPEND | O_RDWR | O_CREAT, 0644);
66 ASSERT_GT(fd, 0);
67
68 // Do a quick check that we can write
69 char buf[5];
70 memset(buf, 'a', sizeof(buf));
71 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
72 ASSERT_EQ(write(fd, buf, sizeof(buf)), sizeof(buf));
73 struct stat sb;
74 ASSERT_EQ(fstat(fd, &sb), 0);
75 ASSERT_EQ(sb.st_size, sizeof(buf));
76
77 // Use F_GETFL; observe O_APPEND
78 int flags = fcntl(fd, F_GETFL);
79 ASSERT_GT(flags, -1, "Fcntl failed");
80 ASSERT_EQ(flags & O_ACCMODE, O_RDWR, "Access mode flags did not match");
81 ASSERT_EQ(flags & ~O_ACCMODE, O_APPEND, "Status flags did not match");
82
83 // Use F_SETFL; try to turn off everything except O_APPEND
84 // (if fcntl paid attention to access bits, this would make the file
85 // read-only).
86 ASSERT_EQ(fcntl(fd, F_SETFL, O_APPEND), 0, "Fcntl failed");
87
88 // We're still appending -- AND writable, because the access bits haven't
89 // changed.
90 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
91 ASSERT_EQ(write(fd, buf, sizeof(buf)), sizeof(buf));
92 ASSERT_EQ(fstat(fd, &sb), 0);
93 ASSERT_EQ(sb.st_size, sizeof(buf) * 2);
94
95 // Clean up
96 ASSERT_EQ(close(fd), 0);
97 ASSERT_EQ(unlink("::file"), 0);
98 END_TEST;
99 }
100
101 RUN_FOR_ALL_FILESYSTEMS(fcntl_tests,
102 RUN_TEST_MEDIUM(TestFcntlAppend)
103 RUN_TEST_MEDIUM(TestFcntlAccessBits)
104 )
105