1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2010 - 2015, Göteborg Bit Factory.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included
13 // in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 //
23 // http://www.opensource.org/licenses/mit-license.php
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26
27 #include <cmake.h>
28 #include <fstream>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <pwd.h>
35 #include <File.h>
36 #include <text.h>
37
38 ////////////////////////////////////////////////////////////////////////////////
File()39 File::File ()
40 : Path::Path ()
41 , _fh (NULL)
42 , _h (-1)
43 , _locked (false)
44 {
45 }
46
47 ////////////////////////////////////////////////////////////////////////////////
File(const Path & other)48 File::File (const Path& other)
49 : Path::Path (other)
50 , _fh (NULL)
51 , _h (-1)
52 , _locked (false)
53 {
54 }
55
56 ////////////////////////////////////////////////////////////////////////////////
File(const File & other)57 File::File (const File& other)
58 : Path::Path (other)
59 , _fh (NULL)
60 , _h (-1)
61 , _locked (false)
62 {
63 }
64
65 ////////////////////////////////////////////////////////////////////////////////
File(const std::string & in)66 File::File (const std::string& in)
67 : Path::Path (in)
68 , _fh (NULL)
69 , _h (-1)
70 , _locked (false)
71 {
72 }
73
74 ////////////////////////////////////////////////////////////////////////////////
~File()75 File::~File ()
76 {
77 if (_fh)
78 close ();
79 }
80
81 ////////////////////////////////////////////////////////////////////////////////
operator =(const File & other)82 File& File::operator= (const File& other)
83 {
84 if (this != &other)
85 Path::operator= (other);
86
87 _locked = false;
88 return *this;
89 }
90
91 ////////////////////////////////////////////////////////////////////////////////
create(int mode)92 bool File::create (int mode /* = 0640 */)
93 {
94 if (open ())
95 {
96 fchmod (_h, mode);
97 close ();
98 return true;
99 }
100
101 return false;
102 }
103
104 ////////////////////////////////////////////////////////////////////////////////
remove() const105 bool File::remove () const
106 {
107 return unlink (_data.c_str ()) == 0 ? true : false;
108 }
109
110 ////////////////////////////////////////////////////////////////////////////////
open()111 bool File::open ()
112 {
113 if (_data != "")
114 {
115 if (! _fh)
116 {
117 bool already_exists = exists ();
118 if (already_exists)
119 if (!readable () || !writable ())
120 throw std::string (format ("ERROR: Task does not have the correct permissions for '{1}'.", _data));
121
122 _fh = fopen (_data.c_str (), (already_exists ? "r+" : "w+"));
123 if (_fh)
124 {
125 _h = fileno (_fh);
126 _locked = false;
127 return true;
128 }
129 }
130 else
131 return true;
132 }
133
134 return false;
135 }
136
137 ////////////////////////////////////////////////////////////////////////////////
openAndLock()138 bool File::openAndLock ()
139 {
140 return open () && lock ();
141 }
142
143 ////////////////////////////////////////////////////////////////////////////////
close()144 void File::close ()
145 {
146 if (_fh)
147 {
148 if (_locked)
149 unlock ();
150
151 fclose (_fh);
152 _fh = NULL;
153 _h = -1;
154 _locked = false;
155 }
156 }
157
158 ////////////////////////////////////////////////////////////////////////////////
lock()159 bool File::lock ()
160 {
161 _locked = false;
162 if (_fh && _h != -1)
163 {
164 // l_type l_whence l_start l_len l_pid
165 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
166 fl.l_pid = getpid ();
167 if (fcntl (_h, F_SETLKW, &fl) == 0)
168 _locked = true;
169 }
170
171 return _locked;
172 }
173
174 ////////////////////////////////////////////////////////////////////////////////
unlock()175 void File::unlock ()
176 {
177 if (_locked)
178 {
179 // l_type l_whence l_start l_len l_pid
180 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0 };
181 fl.l_pid = getpid ();
182
183 fcntl (_h, F_SETLK, &fl);
184 _locked = false;
185 }
186 }
187
188 ////////////////////////////////////////////////////////////////////////////////
189 // Opens if necessary.
read(std::string & contents)190 void File::read (std::string& contents)
191 {
192 contents = "";
193 contents.reserve (size ());
194
195 std::ifstream in (_data.c_str ());
196 if (in.good ())
197 {
198 std::string line;
199 line.reserve (512 * 1024);
200 while (getline (in, line))
201 contents += line + "\n";
202
203 in.close ();
204 }
205 }
206
207 ////////////////////////////////////////////////////////////////////////////////
208 // Opens if necessary.
read(std::vector<std::string> & contents)209 void File::read (std::vector <std::string>& contents)
210 {
211 contents.clear ();
212
213 std::ifstream in (_data.c_str ());
214 if (in.good ())
215 {
216 std::string line;
217 line.reserve (512 * 1024);
218 while (getline (in, line))
219 contents.push_back (line);
220
221 in.close ();
222 }
223 }
224
225 ////////////////////////////////////////////////////////////////////////////////
226 // Opens if necessary.
write(const std::string & line)227 void File::write (const std::string& line)
228 {
229 if (!_fh)
230 open ();
231
232 if (_fh)
233 fputs (line.c_str (), _fh);
234 }
235
236 ////////////////////////////////////////////////////////////////////////////////
237 // Opens if necessary.
write(const std::vector<std::string> & lines)238 void File::write (const std::vector <std::string>& lines)
239 {
240 if (!_fh)
241 open ();
242
243 if (_fh)
244 {
245 std::vector <std::string>::const_iterator it;
246 for (it = lines.begin (); it != lines.end (); ++it)
247 fputs (it->c_str (), _fh);
248 }
249 }
250
251 ////////////////////////////////////////////////////////////////////////////////
252 // Opens if necessary.
append(const std::string & line)253 void File::append (const std::string& line)
254 {
255 if (!_fh)
256 open ();
257
258 if (_fh)
259 {
260 fseek (_fh, 0, SEEK_END);
261 fputs (line.c_str (), _fh);
262 }
263 }
264
265 ////////////////////////////////////////////////////////////////////////////////
266 // Opens if necessary.
append(const std::vector<std::string> & lines)267 void File::append (const std::vector <std::string>& lines)
268 {
269 if (!_fh)
270 open ();
271
272 if (_fh)
273 {
274 fseek (_fh, 0, SEEK_END);
275 std::vector <std::string>::const_iterator it;
276 for (it = lines.begin (); it != lines.end (); ++it)
277 fputs (((*it) + "\n").c_str (), _fh);
278 }
279 }
280
281 ////////////////////////////////////////////////////////////////////////////////
truncate()282 void File::truncate ()
283 {
284 if (!_fh)
285 open ();
286
287 if (_fh)
288 ftruncate (_h, 0);
289 }
290
291 ////////////////////////////////////////////////////////////////////////////////
292 // S_IFMT 0170000 type of file
293 // S_IFIFO 0010000 named pipe (fifo)
294 // S_IFCHR 0020000 character special
295 // S_IFDIR 0040000 directory
296 // S_IFBLK 0060000 block special
297 // S_IFREG 0100000 regular
298 // S_IFLNK 0120000 symbolic link
299 // S_IFSOCK 0140000 socket
300 // S_IFWHT 0160000 whiteout
301 // S_ISUID 0004000 set user id on execution
302 // S_ISGID 0002000 set group id on execution
303 // S_ISVTX 0001000 save swapped text even after use
304 // S_IRUSR 0000400 read permission, owner
305 // S_IWUSR 0000200 write permission, owner
306 // S_IXUSR 0000100 execute/search permission, owner
mode()307 mode_t File::mode ()
308 {
309 struct stat s;
310 if (!stat (_data.c_str (), &s))
311 return s.st_mode;
312
313 return 0;
314 }
315
316 ////////////////////////////////////////////////////////////////////////////////
size() const317 size_t File::size () const
318 {
319 struct stat s;
320 if (!stat (_data.c_str (), &s))
321 return s.st_size;
322
323 return 0;
324 }
325
326 ////////////////////////////////////////////////////////////////////////////////
mtime() const327 time_t File::mtime () const
328 {
329 struct stat s;
330 if (!stat (_data.c_str (), &s))
331 return s.st_mtime;
332
333 return 0;
334 }
335
336 ////////////////////////////////////////////////////////////////////////////////
ctime() const337 time_t File::ctime () const
338 {
339 struct stat s;
340 if (!stat (_data.c_str (), &s))
341 return s.st_ctime;
342
343 return 0;
344 }
345
346 ////////////////////////////////////////////////////////////////////////////////
btime() const347 time_t File::btime () const
348 {
349 struct stat s;
350 if (!stat (_data.c_str (), &s))
351 #ifdef HAVE_ST_BIRTHTIME
352 return s.st_birthtime;
353 #else
354 return s.st_ctime;
355 #endif
356
357 return 0;
358 }
359
360 ////////////////////////////////////////////////////////////////////////////////
create(const std::string & name,int mode)361 bool File::create (const std::string& name, int mode /* = 0640 */)
362 {
363 std::string full_name = expand (name);
364 std::ofstream out (full_name.c_str ());
365 if (out.good ())
366 {
367 out.close ();
368 chmod (full_name.c_str (), mode);
369 return true;
370 }
371
372 return false;
373 }
374
375 ////////////////////////////////////////////////////////////////////////////////
read(const std::string & name)376 std::string File::read (const std::string& name)
377 {
378 std::string contents = "";
379
380 std::ifstream in (name.c_str ());
381 if (in.good ())
382 {
383 std::string line;
384 line.reserve (1024);
385 while (getline (in, line))
386 contents += line + "\n";
387
388 in.close ();
389 }
390
391 return contents;
392 }
393
394 ////////////////////////////////////////////////////////////////////////////////
read(const std::string & name,std::string & contents)395 bool File::read (const std::string& name, std::string& contents)
396 {
397 contents = "";
398
399 std::ifstream in (name.c_str ());
400 if (in.good ())
401 {
402 std::string line;
403 line.reserve (1024);
404 while (getline (in, line))
405 contents += line + "\n";
406
407 in.close ();
408 return true;
409 }
410
411 return false;
412 }
413
414 ////////////////////////////////////////////////////////////////////////////////
read(const std::string & name,std::vector<std::string> & contents)415 bool File::read (const std::string& name, std::vector <std::string>& contents)
416 {
417 contents.clear ();
418
419 std::ifstream in (name.c_str ());
420 if (in.good ())
421 {
422 std::string line;
423 line.reserve (1024);
424 while (getline (in, line))
425 contents.push_back (line);
426
427 in.close ();
428 return true;
429 }
430
431 return false;
432 }
433
434 ////////////////////////////////////////////////////////////////////////////////
write(const std::string & name,const std::string & contents)435 bool File::write (const std::string& name, const std::string& contents)
436 {
437 std::ofstream out (expand (name).c_str (),
438 std::ios_base::out | std::ios_base::trunc);
439 if (out.good ())
440 {
441 out << contents;
442 out.close ();
443 return true;
444 }
445
446 return false;
447 }
448
449 ////////////////////////////////////////////////////////////////////////////////
write(const std::string & name,const std::vector<std::string> & lines,bool addNewlines)450 bool File::write (
451 const std::string& name,
452 const std::vector <std::string>& lines,
453 bool addNewlines /* = true */)
454 {
455 std::ofstream out (expand (name).c_str (),
456 std::ios_base::out | std::ios_base::trunc);
457 if (out.good ())
458 {
459 std::vector <std::string>::const_iterator it;
460 for (it = lines.begin (); it != lines.end (); ++it)
461 {
462 out << *it;
463
464 if (addNewlines)
465 out << "\n";
466 }
467
468 out.close ();
469 return true;
470 }
471
472 return false;
473 }
474
475 ////////////////////////////////////////////////////////////////////////////////
append(const std::string & name,const std::string & contents)476 bool File::append (const std::string& name, const std::string& contents)
477 {
478 std::ofstream out (expand (name).c_str (),
479 std::ios_base::out | std::ios_base::app);
480 if (out.good ())
481 {
482 out << contents;
483 out.close ();
484 return true;
485 }
486
487 return false;
488 }
489
490 ////////////////////////////////////////////////////////////////////////////////
append(const std::string & name,const std::vector<std::string> & lines,bool addNewlines)491 bool File::append (
492 const std::string& name,
493 const std::vector <std::string>& lines,
494 bool addNewlines /* = true */)
495 {
496 std::ofstream out (expand (name).c_str (),
497 std::ios_base::out | std::ios_base::app);
498 if (out.good ())
499 {
500 std::vector <std::string>::const_iterator it;
501 for (it = lines.begin (); it != lines.end (); ++it)
502 {
503 out << *it;
504
505 if (addNewlines)
506 out << "\n";
507 }
508
509 out.close ();
510 return true;
511 }
512
513 return false;
514 }
515
516 ////////////////////////////////////////////////////////////////////////////////
remove(const std::string & name)517 bool File::remove (const std::string& name)
518 {
519 return unlink (expand (name).c_str ()) == 0 ? true : false;
520 }
521
522 ////////////////////////////////////////////////////////////////////////////////
523
524