blob: 230a5d71b0dad2b2064fa6eda1e7a7a7f85ea787 [file] [log] [blame] [edit]
// 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 <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fbl/unique_fd.h>
#include "src/storage/fs_test/fs_test_fixture.h"
namespace fs_test {
namespace {
using FcntlTest = FilesystemTest;
TEST_P(FcntlTest, FcntlAppend) {
fbl::unique_fd fd(open(GetPath("file").c_str(), 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)), static_cast<ssize_t>(sizeof(buf)));
ASSERT_EQ(lseek(fd.get(), 0, SEEK_SET), 0);
ASSERT_EQ(write(fd.get(), buf, sizeof(buf)), static_cast<ssize_t>(sizeof(buf)));
struct stat sb;
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, static_cast<off_t>(sizeof(buf) * 2));
// Use F_GETFL; observe O_APPEND
int flags = fcntl(fd.get(), F_GETFL);
ASSERT_GT(flags, -1);
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);
// Use F_GETFL; observe O_APPEND has been turned off
flags = fcntl(fd.get(), F_GETFL);
ASSERT_GT(flags, -1);
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)), static_cast<ssize_t>(sizeof(buf)));
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, static_cast<off_t>(sizeof(buf) * 2));
// Clean up
ASSERT_EQ(close(fd.release()), 0);
ASSERT_EQ(unlink(GetPath("file").c_str()), 0);
}
TEST_P(FcntlTest, FcntlAccessBits) {
fbl::unique_fd fd(open(GetPath("file").c_str(), 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)), static_cast<ssize_t>(sizeof(buf)));
struct stat sb;
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, static_cast<off_t>(sizeof(buf)));
// Use F_GETFL; observe O_APPEND
int flags = fcntl(fd.get(), F_GETFL);
ASSERT_GT(flags, -1);
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);
// 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)), static_cast<ssize_t>(sizeof(buf)));
ASSERT_EQ(fstat(fd.get(), &sb), 0);
ASSERT_EQ(sb.st_size, static_cast<off_t>(sizeof(buf) * 2));
// Clean up
ASSERT_EQ(close(fd.release()), 0);
ASSERT_EQ(unlink(GetPath("file").c_str()), 0);
}
INSTANTIATE_TEST_SUITE_P(/*no prefix*/, FcntlTest, testing::ValuesIn(AllTestFilesystems()),
testing::PrintToStringParamName());
} // namespace
} // namespace fs_test