Reland of Initial version of file wrapper
Fixes a conversion issue. BUG=webrtc:6177 R=sprang@webrtc.org TBR=mflodman@webrtc.org patch from issue 2214763002 at patchset 450001 (http://crrev.com/2214763002#ps450001) Review URL: https://codereview.webrtc.org/2306553002 . Cr-Commit-Position: refs/heads/master@{#14044}
This commit is contained in:
parent
38a2132b02
commit
4ec6a0ceae
@ -457,6 +457,7 @@ if (rtc_include_tests) {
|
||||
"base/event_tracer_unittest.cc",
|
||||
"base/event_unittest.cc",
|
||||
"base/exp_filter_unittest.cc",
|
||||
"base/file_unittest.cc",
|
||||
"base/filerotatingstream_unittest.cc",
|
||||
"base/fileutils_unittest.cc",
|
||||
"base/helpers_unittest.cc",
|
||||
|
||||
@ -124,6 +124,8 @@ rtc_static_library("rtc_base_approved") {
|
||||
"event_tracer.h",
|
||||
"exp_filter.cc",
|
||||
"exp_filter.h",
|
||||
"file.cc",
|
||||
"file.h",
|
||||
"format_macros.h",
|
||||
"location.cc",
|
||||
"location.h",
|
||||
@ -177,6 +179,14 @@ rtc_static_library("rtc_base_approved") {
|
||||
libs += [ "log" ]
|
||||
}
|
||||
|
||||
if (is_posix) {
|
||||
sources += [ "file_posix.cc" ]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
sources += [ "file_win.cc" ]
|
||||
}
|
||||
|
||||
if (build_with_chromium) {
|
||||
# Dependency on chromium's logging (in //base).
|
||||
deps += [ "//base:base" ]
|
||||
|
||||
@ -54,6 +54,8 @@
|
||||
'event_tracer.h',
|
||||
'exp_filter.cc',
|
||||
'exp_filter.h',
|
||||
'file.cc',
|
||||
'file.h',
|
||||
'format_macros.h',
|
||||
'location.h',
|
||||
'location.cc',
|
||||
@ -103,6 +105,16 @@
|
||||
'trace_event.h',
|
||||
],
|
||||
'conditions': [
|
||||
['os_posix==1', {
|
||||
'sources': [
|
||||
'file_posix.cc',
|
||||
],
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'sources': [
|
||||
'file_win.cc',
|
||||
],
|
||||
}],
|
||||
['build_with_chromium==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/base/base.gyp:base',
|
||||
|
||||
36
webrtc/base/file.cc
Normal file
36
webrtc/base/file.cc
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/file.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
File::File(PlatformFile file) : file_(file) {}
|
||||
|
||||
File::~File() {
|
||||
Close();
|
||||
}
|
||||
|
||||
File::File(File&& other) : file_(other.file_) {
|
||||
other.file_ = kInvalidPlatformFileValue;
|
||||
}
|
||||
|
||||
File& File::operator=(File&& other) {
|
||||
Close();
|
||||
file_ = other.file_;
|
||||
other.file_ = kInvalidPlatformFileValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool File::IsOpen() {
|
||||
return file_ != kInvalidPlatformFileValue;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
67
webrtc/base/file.h
Normal file
67
webrtc/base/file.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_FILE_H_
|
||||
#define WEBRTC_BASE_FILE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/platform_file.h"
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// This class wraps the platform specific APIs for simple file interactions.
|
||||
//
|
||||
// The various read and write methods are best effort, i.e. if an underlying
|
||||
// call does not manage to read/write all the data more calls will be performed,
|
||||
// until an error is detected or all data is read/written.
|
||||
class File {
|
||||
public:
|
||||
// Wraps the given PlatformFile. This class is then responsible for closing
|
||||
// the file, which will be done in the destructor if Close is never called.
|
||||
explicit File(PlatformFile);
|
||||
~File();
|
||||
|
||||
File(File&& other);
|
||||
File& operator=(File&& other);
|
||||
|
||||
static File Open(const std::string& path);
|
||||
|
||||
size_t Write(const uint8_t* data, size_t length);
|
||||
size_t Read(uint8_t* buffer, size_t length);
|
||||
|
||||
// The current position in the file after a call to these methods is platform
|
||||
// dependent (MSVC gives position offset+length, most other
|
||||
// compilers/platforms do not alter the position), i.e. do not depend on it,
|
||||
// do a Seek before any subsequent Read/Write.
|
||||
size_t WriteAt(const uint8_t* data, size_t length, size_t offset);
|
||||
size_t ReadAt(uint8_t* buffer, size_t length, size_t offset);
|
||||
|
||||
// Attempt to position the file at the given offset from the start.
|
||||
// Returns true if successful, false otherwise.
|
||||
bool Seek(size_t offset);
|
||||
|
||||
// Attempt to close the file. Returns true if successful, false otherwise,
|
||||
// most notably when the file is already closed.
|
||||
bool Close();
|
||||
|
||||
bool IsOpen();
|
||||
|
||||
private:
|
||||
PlatformFile file_;
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(File);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_FILE_H_
|
||||
100
webrtc/base/file_posix.cc
Normal file
100
webrtc/base/file_posix.cc
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/file.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
File File::Open(const std::string& path) {
|
||||
return File(::open(path.c_str(), O_RDWR));
|
||||
}
|
||||
|
||||
size_t File::Write(const uint8_t* data, size_t length) {
|
||||
size_t total_written = 0;
|
||||
do {
|
||||
ssize_t written;
|
||||
do {
|
||||
written = ::write(file_, data + total_written, length - total_written);
|
||||
} while (written == -1 && errno == EINTR);
|
||||
if (written == -1)
|
||||
break;
|
||||
total_written += written;
|
||||
} while (total_written < length);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
size_t File::Read(uint8_t* buffer, size_t length) {
|
||||
size_t total_read = 0;
|
||||
do {
|
||||
ssize_t read;
|
||||
do {
|
||||
read = ::read(file_, buffer + total_read, length - total_read);
|
||||
} while (read == -1 && errno == EINTR);
|
||||
if (read == -1)
|
||||
break;
|
||||
total_read += read;
|
||||
} while (total_read < length);
|
||||
return total_read;
|
||||
}
|
||||
|
||||
size_t File::WriteAt(const uint8_t* data, size_t length, size_t offset) {
|
||||
size_t total_written = 0;
|
||||
do {
|
||||
ssize_t written;
|
||||
do {
|
||||
written = ::pwrite(file_, data + total_written, length - total_written,
|
||||
offset + total_written);
|
||||
} while (written == -1 && errno == EINTR);
|
||||
if (written == -1)
|
||||
break;
|
||||
total_written += written;
|
||||
} while (total_written < length);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
size_t File::ReadAt(uint8_t* buffer, size_t length, size_t offset) {
|
||||
size_t total_read = 0;
|
||||
do {
|
||||
ssize_t read;
|
||||
do {
|
||||
read = ::pread(file_, buffer + total_read, length - total_read,
|
||||
offset + total_read);
|
||||
} while (read == -1 && errno == EINTR);
|
||||
if (read == -1)
|
||||
break;
|
||||
total_read += read;
|
||||
} while (total_read < length);
|
||||
return total_read;
|
||||
}
|
||||
|
||||
bool File::Seek(size_t offset) {
|
||||
RTC_DCHECK_LE(offset, static_cast<size_t>(std::numeric_limits<off_t>::max()));
|
||||
return lseek(file_, static_cast<off_t>(offset), SEEK_SET) != -1;
|
||||
}
|
||||
|
||||
bool File::Close() {
|
||||
if (file_ == rtc::kInvalidPlatformFileValue)
|
||||
return false;
|
||||
bool ret = close(file_) == 0;
|
||||
file_ = rtc::kInvalidPlatformFileValue;
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
166
webrtc/base/file_unittest.cc
Normal file
166
webrtc/base/file_unittest.cc
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/file.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
|
||||
#include "webrtc/base/win32.h"
|
||||
|
||||
#else // if defined(WEBRTC_WIN)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace rtc {
|
||||
|
||||
void RemoveFile(const std::string& path) {
|
||||
#if defined(WEBRTC_WIN)
|
||||
::DeleteFile(ToUtf16(path).c_str());
|
||||
#else
|
||||
::unlink(path.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
int LastError() {
|
||||
#if defined(WEBRTC_WIN)
|
||||
return ::GetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VerifyBuffer(uint8_t* buffer, size_t length, uint8_t start_value) {
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
uint8_t val = start_value++;
|
||||
EXPECT_EQ(val, buffer[i]);
|
||||
if (buffer[i] != val)
|
||||
return false;
|
||||
}
|
||||
// Prevent the same buffer from being verified multiple times simply
|
||||
// because some operation that should have written to it failed
|
||||
memset(buffer, 0, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
class FileTest : public ::testing::Test {
|
||||
protected:
|
||||
std::string path_;
|
||||
void SetUp() {
|
||||
path_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), "test_file");
|
||||
ASSERT_FALSE(path_.empty());
|
||||
}
|
||||
rtc::File OpenTempFile() { return rtc::File::Open(path_); }
|
||||
void TearDown() { RemoveFile(path_); }
|
||||
};
|
||||
|
||||
TEST_F(FileTest, DoubleClose) {
|
||||
File file = OpenTempFile();
|
||||
ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
|
||||
|
||||
EXPECT_TRUE(file.Close());
|
||||
EXPECT_FALSE(file.Close());
|
||||
}
|
||||
|
||||
TEST_F(FileTest, SimpleReadWrite) {
|
||||
File file = OpenTempFile();
|
||||
ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
|
||||
|
||||
uint8_t data[100] = {0};
|
||||
uint8_t out[100] = {0};
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
EXPECT_EQ(10u, file.Write(data, 10));
|
||||
|
||||
EXPECT_TRUE(file.Seek(0));
|
||||
EXPECT_EQ(10u, file.Read(out, 10));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 10, 0));
|
||||
|
||||
EXPECT_TRUE(file.Seek(0));
|
||||
EXPECT_EQ(100u, file.Write(data, 100));
|
||||
|
||||
EXPECT_TRUE(file.Seek(0));
|
||||
EXPECT_EQ(100u, file.Read(out, 100));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 100, 0));
|
||||
|
||||
EXPECT_TRUE(file.Seek(1));
|
||||
EXPECT_EQ(50u, file.Write(data, 50));
|
||||
EXPECT_EQ(50u, file.Write(data + 50, 50));
|
||||
|
||||
EXPECT_TRUE(file.Seek(1));
|
||||
EXPECT_EQ(100u, file.Read(out, 100));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 100, 0));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, ReadWriteClose) {
|
||||
File file = OpenTempFile();
|
||||
ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
|
||||
|
||||
uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
uint8_t out[10] = {0};
|
||||
EXPECT_EQ(10u, file.Write(data, 10));
|
||||
EXPECT_TRUE(file.Close());
|
||||
|
||||
File file2 = OpenTempFile();
|
||||
ASSERT_TRUE(file2.IsOpen()) << "Error: " << LastError();
|
||||
EXPECT_EQ(10u, file2.Read(out, 10));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 10, 0));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, RandomAccessRead) {
|
||||
File file = OpenTempFile();
|
||||
ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
|
||||
|
||||
uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
uint8_t out[10] = {0};
|
||||
EXPECT_EQ(10u, file.Write(data, 10));
|
||||
|
||||
EXPECT_EQ(4u, file.ReadAt(out, 4, 0));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 4, 0));
|
||||
|
||||
EXPECT_EQ(4u, file.ReadAt(out, 4, 4));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 4, 4));
|
||||
|
||||
EXPECT_EQ(5u, file.ReadAt(out, 5, 5));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 5, 5));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, RandomAccessReadWrite) {
|
||||
File file = OpenTempFile();
|
||||
ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
|
||||
|
||||
uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
uint8_t out[10] = {0};
|
||||
EXPECT_EQ(10u, file.Write(data, 10));
|
||||
EXPECT_TRUE(file.Seek(4));
|
||||
|
||||
EXPECT_EQ(4u, file.WriteAt(data, 4, 4));
|
||||
EXPECT_EQ(4u, file.ReadAt(out, 4, 4));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 4, 0));
|
||||
|
||||
EXPECT_EQ(2u, file.WriteAt(data, 2, 8));
|
||||
EXPECT_EQ(2u, file.ReadAt(out, 2, 8));
|
||||
EXPECT_TRUE(VerifyBuffer(out, 2, 0));
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
120
webrtc/base/file_win.cc
Normal file
120
webrtc/base/file_win.cc
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/file.h"
|
||||
|
||||
#include <io.h>
|
||||
#include "webrtc/base/win32.h"
|
||||
|
||||
#include <limits> // NOLINT: win32.h should be considered a system header
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
File File::Open(const std::string& path) {
|
||||
HANDLE handle =
|
||||
::CreateFile(ToUtf16(path).c_str(), GENERIC_READ | GENERIC_WRITE, 0,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
return File(handle);
|
||||
}
|
||||
|
||||
size_t File::Write(const uint8_t* data, size_t length) {
|
||||
RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
|
||||
size_t total_written = 0;
|
||||
do {
|
||||
DWORD written;
|
||||
if (!::WriteFile(file_, data + total_written,
|
||||
static_cast<DWORD>(length - total_written), &written,
|
||||
nullptr)) {
|
||||
break;
|
||||
}
|
||||
total_written += written;
|
||||
} while (total_written < length);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
size_t File::Read(uint8_t* buffer, size_t length) {
|
||||
RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
|
||||
size_t total_read = 0;
|
||||
do {
|
||||
DWORD read;
|
||||
if (!::ReadFile(file_, buffer + total_read,
|
||||
static_cast<DWORD>(length - total_read), &read, nullptr)) {
|
||||
break;
|
||||
}
|
||||
total_read += read;
|
||||
} while (total_read < length);
|
||||
return total_read;
|
||||
}
|
||||
|
||||
size_t File::WriteAt(const uint8_t* data, size_t length, size_t offset) {
|
||||
RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
|
||||
size_t total_written = 0;
|
||||
do {
|
||||
DWORD written;
|
||||
|
||||
LARGE_INTEGER offset_li;
|
||||
offset_li.QuadPart = offset + total_written;
|
||||
|
||||
OVERLAPPED overlapped = {0};
|
||||
overlapped.Offset = offset_li.LowPart;
|
||||
overlapped.OffsetHigh = offset_li.HighPart;
|
||||
|
||||
if (!::WriteFile(file_, data + total_written,
|
||||
static_cast<DWORD>(length - total_written), &written,
|
||||
&overlapped)) {
|
||||
break;
|
||||
}
|
||||
|
||||
total_written += written;
|
||||
} while (total_written < length);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
size_t File::ReadAt(uint8_t* buffer, size_t length, size_t offset) {
|
||||
RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
|
||||
size_t total_read = 0;
|
||||
do {
|
||||
DWORD read;
|
||||
|
||||
LARGE_INTEGER offset_li;
|
||||
offset_li.QuadPart = offset + total_read;
|
||||
|
||||
OVERLAPPED overlapped = {0};
|
||||
overlapped.Offset = offset_li.LowPart;
|
||||
overlapped.OffsetHigh = offset_li.HighPart;
|
||||
|
||||
if (!::ReadFile(file_, buffer + total_read,
|
||||
static_cast<DWORD>(length - total_read), &read,
|
||||
&overlapped)) {
|
||||
break;
|
||||
}
|
||||
|
||||
total_read += read;
|
||||
} while (total_read < length);
|
||||
return total_read;
|
||||
}
|
||||
|
||||
bool File::Seek(size_t offset) {
|
||||
LARGE_INTEGER distance;
|
||||
distance.QuadPart = offset;
|
||||
return SetFilePointerEx(file_, distance, nullptr, FILE_BEGIN) != 0;
|
||||
}
|
||||
|
||||
bool File::Close() {
|
||||
if (file_ == kInvalidPlatformFileValue)
|
||||
return false;
|
||||
bool ret = CloseHandle(file_) != 0;
|
||||
file_ = kInvalidPlatformFileValue;
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
@ -39,6 +39,7 @@
|
||||
'base/event_tracer_unittest.cc',
|
||||
'base/event_unittest.cc',
|
||||
'base/exp_filter_unittest.cc',
|
||||
'base/file_unittest.cc',
|
||||
'base/filerotatingstream_unittest.cc',
|
||||
'base/fileutils_unittest.cc',
|
||||
'base/helpers_unittest.cc',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user