int main(int argc, char **argv) { g_BufferedMemorySize = 100; string compressorName; string commandLineOptions; std::vector<string> fuseOptions; fuseOptions.push_back(argv[0]); po::options_description desc("Usage: " PACKAGE "_offline [options] path\n" "\nPath may be directory or file.\n" "\nNo options mean decompression mode.\n\n" "Allowed options"); desc.add_options() ("options,o", po::value<string>(&commandLineOptions), "fc_c:arg - compression method (lzo/bzip2/zlib/lzma)\n" " (default: gz)\n" "fc_b:arg - size of blocks in kilobytes\n" " (default: 100)\n" "fc_d - run in debug mode\n" "fc_ma:arg - files with passed mime types to be\n" " always not compressed\n" "fc_mr:arg - files with passed mime types to be\n" " always compressed\n" "\nOther options are passed directly to fuse library. See fuse documentation for full list of supported options.\n") ("dir_lower", po::value<string>(&g_dirLower), "path") ("help,h", "print this help") ("version,v", "print version") ("quiet,q", "quiet mode") ; po::positional_options_description pdesc; pdesc.add("dir_lower", 1); po::variables_map vm; try { po::store(po::command_line_parser(argc, argv).options(desc).positional(pdesc).run(), vm); } catch (...) { print_help(desc); exit(EXIT_FAILURE); } po::notify(vm); if (vm.count("help")) { print_help(desc); exit(EXIT_SUCCESS); } if (vm.count("version")) { print_license(); exit(EXIT_SUCCESS); } if (vm.count("quiet")) { g_QuietMode = true; } g_RLog = new rlog::RLog("FuseCompress_offline", g_QuietMode ? LOG_NOTICE : LOG_INFO, true); if (vm.count("options")) { typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep(","); tokenizer tokens(commandLineOptions, sep); for (tokenizer::iterator tok_it = tokens.begin(); tok_it != tokens.end(); ++tok_it) { if ((*tok_it).find_first_of("fc_", 0, 3) == 0) { typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep(":"); tokenizer tokens(*tok_it, sep); tokenizer::iterator key = tokens.begin(); tokenizer::iterator value = key; ++value; if (*key == "fc_c") { if (value == tokens.end()) { rError("Compression type not set!"); exit(EXIT_FAILURE); } compressorName = *value; } if (*key == "fc_b") { if (value == tokens.end()) { rError("Block size not set!"); exit(EXIT_FAILURE); } g_BufferedMemorySize = boost::lexical_cast<unsigned int>(*value); } if (*key == "fc_d") { g_DebugMode = true; g_RLog->setLevel(LOG_DEBUG); } if (*key == "fc_ma") { if (value == tokens.end()) { rError("Mime type(s) not set!"); exit(EXIT_FAILURE); } g_CompressedMagic.Add(*value); } if (*key == "fc_mr") { if (value == tokens.end()) { rError("Mime type(s) not set!"); exit(EXIT_FAILURE); } g_CompressedMagic.Remove(*value); } } else { fuseOptions.push_back("-o"); fuseOptions.push_back(*tok_it); } } } if (!vm.count("dir_lower")) { print_help(desc); exit(EXIT_FAILURE); } g_BufferedMemorySize *= 1024; if (compressorName != "") { g_RawOutput = false; if (g_CompressionType.parseType(compressorName) == false) { rError("Compressor %s not found!", compressorName.c_str()); exit(EXIT_FAILURE); } } fs::path pathLower(g_dirLower #if BOOST_VERSION <= 104600 , fs::native #endif ); if (!pathLower.is_complete()) { char cwd[PATH_MAX]; // Transform relative path to absolute path. if (getcwd(cwd, sizeof(cwd)) == NULL) { rError("Cannot determine current working directory!"); exit(EXIT_FAILURE); } pathLower = fs::path(cwd #if BOOST_VERSION <= 104600 , fs::native #endif ) / pathLower; } // Set signal handler to catch SIGINT (CTRL+C). struct sigaction setup_kill; memset(&setup_kill, 0, sizeof(setup_kill)); setup_kill.sa_handler = catch_kill; sigaction(SIGINT, &setup_kill, NULL); // Iterate over directory structure and execute compress // for every files there. if (nftw(const_cast<char *>(pathLower.string().c_str()), compress, 100, FTW_PHYS | FTW_CHDIR)) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { g_BufferedMemorySize = 100; g_DebugMode = false; string compressorName; string commandLineOptions; vector<string> fuseOptions; fuseOptions.push_back(argv[0]); po::options_description desc("Usage: " PACKAGE " [options] dir_lower dir_mount\n" "\nAllowed options"); desc.add_options() ("options,o", po::value<string>(&commandLineOptions), "fc_c:arg - compression method\n" " (lzo/bzip2/zlib/lzma)\n" " (default: zlib)\n" "fc_b:arg - size of blocks in kilobytes\n" " (default: 100)\n" "fc_d - run in debug mode\n" "fc_ma:\"arg1;arg2\" - files with passed mime types to be\n" " always not compressed\n" "fc_mr:\"arg1;arg2\" - files with passed mime types to be\n" " always compressed\n" "\nOther options are passed directly to fuse library. See fuse documentation for full list of supported options.\n") ("dir_lower", po::value<string>(&g_dirLower), "storage directory") ("dir_mount", po::value<string>(&g_dirMount), "mount point") ("help,h", "print this help") ("version,v", "print version") ; po::positional_options_description pdesc; pdesc.add("dir_lower", 1); pdesc.add("dir_mount", 1); po::variables_map vm; try { po::store(po::command_line_parser(argc, argv).options(desc).positional(pdesc).run(), vm); } catch (...) { print_help(desc); exit(EXIT_FAILURE); } po::notify(vm); if (vm.count("help")) { print_help(desc); exit(EXIT_SUCCESS); } if (vm.count("version")) { print_license(); exit(EXIT_SUCCESS); } if (vm.count("options")) { typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep(","); tokenizer tokens(commandLineOptions, sep); for (tokenizer::iterator tok_it = tokens.begin(); tok_it != tokens.end(); ++tok_it) { if ((*tok_it).find_first_of("fc_", 0, 3) == 0) { typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep(":"); tokenizer tokens(*tok_it, sep); tokenizer::iterator key = tokens.begin(); tokenizer::iterator value = key; ++value; if (*key == "fc_c") { if (value == tokens.end()) { std::cerr << "Compression type not set!" << std::endl; exit(EXIT_FAILURE); } compressorName = *value; } if (*key == "fc_b") { if (value == tokens.end()) { std::cerr << "Block size not set!" << std::endl; exit(EXIT_FAILURE); } g_BufferedMemorySize = boost::lexical_cast<unsigned int>(*value); } if (*key == "fc_d") { fuseOptions.push_back("-f"); g_DebugMode = true; } if (*key == "fc_ma") { if (value == tokens.end()) { std::cerr << "Mime type(s) not set!" << std::endl; exit(EXIT_FAILURE); } g_CompressedMagic.Add(*value); } if (*key == "fc_mr") { if (value == tokens.end()) { std::cerr << "Mime type(s) not set!" << std::endl; exit(EXIT_FAILURE); } g_CompressedMagic.Remove(*value); } } else { fuseOptions.push_back("-o"); fuseOptions.push_back(*tok_it); } } } if (vm.count("dir_lower")) { g_dirLower = vm["dir_lower"].as<string>(); } else { print_help(desc); exit(EXIT_FAILURE); } if (vm.count("dir_mount")) { g_dirMount = vm["dir_mount"].as<string>(); } else { print_help(desc); exit(EXIT_FAILURE); } g_BufferedMemorySize *= 1024; // Set up default options for fuse. // fuseOptions.push_back("-o"); fuseOptions.push_back("default_permissions,use_ino,kernel_cache"); fuseOptions.push_back(g_dirMount); // Set default transformation as user wanted. // if ((compressorName != "") && (g_CompressionType.parseType(compressorName) == false)) { cerr << "Compressor " << compressorName << " not found!" << endl; exit(EXIT_FAILURE); } DIR *dir; if ((dir = opendir(g_dirLower.c_str())) == NULL) { int errns = errno; cerr << "Failed to open storage directory " << "'" << g_dirLower << "': " << strerror(errns) << endl; exit(EXIT_FAILURE); } vector<const char *> fuse_c_str; for (unsigned int i = 0; i < fuseOptions.size(); ++i) { fuse_c_str.push_back((fuseOptions[i].c_str())); } init_log(); FuseCompress fusecompress; umask(0); return fusecompress.Run(dir, fuse_c_str.size(), &fuse_c_str[0]); }
ssize_t Compress::write(const char *buf, size_t size, off_t offset) { // Spurious call to write when file has not been opened // happened during testing... if (m_fd == -1) { rWarning("Compress::write Spurios call detected!"); errno = -EBADF; return -1; } assert (m_fd != -1); rDebug("Compress::write size: 0x%lx, offset: 0x%lx", (long int) size, (long int) offset); // We have an oppourtunity to decide whether we really // want to compress the file. We use file magic library // to detect mime type of the file to decide the compress // strategy. if ((m_IsCompressed == true) && (offset == 0) && (m_RawFileSize == FileHeader::MaxSize) && (g_CompressedMagic.isNativelyCompressed(buf, size))) { m_IsCompressed = false; } if (m_IsCompressed == false) { return pwrite(m_fd, buf, size, offset); } else { // If we write data containing only zeros to the end of the file, // we can just increase size of the file. No need to really // compress and write buffer of zeros... if ((m_fh.size == offset) && FileUtils::isZeroOnly(buf, size)) { assert(size > 0); m_fh.size = offset + size; } else { off_t rawFileSize = writeCompressed(m_lm, offset, m_RawFileSize, buf, size, m_fd, m_RawFileSize); if (rawFileSize == -1) return -1; m_RawFileSize = rawFileSize; assert(size > 0); m_fh.size = max(m_fh.size, (off_t) (offset + size)); // Defragment the file only if raw file size if bigger than 4096 bytes // and raw file size is about 20% bigger than it would be uncompressed. if (m_RawFileSize > 4096 && m_RawFileSize > m_fh.size + ((m_fh.size * 2) / 10)) { DefragmentFast(); } } return size; } }