/src/aspell/common/file_util.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // This file is part of The New Aspell |
2 | | // Copyright (C) 2001 by Kevin Atkinson under the GNU LGPL license |
3 | | // version 2.0 or 2.1. You should have received a copy of the LGPL |
4 | | // license along with this library if you did not you can find |
5 | | // it at http://www.gnu.org/. |
6 | | |
7 | | #include "settings.h" |
8 | | |
9 | | //#include "iostream.hpp" |
10 | | |
11 | | #include "config.hpp" |
12 | | #include "file_util.hpp" |
13 | | #include "fstream.hpp" |
14 | | #include "errors.hpp" |
15 | | #include "string_list.hpp" |
16 | | |
17 | | #ifdef USE_FILE_LOCKS |
18 | | # include <fcntl.h> |
19 | | # include <unistd.h> |
20 | | # include <sys/types.h> |
21 | | #endif |
22 | | |
23 | | #include <stdio.h> |
24 | | #include <sys/stat.h> |
25 | | #include <dirent.h> |
26 | | |
27 | | #ifdef WIN32 |
28 | | |
29 | | # include <io.h> |
30 | | # define ACCESS _access |
31 | | # include <windows.h> |
32 | | # include <winbase.h> |
33 | | |
34 | | #else |
35 | | |
36 | | # include <unistd.h> |
37 | 8.16k | # define ACCESS access |
38 | | |
39 | | #endif |
40 | | |
41 | | |
42 | | namespace acommon { |
43 | | |
44 | | // Return false if file is already an absolute path and does not need |
45 | | // a directory prepended. |
46 | 13.8k | bool need_dir(ParmString file) { |
47 | 13.8k | if (file[0] == '/' || (file[0] == '.' && file[1] == '/') |
48 | | #ifdef WIN32 |
49 | | || (asc_isalpha(file[0]) && file[1] == ':') |
50 | | || file[0] == '\\' || (file[0] == '.' && file[1] == '\\') |
51 | | #endif |
52 | 13.8k | ) |
53 | 5.21k | return false; |
54 | 8.64k | else |
55 | 8.64k | return true; |
56 | 13.8k | } |
57 | | |
58 | 11.0k | String add_possible_dir(ParmString dir, ParmString file) { |
59 | 11.0k | if (need_dir(file)) { |
60 | 7.36k | String path; |
61 | 7.36k | path += dir; |
62 | 7.36k | path += '/'; |
63 | 7.36k | path += file; |
64 | 7.36k | return path; |
65 | 7.36k | } else { |
66 | 3.67k | return file; |
67 | 3.67k | } |
68 | 11.0k | } |
69 | | |
70 | | String figure_out_dir(ParmString dir, ParmString file) |
71 | 2.82k | { |
72 | 2.82k | String temp; |
73 | 2.82k | int s = file.size() - 1; |
74 | 34.0k | while (s != -1 && file[s] != '/') --s; |
75 | 2.82k | if (need_dir(file)) { |
76 | 1.28k | temp += dir; |
77 | 1.28k | temp += '/'; |
78 | 1.28k | } |
79 | 2.82k | if (s != -1) { |
80 | 1.68k | temp.append(file, s); |
81 | 1.68k | } |
82 | 2.82k | return temp; |
83 | 2.82k | } |
84 | | |
85 | 0 | time_t get_modification_time(FStream & f) { |
86 | 0 | struct stat s; |
87 | 0 | fstat(f.file_no(), &s); |
88 | 0 | return s.st_mtime; |
89 | 0 | } |
90 | | |
91 | 1.42k | PosibErr<void> open_file_readlock(FStream & in, ParmString file) { |
92 | 1.42k | RET_ON_ERR(in.open(file, "r")); |
93 | 0 | #ifdef USE_FILE_LOCKS |
94 | 0 | int fd = in.file_no(); |
95 | 0 | struct flock fl; |
96 | 0 | fl.l_type = F_RDLCK; |
97 | 0 | fl.l_whence = SEEK_SET; |
98 | 0 | fl.l_start = 0; |
99 | 0 | fl.l_len = 0; |
100 | 0 | fcntl(fd, F_SETLKW, &fl); // ignore errors |
101 | 0 | #endif |
102 | 0 | return no_err; |
103 | 1.42k | } |
104 | | |
105 | 0 | PosibErr<bool> open_file_writelock(FStream & inout, ParmString file) { |
106 | 0 | typedef PosibErr<bool> Ret; |
107 | | #ifndef USE_FILE_LOCKS |
108 | | bool exists = file_exists(file); |
109 | | #endif |
110 | 0 | { |
111 | 0 | Ret pe = inout.open(file, "r+"); |
112 | 0 | if (pe.get_err() != 0) |
113 | 0 | pe = inout.open(file, "w+"); |
114 | 0 | if (pe.has_err()) |
115 | 0 | return pe; |
116 | 0 | } |
117 | 0 | #ifdef USE_FILE_LOCKS |
118 | 0 | int fd = inout.file_no(); |
119 | 0 | struct flock fl; |
120 | 0 | fl.l_type = F_WRLCK; |
121 | 0 | fl.l_whence = SEEK_SET; |
122 | 0 | fl.l_start = 0; |
123 | 0 | fl.l_len = 0; |
124 | 0 | fcntl(fd, F_SETLKW, &fl); // ignore errors |
125 | 0 | struct stat s; |
126 | 0 | fstat(fd, &s); |
127 | 0 | return s.st_size != 0; |
128 | | #else |
129 | | return exists; |
130 | | #endif |
131 | 0 | } |
132 | | |
133 | 0 | void truncate_file(FStream & f, ParmString name) { |
134 | 0 | #ifdef USE_FILE_LOCKS |
135 | 0 | f.restart(); |
136 | 0 | ftruncate(f.file_no(),0); |
137 | | #else |
138 | | f.close(); |
139 | | f.open(name, "w+"); |
140 | | #endif |
141 | 0 | } |
142 | | |
143 | 0 | bool remove_file(ParmString name) { |
144 | 0 | return remove(name) == 0; |
145 | 0 | } |
146 | | |
147 | 8.16k | bool file_exists(ParmString name) { |
148 | 8.16k | return ACCESS(name, F_OK) == 0; |
149 | 8.16k | } |
150 | | |
151 | | bool rename_file(ParmString orig_name, ParmString new_name) |
152 | 0 | { |
153 | 0 | remove(new_name); |
154 | 0 | return rename(orig_name, new_name) == 0; |
155 | 0 | } |
156 | | |
157 | 0 | const char * get_file_name(const char * path) { |
158 | 0 | const char * file_name; |
159 | 0 | if (path != 0) { |
160 | 0 | file_name = strrchr(path,'/'); |
161 | 0 | if (file_name == 0) |
162 | 0 | file_name = path; |
163 | 0 | } else { |
164 | 0 | file_name = 0; |
165 | 0 | } |
166 | 0 | return file_name; |
167 | 0 | } |
168 | | |
169 | | unsigned find_file(const Config * config, const char * option, String & filename) |
170 | 3.42k | { |
171 | 3.42k | StringList sl; |
172 | 3.42k | config->retrieve_list(option, &sl); |
173 | 3.42k | return find_file(sl, filename); |
174 | 3.42k | } |
175 | | |
176 | | unsigned find_file(const StringList & sl, String & filename) |
177 | 3.42k | { |
178 | 3.42k | StringListEnumeration els = sl.elements_obj(); |
179 | 3.42k | const char * dir; |
180 | 3.42k | String path; |
181 | 7.35k | while ( (dir = els.next()) != 0 ) |
182 | 3.93k | { |
183 | 3.93k | path = dir; |
184 | 3.93k | if (path.empty()) continue; |
185 | 3.90k | if (path.back() != '/') path += '/'; |
186 | 3.90k | unsigned dir_len = path.size(); |
187 | 3.90k | path += filename; |
188 | 3.90k | if (file_exists(path)) { |
189 | 0 | filename.swap(path); |
190 | 0 | return dir_len; |
191 | 0 | } |
192 | 3.90k | } |
193 | 3.42k | return 0; |
194 | 3.42k | } |
195 | | |
196 | | PathBrowser::PathBrowser(const StringList & sl, const char * suf) |
197 | | : dir_handle(0) |
198 | 1.10k | { |
199 | 1.10k | els = sl.elements(); |
200 | 1.10k | suffix = suf; |
201 | 1.10k | } |
202 | | |
203 | | PathBrowser::~PathBrowser() |
204 | 1.10k | { |
205 | 1.10k | delete els; |
206 | 1.10k | if (dir_handle) closedir((DIR *)dir_handle); |
207 | 1.10k | } |
208 | | |
209 | | const char * PathBrowser::next() |
210 | 6.46k | { |
211 | 6.46k | if (dir_handle == 0) goto get_next_dir; |
212 | 83.8k | begin: { |
213 | 83.8k | struct dirent * entry = readdir((DIR *)dir_handle); |
214 | 83.8k | if (entry == 0) goto try_again; |
215 | 83.1k | const char * name = entry->d_name; |
216 | 83.1k | unsigned name_len = strlen(name); |
217 | 83.1k | if (suffix.size() != 0 && |
218 | 83.1k | !(name_len > suffix.size() |
219 | 83.1k | && memcmp(name + name_len - suffix.size(), suffix.str(), suffix.size()) == 0)) |
220 | 77.7k | goto begin; |
221 | 5.35k | path = dir; |
222 | 5.35k | if (path.back() != '/') path += '/'; |
223 | 5.35k | path += name; |
224 | 5.35k | } |
225 | 0 | return path.str(); |
226 | 1.54k | try_again: |
227 | 1.54k | if (dir_handle) closedir((DIR *)dir_handle); |
228 | 1.54k | dir_handle = 0; |
229 | 2.65k | get_next_dir: |
230 | 2.65k | dir = els->next(); |
231 | 2.65k | if (!dir) return 0; |
232 | 1.54k | dir_handle = opendir(dir); |
233 | 1.54k | if (dir_handle == 0) goto try_again; |
234 | 734 | goto begin; |
235 | 1.54k | } |
236 | | } |