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