1*07fb1d06SElliott Hughes // Copyright 2017 The ChromiumOS Authors
2*07fb1d06SElliott Hughes // Use of this source code is governed by a BSD-style license that can be
3*07fb1d06SElliott Hughes // found in the LICENSE file.
4*07fb1d06SElliott Hughes
5*07fb1d06SElliott Hughes #include "puffin/file_stream.h"
6*07fb1d06SElliott Hughes
7*07fb1d06SElliott Hughes #include <fcntl.h>
8*07fb1d06SElliott Hughes #include <unistd.h>
9*07fb1d06SElliott Hughes
10*07fb1d06SElliott Hughes #include <algorithm>
11*07fb1d06SElliott Hughes #include <utility>
12*07fb1d06SElliott Hughes
13*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/common.h"
14*07fb1d06SElliott Hughes #include "puffin/src/logging.h"
15*07fb1d06SElliott Hughes
16*07fb1d06SElliott Hughes using std::string;
17*07fb1d06SElliott Hughes
18*07fb1d06SElliott Hughes namespace puffin {
19*07fb1d06SElliott Hughes
Open(const string & path,bool read,bool write)20*07fb1d06SElliott Hughes UniqueStreamPtr FileStream::Open(const string& path, bool read, bool write) {
21*07fb1d06SElliott Hughes TEST_AND_RETURN_VALUE(read || write, nullptr);
22*07fb1d06SElliott Hughes int flags = O_CLOEXEC;
23*07fb1d06SElliott Hughes if (read && write) {
24*07fb1d06SElliott Hughes flags |= O_RDWR | O_CREAT;
25*07fb1d06SElliott Hughes } else if (read) {
26*07fb1d06SElliott Hughes flags |= O_RDONLY;
27*07fb1d06SElliott Hughes } else {
28*07fb1d06SElliott Hughes flags |= O_WRONLY | O_CREAT;
29*07fb1d06SElliott Hughes }
30*07fb1d06SElliott Hughes
31*07fb1d06SElliott Hughes mode_t mode = 0644; // -rw-r--r--
32*07fb1d06SElliott Hughes int fd = open(path.c_str(), flags, mode);
33*07fb1d06SElliott Hughes TEST_AND_RETURN_VALUE(fd >= 0, nullptr);
34*07fb1d06SElliott Hughes return UniqueStreamPtr(new FileStream(fd));
35*07fb1d06SElliott Hughes }
36*07fb1d06SElliott Hughes
GetSize(uint64_t * size) const37*07fb1d06SElliott Hughes bool FileStream::GetSize(uint64_t* size) const {
38*07fb1d06SElliott Hughes auto cur_off = lseek(fd_, 0, SEEK_CUR);
39*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(cur_off >= 0);
40*07fb1d06SElliott Hughes auto fsize = lseek(fd_, 0, SEEK_END);
41*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(fsize >= 0);
42*07fb1d06SElliott Hughes cur_off = lseek(fd_, cur_off, SEEK_SET);
43*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(cur_off >= 0);
44*07fb1d06SElliott Hughes *size = fsize;
45*07fb1d06SElliott Hughes return true;
46*07fb1d06SElliott Hughes }
47*07fb1d06SElliott Hughes
GetOffset(uint64_t * offset) const48*07fb1d06SElliott Hughes bool FileStream::GetOffset(uint64_t* offset) const {
49*07fb1d06SElliott Hughes auto off = lseek(fd_, 0, SEEK_CUR);
50*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(off >= 0);
51*07fb1d06SElliott Hughes *offset = off;
52*07fb1d06SElliott Hughes return true;
53*07fb1d06SElliott Hughes }
54*07fb1d06SElliott Hughes
Seek(uint64_t offset)55*07fb1d06SElliott Hughes bool FileStream::Seek(uint64_t offset) {
56*07fb1d06SElliott Hughes auto off = lseek(fd_, offset, SEEK_SET);
57*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(off == static_cast<off_t>(offset));
58*07fb1d06SElliott Hughes return true;
59*07fb1d06SElliott Hughes }
60*07fb1d06SElliott Hughes
Read(void * buffer,size_t length)61*07fb1d06SElliott Hughes bool FileStream::Read(void* buffer, size_t length) {
62*07fb1d06SElliott Hughes auto c_bytes = static_cast<uint8_t*>(buffer);
63*07fb1d06SElliott Hughes size_t total_bytes_read = 0;
64*07fb1d06SElliott Hughes while (total_bytes_read < length) {
65*07fb1d06SElliott Hughes auto bytes_read =
66*07fb1d06SElliott Hughes read(fd_, c_bytes + total_bytes_read, length - total_bytes_read);
67*07fb1d06SElliott Hughes // if bytes_read is zero then EOF is reached and we should not be here.
68*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(bytes_read > 0);
69*07fb1d06SElliott Hughes total_bytes_read += bytes_read;
70*07fb1d06SElliott Hughes }
71*07fb1d06SElliott Hughes return true;
72*07fb1d06SElliott Hughes }
73*07fb1d06SElliott Hughes
Write(const void * buffer,size_t length)74*07fb1d06SElliott Hughes bool FileStream::Write(const void* buffer, size_t length) {
75*07fb1d06SElliott Hughes auto c_bytes = static_cast<const uint8_t*>(buffer);
76*07fb1d06SElliott Hughes size_t total_bytes_wrote = 0;
77*07fb1d06SElliott Hughes while (total_bytes_wrote < length) {
78*07fb1d06SElliott Hughes auto bytes_wrote =
79*07fb1d06SElliott Hughes write(fd_, c_bytes + total_bytes_wrote, length - total_bytes_wrote);
80*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(bytes_wrote >= 0);
81*07fb1d06SElliott Hughes total_bytes_wrote += bytes_wrote;
82*07fb1d06SElliott Hughes }
83*07fb1d06SElliott Hughes return true;
84*07fb1d06SElliott Hughes }
85*07fb1d06SElliott Hughes
Close()86*07fb1d06SElliott Hughes bool FileStream::Close() {
87*07fb1d06SElliott Hughes return close(fd_) == 0;
88*07fb1d06SElliott Hughes }
89*07fb1d06SElliott Hughes
90*07fb1d06SElliott Hughes } // namespace puffin
91