Spin-off syscall-related file operations (#78)

* [file_utils] spin-off syscall-related file operations

1. Eliminate the potential circular dependency between
   persistent-data/block.h and persistent-data/file_utils.h,
   if the former one wants to include the latter.
2. Avoid namespace pollution by removing the "using namespace std"
   declaration in block.tcc.
3. Correct the header hierarchy: base/xml_utils.h now no longer
   depends on the higher-level persistent-data/file_utils.h

* [file_utils] support block files in get_file_length()
This commit is contained in:
Ming-Hung Tsai
2017-04-30 01:51:52 +08:00
committed by Joe Thornber
parent 8f25e1b234
commit b7d418131d
20 changed files with 210 additions and 191 deletions

143
base/file_utils.cc Normal file
View File

@@ -0,0 +1,143 @@
#include "base/file_utils.h"
#include "base/error_string.h"
#include <sstream>
#include <stdexcept>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
//----------------------------------------------------------------
// FIXME: give this namespace a name
namespace {
using namespace std;
int const DEFAULT_MODE = 0666;
int const OPEN_FLAGS = O_DIRECT;
// FIXME: introduce a new exception for this, or at least lift this
// to exception.h
void syscall_failed(char const *call) {
ostringstream out;
out << "syscall '" << call << "' failed: " << base::error_string(errno);
throw runtime_error(out.str());
}
void syscall_failed(string const &call, string const &message)
{
ostringstream out;
out << "syscall '" << call << "' failed: " << base::error_string(errno) << "\n"
<< message;
throw runtime_error(out.str());
}
}
//----------------------------------------------------------------
int
file_utils::open_file(string const &path, int flags) {
int fd = ::open(path.c_str(), OPEN_FLAGS | flags, DEFAULT_MODE);
if (fd < 0)
syscall_failed("open",
"Note: you cannot run this tool with these options on live metadata.");
return fd;
}
bool
file_utils::file_exists(string const &path) {
struct ::stat info;
int r = ::stat(path.c_str(), &info);
if (r) {
if (errno == ENOENT)
return false;
syscall_failed("stat");
return false; // never get here
} else
return S_ISREG(info.st_mode) || S_ISBLK(info.st_mode);
}
void
file_utils::check_file_exists(string const &file) {
struct stat info;
int r = ::stat(file.c_str(), &info);
if (r)
throw runtime_error("Couldn't stat file");
if (!S_ISREG(info.st_mode))
throw runtime_error("Not a regular file");
}
int
file_utils::create_block_file(string const &path, off_t file_size) {
if (file_exists(path)) {
ostringstream out;
out << __FUNCTION__ << ": file '" << path << "' already exists";
throw runtime_error(out.str());
}
int fd = open_file(path, O_CREAT | O_EXCL | O_RDWR);
int r = ::ftruncate(fd, file_size);
if (r < 0)
syscall_failed("ftruncate");
return fd;
}
int
file_utils::open_block_file(string const &path, off_t min_size, bool writeable, bool excl) {
if (!file_exists(path)) {
ostringstream out;
out << __FUNCTION__ << ": file '" << path << "' doesn't exist";
throw runtime_error(out.str());
}
int flags = writeable ? O_RDWR : O_RDONLY;
if (excl)
flags |= O_EXCL;
return open_file(path, flags);
}
uint64_t
file_utils::get_file_length(string const &file) {
struct stat info;
uint64_t nr_bytes;
int r = ::stat(file.c_str(), &info);
if (r)
throw runtime_error("Couldn't stat path");
if (S_ISREG(info.st_mode))
// It's okay to cast st_size to a uint64_t value.
// If LFS is enabled, st_size should not be negative for regular files.
nr_bytes = static_cast<uint64_t>(info.st_size);
else if (S_ISBLK(info.st_mode)) {
// To get the size of a block device we need to
// open it, and then make an ioctl call.
int fd = ::open(file.c_str(), O_RDONLY);
if (fd < 0)
throw runtime_error("couldn't open block device to ascertain size");
r = ::ioctl(fd, BLKGETSIZE64, &nr_bytes);
if (r) {
::close(fd);
throw runtime_error("ioctl BLKGETSIZE64 failed");
}
::close(fd);
} else
// FIXME: needs a better message
throw runtime_error("bad path");
return nr_bytes;
}
//----------------------------------------------------------------

21
base/file_utils.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef BASE_FILE_UTILS_H
#define BASE_FILE_UTILS_H
#include <string>
#include <sys/types.h>
#include <stdint.h>
//----------------------------------------------------------------
namespace file_utils {
int open_file(std::string const &path, int flags);
bool file_exists(std::string const &path);
void check_file_exists(std::string const &file);
int create_block_file(std::string const &path, off_t file_size);
int open_block_file(std::string const &path, off_t min_size, bool writeable, bool excl = true);
uint64_t get_file_length(std::string const &file);
}
//----------------------------------------------------------------
#endif

View File

@@ -1,8 +1,9 @@
#include "xml_utils.h"
#include "persistent-data/file_utils.h"
#include "base/file_utils.h"
#include <fstream>
#include <iostream>
#include <sys/stat.h>
using namespace xml_utils;
@@ -11,13 +12,13 @@ using namespace xml_utils;
void
xml_parser::parse(std::string const &backup_file, bool quiet)
{
persistent_data::check_file_exists(backup_file);
file_utils::check_file_exists(backup_file);
ifstream in(backup_file.c_str(), ifstream::in);
std::unique_ptr<base::progress_monitor> monitor = create_monitor(quiet);
size_t total = 0;
size_t input_length = get_file_length(backup_file);
size_t input_length = file_utils::get_file_length(backup_file);
XML_Error error_code = XML_ERROR_NONE;
while (!in.eof() && error_code == XML_ERROR_NONE) {
@@ -43,19 +44,6 @@ xml_parser::parse(std::string const &backup_file, bool quiet)
}
}
size_t
xml_parser::get_file_length(string const &file) const
{
struct stat info;
int r;
r = ::stat(file.c_str(), &info);
if (r)
throw runtime_error("Couldn't stat backup path");
return info.st_size;
}
unique_ptr<base::progress_monitor>
xml_parser::create_monitor(bool quiet)
{

View File

@@ -36,7 +36,6 @@ namespace xml_utils {
void parse(std::string const &backup_file, bool quiet);
private:
size_t get_file_length(string const &file) const;
unique_ptr<base::progress_monitor> create_monitor(bool quiet);
XML_Parser parser_;