Make File::close() public.

This commit is contained in:
Victor Zverovich 2014-05-03 15:04:14 -07:00
parent f516fb9cba
commit c6d83b1a3b
3 changed files with 53 additions and 34 deletions

View File

@ -171,13 +171,8 @@ bool IsClosedInternal(int fd) {
#endif #endif
TEST(FileTest, OpenFileInCtor) { TEST(FileTest, OpenFileInCtor) {
int fd = 0; File f(".travis.yml", File::RDONLY);
{ ASSERT_TRUE(IsOpen(f.get()));
File f(".travis.yml", File::RDONLY);
fd = f.get();
ASSERT_TRUE(IsOpen(fd));
}
EXPECT_CLOSED(fd);
} }
TEST(FileTest, OpenFileError) { TEST(FileTest, OpenFileError) {
@ -245,18 +240,36 @@ TEST(FileTest, CloseFileInDtor) {
File f(".travis.yml", File::RDONLY); File f(".travis.yml", File::RDONLY);
fd = f.get(); fd = f.get();
} }
FILE *f = fdopen(fd, "r"); EXPECT_CLOSED(fd);
int error_code = errno; }
if (f)
fclose(f); TEST(FileTest, DtorCloseError) {
EXPECT_TRUE(f == 0); File *f = new File(".travis.yml", File::RDONLY);
EXPECT_EQ(EBADF, error_code); // The close function must be called inside EXPECT_STDERR, otherwise
// the system may allocate freed file descriptor when redirecting the
// output in EXPECT_STDERR.
EXPECT_STDERR(close(f->get()); delete f,
FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
}
TEST(FileTest, Close) {
File f(".travis.yml", File::RDONLY);
int fd = f.get();
f.close();
EXPECT_EQ(-1, f.get());
EXPECT_CLOSED(fd);
} }
TEST(FileTest, CloseError) { TEST(FileTest, CloseError) {
File *fd = new File(".travis.yml", File::RDONLY); File *f = new File(".travis.yml", File::RDONLY);
EXPECT_STDERR(close(fd->get()); delete fd, fmt::SystemError error("", 0);
FormatSystemErrorMessage(EBADF, "cannot close file") + "\n"); std::string message = FormatSystemErrorMessage(EBADF, "cannot close file");
EXPECT_STDERR(
close(f->get());
try { f->close(); } catch (const fmt::SystemError &e) { error = e; }
delete f,
message + "\n");
EXPECT_EQ(message, error.what());
} }
// Attempts to read count characters from the file. // Attempts to read count characters from the file.
@ -287,17 +300,15 @@ TEST(FileTest, ReadError) {
TEST(FileTest, Write) { TEST(FileTest, Write) {
const char MESSAGE[] = "test"; const char MESSAGE[] = "test";
File read_end; File read_end, write_end;
{ File::pipe(read_end, write_end);
File write_end; enum { SIZE = sizeof(MESSAGE) - 1 };
File::pipe(read_end, write_end); std::streamsize offset = 0, count = 0;
enum { SIZE = sizeof(MESSAGE) - 1 }; do {
std::streamsize offset = 0, count = 0; count = write_end.write(MESSAGE + offset, SIZE - offset);
do { offset += count;
count = write_end.write(MESSAGE + offset, SIZE - offset); } while (offset < SIZE && count != 0);
offset += count; write_end = File(); // Close file.
} while (offset < SIZE && count != 0);
}
EXPECT_READ(read_end, MESSAGE); EXPECT_READ(read_end, MESSAGE);
} }
@ -355,7 +366,7 @@ TEST(FileTest, Pipe) {
File::pipe(read_end, write_end); File::pipe(read_end, write_end);
EXPECT_NE(-1, read_end.get()); EXPECT_NE(-1, read_end.get());
EXPECT_NE(-1, write_end.get()); EXPECT_NE(-1, write_end.get());
// TODO: try writing to write_fd and reading from read_fd // TODO: try writing to write_end and reading from read_end
} }
// TODO: test pipe // TODO: test pipe

View File

@ -63,13 +63,21 @@ File::File(const char *path, int oflag) {
fmt::ThrowSystemError(errno, "cannot open file {}") << path; fmt::ThrowSystemError(errno, "cannot open file {}") << path;
} }
File::~File() {
// Don't need to retry close in case of EINTR.
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (fd_ != -1 && ::FMT_POSIX(close(fd_)) != 0)
fmt::ReportSystemError(errno, "cannot close file");
}
void File::close() { void File::close() {
if (fd_ == -1) if (fd_ == -1)
return; return;
// Don't need to retry close in case of EINTR. // Don't need to retry close in case of EINTR.
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (::FMT_POSIX(close(fd_)) != 0) if (::FMT_POSIX(close(fd_)) != 0)
fmt::ReportSystemError(errno, "cannot close file"); fmt::ThrowSystemError(errno, "cannot close file");
fd_ = -1;
} }
std::streamsize File::read(void *buffer, std::size_t count) { std::streamsize File::read(void *buffer, std::size_t count) {

View File

@ -108,9 +108,6 @@ class File {
private: private:
int fd_; // File descriptor. int fd_; // File descriptor.
// Closes the file if its descriptor is not -1.
void close();
// Constructs a File object with a given descriptor. // Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {} explicit File(int fd) : fd_(fd) {}
@ -188,12 +185,15 @@ class File {
#endif #endif
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
~File() { close(); } ~File();
// Returns the file descriptor. // Returns the file descriptor.
// TODO: rename // TODO: rename to descriptor
int get() const FMT_NOEXCEPT(true) { return fd_; } int get() const FMT_NOEXCEPT(true) { return fd_; }
// Closes the file if its descriptor is not -1.
void close();
// Attempts to read count bytes from the file into the specified buffer. // Attempts to read count bytes from the file into the specified buffer.
std::streamsize read(void *buffer, std::size_t count); std::streamsize read(void *buffer, std::size_t count);