103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo// Copyright 2015 The Chromium OS Authors. All rights reserved.
203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo// Use of this source code is governed by a BSD-style license that can be
303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo// found in the LICENSE file.
403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include "file.h"
603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <errno.h>
803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <fcntl.h>
9daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo#ifdef __linux__
10daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo#include <linux/fs.h>
11daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo#endif  // __linux__
1203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <string.h>
1303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <sys/ioctl.h>
1403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <sys/stat.h>
1503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <sys/types.h>
1603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <unistd.h>
1703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
1803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo// TEMP_FAILURE_RETRY is defined by some versions of <unistd.h>.
1903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#ifndef TEMP_FAILURE_RETRY
2003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <utils/Compat.h>
2103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#endif
2203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
2303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo#include <algorithm>
2403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
2503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymonamespace bsdiff {
2603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
2703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymostd::unique_ptr<File> File::FOpen(const char* pathname, int flags) {
28d87c83566c8411c16098dcc09ac56cce6007f9c6Sen Jiang  int fd = TEMP_FAILURE_RETRY(open(pathname, flags, 0644));
2903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (fd < 0)
3003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return std::unique_ptr<File>();
3103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  return std::unique_ptr<File>(new File(fd));
3203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo}
3303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
3403f1debab429e673ba5e9e317c5a04e36e850cefAlex DeymoFile::~File() {
3503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  Close();
3603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo}
3703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
3803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymobool File::Read(void* buf, size_t count, size_t* bytes_read) {
3903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (fd_ < 0) {
4003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    errno = EBADF;
4103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
4203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  }
4303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, buf, count));
4403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (rc == -1)
4503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
4603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  *bytes_read = static_cast<size_t>(rc);
4703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  return true;
4803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo}
4903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
5003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymobool File::Write(const void* buf, size_t count, size_t* bytes_written) {
5103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (fd_ < 0) {
5203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    errno = EBADF;
5303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
5403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  }
5503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  ssize_t rc = TEMP_FAILURE_RETRY(write(fd_, buf, count));
5603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (rc == -1)
5703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
5803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  *bytes_written = static_cast<size_t>(rc);
5903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  return true;
6003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo}
6103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
6203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymobool File::Seek(off_t pos) {
6303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (fd_ < 0) {
6403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    errno = EBADF;
6503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
6603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  }
6703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  // fseek() uses a long value for the offset which could be smaller than off_t.
6803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (pos > std::numeric_limits<long>::max()) {
6903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    errno = EOVERFLOW;
7003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
7103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  }
72d87c83566c8411c16098dcc09ac56cce6007f9c6Sen Jiang  off_t newpos = lseek(fd_, pos, SEEK_SET);
7303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (newpos < 0)
7403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
7503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (newpos != pos) {
7603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    errno = EINVAL;
7703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
7803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  }
7903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  return true;
8003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo}
8103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
8203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymobool File::Close() {
8303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (fd_ < 0) {
8403f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    errno = EBADF;
8503f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    return false;
8603f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  }
8703f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  bool success = close(fd_) == 0;
8803f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  if (!success && errno == EINTR)
8903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    success = true;
9003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  fd_ = -1;
9103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo  return success;
9203f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo}
9303f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
94daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymobool File::GetSize(uint64_t* size) {
95daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo  struct stat stbuf;
96daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo  if (fstat(fd_, &stbuf) == -1)
97daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    return false;
98daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo  if (S_ISREG(stbuf.st_mode)) {
99d87c83566c8411c16098dcc09ac56cce6007f9c6Sen Jiang    *size = stbuf.st_size;
100d87c83566c8411c16098dcc09ac56cce6007f9c6Sen Jiang    return true;
101daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo  }
102daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo  if (S_ISBLK(stbuf.st_mode)) {
103daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo#if defined(BLKGETSIZE64)
104daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    return ioctl(fd_, BLKGETSIZE64, size);
105daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo#elif defined(DKIOCGETBLOCKCOUNT)
106daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    uint64_t sectors = 0;
107daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    if (ioctl(fd_, DKIOCGETBLOCKCOUNT, &sectors) == 0) {
108daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo      *size = sectors << 9;
109daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo      return true;
110daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    }
111daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    return false;
112daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo#else
113daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    // Fall back to doing seeks to know the EOF.
114daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    off_t pos = lseek(fd_, 0, SEEK_CUR);
115daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    if (pos == -1)
116daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo      return false;
117daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    off_t end_pos = lseek(fd_, 0, SEEK_END);
118daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    if (end_pos == -1)
119daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo      return false;
120daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    *size = end_pos;
121daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    lseek(fd_, 0, SEEK_END);
122daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo    return true;
123daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo#endif
124daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo  }
125daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo  return false;
126daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo}
127daf35169e3fa51cc9ff468f12acd435a9b075266Alex Deymo
12803f1debab429e673ba5e9e317c5a04e36e850cefAlex DeymoFile::File(int fd)
12903f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo    : fd_(fd) {}
13003f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo
13103f1debab429e673ba5e9e317c5a04e36e850cefAlex Deymo}  // namespace bsdiff
132