scclib
Stable Cloud Computing C++ Library
fs.cc
Go to the documentation of this file.
1 /*
2 BSD 3-Clause License
3 
4 Copyright (c) 2022, Stable Cloud Computing, Inc.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 1. Redistributions of source code must retain the above copyright notice, this
10  list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <util/fs.h>
32 #include <system_error>
33 #include <dirent.h>
34 #include <cstring>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <sstream>
39 #include <ctime>
40 #include <chrono>
41 #include <iomanip>
42 #include <ios>
43 #include <fcntl.h>
44 #include <libgen.h>
45 #include <string>
46 #include <vector>
47 #include <util/safe_clib.h>
48 
54 const uint64_t NS=1000000000;
55 
56 using namespace scc::util;
57 
58 std::ostream& operator<<(std::ostream& os, FileType t)
59 {
60  switch (t)
61  {
62  case FileType::reg: os << "regular file"; break;
63  case FileType::dir: os << "directory"; break;
64  case FileType::link: os << "symbolic link"; break;
65  case FileType::sock: os << "socket"; break;
66  case FileType::block: os << "block device"; break;
67  case FileType::chr: os << "character device"; break;
68  case FileType::fifo: os << "fifo"; break;
69  default: os << "unknown"; break;
70  }
71  return os;
72 }
73 
74 std::ostream& operator<<(std::ostream& os, FileStat s)
75 {
76  os << s.type << " sz: " << s.size << " alloc: " << s.alloc_size << " ino: " << s.inode << " (" << s.num_links << ")\n";
77  os << "mode: ";
78  os << (s.mode&S_ISUID ? 'u' : '-');
79  os << (s.mode&S_ISGID ? 'g' : '-');
80  os << (s.mode&S_ISVTX ? 's' : '-') << " ";
81  os << (s.mode&S_IRUSR ? 'r' : '-');
82  os << (s.mode&S_IWUSR ? 'w' : '-');
83  os << (s.mode&S_IXUSR ? 'x' : '-') << " ";
84  os << (s.mode&S_IRGRP ? 'r' : '-');
85  os << (s.mode&S_IWGRP ? 'w' : '-');
86  os << (s.mode&S_IXGRP ? 'x' : '-') << " ";
87  os << (s.mode&S_IROTH ? 'r' : '-');
88  os << (s.mode&S_IWOTH ? 'w' : '-');
89  os << (s.mode&S_IXOTH ? 'x' : '-') << " (" << std::oct << s.mode << std::dec << ") ";
90  os << "own: " << s.uid << ":" << s.gid << "\n";
91 
92  using ns = std::chrono::nanoseconds;
93  using sclock = std::chrono::system_clock;
94  using tpoint = std::chrono::time_point<sclock, ns>;
95 
96  tpoint p(ns(s.access_time));
97  time_t t = sclock::to_time_t(p);
98  os << "access: " << std::put_time(std::localtime(&t), "%D %T") << " (" << s.access_time << ")\n";
99  p = tpoint(ns(s.mod_time));
100  t = sclock::to_time_t(p);
101  os << "modify: " << std::put_time(std::localtime(&t), "%D %T") << " (" << s.mod_time << ")\n";
102  p = tpoint(ns(s.change_time));
103  t = sclock::to_time_t(p);
104  os << "change: " << std::put_time(std::localtime(&t), "%D %T") << " (" << s.change_time << ")";
105 
106  return os;
107 }
108 
109 void scc::util::PrintTo(const FileStat& v, std::ostream* os)
110 {
111  *os << v;
112 }
113 
114 void scc::util::PrintTo(const FileType& v, std::ostream* os)
115 {
116  *os << v;
117 }
118 
119 bool scc::util::default_scan_filter(const std::string& name, FileType type)
120 {
121  if (type == FileType::dir && (name == "." || name == ".."))
122  {
123  return false;
124  }
125  return true;
126 }
127 
128 std::map<std::string, FileType> Filesystem::scan_dir(const std::string& dirname,
129  std::function<bool(const std::string&, FileType)> filter, std::system_error* err)
130 {
131  std::map<std::string, FileType> ret;
132 
133  DIR* d = opendir(dirname.c_str());
134  if (d == nullptr)
135  {
136  if (errno == ENOENT || errno == ENOTDIR)
137  {
138  return ret;
139  }
140  auto e = std::system_error(errno, std::system_category(), "scan_dir()");
141  if (err)
142  {
143  *err = e;
144  return ret;
145  }
146  throw e;
147  }
148 
149  errno = 0;
150  dirent* ent;
151  while ((ent = readdir(d)))
152  {
154  switch (ent->d_type)
155  {
156  case DT_REG: type = FileType::reg; break;
157  case DT_DIR: type = FileType::dir; break;
158  case DT_LNK: type = FileType::link; break;
159  case DT_SOCK: type = FileType::sock; break;
160  case DT_BLK: type = FileType::block; break;
161  case DT_CHR: type = FileType::chr; break;
162  case DT_FIFO: type = FileType::fifo; break;
163  }
164 
165  if (filter(ent->d_name, type))
166  {
167  ret[ent->d_name] = type;
168  }
169  }
170  if (errno)
171  {
172  closedir(d);
173  auto e = std::system_error(errno, std::system_category(), "scan_dir()");
174  if (err)
175  {
176  *err = e;
177  return ret;
178  }
179  throw e;
180  }
181  closedir(d);
182 
183  return ret;
184 }
185 
186 FileType Filesystem::file_type(const std::string& name, std::system_error* err)
187 {
189  struct stat st;
190 
191  if (lstat(name.c_str(), &st) == -1)
192  {
193  auto e = std::system_error(errno, std::system_category(), "file_type()");
194  if (err)
195  {
196  *err = e;
197  return type;
198  }
199  throw e;
200  }
201 
202  switch (st.st_mode & S_IFMT)
203  {
204  case S_IFREG: type = FileType::reg; break;
205  case S_IFDIR: type = FileType::dir; break;
206  case S_IFLNK: type = FileType::link; break;
207  case S_IFSOCK: type = FileType::sock; break;
208  case S_IFBLK: type = FileType::block; break;
209  case S_IFCHR: type = FileType::chr; break;
210  case S_IFIFO: type = FileType::fifo; break;
211  }
212 
213  return type;
214 }
215 
216 void Filesystem::remove_dir(const std::string& dirn, std::system_error* err)
217 {
218  if (rmdir(dirn.c_str()) == -1)
219  {
220  if (err) *err = std::system_error(errno, std::system_category(), "remove_dir()");
221  return;
222  }
223 }
224 
225 void Filesystem::remove_file(const std::string& name, std::system_error* err)
226 {
227  if (unlink(name.c_str()) == -1)
228  {
229  if (err) *err = std::system_error(errno, std::system_category(), "remove_file()");
230  }
231 }
232 
233 void Filesystem::remove(const std::string& name, std::system_error* err)
234 {
235  auto ty = file_type(name, err);
236  if (ty == FileType::unknown)
237  {
238  return;
239  }
240  if (ty == FileType::dir)
241  {
242  remove_dir(name, err);
243  return;
244  }
245  remove_file(name, err);
246 }
247 
248 // Recursive.
249 void Filesystem::remove_all(const std::string& name, const FileType& ty, std::system_error* err)
250 {
251  if (ty == FileType::dir)
252  {
253  for (auto& f : scan_dir(name))
254  {
255  std::stringstream newf;
256  newf << name << "/" << f.first;
257  remove_all(newf.str(), f.second, err);
258  }
259  }
260  if (ty == FileType::dir)
261  {
262  remove_dir(name, err);
263  }
264  else
265  {
266  remove_file(name, err);
267  }
268 }
269 
270 void Filesystem::rename(const std::string& old_fn, const std::string& new_fn, std::system_error* err)
271 {
272  if (::rename(old_fn.c_str(), new_fn.c_str()) == -1)
273  {
274  auto e = std::system_error(errno, std::system_category(), "rename()");
275  if (err)
276  {
277  *err = e;
278  return;
279  }
280  throw e;
281  }
282 }
283 
284 void Filesystem::create_dir(const std::string& name, std::system_error* err)
285 {
286  if (mkdir(name.c_str(), 0700) == -1)
287  {
288  auto e = std::system_error(errno, std::system_category(), "create_dir()");
289  if (err)
290  {
291  *err = e;
292  return;
293  }
294  throw e;
295  }
296 }
297 
298 void Filesystem::create_reg(const std::string& name, std::system_error* err)
299 {
300  int fd = safe_open(name.c_str(), O_WRONLY|O_CREAT, 0600);
301  if (fd == -1)
302  {
303  auto e = std::system_error(errno, std::system_category(), "create_reg()");
304  if (err)
305  {
306  *err = e;
307  return;
308  }
309  throw e;
310  }
311  safe_close(fd);
312 }
313 
314 std::string Filesystem::create_tmp_reg(const std::string& prefix, std::system_error* err)
315 {
316  char nam[prefix.size()+7];
317  strcpy(nam, prefix.c_str());
318  strcpy(nam+prefix.size(), "XXXXXX");
319  int fd;
320  do
321  {
322  fd = ::mkstemp(nam);
323  }
324  while (fd == -1 && errno == EINTR);
325  if (fd == -1)
326  {
327  auto e = std::system_error(errno, std::system_category(), "create_tmp_reg()");
328  if (err)
329  {
330  *err = e;
331  return "";
332  }
333  throw e;
334  }
335  safe_close(fd);
336  return std::string(nam);
337 }
338 
339 void Filesystem::create_symlink(const std::string& target, const std::string& name, std::system_error* err)
340 {
341  if (symlink(target.c_str(), name.c_str()) == -1)
342  {
343  auto e = std::system_error(errno, std::system_category(), "create_symlink()");
344  if (err)
345  {
346  *err = e;
347  return;
348  }
349  throw e;
350  }
351 }
352 
353 std::string Filesystem::read_symlink(const std::string& name, std::system_error* err)
354 {
355  char buf[NAME_MAX+1];
356  memset(&buf[0], '\0', NAME_MAX+1);
357 
358  auto ret = readlink(name.c_str(), buf, NAME_MAX);
359  if (ret == -1)
360  {
361  auto e = std::system_error(errno, std::system_category(), "read_symlink()");
362  if (err)
363  {
364  *err = e;
365  return "";
366  }
367  throw e;
368  }
369  return std::string(buf);
370 }
371 
372 void Filesystem::create_link(const std::string& orig_name, const std::string& new_name, std::system_error* err)
373 {
374  if (link(orig_name.c_str(), new_name.c_str()) == -1)
375  {
376  auto e = std::system_error(errno, std::system_category(), "create_link()");
377  if (err)
378  {
379  *err = e;
380  return;
381  }
382  throw e;
383  }
384 }
385 
386 void Filesystem::create_fifo(const std::string& name, std::system_error* err)
387 {
388  if (mkfifo(name.c_str(), 0600) == -1)
389  {
390  auto e = std::system_error(errno, std::system_category(), "create_fifo()");
391  if (err)
392  {
393  *err = e;
394  return;
395  }
396  throw e;
397  }
398 }
399 
400 FileStat Filesystem::file_stat(const std::string& name, std::system_error* err)
401 {
402  FileStat fs;
403  struct stat st;
404  if (lstat(name.c_str(), &st) == -1)
405  {
406  auto e = std::system_error(errno, std::system_category(), "file_stat()");
407  if (err)
408  {
409  *err = e;
410  return fs;
411  }
412  throw e;
413  }
414 
415  switch (st.st_mode & S_IFMT)
416  {
417  case S_IFREG: fs.type = FileType::reg; break;
418  case S_IFDIR: fs.type = FileType::dir; break;
419  case S_IFLNK: fs.type = FileType::link; break;
420  case S_IFSOCK: fs.type = FileType::sock; break;
421  case S_IFBLK: fs.type = FileType::block; break;
422  case S_IFCHR: fs.type = FileType::chr; break;
423  case S_IFIFO: fs.type = FileType::fifo; break;
424  }
425 
426  fs.mode = st.st_mode & ~S_IFMT;
427  fs.uid = st.st_uid;
428  fs.gid = st.st_gid;
429  fs.size = st.st_size;
430  fs.alloc_size = st.st_blocks*512;
431  fs.access_time = st.st_atim.tv_sec*NS + st.st_atim.tv_nsec;
432  fs.mod_time = st.st_mtim.tv_sec*NS + st.st_mtim.tv_nsec;
433  fs.change_time = st.st_ctim.tv_sec*NS + st.st_ctim.tv_nsec;
434  fs.inode = st.st_ino;
435  fs.num_links = st.st_nlink;
436 
437  return fs;
438 }
439 
440 void Filesystem::change_dir(const std::string& name, std::system_error* err)
441 {
442  if (chdir(name.c_str()) == -1)
443  {
444  auto e = std::system_error(errno, std::system_category(), "change_dir()");
445  if (err)
446  {
447  *err = e;
448  return;
449  }
450  throw e;
451  }
452 }
453 
454 std::string Filesystem::get_current_dir(std::system_error* err)
455 {
456  auto dir = get_current_dir_name();
457  if (dir == nullptr)
458  {
459  auto e = std::system_error(errno, std::system_category(), "get_current_dir()");
460  if (err)
461  {
462  *err = e;
463  return "";
464  }
465  throw e;
466  }
467  std::string ret(dir);
468  free(dir);
469  return ret;
470 }
471 
472 void Filesystem::set_mode(const std::string& name, unsigned mode, std::system_error* err)
473 {
474  // no symlink follow is not implemented, cannot apply mode to a symlink
475  if (fchmodat(AT_FDCWD, name.c_str(), mode, 0) == -1)
476  {
477  auto e = std::system_error(errno, std::system_category(), "set_mode()");
478  if (err)
479  {
480  *err = e;
481  return;
482  }
483  throw e;
484  }
485 }
486 
487 void Filesystem::set_ids(const std::string& name, int uid, int gid, std::system_error* err)
488 {
489  if (uid < 0) uid = -1;
490  if (gid < 0) gid = -1;
491 
492  if (fchownat(AT_FDCWD, name.c_str(), uid, gid, AT_SYMLINK_NOFOLLOW) == -1)
493  {
494  auto e = std::system_error(errno, std::system_category(), "set_ids()");
495  if (err)
496  {
497  *err = e;
498  return;
499  }
500  throw e;
501  }
502 }
503 
504 void Filesystem::set_times(const std::string& name, uint64_t access_time, uint64_t mod_time, std::system_error* err)
505 {
506  struct timespec times[2];
507  times[0].tv_sec = (access_time-(access_time%NS))/NS;
508  times[0].tv_nsec = access_time%NS;
509  times[1].tv_sec = (mod_time-(mod_time%NS))/NS;
510  times[1].tv_nsec = mod_time%NS;
511 
512  if (utimensat(AT_FDCWD, name.c_str(), &times[0], AT_SYMLINK_NOFOLLOW) == -1)
513  {
514  auto e = std::system_error(errno, std::system_category(), name);
515  if (err)
516  {
517  *err = e;
518  return;
519  }
520  throw e;
521  }
522 }
523 
524 //#include <iostream>
525 std::map<off_t, off_t> Filesystem::sparse_map(const std::string& name, std::system_error* err)
526 {
527  std::map<off_t, off_t> ret;
528 
529  int fd = scc::util::safe_open(name.c_str(), O_RDONLY);
530  if (fd == -1)
531  {
532  auto e = std::system_error(errno, std::system_category(), "sparse_map()");
533  if (err)
534  {
535  *err = e;
536  return ret;
537  }
538  throw e;
539  }
540 
541  auto throw_err = [&]()
542  {
543  auto e = std::system_error(errno, std::system_category(), "sparse_map()");
544  if (err)
545  {
546  *err = e;
547  safe_close(fd);
548  return ret;
549  }
550  safe_close(fd);
551  throw e;
552  return ret;
553  };
554 
555  struct stat st;
556  if (fstat(fd, &st) < 0)
557  {
558  return throw_err();
559  }
560 
561  off_t idx = 0;
562  off_t starth = -1;
563  while (1)
564  {
565  off_t h = lseek(fd, idx, SEEK_HOLE); // find next hole
566 
567  if (h < 0)
568  {
569  return throw_err();
570  }
571 
572  if (h == idx) // start of hole
573  {
574  starth = idx;
575 
576  int d = lseek(fd, idx, SEEK_DATA); // find next data
577 
578  if (d < 0) // hole at the end of file
579  {
580  ret.emplace(starth, st.st_size-1);
581  break;
582  }
583 
584  idx = d; // go to the start of next data
585  }
586  else // start of data
587  {
588  if (starth >= 0)
589  {
590  ret.emplace(starth, idx-1);
591  starth = -1;
592  }
593 
594  idx = h; // go to the start of next hole
595  }
596 
597  if (h >= st.st_size) // end of file has an implicit hole
598  {
599  if (starth >= 0)
600  {
601  ret.emplace(starth, st.st_size-1);
602  }
603  break;
604  }
605 
606  }
607  return ret;
608 }
609 
610 void Filesystem::set_size(const std::string& name, off_t size, std::system_error* err)
611 {
612  int fd = scc::util::safe_open(name.c_str(), O_WRONLY, 0);
613  if (fd == -1)
614  {
615  auto e = std::system_error(errno, std::system_category(), "set_size()");
616  if (err)
617  {
618  *err = e;
619  return;
620  }
621  throw e;
622  }
623 
624  auto throw_err = [&]()
625  {
626  auto e = std::system_error(errno, std::system_category(), "set_size()");
627  if (err)
628  {
629  *err = e;
630  safe_close(fd);
631  return;
632  }
633  safe_close(fd);
634  throw e;
635  };
636 
637  struct stat st;
638  if (fstat(fd, &st) < 0)
639  {
640  throw_err();
641  return;
642  }
643 
644  if (size < st.st_size)
645  {
646  if (safe_ftruncate(fd, size) < 0)
647  {
648  throw_err();
649  return;
650  }
651  }
652  else if (size > st.st_size)
653  {
654  // set the file pointer to the desired size
655  if (lseek(fd, size-1, SEEK_SET) == -1)
656  {
657  throw_err();
658  return;
659  }
660  // write out the sparse file (0 at the end)
661  if (safe_write(fd, "", 1) < 0)
662  {
663  throw_err();
664  return;
665  }
666  }
667 
668  safe_close(fd);
669 }
670 
671 std::string Filesystem::norm_path(const std::string& base_dir, const std::string& path) noexcept
672 {
673  char _bd[base_dir.size()+1];
674  strcpy(_bd, base_dir.c_str());
675  char _bp[base_dir.size()+1];
676  strcpy(_bp, base_dir.c_str());
677 
678  std::string bd(dirname(_bd)); // these may use the input string as scratch
679  std::string bp(basename(_bp));
680 
681  char _pd[path.size()+1];
682  strcpy(_pd, path.c_str());
683  char _pp[path.size()+1];
684  strcpy(_pp, path.c_str());
685 
686  std::string pd(dirname(_pd));
687  std::string pp(basename(_pp));
688 
689  std::string newp, trail;
690 
691  if (pd[0] == '/') // absolute
692  {
693  newp = pd + "/" + pp;
694  }
695  else
696  {
697  newp = bd + "/" + bp + "/" + pd + "/" + pp;
698  }
699 
700  if (path.size())
701  {
702  if (path[path.size()-1] == '/')
703  {
704  trail = "/";
705  }
706  }
707  else if (base_dir.size() && base_dir[base_dir.size()-1] == '/')
708  {
709  trail = "/";
710  }
711 
712  // split up the path
713  std::vector<std::string> sp;
714  std::stringstream paths(newp);
715  std::string token;
716  while (std::getline(paths, token, '/'))
717  {
718  sp.push_back(token);
719  }
720 
721  // will ignore any sp item which is empty (thus ignoring double //)
722 
723  for (unsigned i = 1; i < sp.size(); i++) // always keep the first entry
724  {
725  if (sp.size() == 0)
726  {
727  continue; // ignore this entry
728  }
729  else if (sp[i] == ".")
730  {
731  sp[i] = ""; // erase this entry
732  }
733  else if (sp[i] == "..")
734  {
735  int back;
736  for (back=i-1; back > 0 && sp[back] == ""; back--) // go back to the last real entry
737  {}
738  if (back == 0)
739  {
740  continue; // use this entry
741  }
742  if (sp[back] == "..")
743  {
744  continue; // use this entry
745  }
746  sp[back] = ""; // erase the last entry
747  sp[i] = ""; // erase this entry
748  }
749  // otherwise, use this entry
750  }
751 
752  std::stringstream ret;
753  ret << sp[0];
754  for (unsigned i = 1; i < sp.size(); i++)
755  {
756  if (sp[i].size() > 0)
757  {
758  ret << "/" << sp[i];
759  }
760  }
761 
762  if (ret.str().size() == 0) // this was either / or // etc.
763  {
764  return "/";
765  }
766  if (ret.str()[ret.str().size()-1] != '/')
767  {
768  return ret.str()+trail;
769  }
770  return ret.str();
771 }
Common file system utilities.
Definition: fs.h:103
static std::string get_current_dir(std::system_error *=nullptr)
Get working directory.
Definition: fs.cc:454
static void create_reg(const std::string &, std::system_error *=nullptr)
Create a regular file.
Definition: fs.cc:298
static std::string norm_path(const std::string &, const std::string &) noexcept
Normalize a path with base directory.
Definition: fs.cc:671
static void create_symlink(const std::string &, const std::string &, std::system_error *=nullptr)
Create a symbolic link.
Definition: fs.cc:339
static void rename(const std::string &, const std::string &, std::system_error *=nullptr)
Rename the file or directory.
Definition: fs.cc:270
static void create_link(const std::string &, const std::string &, std::system_error *=nullptr)
Create a hard link.
Definition: fs.cc:372
static void set_ids(const std::string &, int, int, std::system_error *=nullptr)
Set the user id and/or group id.
Definition: fs.cc:487
static void create_fifo(const std::string &, std::system_error *=nullptr)
Create a named pipe (FIFO).
Definition: fs.cc:386
static FileType file_type(const std::string &, std::system_error *=nullptr)
Get the file type.
Definition: fs.cc:186
static std::map< std::string, FileType > scan_dir(const std::string &, std::function< bool(const std::string &, FileType)>=default_scan_filter, std::system_error *=nullptr)
Scan a directory, and return a map of names and file types.
Definition: fs.cc:128
static FileStat file_stat(const std::string &, std::system_error *=nullptr)
Get the file stat.
Definition: fs.cc:400
static std::string read_symlink(const std::string &, std::system_error *=nullptr)
Read the location of a symbolic link target.
Definition: fs.cc:353
static void set_size(const std::string &, off_t, std::system_error *=nullptr)
Set the file size.
Definition: fs.cc:610
static std::string create_tmp_reg(const std::string &, std::system_error *=nullptr)
Create a temporary regular file.
Definition: fs.cc:314
static void change_dir(const std::string &, std::system_error *=nullptr)
Change working directory.
Definition: fs.cc:440
static void remove(const std::string &, std::system_error *=nullptr)
Remove the file or directory.
Definition: fs.cc:233
static std::map< off_t, off_t > sparse_map(const std::string &, std::system_error *=nullptr)
Map of file sparseness.
Definition: fs.cc:525
static void create_dir(const std::string &, std::system_error *=nullptr)
Create a directory.
Definition: fs.cc:284
static void set_mode(const std::string &, unsigned, std::system_error *=nullptr)
Set the file mode.
Definition: fs.cc:472
static void set_times(const std::string &, uint64_t, uint64_t, std::system_error *=nullptr)
Set the file times.
Definition: fs.cc:504
Common file system utilities.
void PrintTo(const FileStat &, std::ostream *)
Googletest printer.
Definition: fs.cc:109
FileType
File type.
Definition: fs.h:59
bool default_scan_filter(const std::string &, FileType)
Default scan filter.
Definition: fs.cc:119
@ block
block device
@ link
symbolic link
@ reg
regular file
@ chr
character device
@ unknown
unknown or does not exist
int safe_close(int fd)
Signal safe close.
Definition: safe_clib.cc:95
ssize_t safe_write(int fd, const void *buf, size_t count)
Signal safe write.
Definition: safe_clib.cc:141
int safe_open(const char *pathname, int flags)
Signal safe open.
Definition: safe_clib.cc:210
int safe_ftruncate(int fd, off_t length)
Signal safe ftruncate.
Definition: safe_clib.cc:72
std::ostream & operator<<(std::ostream &, const scc::net::InetAddr &)
Print the socket address details to an output stream.
Definition: inet.cc:320
Signal-safe C library wrapper.
File status structure.
Definition: fs.h:75
uint64_t alloc_size
Real allocated size on disk.
Definition: fs.h:81
int gid
Group id.
Definition: fs.h:79
uint64_t change_time
Last status change time; writes, permission changes, etc. (ns since epoch)
Definition: fs.h:84
uint64_t size
Size of file.
Definition: fs.h:80
uint64_t access_time
Last access time; reads, etc. (ns since epoch)
Definition: fs.h:82
int uid
User id.
Definition: fs.h:78
uint16_t num_links
Number of hard links to this inode.
Definition: fs.h:86
uint64_t inode
Inode number.
Definition: fs.h:85
uint64_t mod_time
Last modification time; writes, etc. (ns since epoch)
Definition: fs.h:83
unsigned mode
File mode 07777 format (bits/user/group/all 4=read, 2=write, 3=execute, or uid/gid/sticky)
Definition: fs.h:77
FileType type
File type.
Definition: fs.h:76