Refactor file & file visitor classes
[platform/upstream/csr-framework.git] / src / framework / service / file-system.cpp
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;
                        }