}
+ string
+ dirname(const string& name)
+ {
+ string::size_type pos = name.find_last_of('/');
+ if (pos == string::npos)
+ return string(".");
+ return string(name, 0, pos == 0 ? 1 : pos);
+ }
+
+
+ string
+ basename(const string& name)
+ {
+ string::size_type pos = name.find_last_of('/');
+ return string(name, pos + 1);
+ }
+
+
bool
getMtabData(const string& mount_point, bool& found, MtabData& mtab_data)
{
string stringerror(int errnum);
+ string dirname(const string& name);
+ string basename(const string& name);
+
struct MtabData
{
if (status & (CONTENT | PERMISSIONS | USER | GROUP))
{
- status &= ~(CONTENT | PERMISSIONS | USER | GROUP);
- // TODO use of fullname might be insecure
// TODO check for content sometimes not required
- status |= cmpFiles(processor->dir1.fullname(), processor->dir2.fullname(), name);
+ status &= ~(CONTENT | PERMISSIONS | USER | GROUP);
+
+ string dirname = snapper::dirname(name);
+ string basename = snapper::basename(name);
+
+ SDir subdir1 = SDir::deepopen(processor->dir1, dirname);
+ SDir subdir2 = SDir::deepopen(processor->dir2, dirname);
+
+ status |= cmpFiles(SFile(subdir1, basename), SFile(subdir2, basename));
}
return status;
processor->deleted(from);
processor->created(to);
- // TODO use of fullname might be insecure
- if (checkDir(processor->dir1.fullname() + "/" + from))
+ string dirname = snapper::dirname(from);
+ string basename = snapper::basename(from);
+
+ struct stat buf;
+ SDir tmpdir1 = SDir::deepopen(processor->dir1, dirname);
+ if (tmpdir1.stat(basename, &buf, AT_SYMLINK_NOFOLLOW) == 0 && S_ISDIR(buf.st_mode))
{
- SDir dir_from(processor->dir1.fullname() + "/" + from);
- vector<string> entries = dir_from.entries_recursive();
+ SDir tmpdir2(tmpdir1, basename);
+ vector<string> entries = tmpdir2.entries_recursive();
for (vector<string>::const_iterator it = entries.begin(); it != entries.end(); ++it)
{
processor->deleted(from + "/" + *it);
unsigned int
- cmpFiles(const string& base_path1, const string& base_path2, const string& name)
+ cmpFiles(const SFile& file1, const SFile& file2)
{
- SDir dir1(base_path1);
- SDir dir2(base_path2);
-
- SFile file1(dir1, name); // TODO not secure
- SFile file2(dir2, name); // TODO not secure
-
struct stat stat1;
int r1 = file1.stat(&stat1, AT_SYMLINK_NOFOLLOW);
typedef std::function<void(const string& name, unsigned int status)> cmpdirs_cb_t;
- /* TODO */
+ /* Compares the two files. */
unsigned int
- cmpFiles(const string& base_path, const string& base_path2, const string& name);
+ cmpFiles(const SFile& file1, const SFile& file2);
/* Compares the two directories. All file-operations use the openat
et.al. functions. */
File::getPreToSystemStatus()
{
if (pre_to_system_status == (unsigned int)(-1))
- pre_to_system_status = cmpFiles(file_paths->pre_path, file_paths->system_path, name);
+ {
+ SDir dir1(file_paths->pre_path);
+ SDir dir2(file_paths->system_path);
+
+ string dirname = snapper::dirname(name);
+ string basename = snapper::basename(name);
+
+ SDir subdir1 = SDir::deepopen(dir1, dirname);
+ SDir subdir2 = SDir::deepopen(dir2, dirname);
+
+ pre_to_system_status = cmpFiles(SFile(subdir1, basename), SFile(subdir2, basename));
+ }
+
return pre_to_system_status;
}
File::getPostToSystemStatus()
{
if (post_to_system_status == (unsigned int)(-1))
- post_to_system_status = cmpFiles(file_paths->post_path, file_paths->system_path, name);
+ {
+ SDir dir1(file_paths->post_path);
+ SDir dir2(file_paths->system_path);
+
+ string dirname = snapper::dirname(name);
+ string basename = snapper::basename(name);
+
+ SDir subdir1 = SDir::deepopen(dir1, dirname);
+ SDir subdir2 = SDir::deepopen(dir2, dirname);
+
+ post_to_system_status = cmpFiles(SFile(subdir1, basename), SFile(subdir2, basename));
+ }
+
return post_to_system_status;
}
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
+#include <assert.h>
#include <algorithm>
#include "snapper/FileUtils.h"
SDir::SDir(const SDir& dir, const string& name)
: base_path(dir.base_path), path(dir.path + "/" + name)
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
dirfd = ::openat(dir.dirfd, name.c_str(), O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC);
if (dirfd < 0)
{
if (!S_ISDIR(buf.st_mode))
{
y2err("not a directory path:" << dir.fullname(name));
+ close(dirfd);
throw IOErrorException();
}
}
}
+ SDir
+ SDir::deepopen(const SDir& dir, const string& name)
+ {
+ string::size_type pos = name.find('/');
+ if (pos == string::npos)
+ return SDir(dir, name);
+
+ return deepopen(SDir(dir, string(name, 0, pos)), string(name, pos + 1));
+ }
+
+
string
SDir::fullname(bool with_base_path) const
{
int
SDir::stat(const string& name, struct stat* buf, int flags) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
return ::fstatat(dirfd, name.c_str(), buf, flags);
}
int
SDir::open(const string& name, int flags) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
return ::openat(dirfd, name.c_str(), flags);
}
int
SDir::open(const string& name, int flags, mode_t mode) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
return ::openat(dirfd, name.c_str(), flags, mode);
}
int
SDir::readlink(const string& name, string& buf) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
char tmp[1024];
int ret = ::readlinkat(dirfd, name.c_str(), tmp, sizeof(tmp));
if (ret >= 0)
int
SDir::mkdir(const string& name, mode_t mode) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
return ::mkdirat(dirfd, name.c_str(), mode);
}
int
SDir::unlink(const string& name, int flags) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
return ::unlinkat(dirfd, name.c_str(), flags);
}
int
SDir::chmod(const string& name, mode_t mode, int flags) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
return ::fchmodat(dirfd, name.c_str(), mode, flags);
}
int
SDir::chown(const string& name, uid_t owner, gid_t group, int flags) const
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
+
return ::fchownat(dirfd, name.c_str(), owner, group, flags);
}
int
SDir::rename(const string& oldname, const string& newname) const
{
+ assert(oldname.find('/') == string::npos);
+ assert(oldname != "..");
+
+ assert(newname.find('/') == string::npos);
+ assert(newname != "..");
+
return ::renameat(dirfd, oldname.c_str(), dirfd, newname.c_str());
}
SFile::SFile(const SDir& dir, const string& name)
: dir(dir), name(name)
{
+ assert(name.find('/') == string::npos);
+ assert(name != "..");
}
SDir& operator=(const SDir&);
~SDir();
+ static SDir deepopen(const SDir& dir, const string& name);
+
int fd() const { return dirfd; }
string fullname(bool with_base_path = true) const;