1 // LAF Base Library
2 // Copyright (c) 2001-2018 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 
7 #include <dirent.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 
12 #include <climits>              // Required for PATH_MAX
13 #include <cstdio>               // Required for rename()
14 #include <cstdlib>
15 #include <ctime>
16 #include <stdexcept>
17 #include <vector>
18 
19 #if __APPLE__
20 #include <mach-o/dyld.h>
21 #elif __FreeBSD__
22 #include <sys/sysctl.h>
23 #endif
24 
25 #include "base/paths.h"
26 #include "base/time.h"
27 
28 #define MAXPATHLEN 1024
29 
30 namespace base {
31 
is_file(const std::string & path)32 bool is_file(const std::string& path)
33 {
34   struct stat sts;
35   return (stat(path.c_str(), &sts) == 0 && S_ISREG(sts.st_mode)) ? true: false;
36 }
37 
is_directory(const std::string & path)38 bool is_directory(const std::string& path)
39 {
40   struct stat sts;
41   return (stat(path.c_str(), &sts) == 0 && S_ISDIR(sts.st_mode)) ? true: false;
42 }
43 
make_directory(const std::string & path)44 void make_directory(const std::string& path)
45 {
46   int result = mkdir(path.c_str(), 0777);
47   if (result < 0) {
48     // TODO add errno into the exception
49     throw std::runtime_error("Error creating directory");
50   }
51 }
52 
file_size(const std::string & path)53 size_t file_size(const std::string& path)
54 {
55   struct stat sts;
56   return (stat(path.c_str(), &sts) == 0) ? sts.st_size: 0;
57 }
58 
move_file(const std::string & src,const std::string & dst)59 void move_file(const std::string& src, const std::string& dst)
60 {
61   int result = std::rename(src.c_str(), dst.c_str());
62   if (result != 0)
63     // TODO add errno into the exception
64     throw std::runtime_error("Error moving file");
65 }
66 
delete_file(const std::string & path)67 void delete_file(const std::string& path)
68 {
69   int result = unlink(path.c_str());
70   if (result != 0)
71     // TODO add errno into the exception
72     throw std::runtime_error("Error deleting file");
73 }
74 
has_readonly_attr(const std::string & path)75 bool has_readonly_attr(const std::string& path)
76 {
77   struct stat sts;
78   return (stat(path.c_str(), &sts) == 0 && ((sts.st_mode & S_IWUSR) == 0));
79 }
80 
remove_readonly_attr(const std::string & path)81 void remove_readonly_attr(const std::string& path)
82 {
83   struct stat sts;
84   int result = stat(path.c_str(), &sts);
85   if (result == 0) {
86     result = chmod(path.c_str(), sts.st_mode | S_IWUSR);
87     if (result != 0)
88       // TODO add errno into the exception
89       throw std::runtime_error("Error removing read-only attribute");
90   }
91 }
92 
get_modification_time(const std::string & path)93 Time get_modification_time(const std::string& path)
94 {
95   struct stat sts;
96   int result = stat(path.c_str(), &sts);
97   if (result != 0)
98     return Time();
99 
100   std::tm* t = std::localtime(&sts.st_mtime);
101   return Time(
102     t->tm_year+1900, t->tm_mon+1, t->tm_mday,
103     t->tm_hour, t->tm_min, t->tm_sec);
104 }
105 
remove_directory(const std::string & path)106 void remove_directory(const std::string& path)
107 {
108   int result = rmdir(path.c_str());
109   if (result != 0) {
110     // TODO add errno into the exception
111     throw std::runtime_error("Error removing directory");
112   }
113 }
114 
get_current_path()115 std::string get_current_path()
116 {
117   std::vector<char> path(MAXPATHLEN);
118   if (getcwd(&path[0], path.size()))
119     return std::string(&path[0]);
120   else
121     return std::string();
122 }
123 
get_app_path()124 std::string get_app_path()
125 {
126   std::vector<char> path(MAXPATHLEN);
127 
128 #if __APPLE__
129   uint32_t size = path.size();
130   while (_NSGetExecutablePath(&path[0], &size) == -1)
131     path.resize(size);
132 #elif __FreeBSD__
133   size_t size = path.size();
134   const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
135   while (sysctl(mib, 4, &path[0], &size, NULL, 0) == -1)
136       path.resize(size);
137 #else  // Linux
138   if (readlink("/proc/self/exe", &path[0], path.size()) == -1)
139     return std::string();
140 #endif
141 
142   return std::string(&path[0]);
143 }
144 
get_temp_path()145 std::string get_temp_path()
146 {
147   char* tmpdir = getenv("TMPDIR");
148   if (tmpdir)
149     return tmpdir;
150   else
151     return "/tmp";
152 }
153 
get_user_docs_folder()154 std::string get_user_docs_folder()
155 {
156   char* tmpdir = getenv("HOME");
157   if (tmpdir)
158     return tmpdir;
159   else
160     return "/";
161 }
162 
get_canonical_path(const std::string & path)163 std::string get_canonical_path(const std::string& path)
164 {
165   char buffer[PATH_MAX];
166   // Ignore return value as realpath() returns nullptr anyway when the
167   // resolved_path parameter is specified.
168   realpath(path.c_str(), buffer);
169   return path;
170 }
171 
list_files(const std::string & path)172 paths list_files(const std::string& path)
173 {
174   paths files;
175   DIR* handle = opendir(path.c_str());
176   if (handle) {
177     dirent* item;
178     while ((item = readdir(handle)) != nullptr) {
179       std::string filename = item->d_name;
180       if (filename != "." && filename != "..")
181         files.push_back(filename);
182     }
183 
184     closedir(handle);
185   }
186   return files;
187 }
188 
189 }
190