blob: 06b690467153b1eac8a73633b2006cf05d29c4b1 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fbl/unique_fd.h>
#include <zircon/syscalls.h>
#include <unittest/unittest.h>
#include "filesystems.h"
bool TestFcntlAppend(void) {
BEGIN_TEST;
fbl::unique_fd fd(open("::file", O_APPEND | O_RDWR | O_CREAT, 0644));
ASSERT_TRUE(fd);
// Do a quick check that O_APPEND is appending
char buf[5];
memset(buf, 'a', sizeof(buf));
ASSERT_EQ(lseek(fd.get(), 0, SEEK_SET), 0);
ASSERT_EQ(write(fd.get(), buf, sizeof(buf)), sizeof(buf));
ASSERT_EQ(lseek(fd.get(), 0, SEEK_SET), 0);
ASSERT_EQ(write(fd.get(), buf, sizeof(buf)), sizeof(buf));
struct stat sb;
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, sizeof(buf) * 2);
// Use F_GETFL; observe O_APPEND
int flags = fcntl(fd.get(), F_GETFL);
ASSERT_GT(flags, -1, "Fcntl failed");
ASSERT_EQ(flags & O_ACCMODE, O_RDWR, "Access mode flags did not match");
ASSERT_EQ(flags & ~O_ACCMODE, O_APPEND, "Status flags did not match");
// Use F_SETFL; turn off O_APPEND
ASSERT_EQ(fcntl(fd.get(), F_SETFL, flags & ~O_APPEND), 0, "Fcntl failed");
// Use F_GETFL; observe O_APPEND has been turned off
flags = fcntl(fd.get(), F_GETFL);
ASSERT_GT(flags, -1, "Fcntl failed");
ASSERT_EQ(flags & O_ACCMODE, O_RDWR, "Access mode flags did not match");
ASSERT_EQ(flags & ~O_ACCMODE, 0, "Status flags did not match");
// Write to the file, verify it is no longer appending.
ASSERT_EQ(lseek(fd.get(), 0, SEEK_SET), 0);
ASSERT_EQ(write(fd.get(), buf, sizeof(buf)), sizeof(buf));
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, sizeof(buf) * 2);
// Clean up
ASSERT_EQ(close(fd.release()), 0);
ASSERT_EQ(unlink("::file"), 0);
END_TEST;
}
bool TestFcntlAccessBits(void) {
BEGIN_TEST;
fbl::unique_fd fd(open("::file", O_APPEND | O_RDWR | O_CREAT, 0644));
ASSERT_TRUE(fd);
// Do a quick check that we can write
char buf[5];
memset(buf, 'a', sizeof(buf));
ASSERT_EQ(lseek(fd.get(), 0, SEEK_SET), 0);
ASSERT_EQ(write(fd.get(), buf, sizeof(buf)), sizeof(buf));
struct stat sb;
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, sizeof(buf));
// Use F_GETFL; observe O_APPEND
int flags = fcntl(fd.get(), F_GETFL);
ASSERT_GT(flags, -1, "Fcntl failed");
ASSERT_EQ(flags & O_ACCMODE, O_RDWR, "Access mode flags did not match");
ASSERT_EQ(flags & ~O_ACCMODE, O_APPEND, "Status flags did not match");
// Use F_SETFL; try to turn off everything except O_APPEND
// (if fcntl paid attention to access bits, this would make the file
// read-only).
ASSERT_EQ(fcntl(fd.get(), F_SETFL, O_APPEND), 0, "Fcntl failed");
// We're still appending -- AND writable, because the access bits haven't
// changed.
ASSERT_EQ(lseek(fd.get(), 0, SEEK_SET), 0);
ASSERT_EQ(write(fd.get(), buf, sizeof(buf)), sizeof(buf));
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, sizeof(buf) * 2);
// Clean up
ASSERT_EQ(close(fd.release()), 0);
ASSERT_EQ(unlink("::file"), 0);
END_TEST;
}
RUN_FOR_ALL_FILESYSTEMS(fcntl_tests,
RUN_TEST_MEDIUM(TestFcntlAppend) RUN_TEST_MEDIUM(TestFcntlAccessBits))