blob: 383997419cc82e8975cdac51ca954441a52525c8 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <base/logging.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fstream>
#ifdef __ANDROID__
#include <fcntl.h> // open flags
#include <ftw.h> // nftw
#include <libgen.h> // dirname
#include <sys/stat.h> // mkdir
#include <ziparchive/zip_archive.h>
#endif
#include "tools.h"
namespace huddly {
const int kShellCmdOutBufSize = 128;
bool RunCommand(const std::string& cmd, std::string* output) {
char buff[kShellCmdOutBufSize];
std::string result;
// TODO(crbug.com/719567): Use DLOG(INFO) instead of "if (verbose) std::out".
bool verbose = false;
#ifdef DEV_DEBUG
verbose = true;
#endif // DEV_DEBUG
if (verbose)
LOG(INFO) << "[CMD] " << cmd;
std::FILE* pipe(popen(cmd.c_str(), "r"));
if (!pipe) {
*output = "failed to open pipe";
return false;
}
while (fgets(buff, sizeof(buff), pipe) != nullptr) {
result += buff;
}
if (verbose)
LOG(INFO) << "[OUT] " << result;
pclose(pipe);
*output = result;
return true;
}
std::string UsbIdToString(uint16_t vendor_id, uint16_t product_id) {
char buffer[10];
snprintf(buffer, sizeof(buffer), "%04x:%04x", vendor_id, product_id);
return buffer;
}
uint32_t LittleEndianUint8ArrayToUint32(uint8_t* array) {
return array[0] | array[1] << 8 | array[2] << 16 | array[3] << 24;
}
uint64_t GetNowMilliSec() {
struct timeval tp;
gettimeofday(&tp, nullptr);
return static_cast<uint16_t>(tp.tv_sec * 1000) +
static_cast<uint64_t>(tp.tv_usec / 1000);
}
void SleepMilliSec(uint32_t millisec) {
// Blocking sleep.
// TODO(porce): research the impact of EINTR and the alternative of nanosleep.
usleep(millisec * 1000);
}
bool GetFileSize(const std::string& img_path,
uint32_t* file_size,
std::string* err_msg) {
// TODO(porce): file_size - uint32_t or uint64_t
struct stat file_stat;
if (stat(img_path.c_str(), &file_stat) < 0) {
*err_msg += ".. failed to get file size: ";
*err_msg += strerror(errno);
return false;
}
*file_size = static_cast<uint32_t>(file_stat.st_size);
return true;
}
uint32_t ReadFileToArray(const std::string& img_path,
uint32_t data_len,
uint8_t* data,
std::string* err_msg) {
if (data_len == 0 || data == nullptr) {
*err_msg += ".. failed to read file. Zero data_len or null data";
return 0;
}
std::ifstream fin(img_path, std::ifstream::binary);
fin.read(reinterpret_cast<char*>(data), data_len);
return fin.gcount();
}
#ifdef __ANDROID__
/**
* Returns a pointer to a string representing the parent directory
* of the given path
*
* Note: Required call to {@code free()} to prevent memory leak
*
* @param path - the full path
* @return an allocated char pointer of the name of the parent directory
*/
static inline char* parentname(const char* path) {
size_t slen = strlen(dirname(path)) + 1;
char* sub_path = (char*)malloc(slen);
std::strncpy(sub_path, path, slen);
sub_path[slen - 1] = (char)'\0';
return sub_path;
}
/**
* Given an absolute directory path creates the necessary parent directories
*
* Note: Absolute Path required
*
* @param path - absolute path
* @param mode - masked File permissions bits for new directory
* @return |0| if successful, |-1| otherwise.
*/
static int mkdirs(const char* path, mode_t mode) {
if (!path) {
errno = EINVAL;
return -1;
}
// check if path already exists
std::ifstream f(path);
if (f.good()) {
return 0;
}
// Check path is root
if (strlen(path) == 1 && path[0] == '/') {
return 0;
}
char* sub_path = parentname(path);
mkdirs(sub_path, mode);
free(sub_path);
return mkdir(path, mode);
}
/**
* Creates parent hierarchy if it does not exist
*
* Note: Absolute Path required
*
* @param path - absolute path
* @param mode - masked File permissions bits for created directories
* @return |0| if successful, |-1| otherwise.
*/
static int CheckFileParents(const char* path, mode_t mode) {
char* sub_path = parentname(path);
int ret = mkdirs(sub_path, mode);
free(sub_path);
return ret;
}
/**
* Uncompresses a zip file to a given directory
*
* @param path - absolute destination directory path
* @param mode - absolute path to zip file
* @param err_msg - error message
* @return |true| if successful, |false| otherwise.
*/
bool UncompressZip(const char* dir_path,
const char* file_path,
std::string* err_msg) {
ZipArchiveHandle handle;
void* iteration_cookie;
ZipEntry data;
ZipString name;
if (OpenArchive(file_path, &handle) != 0) {
*err_msg = std::string("Unable to open archive: ") + "\t" + strerror(errno);
return false;
}
if (StartIteration(handle, &iteration_cookie, nullptr, nullptr) != 0) {
*err_msg = std::string("Unable to uncompress: ") + "\t" + strerror(errno);
return false;
}
while (!Next(iteration_cookie, &data, &name)) {
std::string file_entry_name(name.name, name.name + name.name_length);
std::string path = std::string(dir_path) + file_entry_name;
CheckFileParents(path.c_str(), 0700);
int fd = open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0600);
if (fd < 0) {
*err_msg = std::string("Unable to create temp file: ") + path + "\t" +
strerror(errno);
return false;
}
int32_t res = ExtractEntryToFile(handle, &data, fd);
close(fd);
if (res != 0) {
*err_msg =
std::string("Unable to extract file: ") + "\t" + strerror(errno);
return false;
}
}
EndIteration(iteration_cookie);
CloseArchive(handle);
return true;
}
int NftwDeleteFile(const char* fpath,
const struct stat* sb,
int typeFlag,
struct FTW* ftwbuf) {
int ret = remove(fpath);
if (ret != 0) {
LOG(INFO) << "Error deleting: " << fpath << strerror(errno);
}
return ret;
}
#endif
} // namespace huddly