1 /* Copyright (C) 2004 J.F.Dockes
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU Lesser General Public License as published by
4  *   the Free Software Foundation; either version 2.1 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU Lesser General Public License for more details.
11  *
12  *   You should have received a copy of the GNU Lesser General Public License
13  *   along with this program; if not, write to the
14  *   Free Software Foundation, Inc.,
15  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 #ifndef _PATHUT_H_INCLUDED_
18 #define _PATHUT_H_INCLUDED_
19 
20 #include <string>
21 #include <vector>
22 #include <set>
23 #include <cstdint>
24 #include <fstream>
25 
26 // Must be called in main thread before starting other threads
27 extern void pathut_init_mt();
28 
29 /// Add a / at the end if none there yet.
30 extern void path_catslash(std::string& s);
31 /// Concatenate 2 paths
32 extern std::string path_cat(const std::string& s1, const std::string& s2);
33 /// Get the simple file name (get rid of any directory path prefix
34 extern std::string path_getsimple(const std::string& s);
35 /// Simple file name + optional suffix stripping
36 extern std::string path_basename(const std::string& s,
37                                  const std::string& suff = std::string());
38 /// Component after last '.'
39 extern std::string path_suffix(const std::string& s);
40 /// Get the father directory
41 extern std::string path_getfather(const std::string& s);
42 /// Test if path is absolute
43 extern bool path_isabsolute(const std::string& s);
44 /// Test if path is root (x:/). root is defined by root/.. == root
45 extern bool path_isroot(const std::string& p);
46 /// Test if sub is a subdirectory of top. This is a textual test,
47 /// links not allowed
48 extern bool path_isdesc(const std::string& top, const std::string& sub);
49 
50 /// Clean up path by removing duplicated / and resolving ../ + make it absolute
51 extern std::string path_canon(const std::string& s, const std::string *cwd = 0);
52 
53 /// Check that path refers to same file. Uses dev/ino on Linux,
54 /// textual comparison on Windows.
55 bool path_samefile(const std::string& p1, const std::string& p2);
56 
57 /// Get the current user's home directory
58 extern std::string path_home();
59 /// Expand ~ at the beginning of std::string
60 extern std::string path_tildexpand(const std::string& s);
61 /// Use getcwd() to make absolute path if needed. Beware: ***this can fail***
62 /// we return an empty path in this case.
63 extern std::string path_absolute(const std::string& s);
64 
65 /// Stat parameter and check if it's a directory
66 extern bool path_isdir(const std::string& path, bool follow = false);
67 /// Stat parameter and check if it's a regular file
68 extern bool path_isfile(const std::string& path, bool follow = false);
69 
70 /// Retrieve file size
71 extern long long path_filesize(const std::string& path);
72 
73 /// Check that path is traversable and last element exists
74 /// Returns true if last elt could be checked to exist. False may mean that
75 /// the file/dir does not exist or that an error occurred.
76 bool path_exists(const std::string& path);
77 /// Same but must be readable
78 bool path_readable(const std::string& path);
79 
80 #ifdef _WIN32
81 #  ifndef R_OK
82 #    define R_OK 4
83 #  endif
84 #  ifndef W_OK
85 #    define W_OK 2
86 #  endif
87 #  ifndef X_OK
88 // Not useful/supported on Windows. Define as R_OK
89 #    define X_OK R_OK
90 #  endif
91 #  ifndef F_OK
92 #    define F_OK 0
93 #  endif
94 #endif /* _WIN32 */
95 /// access() or _waccess()
96 bool path_access(const std::string& path, int mode);
97 
98 /// Retrieve essential file attributes. This is used rather than a
99 /// bare stat() to ensure consistent use of the time fields (on
100 /// windows, we set ctime=mtime as ctime is actually the creation
101 /// time, for which we have no use).
102 /// Only st_mtime, st_ctime, st_size, st_mode (file type bits) are set on
103 /// all systems. st_dev and st_ino are set for special posix usage.
104 /// The rest is zeroed.
105 /// @ret 0 for success
106 struct PathStat {
107     enum PstType {PST_REGULAR, PST_SYMLINK, PST_DIR, PST_OTHER};
108     PstType pst_type;
109     int64_t pst_size;
110     uint64_t pst_mode;
111     int64_t pst_mtime;
112     int64_t pst_ctime;
113     uint64_t pst_ino;
114     uint64_t pst_dev;
115     uint64_t pst_blocks;
116     uint64_t pst_blksize;
117 };
118 extern int path_fileprops(const std::string path, struct PathStat *stp,
119                           bool follow = true);
120 
121 
122 /// Return separator for PATH environment variable
123 extern std::string path_PATHsep();
124 
125 #ifdef _WIN32
126 #include <memory>
127 bool wchartoutf8(const wchar_t *in, std::string& out, size_t len = 0);
128 std::string wchartoutf8(const wchar_t *in, size_t len = 0);
129 bool utf8towchar(const std::string& in, wchar_t *out, size_t obytescap);
130 std::unique_ptr<wchar_t[]> utf8towchar(const std::string& in);
131 #endif
132 
133 /// Directory reading interface. UTF-8 on Windows.
134 class PathDirContents {
135 public:
136     PathDirContents(const std::string& dirpath);
137     ~PathDirContents();
138 
139     bool opendir();
140     struct Entry {
141         std::string d_name;
142     };
143     const struct Entry* readdir();
144     void rewinddir();
145 
146 private:
147     class Internal;
148     Internal *m{nullptr};
149 };
150 
151 /// Dump directory
152 extern bool listdir(const std::string& dir, std::string& reason,
153                     std::set<std::string>& entries);
154 
155 /** A small wrapper around statfs et al, to return percentage of disk
156     occupation
157     @param[output] pc percent occupied
158     @param[output] avmbs Mbs available to non-superuser. Mb=1024*1024
159 */
160 bool fsocc(const std::string& path, int *pc, long long *avmbs = 0);
161 
162 /// mkdir -p
163 extern bool path_makepath(const std::string& path, int mode);
164 
165 ///
166 bool path_chdir(const std::string& path);
167 std::string path_cwd();
168 bool path_unlink(const std::string& path);
169 bool path_rmdir(const std::string& path);
170 
171 /* Open file, trying to do the right thing with non-ASCII paths on
172  * Windows, where it only works with MSVC at the moment if the path is
173  * not ASCII, because it uses fstream(wchar_t*), which is an MSVC
174  * extension. On other OSes, just builds the fstream.  We'd need to
175  * find a way to make this work with g++. It would be easier in this
176  * case to use a FILE (_openw(), then fdopen()), but conftree really
177  * depends on std::iostream.
178  *
179  * @param path an utf-8 file path.
180  * @param mode is an std::fstream mode (ios::in etc.) */
181 extern bool path_streamopen(
182     const std::string& path, int mode, std::fstream& outstream);
183 
184 /// Encode according to rfc 1738
185 extern std::string url_encode(const std::string& url,
186                               std::string::size_type offs = 0);
187 extern std::string url_decode(const std::string& encoded);
188 //// Convert to file path if url is like file://. This modifies the
189 //// input (and returns a copy for convenience)
190 extern std::string fileurltolocalpath(std::string url);
191 /// Test for file:/// url
192 extern bool urlisfileurl(const std::string& url);
193 ///
194 extern std::string url_parentfolder(const std::string& url);
195 /// Return the host+path part of an url. This is not a general
196 /// routine, it does the right thing only in the recoll context
197 extern std::string url_gpath(const std::string& url);
198 /// Turn absolute path into file:// url
199 extern std::string path_pathtofileurl(const std::string& path);
200 
201 /// URI parser, loosely from rfc2396.txt
202 class ParsedUri {
203 public:
204     ParsedUri(std::string uri);
205     bool parsed{false};
206     std::string scheme;
207     std::string user;
208     std::string pass;
209     std::string host;
210     std::string port;
211     std::string path;
212     std::string query;
213     std::vector<std::pair<std::string,std::string>> parsedquery;
214     std::string fragment;
215 };
216 
217 #ifdef _WIN32
218 /// Convert \ separators to /
219 void path_slashize(std::string& s);
220 void path_backslashize(std::string& s);
221 extern std::string path_shortpath(const std::string& path);
222 #else
223 #define path_shortpath(path) (path)
224 #endif
225 
226 /// Lock/pid file class. This is quite close to the pidfile_xxx
227 /// utilities in FreeBSD with a bit more encapsulation. I'd have used
228 /// the freebsd code if it was available elsewhere
229 class Pidfile {
230 public:
Pidfile(const std::string & path)231     Pidfile(const std::string& path)    : m_path(path), m_fd(-1) {}
232     ~Pidfile();
233     /// Open/create the pid file.
234     /// @return 0 if ok, > 0 for pid of existing process, -1 for other error.
235     int open();
236     /// Write pid into the pid file
237     /// @return 0 ok, -1 error
238     int write_pid();
239     /// Close the pid file (unlocks)
240     int close();
241     /// Delete the pid file
242     int remove();
getreason()243     const std::string& getreason() {
244         return m_reason;
245     }
246 private:
247     std::string m_path;
248     int    m_fd;
249     std::string m_reason;
250     int read_pid();
251     int flopen();
252 };
253 
254 #endif /* _PATHUT_H_INCLUDED_ */
255