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 18bool test_fcntl_append(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 62bool test_fcntl_access_bits(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 101RUN_FOR_ALL_FILESYSTEMS(fcntl_tests, 102 RUN_TEST_MEDIUM(test_fcntl_append) 103 RUN_TEST_MEDIUM(test_fcntl_access_bits) 104) 105