Tizen 2.0 Release
[framework/web/wrt-commons.git] / modules / utils / src / folder_size.cpp
index 87646f7..2029434 100644 (file)
  * @version     1.0
  * @brief       Implementation for function calculating directory size
  */
-
+#include <stddef.h>
 #include <string.h>
-#include <dirent.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <fts.h>
 
 #include <sstream>
 #include <vector>
 
 #include <dpl/log/log.h>
 #include <dpl/foreach.h>
-#include <folder_size.h>
+#include <dpl/utils/folder_size.h>
 
 namespace Utils {
-namespace {
-
-size_t getObjectSize(const std::string& path)
-{
-    struct stat tmp;
-
-    if (stat(path.c_str(), &tmp) == -1) {
-        LogError("Failed to open file" << path);
-        return 0;
-    }
-    //it is not a file nor a directory
-    //not counting
-    if (!S_ISDIR(tmp.st_mode) && !S_ISREG(tmp.st_mode)) {
-        LogWarning("Not a regular file nor a directory: " << path);
-        return 0;
-    }
-    return tmp.st_size;
-}
-}
 
 size_t getFolderSize(const std::string& path)
 {
     size_t size = 0;
-
-    DIR *dir;
-    std::vector<std::string> localDirs;
-    if ((dir=opendir(path.c_str())) == NULL) {
-        LogError("Cannot open dir " << path);
+    FTS *fts;
+    FTSENT *ftsent;
+    char * const paths[] = {const_cast<char * const>(path.c_str()), NULL};
+
+    if ((fts = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
+        //ERROR
+        int error = errno;
+        LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
+                << strerror(error));
         return 0;
     }
-    struct dirent* el;
-    while ((el = readdir(dir)) != 0) {
-        if (strcmp(el->d_name, ".") == 0 || strcmp(el->d_name, "..") == 0) {
-            continue;
-        }
-        struct stat tmp;
-        std::string local = path + el->d_name;
-        if (stat(local.c_str(), &tmp) == -1) {
-            LogError("Failed to open file " << local);
-            char* errstring = strerror(errno);
-            LogError("Reason: " << errstring);
-            continue;
-        }
 
-        size += getObjectSize(local);
-        if (S_ISDIR(tmp.st_mode)) {
-            localDirs.push_back(local + "/");
+    while ((ftsent = fts_read(fts)) != NULL) {
+        switch (ftsent->fts_info) {
+            case FTS_DP:
+            case FTS_DC:
+                //directory in postorder and directory causing a loop
+                break;
+            case FTS_F:
+            case FTS_D:
+            case FTS_NSOK:
+            case FTS_SL:
+            case FTS_SLNONE:
+            case FTS_DEFAULT:
+                //regular files and other objects that can be counted
+                size += ftsent->fts_statp->st_size;
+                break;
+            case FTS_NS:
+            case FTS_DOT:
+            case FTS_DNR:
+            case FTS_ERR:
+            default:
+                LogWarning(__PRETTY_FUNCTION__
+                        << ": traversal failed on file: "
+                        << ftsent->fts_path
+                        << " with error: "
+                        << strerror(ftsent->fts_errno));
+                return 0;
         }
     }
 
-    closedir(dir);
-
-    FOREACH (localDir, localDirs) {
-        size += getFolderSize(*localDir);
+    if (fts_close(fts) == -1) {
+        int error = errno;
+        LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
+                << strerror(error));
+        return 0;
     }
 
     return size;
@@ -119,10 +115,11 @@ const int stepSize = 1024;
 template<typename... Rest>
 struct Pre;
 
+
 template<typename Postfix, typename... Rest>
 struct Pre<Postfix, Rest...>
 {
-    static const double value = Pre<Rest...>::value * stepSize;
+    static const double value;
     static std::string printSize(double fileSize)
     {
         if(fileSize >= Pre<Rest...>::value) {
@@ -149,9 +146,14 @@ struct Pre<>
         }
 
 };
+
 const double Pre<>::value = 1.0;
+template<typename Postfix, typename... Params> const double Pre<Postfix, Params...>::value(Pre<>::value * stepSize);
+
 
 typedef Pre<PrefixGB, PrefixMB, PrefixKB, PrefixB> FolderSizeToStringType;
+
+
 } //anonymous namespace