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