blob: e1b46db5b5e416254a374eb7d61e1a1a9700048f [file] [log] [blame]
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "third_party/ijar/platform_utils.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#if defined(COMPILER_MSVC) || defined(__CYGWIN__)
#include <windows.h>
#endif // defined(COMPILER_MSVC) || defined(__CYGWIN__)
#ifndef COMPILER_MSVC
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#endif // not COMPILER_MSVC
#include <string>
#if defined(COMPILER_MSVC) || defined(__CYGWIN__)
#include "src/main/cpp/util/errors.h"
#include "src/main/cpp/util/file_platform.h"
#endif // defined(COMPILER_MSVC) || defined(__CYGWIN__)
namespace devtools_ijar {
using std::string;
bool stat_file(const char* path, Stat* result) {
#if defined(COMPILER_MSVC) || defined(__CYGWIN__)
std::wstring wpath;
if (!blaze_util::AsWindowsPathWithUncPrefix(path, &wpath)) {
blaze_util::die(255, "stat_file: AsWindowsPathWithUncPrefix(%s) failed",
path);
}
bool success = false;
BY_HANDLE_FILE_INFORMATION info;
HANDLE handle = ::CreateFileW(
/* lpFileName */ wpath.c_str(),
/* dwDesiredAccess */ GENERIC_READ,
/* dwShareMode */ FILE_SHARE_READ,
/* lpSecurityAttributes */ NULL,
/* dwCreationDisposition */ OPEN_EXISTING,
/* dwFlagsAndAttributes */ FILE_ATTRIBUTE_NORMAL,
/* hTemplateFile */ NULL);
if (handle != INVALID_HANDLE_VALUE &&
::GetFileInformationByHandle(handle, &info)) {
success = true;
// TODO(laszlocsomor): use info.nFileSizeHigh after we updated total_size to
// be u8 type.
result->total_size = info.nFileSizeLow;
// TODO(laszlocsomor): query the actual permissions and write in file_mode.
result->file_mode = 0777;
result->is_directory = (info.dwFileAttributes != INVALID_FILE_ATTRIBUTES) &&
(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
::CloseHandle(handle);
return success;
#else // !(defined(COMPILER_MSVC) || defined(__CYGWIN__))
struct stat statst;
if (stat(path, &statst) < 0) {
return false;
}
result->total_size = statst.st_size;
result->file_mode = statst.st_mode;
result->is_directory = (statst.st_mode & S_IFDIR) != 0;
return true;
#endif // defined(COMPILER_MSVC) || defined(__CYGWIN__)
}
bool write_file(const char* path, mode_t perm, const void* data, size_t size) {
#ifdef COMPILER_MSVC
// TODO(laszlocsomor) 2016-12-01: implement this and other methods, in order
// to close https://github.com/bazelbuild/bazel/issues/2157.
fprintf(stderr, "Not yet implemented on Windows\n");
return false;
#else // not COMPILER_MSVC
int fd = open(path, O_CREAT | O_WRONLY, perm);
if (fd < 0) {
fprintf(stderr, "Cannot open file %s for writing: %s\n", path,
strerror(errno));
return false;
}
bool result = true;
int error = write(fd, data, size);
// Check for an error condition, or if we didn't write all of the data.
if (error < 0 || static_cast<size_t>(error) != size) {
fprintf(stderr, "Cannot write %zu bytes to file %s: %s\n", size, path,
strerror(errno));
result = false;
}
if (close(fd)) {
fprintf(stderr, "Cannot close file %s: %s\n", path, strerror(errno));
result = false;
}
return result;
#endif // COMPILER_MSVC
}
bool read_file(const char* path, void* buffer, size_t size) {
#ifdef COMPILER_MSVC
// TODO(laszlocsomor) 2016-12-01: implement this and other methods, in order
// to close https://github.com/bazelbuild/bazel/issues/2157.
fprintf(stderr, "Not yet implemented on Windows\n");
return false;
#else // not COMPILER_MSVC
// read the input file
int fd = open(path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Can't open file %s for reading: %s\n", path,
strerror(errno));
return false;
}
bool result = true;
size_t nb_read = 0;
while (nb_read < size) {
size_t to_read = size - nb_read;
if (to_read > 16384 /* 16K */) {
to_read = 16384;
}
ssize_t r = read(fd, static_cast<uint8_t*>(buffer) + nb_read, to_read);
if (r < 0) {
fprintf(stderr, "Can't read %zu bytes from file %s: %s\n", to_read, path,
strerror(errno));
result = false;
break;
}
nb_read += r;
}
if (close(fd)) {
fprintf(stderr, "Cannot close file %s: %s\n", path, strerror(errno));
result = false;
}
return result;
#endif // COMPILER_MSVC
}
string get_cwd() {
#ifdef COMPILER_MSVC
// TODO(laszlocsomor) 2016-12-01: implement this and other methods, in order
// to close https://github.com/bazelbuild/bazel/issues/2157.
fprintf(stderr, "Not yet implemented on Windows\n");
return "";
#else // not COMPILER_MSVC
char cwd[PATH_MAX];
if (getcwd(cwd, PATH_MAX) == NULL) {
fprintf(stderr, "getcwd() failed: %s\n", strerror(errno));
return "";
} else {
return string(cwd);
}
#endif // COMPILER_MSVC
}
bool make_dirs(const char* path, mode_t mode) {
#ifdef COMPILER_MSVC
// TODO(laszlocsomor) 2016-12-01: implement this and other methods, in order
// to close https://github.com/bazelbuild/bazel/issues/2157.
fprintf(stderr, "Not yet implemented on Windows\n");
return false;
#else // not COMPILER_MSVC
// Directories created must have executable bit set and be owner writeable.
// Otherwise, we cannot write or create any file inside.
mode |= S_IWUSR | S_IXUSR;
char path_[PATH_MAX];
Stat file_stat;
strncpy(path_, path, PATH_MAX);
path_[PATH_MAX - 1] = 0;
char* pointer = path_;
while ((pointer = strchr(pointer, '/')) != NULL) {
if (path_ != pointer) { // skip leading slash
*pointer = 0;
if (!stat_file(path_, &file_stat) && mkdir(path_, mode) < 0) {
fprintf(stderr, "Cannot create folder %s: %s\n", path_,
strerror(errno));
return false;
}
*pointer = '/';
}
pointer++;
}
return true;
#endif // COMPILER_MSVC
}
} // namespace devtools_ijar