move.cc (fstransform-0.9.3-src) | : | move.cc (fstransform-0.9.4) | ||
---|---|---|---|---|
skipping to change at line 29 | skipping to change at line 29 | |||
* | * | |||
* move.cc | * move.cc | |||
* | * | |||
* Created on: Aug 18, 2011 | * Created on: Aug 18, 2011 | |||
* Author: max | * Author: max | |||
*/ | */ | |||
#include "first.hh" | #include "first.hh" | |||
#include "move.hh" | #include "move.hh" | |||
#include "io/io.hh" // for fm_io | #include "io/io.hh" // for fm_io | |||
#include "io/io_posix.hh" // for fm_io_posix | #include "io/io_posix.hh" // for fm_io_posix | |||
#include "io/io_prealloc.hh" // for fm_io_prealloc | ||||
#if defined(FT_HAVE_STRING_H) | ||||
# include <stdlib.h> // for atoi() | ||||
#elif defined(FT_HAVE_CSTRING) | ||||
# include <cstdlib> // for atoi() | ||||
#endif | ||||
#if defined(FT_HAVE_STRING_H) | #if defined(FT_HAVE_STRING_H) | |||
# include <string.h> // for strcmp() | # include <string.h> // for strcmp() | |||
#elif defined(FT_HAVE_CSTRING) | #elif defined(FT_HAVE_CSTRING) | |||
# include <cstring> // for strcmp() | # include <cstring> // for strcmp() | |||
#endif | #endif | |||
#include <vector> // for std::vector | #include <vector> // for std::vector | |||
FT_NAMESPACE_BEGIN | FT_NAMESPACE_BEGIN | |||
enum { FC_ARGS_COUNT = FT_IO_NS fm_io::FC_ARGS_COUNT }; | enum { FC_ARGS_COUNT = FT_IO_NS fm_io::FC_ARGS_COUNT }; | |||
static char const* const* label = FT_IO_NS fm_io::label; | // static char const* const* label = FT_IO_NS fm_io::label; | |||
static char const* const* LABEL = FT_IO_NS fm_io::LABEL; | static char const* const* LABEL = FT_IO_NS fm_io::LABEL; | |||
/** default constructor */ | /** default constructor */ | |||
fm_move::fm_move() | fm_move::fm_move() | |||
: this_io(0) | : this_io(0), quit_immediately(false) | |||
{ } | { } | |||
/** destructor. calls quit() */ | /** destructor. calls quit() */ | |||
fm_move::~fm_move() | fm_move::~fm_move() | |||
{ | { | |||
quit(); | quit(); | |||
} | } | |||
/** | /** | |||
* checks that I/O is open. | * checks that I/O is open. | |||
skipping to change at line 75 | skipping to change at line 82 | |||
if (this_io->is_open()) | if (this_io->is_open()) | |||
this_io = & io; | this_io = & io; | |||
else | else | |||
err = ENOTCONN; // I/O is not open ! | err = ENOTCONN; // I/O is not open ! | |||
return err; | return err; | |||
} | } | |||
/** performs cleanup. called by destructor, you can also call it explicitly afte r (or instead of) run() */ | /** performs cleanup. called by destructor, you can also call it explicitly afte r (or instead of) run() */ | |||
void fm_move::quit() | void fm_move::quit() | |||
{ | { | |||
if (this_io != 0) { | if (this_io != NULL) { | |||
if (this_io->is_open()) | if (this_io->is_open()) | |||
this_io->close(); | this_io->close(); | |||
this_io = 0; | this_io = NULL; | |||
} | } | |||
} | } | |||
bool fm_move::is_initialized() const | bool fm_move::is_initialized() const | |||
{ | { | |||
return this_io != NULL && this_io->is_open(); | return this_io != NULL && this_io->is_open(); | |||
} | } | |||
/** return EISCONN if remapper is initialized, else call quit_io() and return 0 */ | /** return EISCONN if remapper is initialized, else call quit_io() and return 0 */ | |||
int fm_move::check_is_closed() | int fm_move::check_is_closed() | |||
skipping to change at line 123 | skipping to change at line 130 | |||
} | } | |||
return err; | return err; | |||
} | } | |||
/** | /** | |||
* high-level do-everything method. calls in sequence init(), run() and cleanup( ). | * high-level do-everything method. calls in sequence init(), run() and cleanup( ). | |||
* return 0 if success, else error. | * return 0 if success, else error. | |||
*/ | */ | |||
int fm_move::main(int argc, char ** argv) | int fm_move::main(int argc, char ** argv) | |||
{ | { | |||
fm_move mover; | #ifdef ZTEST | |||
ztest(); | ||||
ztest_ptr(); | ||||
#endif | ||||
if (argc == 2 && !strcmp("--help", argv[1])) | fm_move mover; | |||
return mover.usage(argv[0]); | ||||
int err = mover.init(argc, argv); | int err = mover.init(argc, argv); | |||
if (err == 0) | if (err == 0 && !mover.quit_immediately) | |||
err = mover.run(); | err = mover.run(); | |||
/* | /* | |||
* note 1.2.2) fsmove::main() must check for unreported errors | * note 1.2.2) fsmove::main() must check for unreported errors | |||
* and log them them with message "failed with unreported error" | * and log them them with message "failed with unreported error" | |||
*/ | */ | |||
if (!ff_log_is_reported(err)) | if (!ff_log_is_reported(err)) | |||
err = ff_log(FC_ERROR, err, "failed with unreported error"); | err = ff_log(FC_ERROR, err, "failed with unreported error"); | |||
return err; | return err; | |||
} | } | |||
/** print command-line usage to stdout and return 0 */ | /** print command-line usage to stdout and return 0 */ | |||
int fm_move::usage(const char * program_name) { | int fm_move::usage(const char * program_name) | |||
{ | ||||
quit_immediately = true; | ||||
ff_log(FC_NOTICE, 0, "Usage: %s [OPTION]... %s %s [--exclude FILE...]", prog ram_name, LABEL[0], LABEL[1]); | ff_log(FC_NOTICE, 0, "Usage: %s [OPTION]... %s %s [--exclude FILE...]", prog ram_name, LABEL[0], LABEL[1]); | |||
ff_log(FC_NOTICE, 0, "Recursively move files and folders from %s to %s,", LA BEL[0], LABEL[1]); | ff_log(FC_NOTICE, 0, "Recursively move files and folders from %s to %s,", LA BEL[0], LABEL[1]); | |||
ff_log(FC_NOTICE, 0, "even if %s and %s are almost full or share their free space", LABEL[0], LABEL[1]); | ff_log(FC_NOTICE, 0, "even if %s and %s are almost full or share their free space", LABEL[0], LABEL[1]); | |||
ff_log(FC_NOTICE, 0, "(for example if %s is a file system inside a loop-file _inside_ %s)\n", LABEL[0], LABEL[1]); | ff_log(FC_NOTICE, 0, "(for example if %s is a file system inside a loop-file _inside_ %s)\n", LABEL[1], LABEL[0]); | |||
return ff_log(FC_NOTICE, 0, | return ff_log(FC_NOTICE, 0, | |||
"Mandatory arguments to long options are mandatory for short options too.\n " | "Mandatory arguments to long options are mandatory for short options too.\n " | |||
" -- end of options. treat subsequent parameters as arg uments\n" | " -- end of options. treat subsequent parameters as arg uments\n" | |||
" even if they start with '-'\n" | " even if they start with '-'\n" | |||
" -e, --exclude FILE... skip these files, i.e. do not move them.\n" | " -e, --exclude FILE... skip these files, i.e. do not move them.\n" | |||
" must be last argument\n" | " must be last argument\n" | |||
" -f, --force-run run even if some safety checks fail\n" | " -f, --force-run run even if some safety checks fail\n" | |||
" --io=posix use POSIX I/O (default)\n" | " --io=posix use POSIX I/O and move files (default)\n" | |||
#ifdef FT_HAVE_FM_IO_IO_PREALLOC | ||||
" --io=prealloc use POSIX I/O and preallocate files (do NOT move t | ||||
hem)\n" | ||||
#endif | ||||
" --inode-cache-mem use in-memory inode cache (default)\n" | ||||
" --inode-cache=DIR create and use directory DIR for inode cache\n" | ||||
" --log-color=MODE set messages color. MODE is one of:" | ||||
" auto (default), none, ansi\n" | ||||
" --log-format=FMT set messages format. FMT is one of:\n" | ||||
" msg (default), level_msg, time_level_msg,\n" | ||||
" time_level_function_msg\n" | ||||
" -n, --no-action, --simulate-run\n" | " -n, --no-action, --simulate-run\n" | |||
" do not actually move any file or directory\n" | " do not actually move any file or directory\n" | |||
" -q, --quiet be quiet\n" | " -q, --quiet be quiet\n" | |||
" -qq be very quiet, only print warnings or errors\n" | " -qq be very quiet, only print warnings or errors\n" | |||
" -v, --verbose be verbose, print what is being done\n" | " -v, --verbose be verbose, print what is being done\n" | |||
" -vv be very verbose, print a lot of detailed output\n" | " -vv be very verbose, print a lot of detailed output\n" | |||
" -vvv be incredibly verbose (warning: prints LOTS of out put)\n" | " -vvv be incredibly verbose (warning: prints LOTS of out put)\n" | |||
" --help display this help and exit\n" | " --help display this help and exit\n" | |||
" --version output version information and exit\n"); | " --version output version information and exit\n"); | |||
} | } | |||
/** output version information and return 0 */ | /** output version information and return 0 */ | |||
int fm_move::version() | int fm_move::version() | |||
{ | { | |||
quit_immediately = true; | ||||
return ff_log(FC_NOTICE, 0, | return ff_log(FC_NOTICE, 0, | |||
"fsmove (fstransform utilities) " FT_VERSION "\n" | "fsmove (fstransform utilities) " FT_VERSION "\n" | |||
"Copyright (C) 2011-2012 Massimiliano Ghilardi\n" | "Copyright (C) 2011-2017 Massimiliano Ghilardi\n" | |||
"\n" | "\n" | |||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses /gpl.html>.\n" | "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses /gpl.html>.\n" | |||
"This is free software: you are free to change and redistribute it.\ n" | "This is free software: you are free to change and redistribute it.\ n" | |||
"There is NO WARRANTY, to the extent permitted by law.\n"); | "There is NO WARRANTY, to the extent permitted by law.\n"); | |||
} | } | |||
int fm_move::invalid_cmdline(const char * program_name, int err, const char * fm t, ...) | int fm_move::invalid_cmdline(const char * program_name, int err, const char * fm t, ...) | |||
{ | { | |||
va_list args; | va_list args; | |||
skipping to change at line 204 | skipping to change at line 228 | |||
/** | /** | |||
* parse command line and initialize all subsystems (job, I/O, log...) | * parse command line and initialize all subsystems (job, I/O, log...) | |||
* return 0 if success, else error. | * return 0 if success, else error. | |||
* | * | |||
* implementation: parse command line, fill a fm_args and call init(const fm_arg s &) | * implementation: parse command line, fill a fm_args and call init(const fm_arg s &) | |||
*/ | */ | |||
int fm_move::init(int argc, char const* const* argv) | int fm_move::init(int argc, char const* const* argv) | |||
{ | { | |||
fm_args args; | fm_args args; | |||
int err; | int err; | |||
ft_log_level level = FC_INFO, new_level; | ||||
fm_io_kind io_kind; | fm_io_kind io_kind; | |||
ft_log_fmt format = FC_FMT_MSG; | ||||
ft_log_level level = FC_INFO, new_level; | ||||
ft_log_color color = FC_COL_AUTO; | ||||
bool format_set = false; | ||||
do { | do { | |||
if ((err = check_is_closed()) != 0) | if ((err = check_is_closed()) != 0) | |||
break; | break; | |||
if (argc == 0) { | if (argc == 0) { | |||
err = invalid_cmdline("fsmove", 0, "missing arguments: %s %s", label [0], label[1], label[2]); | err = invalid_cmdline("fsmove", 0, "missing arguments: %s %s", LABEL [0], LABEL[1]); | |||
break; | break; | |||
} | } | |||
const char * arg, * program_name = argv[0]; | const char * arg, * program_name = argv[0]; | |||
ft_size io_args_n = 0; | ft_size io_args_n = 0; | |||
bool allow_opts = true; | bool allow_opts = true; | |||
// skip program_name | // skip program_name | |||
while (err == 0 && --argc) { | while (err == 0 && --argc) { | |||
arg = * ++argv; | arg = * ++argv; | |||
/* -e is allowed even after '--', but must be last argument */ | /* -e is allowed even after '--', but must be last argument */ | |||
if (io_args_n == FC_ARGS_COUNT && argc > 0 && arg[0] == '-' | if (io_args_n == FC_ARGS_COUNT && argc > 0 && arg[0] == '-' | |||
&& (!strcmp(arg, "-e") || !strcmp(arg, "--exclude")) ) | && (!strcmp(arg, "-e") || !strcmp(arg, "--exclude")) ) | |||
{ | { | |||
args.exclude_list = argv; | args.exclude_list = argv + 1; | |||
// -e uses all remaining arguments, so stop processing them | // -e uses all remaining arguments, so stop processing them | |||
break; | break; | |||
} | } | |||
if (allow_opts && arg[0] == '-') { | if (allow_opts && arg[0] == '-') { | |||
/* -- end of options*/ | /* -- end of options*/ | |||
if (!strcmp(arg, "--")) | if (!strcmp(arg, "--")) | |||
allow_opts = false; | allow_opts = false; | |||
skipping to change at line 257 | skipping to change at line 284 | |||
|| (new_level = FC_TRACE, !strcmp(arg, "-vv")) | || (new_level = FC_TRACE, !strcmp(arg, "-vv")) | |||
|| (new_level = FC_DUMP, !strcmp(arg, "-vvv"))) | || (new_level = FC_DUMP, !strcmp(arg, "-vvv"))) | |||
{ | { | |||
if (level == FC_INFO) | if (level == FC_INFO) | |||
level = new_level; | level = new_level; | |||
else { | else { | |||
err = invalid_cmdline(program_name, 0, "options -q, -qq, -v, -vv, -vvv, --quiet, --verbose are mutually exclusive"); | err = invalid_cmdline(program_name, 0, "options -q, -qq, -v, -vv, -vvv, --quiet, --verbose are mutually exclusive"); | |||
break; | break; | |||
} | } | |||
} | } | |||
else if (!strncmp(arg, "--log-color=", 12)) { | ||||
/* --color=(auto|none|ansi) */ | ||||
arg += 12; | ||||
if (!strcmp(arg, "ansi")) | ||||
color = FC_COL_ANSI; | ||||
else if (!strcmp(arg, "none")) | ||||
color = FC_COL_NONE; | ||||
else | ||||
color = FC_COL_AUTO; | ||||
} | ||||
else if (!strncmp(arg, "--log-format=", 13)) { | ||||
/* --color=(auto|none|ansi) */ | ||||
arg += 13; | ||||
if (!strcmp(arg, "level_msg")) | ||||
format = FC_FMT_LEVEL_MSG; | ||||
else if (!strcmp(arg, "time_level_msg")) | ||||
format = FC_FMT_DATETIME_LEVEL_MSG; | ||||
else if (!strcmp(arg, "time_level_function_msg")) | ||||
format = FC_FMT_DATETIME_LEVEL_CALLER_MSG; | ||||
else | ||||
format = FC_FMT_MSG; | ||||
format_set = true; | ||||
} | ||||
else if (!strncmp(arg, "--x-log-", 8)) { | ||||
/* --x-log-FILE=LEVEL */ | ||||
arg += 8; | ||||
const char * equal = strchr(arg, '='); | ||||
ft_mstring logger_name(arg, equal ? equal - arg : strlen(arg | ||||
)); | ||||
ft_log_level logger_level = equal ? (ft_log_level) atoi(equa | ||||
l+1) : FC_INFO; | ||||
ft_log::get_logger(logger_name).set_level(logger_level); | ||||
} | ||||
/* -f force run: degrade failed sanity checks from ERRORS (which stop execution) to WARNINGS (which let execution continue) */ | /* -f force run: degrade failed sanity checks from ERRORS (which stop execution) to WARNINGS (which let execution continue) */ | |||
else if (!strcmp(arg, "-f") || !strcmp(arg, "--force-run")) { | else if (!strcmp(arg, "-f") || !strcmp(arg, "--force-run")) { | |||
args.force_run = true; | args.force_run = true; | |||
} | } | |||
/* -n simulate run: do not read or write device blocks */ | /* -n simulate run: do not read or write device blocks */ | |||
else if (!strcmp(arg, "-n") || !strcmp(arg, "--no-action") || !s trcmp(arg, "--simulate-run")) { | else if (!strcmp(arg, "-n") || !strcmp(arg, "--no-action") || !s trcmp(arg, "--simulate-run")) { | |||
args.simulate_run = true; | args.simulate_run = true; | |||
} | } | |||
/* --posix */ | /* --io=posix */ | |||
else if ((io_kind = FC_IO_POSIX, !strcmp(arg, "--posix"))) | else if ((io_kind = FC_IO_POSIX, !strcmp(arg, "--io=posix")) | |||
#ifdef FT_HAVE_FM_IO_IO_PREALLOC | ||||
|| (io_kind = FC_IO_PREALLOC, !strcmp(arg, "--io=preall | ||||
oc")) | ||||
#endif | ||||
) | ||||
{ | { | |||
if (args.io_kind == FC_IO_AUTODETECT) | if (args.io_kind == FC_IO_AUTODETECT) | |||
args.io_kind = io_kind; | args.io_kind = io_kind; | |||
else | else { | |||
err = invalid_cmdline(program_name, 0, "option --posix c | #ifdef FT_HAVE_FM_IO_IO_PREALLOC | |||
an only be specified once"); | err = invalid_cmdline(program_name, 0, "options --io=pos | |||
} else { | ix and --io=prealloc are mutually exclusive"); | |||
#else | ||||
err = invalid_cmdline(program_name, 0, "option --io=posi | ||||
x can be specified only once"); | ||||
#endif | ||||
} | ||||
} | ||||
else if (!strcmp(arg, "--inode-cache-mem")) { | ||||
args.inode_cache_path = NULL; | ||||
} | ||||
else if (!strncmp(arg, "--inode-cache=", 14)) { | ||||
// do not allow empty dir name | ||||
if (arg[14] != '\0') | ||||
args.inode_cache_path = arg + 14; | ||||
} | ||||
else if (!strcmp(arg, "--help")) { | ||||
return usage(args.program_name); | ||||
} | ||||
else if (!strcmp(arg, "--version")) { | ||||
return version(); | ||||
} | ||||
else { | ||||
err = invalid_cmdline(program_name, 0, "unknown option: '%s' ", arg); | err = invalid_cmdline(program_name, 0, "unknown option: '%s' ", arg); | |||
break; | break; | |||
} | } | |||
continue; | continue; | |||
} | } | |||
/** found an argument */ | /** found an argument */ | |||
if (io_args_n < FC_ARGS_COUNT) | if (io_args_n < FC_ARGS_COUNT) | |||
args.io_args[io_args_n++] = arg; | args.io_args[io_args_n++] = arg; | |||
else | else | |||
err = invalid_cmdline(program_name, 0, "too many arguments"); | err = invalid_cmdline(program_name, 0, "too many arguments"); | |||
} | } | |||
if (err == 0) { | if (err != 0) | |||
/* if autodetect, use POSIX I/O */ | break; | |||
if (args.io_kind == FC_IO_AUTODETECT) | ||||
args.io_kind = FC_IO_POSIX; | /* if autodetect, use POSIX I/O */ | |||
if (args.io_kind == FC_IO_AUTODETECT) | ||||
if (args.io_kind == FC_IO_POSIX && io_args_n < FC_ARGS_COUNT) { | args.io_kind = FC_IO_POSIX; | |||
switch (io_args_n) { | ||||
case 0: | if (args.io_kind == FC_IO_POSIX || args.io_kind == FC_IO_PREALLOC) { | |||
err = invalid_cmdline(program_name, 0, "missing argument | ||||
s: %s %s", label[0], label[1]); | if (io_args_n == 0) { | |||
break; | err = invalid_cmdline(program_name, 0, "missing arguments: %s %s | |||
case 1: | ", LABEL[0], LABEL[1]); | |||
err = invalid_cmdline(program_name, 0, "missing argument | break; | |||
: %s", label[1]); | } else if (io_args_n == 1) { | |||
break; | err = invalid_cmdline(program_name, 0, "missing argument: %s", L | |||
} | ABEL[1]); | |||
break; | ||||
} | ||||
const char * source_root = args.io_args[FT_IO_NS fm_io::FC_SOURCE_RO | ||||
OT]; | ||||
if (args.inode_cache_path != NULL && source_root != NULL | ||||
&& (args.inode_cache_path[0] == '/') != (source_root[0] == '/')) | ||||
{ | ||||
err = invalid_cmdline(program_name, 0, | ||||
"relative/absolute path mismatch between s | ||||
ource directory `%s'\n" | ||||
"\tand inode-cache directory `%s':\n" | ||||
"\tthey must be either both absolute, i.e. | ||||
starting with `/',\n" | ||||
"\tor both relative, i.e. NOT starting wit | ||||
h `/'", | ||||
source_root, | ||||
args.inode_cache_path); | ||||
break; | ||||
} | } | |||
} | } | |||
} while (0); | } while (0); | |||
if (err == 0) { | if (err == 0) { | |||
ft_log_fmt format = level < FC_DEBUG ? FC_FMT_DATETIME_LEVEL_MSG : level | ft_log::get_root_logger().set_level(level); | |||
== FC_DEBUG ? FC_FMT_LEVEL_MSG : FC_FMT_MSG; | ||||
if (level <= FC_DEBUG) { | ||||
/* note 1.4.1) -v enables FC_FMT_LEVEL_MSG also for stdout/stderr */ | ||||
/* note 1.4.2) -vv enables FC_FMT_DATETIME_LEVEL_MSG also for stdout | ||||
/stderr */ | ||||
ft_log_appender::redefine(stdout, format, level, FC_NOTICE); | ||||
ft_log_appender::redefine(stderr, format, FC_WARN); | ||||
} else if (level > FC_INFO) | /* note 1.4.1) -v sets format FC_FMT_LEVEL_MSG */ | |||
ft_log_appender::redefine(stdout, format, level); | /* note 1.4.2) -vv sets format FC_FMT_DATETIME_LEVEL_MSG */ | |||
if (!format_set) | ||||
format = level < FC_DEBUG ? FC_FMT_DATETIME_LEVEL_MSG : level == FC_ | ||||
DEBUG ? FC_FMT_LEVEL_MSG : FC_FMT_MSG; | ||||
ft_log::get_root_logger().set_level(level); | // no dot alter appenders min_level | |||
ft_log_appender::reconfigure_all(format, FC_LEVEL_NOT_SET, color); | ||||
err = init(args); | err = init(args); | |||
} | } | |||
return err; | return err; | |||
} | } | |||
/** | /** | |||
* initialize all subsystems (job, I/O, log...) using specified arguments | * initialize all subsystems (job, I/O, log...) using specified arguments | |||
* return 0 if success, else error. | * return 0 if success, else error. | |||
*/ | */ | |||
int fm_move::init(const fm_args & args) | int fm_move::init(const fm_args & args) | |||
{ | { | |||
FT_IO_NS fm_io * io = NULL; | FT_IO_NS fm_io * io = NULL; | |||
int err = 0; | int err = 0; | |||
switch (args.io_kind) { | switch (args.io_kind) { | |||
case FC_IO_POSIX: | case FC_IO_POSIX: | |||
if ((err = check_is_closed()) != 0) | if ((err = check_is_closed()) != 0) | |||
break; | ||||
io = new FT_IO_NS fm_io_posix(); | ||||
break; | break; | |||
default: | ||||
ff_log(FC_ERROR, 0, "tried to initialize unknown I/O '%d': not POSIX | io = new FT_IO_NS fm_io_posix(); | |||
", (int) args.io_kind); | break; | |||
err = -ENOSYS; | #ifdef FT_HAVE_FM_IO_IO_PREALLOC | |||
case FC_IO_PREALLOC: | ||||
if ((err = check_is_closed()) != 0) | ||||
break; | break; | |||
io = new FT_IO_NS fm_io_prealloc(); | ||||
break; | ||||
#endif | ||||
default: | ||||
ff_log(FC_ERROR, 0, "tried to initialize unknown I/O '%d': not POSIX" | ||||
#ifdef FT_HAVE_FM_IO_IO_PREALLOC | ||||
", not PREALLOC" | ||||
#endif | ||||
, (int) args.io_kind); | ||||
err = -ENOSYS; | ||||
break; | ||||
} | } | |||
if (io != NULL) { | if (io != NULL) { | |||
if ((err = io->open(args)) == 0) | if ((err = io->open(args)) == 0) | |||
this_io = io; | this_io = io; | |||
else | else | |||
delete io; | delete io; | |||
} | } | |||
return err; | return err; | |||
} | } | |||
End of changes. 27 change blocks. | ||||
60 lines changed or deleted | 174 lines changed or added |