📄 basepkg.cc
字号:
//=======================================================================// BasePkg.cc//-----------------------------------------------------------------------// This file is part of the package paco// Copyright (C) 2004-2007 David Rosal <david.3r@gmail.com>// For more information visit http://paco.sourceforge.net//=======================================================================#include "config.h"#include "paco.h"#include "File.h"#include "BaseConfig.h"#include "BasePkg.h"#include <cstring>#include <fstream>#include <algorithm>#include <cctype>// For *BSD statfs()#if HAVE_SYS_PARAM_H# include <sys/param.h>#endif#if HAVE_SYS_MOUNT_H# include <sys/mount.h>#endif#if (HAVE_SYS_STATVFS_H && HAVE_STATVFS)# define STATFS statvfs# include <sys/statvfs.h>#elif HAVE_STATFS# define STATFS statfs# if HAVE_SYS_VFS_H# include <sys/vfs.h># elif HAVE_SYS_STATFS# include <sys/statfs.h># endif#elif STATFS# undef STATFS#endifusing std::string;using namespace Paco;BasePkg::BasePkg(string const& __name): mName(__name), mLog(BaseConfig::logdir() + "/" + mName), mDate(0), mSizeInst(0), mSizeMiss(0), mFilesInst(0), mFilesMiss(0), mSortType(NO_SORT), mSortReverse(false), mConfOpts(){ if (mName.empty() || ispunct(mName.at(0))) throw ConstructorError(); // Check for the '#!paco' header (security issue) std::ifstream f(log().c_str()); string buf; if (!(f && getline(f, buf) && buf.find("#!paco") == 0)) throw ConstructorError(); while (getline(f, buf) && buf.size() > 3 && buf[0] == '#' && buf[2] == ':') { switch (buf[1]) { case 'd': mDate = str2num<int>(buf.substr(3)); break; case '#': sscanf(buf.c_str(), "##:%ld|%ld|%ld|%ld", &mSizeInst, &mSizeMiss, &mFilesInst, &mFilesMiss); break; case 'c': mConfOpts = buf.substr(3); return; } }}// [virtual]BasePkg::~BasePkg(){ for (iterator f = begin(); f != end(); ++f) { assert(*f != NULL); if (*f) { delete *f; *f = NULL; } }}void BasePkg::getFiles(int type /* = ALL_FILES */){ clear(); string buf; FileStream<std::ifstream> f(mLog); // skip the header while (getline(f, buf) && buf[0] == '#') ; if (f.eof()) return; char path[4096]; long raw, bz2, gz, s; // Read files do { if (UNLIKELY(4 != sscanf(buf.c_str(), "%[^|]|%ld|%ld|%ld", path, &raw, &gz, &bz2))) { goto ____parse_error; } switch (path[0]) { case '/': if (type & INSTALLED_FILES) { if (raw != File::SIZEOF_MISSING) push_back(new File(path, raw)); if (gz != File::SIZEOF_MISSING) push_back(new File(string(path) + ".gz", gz)); if (bz2 != File::SIZEOF_MISSING) push_back(new File(string(path) + ".bz2", bz2)); } break; case '-': if (type & MISSING_FILES) { s = (raw != File::SIZEOF_MISSING) ? raw : 0 + (gz != File::SIZEOF_MISSING) ? gz : 0 + (bz2 != File::SIZEOF_MISSING) ? bz2 : 0; push_back(new File(&path[1], s, File::MISSING)); } break; default: ____parse_error: throw X("Parse error while reading " + mLog + "\nRun 'paco -au' to update the database"); } } while (getline(f, buf));}bool BasePkg::hasFile(File* file){ sort(); return std::binary_search(begin(), end(), file, Sorter());}void BasePkg::sort( SortType type, // = SORT_NAME bool reverse) // = false{ // sort only if the list is not already sorted if (mSortType != type) { std::sort(begin(), end(), Sorter(type)); mSortType = type; } // reverse only if needed if (mSortReverse != reverse) { std::reverse(begin(), end()); mSortReverse = reverse; }}//// Update the log file @log.// IMPORTANT: If return value is false it means that the log does not// exist or it was empty and it has been removed.//// [static]bool BasePkg::updateLog(string const& log){ if (access(log.c_str(), F_OK) < 0) return false; FileStream<std::ifstream> f(log); string buf; if (!(getline(f, buf) && !buf.find("#!paco"))) return true; // header std::ostringstream s; while (getline(f, buf) && buf[0] == '#') { if (buf.size() > 1 && buf[1] != '#') s << buf << "\n"; } if (f.eof()) { // empty log (no logged files, only header) unlink(log.c_str()); return false; } char* p; char* file; enum { RAW, GZ, BZ2, NSIZES }; long size[NSIZES], sizeInst = 0, sizeMiss = 0, filesInst = 0, filesMiss = 0; do { if (UNLIKELY(!(file = strchr(buf.c_str(), '/')))) continue; else if ((p = strchr(file, '|'))) *p++ = 0; if (getSize(size[RAW], file) + getSize(size[GZ], file, ".gz") + getSize(size[BZ2], file, ".bz2")) { // installed file s << file; for (uint i = 0; i < NSIZES; ++i) { s << "|" << size[i]; if (size[i] > 0) sizeInst += size[i]; } s << "\n"; filesInst++; } else if (p && LIKELY(3 == sscanf(p, "%ld|%ld|%ld", &size[RAW], &size[GZ], &size[BZ2]))) { // missing file s << "-" << file; for (uint i = 0; i < NSIZES; ++i) { s << "|" << size[i]; if (size[i] > 0) sizeMiss += size[i]; } s << "\n"; filesMiss++; } else { // missing file with unknown sizes s << "-" << file << "|-2|-2|-2\n"; filesMiss++; } } while (getline(f, buf)); f.close(); FileStream<std::ofstream> f2(log); f2 << "#!paco-" PACKAGE_VERSION "\n##:" << sizeInst << "|" << sizeMiss << "|" << filesInst << "|" << filesMiss << "\n" << s.str(); return true;}// [static]bool BasePkg::getSize(long& size, string const& base, string const& suffix){ string path(base + suffix); struct stat s; if (lstat(path.c_str(), &s) < 0) size = File::SIZEOF_MISSING; else if (S_ISREG(s.st_mode)) {#if STATFS struct STATFS f;#endif int bsize; if (BaseConfig::blockSize()) bsize = BaseConfig::blockSize();#if STATFS else if (LIKELY(!STATFS(path.c_str(), &f) && (f.f_bsize > 0))) bsize = f.f_bsize;#endif else bsize = s.st_blksize; size = ((s.st_size / bsize) + ((s.st_size % bsize) > 0)) * bsize; } else if (S_ISLNK(s.st_mode)) size = File::SIZEOF_SYMLINK; return (size != File::SIZEOF_MISSING);}//-----------------//// BasePkg::Sorter ////-----------------//BasePkg::Sorter::Sorter(SortType type /* = SORT_NAME */): mSortFunc(type == SORT_NAME ? &Sorter::sortByName : &Sorter::sortBySize){ }inline bool BasePkg::Sorter::operator()(File* left, File* right) const{ return (this->*mSortFunc)(left, right);}inline bool BasePkg::Sorter::sortByName(File* left, File* right) const{ return left->name() > right->name();}inline bool BasePkg::Sorter::sortBySize(File* left, File* right) const{ return left->size() > right->size();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -