-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: Moving File into `/folly`. Test Plan: Same unit tests, rebuild affected code outside folly. Reviewed By: philipp@fb.com FB internal diff: D714462
- Loading branch information
Showing
4 changed files
with
294 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* Copyright 2013 Facebook, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "folly/File.h" | ||
#include "folly/ScopeGuard.h" | ||
|
||
#include <system_error> | ||
|
||
#include <glog/logging.h> | ||
|
||
namespace folly { | ||
|
||
File::File() | ||
: fd_(-1) | ||
, ownsFd_(false) | ||
{} | ||
|
||
File::File(int fd, bool ownsFd) | ||
: fd_(fd) | ||
, ownsFd_(ownsFd) | ||
{} | ||
|
||
File::File(const char* name, int flags, mode_t mode) | ||
: fd_(::open(name, flags, mode)) | ||
, ownsFd_(false) { | ||
|
||
if (fd_ < 0) { | ||
throw std::system_error(errno, std::system_category(), "open() failed"); | ||
} | ||
ownsFd_ = true; | ||
} | ||
|
||
File::File(File&& other) | ||
: fd_(other.fd_) | ||
, ownsFd_(other.ownsFd_) { | ||
|
||
other.release(); | ||
} | ||
|
||
File& File::operator=(File&& other) { | ||
closeNoThrow(); | ||
swap(other); | ||
return *this; | ||
} | ||
|
||
File::~File() { | ||
closeNoThrow(); // ignore error | ||
} | ||
|
||
/* static */ File File::temporary() { | ||
// make a temp file with tmpfile(), dup the fd, then return it in a File. | ||
FILE* tmpFile = tmpfile(); | ||
if (!tmpFile) { | ||
throw std::system_error(errno, std::system_category(), "tmpfile() failed"); | ||
} | ||
SCOPE_EXIT { fclose(tmpFile); }; | ||
|
||
int fd = dup(fileno(tmpFile)); | ||
if (fd < 0) { | ||
throw std::system_error(errno, std::system_category(), "dup() failed"); | ||
} | ||
|
||
return File(fd, true); | ||
} | ||
|
||
void File::release() { | ||
fd_ = -1; | ||
ownsFd_ = false; | ||
} | ||
|
||
void File::swap(File& other) { | ||
using std::swap; | ||
swap(fd_, other.fd_); | ||
swap(ownsFd_, other.ownsFd_); | ||
} | ||
|
||
void swap(File& a, File& b) { | ||
a.swap(b); | ||
} | ||
|
||
void File::close() { | ||
if (!closeNoThrow()) { | ||
throw std::system_error(errno, std::system_category(), "close() failed"); | ||
} | ||
} | ||
|
||
bool File::closeNoThrow() { | ||
int r = ownsFd_ ? ::close(fd_) : 0; | ||
release(); | ||
return r == 0; | ||
} | ||
|
||
} // namespace folly |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
* Copyright 2013 Facebook, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#ifndef FOLLY_FILE_H_ | ||
#define FOLLY_FILE_H_ | ||
|
||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
#include <fcntl.h> | ||
|
||
namespace folly { | ||
|
||
/** | ||
* A File represents an open file. | ||
*/ | ||
class File { | ||
public: | ||
/** | ||
* Creates an empty File object, for late initialization. | ||
*/ | ||
File(); | ||
|
||
/** | ||
* Create a File object from an existing file descriptor. | ||
* Takes ownership of the file descriptor if ownsFd is true. | ||
*/ | ||
/* implicit */ File(int fd, | ||
bool ownsFd = false); | ||
|
||
/** | ||
* Open and create a file object. Throws on error. | ||
*/ | ||
/* implicit */ File(const char* name, | ||
int flags = O_RDONLY, | ||
mode_t mode = 0644); | ||
|
||
~File(); | ||
|
||
/** | ||
* Create and return a temporary, owned file (uses tmpfile()). | ||
*/ | ||
static File temporary(); | ||
|
||
/** | ||
* Return the file descriptor, or -1 if the file was closed. | ||
*/ | ||
int fd() const { return fd_; } | ||
|
||
/** | ||
* If we own the file descriptor, close the file and throw on error. | ||
* Otherwise, do nothing. | ||
*/ | ||
void close(); | ||
|
||
/** | ||
* Closes the file (if owned). Returns true on success, false (and sets | ||
* errno) on error. | ||
*/ | ||
bool closeNoThrow(); | ||
|
||
/** | ||
* Releases the file descriptor; no longer owned by this File. | ||
*/ | ||
void release(); | ||
|
||
/** | ||
* Swap this File with another. | ||
*/ | ||
void swap(File& other); | ||
|
||
// movable | ||
File(File&&); | ||
File& operator=(File&&); | ||
|
||
private: | ||
// unique | ||
File(const File&) = delete; | ||
File& operator=(const File&) = delete; | ||
|
||
int fd_; | ||
bool ownsFd_; | ||
}; | ||
|
||
void swap(File& a, File& b); | ||
|
||
} // namespace folly | ||
|
||
#endif /* FOLLY_FILE_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* | ||
* Copyright 2013 Facebook, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "folly/File.h" | ||
|
||
#include <glog/logging.h> | ||
#include <gtest/gtest.h> | ||
|
||
#include "folly/Benchmark.h" | ||
#include "folly/String.h" | ||
|
||
using namespace folly; | ||
|
||
namespace { | ||
void expectWouldBlock(ssize_t r) { | ||
int savedErrno = errno; | ||
EXPECT_EQ(-1, r); | ||
EXPECT_EQ(EAGAIN, savedErrno) << errnoStr(errno); | ||
} | ||
void expectOK(ssize_t r) { | ||
int savedErrno = errno; | ||
EXPECT_LE(0, r) << ": errno=" << errnoStr(errno); | ||
} | ||
} // namespace | ||
|
||
TEST(File, Simple) { | ||
// Open a file, ensure it's indeed open for reading | ||
char buf = 'x'; | ||
{ | ||
File f("/etc/hosts"); | ||
EXPECT_NE(-1, f.fd()); | ||
EXPECT_EQ(1, ::read(f.fd(), &buf, 1)); | ||
f.close(); | ||
EXPECT_EQ(-1, f.fd()); | ||
} | ||
} | ||
|
||
TEST(File, OwnsFd) { | ||
// Wrap a file descriptor, make sure that ownsFd works | ||
// We'll test that the file descriptor is closed by closing the writing | ||
// end of a pipe and making sure that a non-blocking read from the reading | ||
// end returns 0. | ||
|
||
char buf = 'x'; | ||
int p[2]; | ||
expectOK(::pipe(p)); | ||
int flags = ::fcntl(p[0], F_GETFL); | ||
expectOK(flags); | ||
expectOK(::fcntl(p[0], F_SETFL, flags | O_NONBLOCK)); | ||
expectWouldBlock(::read(p[0], &buf, 1)); | ||
{ | ||
File f(p[1]); | ||
EXPECT_EQ(p[1], f.fd()); | ||
} | ||
// Ensure that moving the file doesn't close it | ||
{ | ||
File f(p[1]); | ||
EXPECT_EQ(p[1], f.fd()); | ||
File f1(std::move(f)); | ||
EXPECT_EQ(-1, f.fd()); | ||
EXPECT_EQ(p[1], f1.fd()); | ||
} | ||
expectWouldBlock(::read(p[0], &buf, 1)); // not closed | ||
{ | ||
File f(p[1], true); | ||
EXPECT_EQ(p[1], f.fd()); | ||
} | ||
ssize_t r = ::read(p[0], &buf, 1); // eof | ||
expectOK(r); | ||
EXPECT_EQ(0, r); | ||
::close(p[0]); | ||
} | ||
|