32 #include <system_error>
35 #include <sys/types.h>
54 const uint64_t NS=1000000000;
56 using namespace scc::util;
69 default: os <<
"unknown";
break;
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";
92 using ns = std::chrono::nanoseconds;
93 using sclock = std::chrono::system_clock;
94 using tpoint = std::chrono::time_point<sclock, ns>;
97 time_t t = sclock::to_time_t(p);
98 os <<
"access: " << std::put_time(std::localtime(&t),
"%D %T") <<
" (" << s.
access_time <<
")\n";
100 t = sclock::to_time_t(p);
101 os <<
"modify: " << std::put_time(std::localtime(&t),
"%D %T") <<
" (" << s.
mod_time <<
")\n";
103 t = sclock::to_time_t(p);
104 os <<
"change: " << std::put_time(std::localtime(&t),
"%D %T") <<
" (" << s.
change_time <<
")";
129 std::function<
bool(
const std::string&,
FileType)> filter, std::system_error* err)
131 std::map<std::string, FileType> ret;
133 DIR* d = opendir(dirname.c_str());
136 if (errno == ENOENT || errno == ENOTDIR)
140 auto e = std::system_error(errno, std::system_category(),
"scan_dir()");
151 while ((ent = readdir(d)))
165 if (filter(ent->d_name, type))
167 ret[ent->d_name] = type;
173 auto e = std::system_error(errno, std::system_category(),
"scan_dir()");
191 if (lstat(name.c_str(), &st) == -1)
193 auto e = std::system_error(errno, std::system_category(),
"file_type()");
202 switch (st.st_mode & S_IFMT)
216 void Filesystem::remove_dir(
const std::string& dirn, std::system_error* err)
218 if (rmdir(dirn.c_str()) == -1)
220 if (err) *err = std::system_error(errno, std::system_category(),
"remove_dir()");
225 void Filesystem::remove_file(
const std::string& name, std::system_error* err)
227 if (unlink(name.c_str()) == -1)
229 if (err) *err = std::system_error(errno, std::system_category(),
"remove_file()");
242 remove_dir(name, err);
245 remove_file(name, err);
249 void Filesystem::remove_all(
const std::string& name,
const FileType& ty, std::system_error* err)
255 std::stringstream newf;
256 newf << name <<
"/" << f.first;
257 remove_all(newf.str(), f.second, err);
262 remove_dir(name, err);
266 remove_file(name, err);
270 void Filesystem::rename(
const std::string& old_fn,
const std::string& new_fn, std::system_error* err)
272 if (::
rename(old_fn.c_str(), new_fn.c_str()) == -1)
274 auto e = std::system_error(errno, std::system_category(),
"rename()");
286 if (mkdir(name.c_str(), 0700) == -1)
288 auto e = std::system_error(errno, std::system_category(),
"create_dir()");
300 int fd =
safe_open(name.c_str(), O_WRONLY|O_CREAT, 0600);
303 auto e = std::system_error(errno, std::system_category(),
"create_reg()");
316 char nam[prefix.size()+7];
317 strcpy(nam, prefix.c_str());
318 strcpy(nam+prefix.size(),
"XXXXXX");
324 while (fd == -1 && errno == EINTR);
327 auto e = std::system_error(errno, std::system_category(),
"create_tmp_reg()");
336 return std::string(nam);
341 if (symlink(target.c_str(), name.c_str()) == -1)
343 auto e = std::system_error(errno, std::system_category(),
"create_symlink()");
355 char buf[NAME_MAX+1];
356 memset(&buf[0],
'\0', NAME_MAX+1);
358 auto ret = readlink(name.c_str(), buf, NAME_MAX);
361 auto e = std::system_error(errno, std::system_category(),
"read_symlink()");
369 return std::string(buf);
374 if (
link(orig_name.c_str(), new_name.c_str()) == -1)
376 auto e = std::system_error(errno, std::system_category(),
"create_link()");
388 if (mkfifo(name.c_str(), 0600) == -1)
390 auto e = std::system_error(errno, std::system_category(),
"create_fifo()");
404 if (lstat(name.c_str(), &st) == -1)
406 auto e = std::system_error(errno, std::system_category(),
"file_stat()");
415 switch (st.st_mode & S_IFMT)
426 fs.mode = st.st_mode & ~S_IFMT;
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;
442 if (chdir(name.c_str()) == -1)
444 auto e = std::system_error(errno, std::system_category(),
"change_dir()");
456 auto dir = get_current_dir_name();
459 auto e = std::system_error(errno, std::system_category(),
"get_current_dir()");
467 std::string ret(
dir);
475 if (fchmodat(AT_FDCWD, name.c_str(), mode, 0) == -1)
477 auto e = std::system_error(errno, std::system_category(),
"set_mode()");
489 if (uid < 0) uid = -1;
490 if (gid < 0) gid = -1;
492 if (fchownat(AT_FDCWD, name.c_str(), uid, gid, AT_SYMLINK_NOFOLLOW) == -1)
494 auto e = std::system_error(errno, std::system_category(),
"set_ids()");
504 void Filesystem::set_times(
const std::string& name, uint64_t access_time, uint64_t mod_time, std::system_error* err)
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;
512 if (utimensat(AT_FDCWD, name.c_str(), ×[0], AT_SYMLINK_NOFOLLOW) == -1)
514 auto e = std::system_error(errno, std::system_category(), name);
527 std::map<off_t, off_t> ret;
532 auto e = std::system_error(errno, std::system_category(),
"sparse_map()");
541 auto throw_err = [&]()
543 auto e = std::system_error(errno, std::system_category(),
"sparse_map()");
556 if (fstat(fd, &st) < 0)
565 off_t h = lseek(fd, idx, SEEK_HOLE);
576 int d = lseek(fd, idx, SEEK_DATA);
580 ret.emplace(starth, st.st_size-1);
590 ret.emplace(starth, idx-1);
601 ret.emplace(starth, st.st_size-1);
615 auto e = std::system_error(errno, std::system_category(),
"set_size()");
624 auto throw_err = [&]()
626 auto e = std::system_error(errno, std::system_category(),
"set_size()");
638 if (fstat(fd, &st) < 0)
644 if (size < st.st_size)
652 else if (size > st.st_size)
655 if (lseek(fd, size-1, SEEK_SET) == -1)
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());
678 std::string bd(dirname(_bd));
679 std::string bp(basename(_bp));
681 char _pd[path.size()+1];
682 strcpy(_pd, path.c_str());
683 char _pp[path.size()+1];
684 strcpy(_pp, path.c_str());
686 std::string pd(dirname(_pd));
687 std::string pp(basename(_pp));
689 std::string newp, trail;
693 newp = pd +
"/" + pp;
697 newp = bd +
"/" + bp +
"/" + pd +
"/" + pp;
702 if (path[path.size()-1] ==
'/')
707 else if (base_dir.size() && base_dir[base_dir.size()-1] ==
'/')
713 std::vector<std::string> sp;
714 std::stringstream paths(newp);
716 while (std::getline(paths, token,
'/'))
723 for (
unsigned i = 1; i < sp.size(); i++)
729 else if (sp[i] ==
".")
733 else if (sp[i] ==
"..")
736 for (back=i-1; back > 0 && sp[back] ==
""; back--)
742 if (sp[back] ==
"..")
752 std::stringstream ret;
754 for (
unsigned i = 1; i < sp.size(); i++)
756 if (sp[i].size() > 0)
762 if (ret.str().size() == 0)
766 if (ret.str()[ret.str().size()-1] !=
'/')
768 return ret.str()+trail;
Common file system utilities.
static std::string get_current_dir(std::system_error *=nullptr)
Get working directory.
static void create_reg(const std::string &, std::system_error *=nullptr)
Create a regular file.
static std::string norm_path(const std::string &, const std::string &) noexcept
Normalize a path with base directory.
static void create_symlink(const std::string &, const std::string &, std::system_error *=nullptr)
Create a symbolic link.
static void rename(const std::string &, const std::string &, std::system_error *=nullptr)
Rename the file or directory.
static void create_link(const std::string &, const std::string &, std::system_error *=nullptr)
Create a hard link.
static void set_ids(const std::string &, int, int, std::system_error *=nullptr)
Set the user id and/or group id.
static void create_fifo(const std::string &, std::system_error *=nullptr)
Create a named pipe (FIFO).
static FileType file_type(const std::string &, std::system_error *=nullptr)
Get the file type.
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.
static FileStat file_stat(const std::string &, std::system_error *=nullptr)
Get the file stat.
static std::string read_symlink(const std::string &, std::system_error *=nullptr)
Read the location of a symbolic link target.
static void set_size(const std::string &, off_t, std::system_error *=nullptr)
Set the file size.
static std::string create_tmp_reg(const std::string &, std::system_error *=nullptr)
Create a temporary regular file.
static void change_dir(const std::string &, std::system_error *=nullptr)
Change working directory.
static void remove(const std::string &, std::system_error *=nullptr)
Remove the file or directory.
static std::map< off_t, off_t > sparse_map(const std::string &, std::system_error *=nullptr)
Map of file sparseness.
static void create_dir(const std::string &, std::system_error *=nullptr)
Create a directory.
static void set_mode(const std::string &, unsigned, std::system_error *=nullptr)
Set the file mode.
static void set_times(const std::string &, uint64_t, uint64_t, std::system_error *=nullptr)
Set the file times.
Common file system utilities.
void PrintTo(const FileStat &, std::ostream *)
Googletest printer.
bool default_scan_filter(const std::string &, FileType)
Default scan filter.
@ unknown
unknown or does not exist
int safe_close(int fd)
Signal safe close.
ssize_t safe_write(int fd, const void *buf, size_t count)
Signal safe write.
int safe_open(const char *pathname, int flags)
Signal safe open.
int safe_ftruncate(int fd, off_t length)
Signal safe ftruncate.
std::ostream & operator<<(std::ostream &, const scc::net::InetAddr &)
Print the socket address details to an output stream.
Signal-safe C library wrapper.
uint64_t alloc_size
Real allocated size on disk.
uint64_t change_time
Last status change time; writes, permission changes, etc. (ns since epoch)
uint64_t size
Size of file.
uint64_t access_time
Last access time; reads, etc. (ns since epoch)
uint16_t num_links
Number of hard links to this inode.
uint64_t inode
Inode number.
uint64_t mod_time
Last modification time; writes, etc. (ns since epoch)
unsigned mode
File mode 07777 format (bits/user/group/all 4=read, 2=write, 3=execute, or uid/gid/sticky)