Refactor file & file visitor classes 43/77043/3
authorKyungwook Tak <k.tak@samsung.com>
Tue, 28 Jun 2016 10:18:14 +0000 (19:18 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Wed, 29 Jun 2016 05:44:16 +0000 (14:44 +0900)
Remove duplicated call of checking file's status e.g.,
pkgmgr_is_preloaded, ::stat(), regex...
And Make flag for file visitor to turn on and off of visiting inside of
package path

Change-Id: Ib80a2145f27d9951168951043ef600efcd2e1b87
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
src/framework/service/cs-logic.cpp
src/framework/service/cs-logic.h
src/framework/service/file-system.cpp
src/framework/service/file-system.h
test/internals/test-file-system.cpp

index 1d24873..bcfa7b2 100644 (file)
@@ -110,6 +110,7 @@ std::string resolvePath(const std::string &_path)
 std::string canonicalizePath(const std::string &path, bool checkAccess)
 {
        auto resolved = resolvePath(path);
+
        auto target = File::getPkgPath(resolved);
 
        if (checkAccess && !isReadable(path)) {
@@ -127,6 +128,18 @@ std::string canonicalizePath(const std::string &path, bool checkAccess)
        return target;
 }
 
+FilePtr canonicalizePathWithFile(const std::string &path)
+{
+       auto resolved = resolvePath(path);
+
+       auto fileptr = File::create(path, nullptr);
+
+       if (!isReadable(fileptr->getName()))
+               ThrowExcWarn(CSR_ERROR_FILE_DO_NOT_EXIST, "File is not readable: " << fileptr->getName());
+
+       return fileptr;
+}
+
 } // namespace anonymous
 
 CsLogic::CsLogic(const std::shared_ptr<CsLoader> &loader,
@@ -204,7 +217,7 @@ CsDetectedPtr CsLogic::scanAppDelta(const std::string &pkgPath, const std::strin
        auto lastScanTime = this->m_db->getLastScanTime(pkgPath, t);
 
        // traverse files in app and take which is more danger than riskiest
-       auto visitor = FsVisitor::create(pkgPath, lastScanTime);
+       auto visitor = FsVisitor::create(pkgPath, false, lastScanTime);
 
        CsDetectedPtr riskiest;
 
@@ -246,16 +259,10 @@ CsDetectedPtr CsLogic::scanAppDelta(const std::string &pkgPath, const std::strin
        return riskiest;
 }
 
-RawBuffer CsLogic::scanApp(const CsContext &context, const std::string &pkgPath)
+RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
 {
-       auto fileptr = File::create(pkgPath);
-
-       if (!fileptr)
-               ThrowExc(CSR_ERROR_SERVER, "fileptr shouldn't be empty because didn't check modified");
-       if (!fileptr->isInApp())
-               ThrowExc(CSR_ERROR_SERVER, "fileptr should be in app.");
-
-       const auto &pkgId = fileptr->getAppPkgId();
+       const auto &pkgPath = pkgPtr->getName();
+       const auto &pkgId = pkgPtr->getAppPkgId();
 
        if (context.isScanOnCloud && this->m_loader->scanAppOnCloudSupported())
                return this->scanAppOnCloud(context, pkgPath, pkgId);
@@ -399,7 +406,7 @@ RawBuffer CsLogic::scanFileWithoutDelta(const CsContext &context,
 
        this->m_db->insertDetectedFile(d.targetName, d, this->m_dataVersion);
 
-       return this->handleAskUser(context, d, std::forward<FilePtr>(fileptr));
+       return this->handleAskUser(context, d, std::move(fileptr));
 }
 
 RawBuffer CsLogic::scanFile(const CsContext &context, const std::string &filepath)
@@ -409,43 +416,33 @@ RawBuffer CsLogic::scanFile(const CsContext &context, const std::string &filepat
 
        setCoreUsage(context.coreUsage);
 
-       auto target = canonicalizePath(filepath, true);
+       auto target = canonicalizePathWithFile(filepath);
 
-       if (File::isInApp(target))
+       if (target->isInApp())
                return this->scanApp(context, target);
 
-       DEBUG("Scan request on file: " << target);
-
-       CsEngineContext engineContext(this->m_loader);
-       auto since = this->m_loader->getEngineLatestUpdateTime(engineContext.get());
-
-       auto history = this->m_db->getDetectedAllByNameOnPath(target, since);
+       const auto &name = target->getName();
 
-       FilePtr fileptr;
+       if (target->isDir())
+               ThrowExc(CSR_ERROR_FILE_SYSTEM, "file type shouldn't be directory: " << name);
 
-       // if history exist, fileptr can be null because of modified since value
-       // from history.
-       if (history)
-               fileptr = File::createIfModified(target, static_cast<time_t>(history->ts));
-       else
-               fileptr = File::create(target);
-
-       // non-null fileptr means the file is modified since the last history
-       // OR there's no history at all.
-       if (fileptr) {
-               if (history)
-                       this->m_db->deleteDetectedByNameOnPath(target);
+       DEBUG("Scan request on file: " << name);
 
-               if (fileptr->isDir())
-                       ThrowExc(CSR_ERROR_FILE_SYSTEM,
-                                        "file type shouldn't be directory: " << target);
+       CsEngineContext engineContext(this->m_loader);
+       auto since = this->m_loader->getEngineLatestUpdateTime(engineContext.get());
+       auto history = this->m_db->getDetectedAllByNameOnPath(name, since);
 
-               DEBUG("file[" << target << "] is modified since the detected time. "
+       if (history == nullptr) {
+               DEBUG("No history exist on target. Newly scan needed: " << name);
+               return this->scanFileWithoutDelta(context, name, std::move(target));
+       } else if (target->isModifiedSince(history->ts)) {
+               DEBUG("file[" << name << "] is modified since the detected time. "
                          "let's remove history and re-scan");
-               return this->scanFileWithoutDelta(context, target, std::move(fileptr));
+               this->m_db->deleteDetectedByNameOnPath(name);
+               return this->scanFileWithoutDelta(context, name, std::move(target));
        }
 
-       DEBUG("Usable scan history exist on file: " << target);
+       DEBUG("Usable scan history exist on file: " << name);
 
        if (history->isIgnored)
                return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
@@ -484,12 +481,14 @@ RawBuffer CsLogic::getScannableFiles(const std::string &dir, const std::function
        if (this->m_db->getEngineState(CSR_ENGINE_CS) != CSR_STATE_ENABLE)
                ThrowExc(CSR_ERROR_ENGINE_DISABLED, "engine is disabled");
 
+       auto targetdir = canonicalizePath(dir, true);
+
        CsEngineContext csEngineContext(this->m_loader);
        auto since = this->m_loader->getEngineLatestUpdateTime(csEngineContext.get());
 
-       auto lastScanTime = this->m_db->getLastScanTime(dir, since);
+       auto lastScanTime = this->m_db->getLastScanTime(targetdir, since);
 
-       auto visitor = FsVisitor::create(dir, lastScanTime);
+       auto visitor = FsVisitor::create(targetdir, true, lastScanTime);
 
        isCancelled();
 
@@ -498,26 +497,20 @@ RawBuffer CsLogic::getScannableFiles(const std::string &dir, const std::function
        while (auto file = visitor->next()) {
                isCancelled();
 
-               if (file->isInApp()) {
-                       DEBUG("Scannable app: " << file->getAppPkgPath());
-                       fileset.insert(file->getAppPkgPath());
-               } else {
-                       DEBUG("Scannable file: " << file->getPath());
-                       fileset.insert(file->getPath());
-               }
+               DEBUG("Scannable item: " << file->getName());
+               fileset.insert(file->getName());
        }
 
        if (lastScanTime != -1) {
 
                // for case: scan history exist and not modified.
-               for (auto &row : this->m_db->getDetectedAllByNameOnDir(File::getPkgPath(dir), since)) {
+               for (auto &row : this->m_db->getDetectedAllByNameOnDir(targetdir, since)) {
                        isCancelled();
 
                        try {
-                               auto fileptr = File::create(row->targetName);
+                               auto fileptr = File::create(row->targetName, nullptr);
 
-                               fileset.insert(fileptr->isInApp() ?
-                                               fileptr->getAppPkgPath() : fileptr->getPath());
+                               fileset.insert(fileptr->getName());
                        } catch (const Exception &e) {
                                if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST ||
                                        e.error() == CSR_ERROR_FILE_SYSTEM)
@@ -562,7 +555,7 @@ RawBuffer CsLogic::judgeStatus(const std::string &filepath, csr_cs_action_e acti
        // for file existence / status check. exception thrown.
        FilePtr file;
        try {
-               file = File::create(filepath);
+               file = File::create(filepath, nullptr);
        } catch (const Exception &e) {
                ERROR("file system related exception occured on file: " << filepath <<
                          " This case might be file not exist or type invalid,"
@@ -572,7 +565,7 @@ RawBuffer CsLogic::judgeStatus(const std::string &filepath, csr_cs_action_e acti
                throw;
        }
 
-       const auto &targetName = (file->isInApp() ? file->getAppPkgPath() : filepath);
+       const auto &targetName = file->getName();
 
        CsEngineContext csEngineContext(this->m_loader);
        auto since = this->m_loader->getEngineLatestUpdateTime(csEngineContext.get());
@@ -586,8 +579,7 @@ RawBuffer CsLogic::judgeStatus(const std::string &filepath, csr_cs_action_e acti
        }
 
        // file create based on fileInAppPath(for app target, it is worst detected)
-       if (!isCloudHistory && File::createIfModified(history->fileInAppPath,
-                                                                                                 static_cast<time_t>(history->ts)))
+       if (!isCloudHistory && file->isModifiedSince(history->ts))
                ThrowExc(CSR_ERROR_FILE_CHANGED,
                                 "File[" << history->fileInAppPath << "] modified since db delta inserted."
                                 " Don't refresh detected history to know that it's changed since the"
@@ -761,11 +753,10 @@ RawBuffer CsLogic::handleAskUser(const CsContext &c, CsDetected &d, FilePtr &&fi
        if (d.response == CSR_CS_USER_RESPONSE_REMOVE && !d.targetName.empty()) {
                try {
                        FilePtr _fileptr;
-
                        if (fileptr)
-                               _fileptr = std::forward<FilePtr>(fileptr);
+                               _fileptr = std::move(fileptr);
                        else
-                               _fileptr = File::create(d.targetName);
+                               _fileptr = File::create(d.targetName, nullptr);
 
                        _fileptr->remove();
                } catch (const Exception &e) {
@@ -780,7 +771,7 @@ RawBuffer CsLogic::handleAskUser(const CsContext &c, CsDetected &d, FilePtr &&fi
                                throw;
                }
 
-               this->m_db->deleteDetectedByNameOnPath(File::getPkgPath(d.targetName));
+               this->m_db->deleteDetectedByNameOnPath(d.targetName);
        }
 
        return BinaryQueue::Serialize(CSR_ERROR_NONE, d).pop();
index ca9ef58..86ce3d3 100644 (file)
@@ -56,7 +56,7 @@ public:
        RawBuffer getIgnoredList(const StrSet &dirSet);
 
 private:
-       RawBuffer scanApp(const CsContext &context, const std::string &pkgPath);
+       RawBuffer scanApp(const CsContext &context, const FilePtr &pkgPtr);
        RawBuffer scanAppOnCloud(const CsContext &context, const std::string &pkgPath,
                                                         const std::string &pkgId);
        CsDetectedPtr scanAppDelta(const std::string &pkgPath, const std::string &pkgId,
index a87ce29..c08f345 100644 (file)
@@ -100,35 +100,6 @@ int File::getPkgTypes(const std::string &user, const std::string &pkgid)
        return type;
 }
 
-bool File::isInApp(const std::string &path)
-{
-       std::smatch matched;
-
-       for (const auto &rege : g_regexprs) {
-               if (!std::regex_search(path, matched, rege))
-                       continue;
-
-               std::string pkgUser;
-               std::string pkgId;
-
-               if (matched.size() == 3) {
-                       pkgId = matched[2];
-               } else if (matched.size() == 4) {
-                       pkgUser = matched[2];
-                       pkgId = matched[3];
-               } else {
-                       continue;
-               }
-
-               auto type = File::getPkgTypes(pkgUser, pkgId);
-
-               return (type & static_cast<int>(Type::Package)) &&
-                          (!(type & static_cast<int>(Type::PreLoaded)));
-       }
-
-       return false;
-}
-
 std::string File::getPkgPath(const std::string &path)
 {
        std::smatch matched;
@@ -161,8 +132,28 @@ std::string File::getPkgPath(const std::string &path)
        return path;
 }
 
-File::File(const std::string &fpath, int type) : m_path(fpath), m_type(type)
+File::File(const std::string &fpath, const FilePtr &parentdir, int type,
+                  std::unique_ptr<struct stat> &&statptr) :
+       m_path(fpath), m_type(type), m_statptr(std::move(statptr))
 {
+       if (parentdir != nullptr) {
+               if (parentdir->isPackage()) {
+                       this->m_appPkgPath = parentdir->getAppPkgPath();
+                       this->m_appPkgId = parentdir->getAppPkgId();
+                       this->m_appUser = parentdir->getAppUser();
+
+                       this->m_type |= static_cast<int>(File::Type::Package);
+
+                       if (parentdir->isPreloaded())
+                               this->m_type |= static_cast<int>(File::Type::PreLoaded);
+
+                       return;
+               } else if (!this->isDir()) {
+                       this->m_type &= ~(static_cast<int>(File::Type::Package) |
+                                                         static_cast<int>(File::Type::PreLoaded));
+               }
+       }
+
        std::smatch matched;
 
        for (const auto &rege : g_regexprs) {
@@ -187,42 +178,6 @@ File::File(const std::string &fpath, int type) : m_path(fpath), m_type(type)
        }
 }
 
-const std::string &File::getPath() const noexcept
-{
-       return this->m_path;
-}
-
-bool File::isInApp() const noexcept
-{
-       return (this->m_type & static_cast<int>(Type::Package)) &&
-                  (!(this->m_type & static_cast<int>(Type::PreLoaded)));
-}
-
-bool File::isDir() const noexcept
-{
-       return this->m_type & static_cast<int>(Type::Directory);
-}
-
-bool File::isModified() const noexcept
-{
-       return this->m_type & static_cast<int>(Type::Modified);
-}
-
-const std::string &File::getAppPkgId() const noexcept
-{
-       return this->m_appPkgId;
-}
-
-const std::string &File::getAppUser() const noexcept
-{
-       return this->m_appUser;
-}
-
-const std::string &File::getAppPkgPath() const noexcept
-{
-       return this->m_appPkgPath;
-}
-
 void File::remove() const
 {
        if (this->isInApp()) {
@@ -236,18 +191,18 @@ void File::remove() const
        }
 }
 
-FilePtr File::createIfModified(const std::string &fpath, time_t modifiedSince)
+FilePtr File::createIfModified(const std::string &fpath, const FilePtr &parentdir, time_t modifiedSince)
 {
-       return File::createInternal(fpath, modifiedSince, true);
+       return File::createInternal(fpath, parentdir, modifiedSince, true);
 }
 
-FilePtr File::create(const std::string &fpath, time_t modifiedSince)
+FilePtr File::create(const std::string &fpath, const FilePtr &parentdir, time_t modifiedSince)
 {
-       return File::createInternal(fpath, modifiedSince, false);
+       return File::createInternal(fpath, parentdir, modifiedSince, false);
 }
 
-FilePtr File::createInternal(const std::string &fpath, time_t modifiedSince,
-                                                        bool isModifiedOnly)
+FilePtr File::createInternal(const std::string &fpath, const FilePtr &parentdir,
+                                                        time_t modifiedSince, bool isModifiedOnly)
 {
        auto statptr = getStat(fpath);
 
@@ -267,7 +222,7 @@ FilePtr File::createInternal(const std::string &fpath, time_t modifiedSince,
        if (isModifiedOnly && !(type & static_cast<int>(Type::Modified)))
                return nullptr;
        else
-               return FilePtr(new File(fpath, type));
+               return FilePtr(new File(fpath, parentdir, type, std::move(statptr)));
 }
 
 FsVisitor::DirPtr FsVisitor::openDir(const std::string &dir)
@@ -275,7 +230,7 @@ FsVisitor::DirPtr FsVisitor::openDir(const std::string &dir)
        return std::unique_ptr<DIR, int(*)(DIR *)>(::opendir(dir.c_str()), ::closedir);
 }
 
-FsVisitorPtr FsVisitor::create(const std::string &dirpath, time_t modifiedSince)
+FsVisitorPtr FsVisitor::create(const std::string &dirpath, bool isBasedOnName, time_t modifiedSince)
 {
        auto statptr = getStat(dirpath);
        if (statptr == nullptr)
@@ -284,19 +239,18 @@ FsVisitorPtr FsVisitor::create(const std::string &dirpath, time_t modifiedSince)
        else if (!S_ISDIR(statptr->st_mode))
                ThrowExc(CSR_ERROR_FILE_SYSTEM, "file type is not directory: " << dirpath);
        else
-               return FsVisitorPtr(new FsVisitor(dirpath, modifiedSince));
+               return FsVisitorPtr(new FsVisitor(dirpath, isBasedOnName, modifiedSince));
 }
 
-FsVisitor::FsVisitor(const std::string &dirpath, time_t modifiedSince) :
-       m_since(modifiedSince), m_dirptr(openDir(dirpath)),
-       m_entryBuf(static_cast<struct dirent *>(::malloc(
-                       offsetof(struct dirent, d_name) + NAME_MAX + 1)))
+FsVisitor::FsVisitor(const std::string &dirpath, bool isBasedOnName, time_t modifiedSince) :
+       m_since(modifiedSince), m_dirptr(nullptr, ::closedir),
+       m_entryBuf(static_cast<struct dirent *>(::malloc(offsetof(struct dirent, d_name) + NAME_MAX + 1))),
+       m_isDone(true), m_isBasedOnName(isBasedOnName)
 {
-       if (!this->m_dirptr)
-               ThrowExc(CSR_ERROR_SERVER, "Failed to open dir: " << dirpath);
+       if (this->m_entryBuf == nullptr)
+               throw std::bad_alloc();
 
-       DEBUG("dir opened: " << dirpath);
-       this->m_dirs.push((dirpath.back() == '/') ? dirpath : (dirpath + '/'));
+       this->m_dirs.emplace(File::create(dirpath, nullptr));
 }
 
 FsVisitor::~FsVisitor()
@@ -306,63 +260,83 @@ FsVisitor::~FsVisitor()
 
 FilePtr FsVisitor::next()
 {
-       struct dirent *result = nullptr;
        while (true) {
-               bool isDone = false;
-
-               if (readdir_r(this->m_dirptr.get(), this->m_entryBuf, &result) != 0) {
-                       ERROR("readdir_r error on dir: " << this->m_dirs.front() <<
-                                 " with errno: " << errno << ". Silently ignore this error & dir stream"
-                                 " to reduce side-effect of traversing all the other file systems.");
-                       isDone = true;
-               } else if (result == nullptr) {
-                       DEBUG("End of stream of dir: " << this->m_dirs.front());
-                       isDone = true;
-               } else if (isInBlackList(this->m_dirs.front())) {
-                       DEBUG("dir[" << this->m_dirs.front() << "] is in black list.");
-                       isDone = true;
-               }
-
-               if (isDone) {
-                       this->m_dirs.pop();
+               if (this->m_isDone) {
                        while (!this->m_dirs.empty() &&
-                                       !(this->m_dirptr = openDir(this->m_dirs.front())))
+                                  !(this->m_dirptr = openDir(this->m_dirs.front()->getPath())) &&
+                                  isInBlackList(this->m_dirs.front()->getPath()))
                                this->m_dirs.pop();
 
-                       if (this->m_dirs.empty())
+                       if (this->m_dirs.empty()) {
+                               this->m_currentdir.reset();
+                               this->m_isDone = true;
                                return nullptr;
+                       } else {
+                               this->m_currentdir = std::move(this->m_dirs.front());
+                               this->m_dirs.pop();
+                               this->m_isDone = false;
+                               DEBUG("dir opened: " << this->m_currentdir->getPath());
+                       }
+               }
 
-                       DEBUG("dir opened: " << this->m_dirs.front());
+               struct dirent *result = nullptr;
+               const auto &parent_dirpath = this->m_currentdir->getPath();
+               if (::readdir_r(this->m_dirptr.get(), this->m_entryBuf, &result) != 0) {
+                       ERROR("readdir_r error on dir: " << parent_dirpath <<
+                                 " with errno: " << errno << ". Silently ignore this error & dir stream"
+                                 " to reduce side-effect of traversing all the other file systems.");
+                       this->m_isDone = true;
+                       continue;
+               } else if (result == nullptr) {
+                       DEBUG("End of stream of dir: " << parent_dirpath);
+                       this->m_isDone = true;
                        continue;
                }
 
-               auto &dir = this->m_dirs.front();
                const auto &name = result->d_name;
                auto name_size = ::strlen(name);
 
                if (name_size == 0)
                        continue;
 
+               auto fullpath = (parent_dirpath.back() == '/') ?
+                               (parent_dirpath + name) : (parent_dirpath + "/" + name);
+
                if (result->d_type == DT_DIR) {
-                       if (name_size == 1 && ::strcmp(name, ".") == 0)
-                               continue;
-                       else if (name_size == 2 && ::strcmp(name, "..") == 0)
+                       if ((name_size == 1 && name[0] == '.') ||
+                               (name_size == 2 && name[0] == '.' && name[1] == '.'))
                                continue;
 
-                       DEBUG("push dir to dirs: " << (dir + name + '/'));
-                       this->m_dirs.emplace(dir + name + '/');
+                       FilePtr dirptr;
+                       try {
+                               dirptr = File::create(fullpath, this->m_currentdir);
+                       } catch (const Exception &e) {
+                               if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) {
+                                       WARN("Perm denied to create file on pkg path: " << fullpath);
+                                       continue;
+                               } else {
+                                       throw;
+                               }
+                       }
+
+                       if (this->m_isBasedOnName && dirptr->isInApp())
+                               return dirptr;
+
+                       DEBUG("push dir to dirs queue: " << fullpath);
+                       this->m_dirs.emplace(std::move(dirptr));
                } else if (result->d_type == DT_REG) {
                        try {
-                               auto fileptr = File::createIfModified(dir + name, this->m_since);
+                               auto fileptr = File::createIfModified(
+                                               fullpath, this->m_currentdir, this->m_since);
 
                                if (fileptr)
                                        return fileptr;
                        } catch (const Exception &e) {
                                if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST)
-                                       WARN("file not exist: " << dir << name << " msg: " << e.what());
+                                       WARN("file not exist: " << fullpath << " msg: " << e.what());
                                else if (e.error() == CSR_ERROR_FILE_SYSTEM)
                                        WARN("file type is not regular...? can it be happened?"
-                                                " :" << dir << name << " msg: " << e.what());
+                                                " :" << fullpath << " msg: " << e.what());
                                else
                                        throw;
                        }
index b59c6e9..add4ad8 100644 (file)
@@ -28,6 +28,7 @@
 #include <cstddef>
 #include <ctime>
 #include <dirent.h>
+#include <sys/stat.h>
 
 namespace Csr {
 
@@ -38,21 +39,69 @@ class File {
 public:
        File() = delete;
 
-       const std::string &getPath() const noexcept;
-       bool isInApp() const noexcept;
-       bool isDir() const noexcept;
-       bool isModified() const noexcept;
-       const std::string &getAppPkgId() const noexcept;
-       const std::string &getAppUser() const noexcept;
-       const std::string &getAppPkgPath() const noexcept;
+       inline bool isInApp() const noexcept
+       {
+               return this->isPackage() && !this->isPreloaded();
+       }
+
+       inline bool isPackage() const noexcept
+       {
+               return this->m_type & static_cast<int>(Type::Package);
+       }
+
+       inline bool isPreloaded() const noexcept
+       {
+               return this->m_type & static_cast<int>(Type::PreLoaded);
+       }
+
+       inline bool isModified() const noexcept
+       {
+               return this->m_type & static_cast<int>(Type::Modified);
+       }
+
+       inline bool isModifiedSince(time_t since) const noexcept
+       {
+               return this->m_statptr->st_ctime > since;
+       }
+
+       inline bool isDir() const noexcept
+       {
+               return this->m_type & static_cast<int>(Type::Directory);
+       }
+
+       inline const std::string &getName() const noexcept
+       {
+               return (this->isInApp()) ? this->m_appPkgPath : this->m_path;
+       }
+
+       inline const std::string &getPath() const noexcept
+       {
+               return this->m_path;
+       }
+
+       inline const std::string &getAppPkgId() const noexcept
+       {
+               return this->m_appPkgId;
+       }
+
+       inline const std::string &getAppUser() const noexcept
+       {
+               return this->m_appUser;
+       }
+
+       inline const std::string &getAppPkgPath() const noexcept
+       {
+               return this->m_appPkgPath;
+       }
 
        void remove() const;
 
        // throws FileNotExist and FileSystemError
-       static FilePtr create(const std::string &fpath, time_t modifiedSince = -1);
-       static FilePtr createIfModified(const std::string &fpath, time_t modifiedSince = -1);
+       static FilePtr create(const std::string &fpath, const FilePtr &parentdir,
+                                                 time_t modifiedSince = -1);
+       static FilePtr createIfModified(const std::string &fpath, const FilePtr &parentdir,
+                                                                       time_t modifiedSince = -1);
 
-       static bool isInApp(const std::string &path);
        static std::string getPkgPath(const std::string &path);
 
 private:
@@ -64,14 +113,16 @@ private:
                Directory = (1 << 4)
        };
 
-       static FilePtr createInternal(const std::string &fpath, time_t modifiedSince,
-                                                                 bool isModifiedOnly);
+       static FilePtr createInternal(const std::string &fpath, const FilePtr &parentdir,
+                                                                 time_t modifiedSince, bool isModifiedOnly);
        static int getPkgTypes(const std::string &user, const std::string &pkgid);
 
-       explicit File(const std::string &fpath, int type);
+       explicit File(const std::string &fpath, const FilePtr &parentdir, int type,
+                                 std::unique_ptr<struct stat> &&statptr);
 
        std::string m_path;
        int m_type;
+       std::unique_ptr<struct stat> m_statptr;
        std::string m_appPkgId;    // meaningful only if inApp == true
        std::string m_appUser;     // meaningful only if inApp == true
        std::string m_appPkgPath;  // meaningful only if inApp == true
@@ -89,19 +140,23 @@ public:
        FilePtr next();
 
        // throws FileNotExist and FileSystemError
-       static FsVisitorPtr create(const std::string &dirpath, time_t modifiedSince = -1);
+       static FsVisitorPtr create(const std::string &dirpath, bool isBasedOnName,
+                                                          time_t modifiedSince = -1);
 
 private:
        using DirPtr = std::unique_ptr<DIR, int(*)(DIR *)>;
 
        static DirPtr openDir(const std::string &);
 
-       FsVisitor(const std::string &dirpath, time_t modifiedSince = -1);
+       FsVisitor(const std::string &dirpath, bool isBasedOnName, time_t modifiedSince = -1);
 
        time_t m_since;
-       std::queue<std::string> m_dirs;
+       std::queue<FilePtr> m_dirs;
        DirPtr m_dirptr;
        struct dirent *m_entryBuf;
+       FilePtr m_currentdir;
+       bool m_isDone;
+       bool m_isBasedOnName;
 };
 
 } // namespace Csr
index 0c22437..b0aba7e 100644 (file)
@@ -53,7 +53,7 @@ void __assertFile(const File &file, const std::string &path,
        ASSERT_IF(file.getPath(), path);
        ASSERT_IF(file.getAppUser(), user);
        ASSERT_IF(file.getAppPkgId(), pkgId);
-       ASSERT_IF(file.getAppPkgPath(), pkgPath);
+       ASSERT_IF(file.getName(), pkgPath);
        ASSERT_IF(file.isInApp(), inApp);
 }
 
@@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(remove_file)
 
        __createFile(fpath);
 
-       auto file = File::create(fpath);
+       auto file = File::create(fpath, nullptr);
        BOOST_REQUIRE_NO_THROW(file->remove());
 
        bool isRemoved = access(fpath.c_str(), F_OK) != 0 && errno == ENOENT;
@@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(remove_app)
        Test::uninstall_app(TEST_TPK_PKG_ID);
        ASSERT_INSTALL_APP(TEST_TPK_PATH, TEST_TPK_TYPE);
 
-       auto app = File::create(TEST_TPK_MAL_FILE());
+       auto app = File::create(TEST_TPK_MAL_FILE(), nullptr);
        CHECK_IS_NOT_NULL(app);
        app->remove();
 
@@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(remove_app)
 
 BOOST_AUTO_TEST_CASE(file_visitor_positive_existing)
 {
-       CHECK_IS_NOT_NULL(File::create(TEST_WRITE_FILE));
+       CHECK_IS_NOT_NULL(File::create(TEST_WRITE_FILE, nullptr));
 }
 
 BOOST_AUTO_TEST_CASE(file_visitor_positive_modified)
@@ -181,13 +181,13 @@ BOOST_AUTO_TEST_CASE(file_visitor_positive_modified)
        // if modifiedSince is same to modified time in file stat,
        // the file will be regarded as ''not modified'' no File::create returns null.
 
-       CHECK_IS_NOT_NULL(File::create(file, beforeWrite));
-       CHECK_IS_NULL(File::create(file, afterWrite));
+       CHECK_IS_NOT_NULL(File::create(file, nullptr, beforeWrite));
+       CHECK_IS_NULL(File::create(file, nullptr, afterWrite));
 }
 
 BOOST_AUTO_TEST_CASE(file_visitor_negative_non_existing)
 {
-       BOOST_REQUIRE_THROW(File::create(TEST_DIR "/non_existing_file"), Csr::Exception);
+       BOOST_REQUIRE_THROW(File::create(TEST_DIR "/non_existing_file", nullptr), Csr::Exception);
 }
 
 BOOST_AUTO_TEST_CASE(directory_visitor_positive_existing)
@@ -195,7 +195,7 @@ BOOST_AUTO_TEST_CASE(directory_visitor_positive_existing)
        std::string dir(TEST_DIR_VISIT);
 
        // test for existing dir
-       auto visitor = FsVisitor::create(dir);
+       auto visitor = FsVisitor::create(dir, true);
        CHECK_IS_NOT_NULL(visitor);
 
        int cnt = 0;
@@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(directory_visitor_positive_modified)
 
        __writeFile(file);
 
-       auto visitor = FsVisitor::create(dir, beforeWrite);
+       auto visitor = FsVisitor::create(dir, true, beforeWrite);
        CHECK_IS_NOT_NULL(visitor);
 
        int cnt = 0;
@@ -226,4 +226,13 @@ BOOST_AUTO_TEST_CASE(directory_visitor_positive_modified)
        ASSERT_IF(cnt, 1);
 }
 
+BOOST_AUTO_TEST_CASE(app_directory_visitor_positive)
+{
+       auto visitor = FsVisitor::create(TEST_DIR_APPS(), true);
+       CHECK_IS_NOT_NULL(visitor);
+
+       while (auto file = visitor->next())
+               BOOST_MESSAGE("visit target name: " << file->getPath());
+}
+
 BOOST_AUTO_TEST_SUITE_END()