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