-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
48e3ad6
commit 4724e17
Showing
11 changed files
with
249 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ cmake_install.cmake | |
install_manifest.txt | ||
compile_commands.json | ||
CTestTestfile.cmake | ||
build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
cmake_minimum_required(VERSION 3.0.0) | ||
project(sparse VERSION 1.0.0) | ||
|
||
add_executable(sparse src/main.cpp src/config.cpp src/file.cpp src/memory.cpp src/stats.cpp) | ||
|
||
target_include_directories(sparse PRIVATE src/include) | ||
|
||
include(CTest) | ||
enable_testing() | ||
|
||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) | ||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) | ||
include(CPack) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#include "config.hpp" | ||
|
||
#include <argp.h> | ||
#include <cstdlib> | ||
#include <unistd.h> | ||
|
||
const char *argp_program_version = "v1.0.0"; | ||
const char *argp_program_bug_address = "Andrew Grechkin <[email protected]>"; | ||
|
||
auto args_doc = "FILE"; | ||
auto doc = "sparse -- a simple tool to pipe standard input into a sparse file"; | ||
|
||
const argp_option options[] = { | ||
{"input", 'i', "FILE", 0, "Input from FILE instead of standard input" }, | ||
{"verbose", 'v', 0, 0, "Produce verbose output" }, | ||
{ 0 }, | ||
}; | ||
|
||
error_t parse_opt(int key, char *arg, struct argp_state *state) { | ||
auto args = static_cast<Config*>(state->input); | ||
switch (key) { | ||
case 'v': | ||
args->verbose = 1; | ||
break; | ||
case 'i': | ||
args->input_file = arg; | ||
break; | ||
case ARGP_KEY_NO_ARGS: | ||
argp_usage(state); | ||
case ARGP_KEY_ARG: | ||
args->file = arg; | ||
state->next = state->argc; | ||
break; | ||
default: | ||
return ARGP_ERR_UNKNOWN; | ||
} | ||
return 0; | ||
} | ||
|
||
const argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 }; | ||
|
||
int Config::parse(int argc, char ** argv) | ||
{ | ||
buf_size = getpagesize(); | ||
return argp_parse(&argp, argc, argv, 0, nullptr, this); | ||
} | ||
|
||
Config& Config::get() | ||
{ | ||
static Config inst; | ||
return inst; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#include "config.hpp" | ||
#include "file.hpp" | ||
#include "stats.hpp" | ||
#include "memory.hpp" | ||
|
||
#include <cstdlib> | ||
#include <cstdio> | ||
#include <err.h> | ||
#include <unistd.h> | ||
#include <fcntl.h> | ||
|
||
File::~File() | ||
{ | ||
if (close(fd)) | ||
warn("Unable to properly close destination file"); | ||
} | ||
|
||
File::File(const char* path) | ||
{ | ||
auto mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; | ||
|
||
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); | ||
|
||
if (fd == -1) | ||
err(EXIT_FAILURE, "Unable to create file '%s'", path); | ||
} | ||
|
||
void File::save_sparce_file(int src) | ||
{ | ||
auto& config = Config::get(); | ||
|
||
auto buf = malloc(config.buf_size); | ||
if (!buf) | ||
err(EXIT_FAILURE, "Unable to create buffer"); | ||
|
||
auto stats = Stats(); | ||
while (true) { | ||
auto bytes_read = read(src, buf, config.buf_size); | ||
|
||
if (bytes_read == 0) { | ||
break; | ||
} else if (bytes_read < 0) { | ||
err(EXIT_FAILURE, "Unable to read data from source"); | ||
} | ||
|
||
stats.total_read += bytes_read; | ||
if (is_memory_dirty(buf, bytes_read)) { | ||
auto bytes_written = write(fd, buf, bytes_read); | ||
if (bytes_written != bytes_read) { | ||
err(EXIT_FAILURE, "Unable to write into destination file"); | ||
} | ||
stats.total_written += bytes_written; | ||
} else { | ||
lseek(fd, bytes_read, SEEK_CUR); | ||
ftruncate(fd, current_offset()); | ||
stats.total_saved += bytes_read; | ||
} | ||
} | ||
|
||
if (config.verbose) { | ||
printf("Buffer used: %ld bytes\n", config.buf_size); | ||
stats.print(); | ||
} | ||
} | ||
|
||
size_t File::current_offset() const | ||
{ | ||
return lseek(fd, 0, SEEK_CUR); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#ifndef __SPARSE__CONFIG_HPP__ | ||
#define __SPARSE__CONFIG_HPP__ | ||
|
||
#include <cstddef> | ||
|
||
struct Config | ||
{ | ||
static Config& get(); | ||
|
||
size_t verbose = 0; | ||
size_t buf_size = 0; | ||
char *input_file = nullptr; | ||
char *file = nullptr; | ||
|
||
int parse(int argc, char ** argv); | ||
|
||
Config(const Config&) = delete; | ||
void operator= (const Config&) = delete; | ||
|
||
private: | ||
Config() {} | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#ifndef __SPARSE__FILE_HPP__ | ||
#define __SPARSE__FILE_HPP__ | ||
|
||
#include <cstdlib> | ||
|
||
class File | ||
{ | ||
public: | ||
~File(); | ||
File(const char* path); | ||
void save_sparce_file(int src); | ||
void save_sparce_file(int src, int buf_size); | ||
size_t current_offset() const; | ||
|
||
private: | ||
int fd; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#ifndef __SPARSE__MEMORY_HPP__ | ||
#define __SPARSE__MEMORY_HPP__ | ||
|
||
#include <cstdlib> | ||
|
||
bool is_memory_dirty(const void* buf, size_t size); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#ifndef __SPARSE__STATS_HPP__ | ||
#define __SPARSE__STATS_HPP__ | ||
|
||
#include <cstdlib> | ||
|
||
struct Stats | ||
{ | ||
size_t total_read = 0; | ||
size_t total_written = 0; | ||
size_t total_saved = 0; | ||
void print() const; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#include "config.hpp" | ||
#include "file.hpp" | ||
|
||
#include <cstdio> | ||
#include <error.h> | ||
#include <unistd.h> | ||
#include <err.h> | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
auto& config = Config::get(); | ||
|
||
auto err = config.parse(argc, argv); | ||
if (!err) { | ||
auto src = 0; | ||
if (config.input_file) { | ||
} | ||
|
||
auto dst = File(config.file); | ||
dst.save_sparce_file(src); | ||
|
||
if (src && close(src)) | ||
::err(EXIT_FAILURE, "Unable to close source"); | ||
|
||
return EXIT_SUCCESS; | ||
} | ||
|
||
return err; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#include "memory.hpp" | ||
|
||
#include <cstring> | ||
|
||
bool is_memory_dirty(const void* buf, size_t size) | ||
{ | ||
auto ptr = static_cast<const char*>(buf); | ||
return *ptr || std::memcmp(ptr, ptr + 1, size - 1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#include "stats.hpp" | ||
|
||
#include <cstdio> | ||
|
||
void Stats::print() const | ||
{ | ||
std::printf("Read total: %lu bytes\n", total_read); | ||
std::printf("Saved total: %lu bytes\n", total_saved); | ||
std::printf("Written total: %lu bytes\n", total_written); | ||
} |