<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "platform/globals.h"
#if defined(TARGET_OS_LINUX)

#include "bin/file.h"

#include <errno.h>  // NOLINT
#include <fcntl.h>  // NOLINT
#include <sys/stat.h>  // NOLINT
#include <sys/types.h>  // NOLINT
#include <sys/sendfile.h>  // NOLINT
#include <unistd.h>  // NOLINT
#include <libgen.h>  // NOLINT

#include "bin/builtin.h"
#include "bin/log.h"


namespace dart {
namespace bin {

class FileHandle {
 public:
  explicit FileHandle(int fd) : fd_(fd) { }
  ~FileHandle() { }
  int fd() const { return fd_; }
  void set_fd(int fd) { fd_ = fd; }

 private:
  int fd_;

  DISALLOW_COPY_AND_ASSIGN(FileHandle);
};


File::~File() {
  // Close the file (unless it's a standard stream).
  if (handle_->fd() > STDERR_FILENO) {
    Close();
  }
  delete handle_;
}


void File::Close() {
  ASSERT(handle_->fd() >= 0);
  int err = TEMP_FAILURE_RETRY(close(handle_->fd()));
  if (err != 0) {
    const int kBufferSize = 1024;
    char error_buf[kBufferSize];
    Log::PrintErr("%s\n", strerror_r(errno, error_buf, kBufferSize));
  }
  handle_->set_fd(kClosedFd);
}


bool File::IsClosed() {
  return handle_->fd() == kClosedFd;
}


int64_t File::Read(void* buffer, int64_t num_bytes) {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
}


int64_t File::Write(const void* buffer, int64_t num_bytes) {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes));
}


off64_t File::Position() {
  ASSERT(handle_->fd() >= 0);
  return lseek64(handle_->fd(), 0, SEEK_CUR);
}


bool File::SetPosition(off64_t position) {
  ASSERT(handle_->fd() >= 0);
  return lseek64(handle_->fd(), position, SEEK_SET) >= 0;
}


bool File::Truncate(off64_t length) {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(ftruncate64(handle_->fd(), length) != -1);
}


bool File::Flush() {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(fsync(handle_->fd()) != -1);
}


off64_t File::Length() {
  ASSERT(handle_->fd() >= 0);
  struct stat64 st;
  if (TEMP_FAILURE_RETRY(fstat64(handle_->fd(), &st)) == 0) {
    return st.st_size;
  }
  return -1;
}


File* File::Open(const char* name, FileOpenMode mode) {
  // Report errors for non-regular files.
  struct stat64 st;
  if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
    // Only accept regular files and character devices.
    if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
      errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
      return NULL;
    }
  }
  int flags = O_RDONLY;
  if ((mode & kWrite) != 0) {
    flags = (O_RDWR | O_CREAT);
  }
  if ((mode & kTruncate) != 0) {
    flags = flags | O_TRUNC;
  }
  flags |= O_CLOEXEC;
  int fd = TEMP_FAILURE_RETRY(open64(name, flags, 0666));
  if (fd < 0) {
    return NULL;
  }
  if (((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) {
    off64_t position = lseek64(fd, 0, SEEK_END);
    if (position < 0) {
      return NULL;
    }
  }
  return new File(new FileHandle(fd));
}


File* File::OpenStdio(int fd) {
  if (fd < 0 || 2 < fd) return NULL;
  return new File(new FileHandle(fd));
}


bool File::Exists(const char* name) {
  struct stat64 st;
  if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
    return S_ISREG(st.st_mode);
  } else {
    return false;
  }
}


bool File::Create(const char* name) {
  int fd = TEMP_FAILURE_RETRY(
      open64(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666));
  if (fd < 0) {
    return false;
  }
  return (close(fd) == 0);
}


bool File::CreateLink(const char* name, const char* target) {
  int status = TEMP_FAILURE_RETRY(symlink(target, name));
  return (status == 0);
}


bool File::Delete(const char* name) {
  File::Type type = File::GetType(name, true);
  if (type == kIsFile) {
    return TEMP_FAILURE_RETRY(unlink(name)) == 0;
  } else if (type == kIsDirectory) {
    errno = EISDIR;
  } else {
    errno = ENOENT;
  }
  return false;
}


bool File::DeleteLink(const char* name) {
  File::Type type = File::GetType(name, false);
  if (type == kIsLink) {
    return TEMP_FAILURE_RETRY(unlink(name)) == 0;
  }
  errno = EINVAL;
  return false;
}


bool File::Rename(const char* old_path, const char* new_path) {
  File::Type type = File::GetType(old_path, true);
  if (type == kIsFile) {
    return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
  } else if (type == kIsDirectory) {
    errno = EISDIR;
  } else {
    errno = ENOENT;
  }
  return false;
}


bool File::RenameLink(const char* old_path, const char* new_path) {
  File::Type type = File::GetType(old_path, false);
  if (type == kIsLink) {
    return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
  } else if (type == kIsDirectory) {
    errno = EISDIR;
  } else {
    errno = EINVAL;
  }
  return false;
}


bool File::Copy(const char* old_path, const char* new_path) {
  File::Type type = File::GetType(old_path, true);
  if (type == kIsFile) {
    struct stat64 st;
    if (TEMP_FAILURE_RETRY(stat64(old_path, &st)) != 0) {
      return false;
    }
    int old_fd = TEMP_FAILURE_RETRY(open64(old_path, O_RDONLY | O_CLOEXEC));
    if (old_fd < 0) {
      return false;
    }
    int new_fd = TEMP_FAILURE_RETRY(
        open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode));
    if (new_fd < 0) {
      VOID_TEMP_FAILURE_RETRY(close(old_fd));
      return false;
    }
    off64_t offset = 0;
    int result = 1;
    while (result > 0) {
      // Loop to ensure we copy everything, and not only up to 2GB.
      result = TEMP_FAILURE_RETRY(
          sendfile64(new_fd, old_fd, &offset, kMaxUint32));
    }
    // From sendfile man pages:
    //   Applications may wish to fall back to read(2)/write(2) in the case
    //   where sendfile() fails with EINVAL or ENOSYS.
    if (result < 0 && (errno == EINVAL || errno == ENOSYS)) {
      const intptr_t kBufferSize = 8 * 1024;
      uint8_t buffer[kBufferSize];
      while ((result = TEMP_FAILURE_RETRY(
          read(old_fd, buffer, kBufferSize))) > 0) {
        int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result));
        if (wrote != result) {
          result = -1;
          break;
        }
      }
    }
    if (result < 0) {
      int e = errno;<commit_msg>Nit fix: 1024 -> KB.<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "platform/globals.h"
#if defined(TARGET_OS_LINUX)

#include "bin/file.h"

#include <errno.h>  // NOLINT
#include <fcntl.h>  // NOLINT
#include <sys/stat.h>  // NOLINT
#include <sys/types.h>  // NOLINT
#include <sys/sendfile.h>  // NOLINT
#include <unistd.h>  // NOLINT
#include <libgen.h>  // NOLINT

#include "bin/builtin.h"
#include "bin/log.h"


namespace dart {
namespace bin {

class FileHandle {
 public:
  explicit FileHandle(int fd) : fd_(fd) { }
  ~FileHandle() { }
  int fd() const { return fd_; }
  void set_fd(int fd) { fd_ = fd; }

 private:
  int fd_;

  DISALLOW_COPY_AND_ASSIGN(FileHandle);
};


File::~File() {
  // Close the file (unless it's a standard stream).
  if (handle_->fd() > STDERR_FILENO) {
    Close();
  }
  delete handle_;
}


void File::Close() {
  ASSERT(handle_->fd() >= 0);
  int err = TEMP_FAILURE_RETRY(close(handle_->fd()));
  if (err != 0) {
    const int kBufferSize = 1024;
    char error_buf[kBufferSize];
    Log::PrintErr("%s\n", strerror_r(errno, error_buf, kBufferSize));
  }
  handle_->set_fd(kClosedFd);
}


bool File::IsClosed() {
  return handle_->fd() == kClosedFd;
}


int64_t File::Read(void* buffer, int64_t num_bytes) {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
}


int64_t File::Write(const void* buffer, int64_t num_bytes) {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes));
}


off64_t File::Position() {
  ASSERT(handle_->fd() >= 0);
  return lseek64(handle_->fd(), 0, SEEK_CUR);
}


bool File::SetPosition(off64_t position) {
  ASSERT(handle_->fd() >= 0);
  return lseek64(handle_->fd(), position, SEEK_SET) >= 0;
}


bool File::Truncate(off64_t length) {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(ftruncate64(handle_->fd(), length) != -1);
}


bool File::Flush() {
  ASSERT(handle_->fd() >= 0);
  return TEMP_FAILURE_RETRY(fsync(handle_->fd()) != -1);
}


off64_t File::Length() {
  ASSERT(handle_->fd() >= 0);
  struct stat64 st;
  if (TEMP_FAILURE_RETRY(fstat64(handle_->fd(), &st)) == 0) {
    return st.st_size;
  }
  return -1;
}


File* File::Open(const char* name, FileOpenMode mode) {
  // Report errors for non-regular files.
  struct stat64 st;
  if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
    // Only accept regular files and character devices.
    if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
      errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
      return NULL;
    }
  }
  int flags = O_RDONLY;
  if ((mode & kWrite) != 0) {
    flags = (O_RDWR | O_CREAT);
  }
  if ((mode & kTruncate) != 0) {
    flags = flags | O_TRUNC;
  }
  flags |= O_CLOEXEC;
  int fd = TEMP_FAILURE_RETRY(open64(name, flags, 0666));
  if (fd < 0) {
    return NULL;
  }
  if (((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) {
    off64_t position = lseek64(fd, 0, SEEK_END);
    if (position < 0) {
      return NULL;
    }
  }
  return new File(new FileHandle(fd));
}


File* File::OpenStdio(int fd) {
  if (fd < 0 || 2 < fd) return NULL;
  return new File(new FileHandle(fd));
}


bool File::Exists(const char* name) {
  struct stat64 st;
  if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
    return S_ISREG(st.st_mode);
  } else {
    return false;
  }
}


bool File::Create(const char* name) {
  int fd = TEMP_FAILURE_RETRY(
      open64(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666));
  if (fd < 0) {
    return false;
  }
  return (close(fd) == 0);
}


bool File::CreateLink(const char* name, const char* target) {
  int status = TEMP_FAILURE_RETRY(symlink(target, name));
  return (status == 0);
}


bool File::Delete(const char* name) {
  File::Type type = File::GetType(name, true);
  if (type == kIsFile) {
    return TEMP_FAILURE_RETRY(unlink(name)) == 0;
  } else if (type == kIsDirectory) {
    errno = EISDIR;
  } else {
    errno = ENOENT;
  }
  return false;
}


bool File::DeleteLink(const char* name) {
  File::Type type = File::GetType(name, false);
  if (type == kIsLink) {
    return TEMP_FAILURE_RETRY(unlink(name)) == 0;
  }
  errno = EINVAL;
  return false;
}


bool File::Rename(const char* old_path, const char* new_path) {
  File::Type type = File::GetType(old_path, true);
  if (type == kIsFile) {
    return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
  } else if (type == kIsDirectory) {
    errno = EISDIR;
  } else {
    errno = ENOENT;
  }
  return false;
}


bool File::RenameLink(const char* old_path, const char* new_path) {
  File::Type type = File::GetType(old_path, false);
  if (type == kIsLink) {
    return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
  } else if (type == kIsDirectory) {
    errno = EISDIR;
  } else {
    errno = EINVAL;
  }
  return false;
}


bool File::Copy(const char* old_path, const char* new_path) {
  File::Type type = File::GetType(old_path, true);
  if (type == kIsFile) {
    struct stat64 st;
    if (TEMP_FAILURE_RETRY(stat64(old_path, &st)) != 0) {
      return false;
    }
    int old_fd = TEMP_FAILURE_RETRY(open64(old_path, O_RDONLY | O_CLOEXEC));
    if (old_fd < 0) {
      return false;
    }
    int new_fd = TEMP_FAILURE_RETRY(
        open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode));
    if (new_fd < 0) {
      VOID_TEMP_FAILURE_RETRY(close(old_fd));
      return false;
    }
    off64_t offset = 0;
    int result = 1;
    while (result > 0) {
      // Loop to ensure we copy everything, and not only up to 2GB.
      result = TEMP_FAILURE_RETRY(
          sendfile64(new_fd, old_fd, &offset, kMaxUint32));
    }
    // From sendfile man pages:
    //   Applications may wish to fall back to read(2)/write(2) in the case
    //   where sendfile() fails with EINVAL or ENOSYS.
    if (result < 0 && (errno == EINVAL || errno == ENOSYS)) {
      const intptr_t kBufferSize = 8 * KB;
      uint8_t buffer[kBufferSize];
      while ((result = TEMP_FAILURE_RETRY(
          read(old_fd, buffer, kBufferSize))) > 0) {
        int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result));
        if (wrote != result) {
          result = -1;
          break;
        }
      }
    }
    if (result < 0) {
      int e = errno;
{'fraction_non_alphanumeric': 0.15275283092541975, 'fraction_numerical': 0.019367434595860992, 'mean_word_length': 3.2615640599001665, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 80, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1042963', 'n_tokens_mistral': 5079, 'n_tokens_neox': 4869, 'n_words': 1184}