mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-10-16 09:52:31 +00:00
Convert indentation to spaces
The tab war is lost
This commit is contained in:
@@ -5,13 +5,13 @@ LOCAL_MODULE:= libutils
|
||||
LOCAL_C_INCLUDES := jni/include $(LOCAL_PATH)/include
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
LOCAL_SRC_FILES := \
|
||||
missing.cpp \
|
||||
new.cpp \
|
||||
files.cpp \
|
||||
misc.cpp \
|
||||
selinux.cpp \
|
||||
logging.cpp \
|
||||
xwrap.cpp \
|
||||
stream.cpp
|
||||
missing.cpp \
|
||||
new.cpp \
|
||||
files.cpp \
|
||||
misc.cpp \
|
||||
selinux.cpp \
|
||||
logging.cpp \
|
||||
xwrap.cpp \
|
||||
stream.cpp
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
@@ -10,264 +10,264 @@
|
||||
using namespace std;
|
||||
|
||||
struct cpio_newc_header {
|
||||
char magic[6];
|
||||
char ino[8];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char nlink[8];
|
||||
char mtime[8];
|
||||
char filesize[8];
|
||||
char devmajor[8];
|
||||
char devminor[8];
|
||||
char rdevmajor[8];
|
||||
char rdevminor[8];
|
||||
char namesize[8];
|
||||
char check[8];
|
||||
char magic[6];
|
||||
char ino[8];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char nlink[8];
|
||||
char mtime[8];
|
||||
char filesize[8];
|
||||
char devmajor[8];
|
||||
char devminor[8];
|
||||
char rdevmajor[8];
|
||||
char rdevminor[8];
|
||||
char namesize[8];
|
||||
char check[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
static uint32_t x8u(const char *hex) {
|
||||
uint32_t val, inpos = 8, outpos;
|
||||
char pattern[6];
|
||||
uint32_t val, inpos = 8, outpos;
|
||||
char pattern[6];
|
||||
|
||||
while (*hex == '0') {
|
||||
hex++;
|
||||
if (!--inpos) return 0;
|
||||
}
|
||||
// Because scanf gratuitously treats %*X differently than printf does.
|
||||
sprintf(pattern, "%%%dx%%n", inpos);
|
||||
sscanf(hex, pattern, &val, &outpos);
|
||||
if (inpos != outpos)
|
||||
LOGE("bad cpio header\n");
|
||||
while (*hex == '0') {
|
||||
hex++;
|
||||
if (!--inpos) return 0;
|
||||
}
|
||||
// Because scanf gratuitously treats %*X differently than printf does.
|
||||
sprintf(pattern, "%%%dx%%n", inpos);
|
||||
sscanf(hex, pattern, &val, &outpos);
|
||||
if (inpos != outpos)
|
||||
LOGE("bad cpio header\n");
|
||||
|
||||
return val;
|
||||
return val;
|
||||
}
|
||||
|
||||
cpio_entry_base::cpio_entry_base(const cpio_newc_header *h)
|
||||
: mode(x8u(h->mode)), uid(x8u(h->uid)), gid(x8u(h->gid)), filesize(x8u(h->filesize)) {};
|
||||
|
||||
void cpio::dump(const char *file) {
|
||||
fprintf(stderr, "Dump cpio: [%s]\n", file);
|
||||
dump(xfopen(file, "we"));
|
||||
fprintf(stderr, "Dump cpio: [%s]\n", file);
|
||||
dump(xfopen(file, "we"));
|
||||
}
|
||||
|
||||
void cpio::rm(entry_map::iterator &it) {
|
||||
fprintf(stderr, "Remove [%s]\n", it->first.data());
|
||||
entries.erase(it);
|
||||
fprintf(stderr, "Remove [%s]\n", it->first.data());
|
||||
entries.erase(it);
|
||||
}
|
||||
|
||||
void cpio::rm(const char *name, bool r) {
|
||||
size_t len = strlen(name);
|
||||
for (auto it = entries.begin(); it != entries.end();) {
|
||||
if (it->first.compare(0, len, name) == 0 &&
|
||||
((r && it->first[len] == '/') || it->first[len] == '\0')) {
|
||||
auto tmp = it;
|
||||
++it;
|
||||
rm(tmp);
|
||||
if (!r) return;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
size_t len = strlen(name);
|
||||
for (auto it = entries.begin(); it != entries.end();) {
|
||||
if (it->first.compare(0, len, name) == 0 &&
|
||||
((r && it->first[len] == '/') || it->first[len] == '\0')) {
|
||||
auto tmp = it;
|
||||
++it;
|
||||
rm(tmp);
|
||||
if (!r) return;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void extract_entry(const entry_map::value_type &e, const char *file) {
|
||||
fprintf(stderr, "Extract [%s] to [%s]\n", e.first.data(), file);
|
||||
unlink(file);
|
||||
rmdir(file);
|
||||
if (S_ISDIR(e.second->mode)) {
|
||||
mkdir(file, e.second->mode & 0777);
|
||||
} else if (S_ISREG(e.second->mode)) {
|
||||
int fd = creat(file, e.second->mode & 0777);
|
||||
xwrite(fd, e.second->data, e.second->filesize);
|
||||
fchown(fd, e.second->uid, e.second->gid);
|
||||
close(fd);
|
||||
} else if (S_ISLNK(e.second->mode)) {
|
||||
auto target = strndup((char *) e.second->data, e.second->filesize);
|
||||
symlink(target, file);
|
||||
free(target);
|
||||
}
|
||||
fprintf(stderr, "Extract [%s] to [%s]\n", e.first.data(), file);
|
||||
unlink(file);
|
||||
rmdir(file);
|
||||
if (S_ISDIR(e.second->mode)) {
|
||||
mkdir(file, e.second->mode & 0777);
|
||||
} else if (S_ISREG(e.second->mode)) {
|
||||
int fd = creat(file, e.second->mode & 0777);
|
||||
xwrite(fd, e.second->data, e.second->filesize);
|
||||
fchown(fd, e.second->uid, e.second->gid);
|
||||
close(fd);
|
||||
} else if (S_ISLNK(e.second->mode)) {
|
||||
auto target = strndup((char *) e.second->data, e.second->filesize);
|
||||
symlink(target, file);
|
||||
free(target);
|
||||
}
|
||||
}
|
||||
|
||||
void cpio::extract() {
|
||||
for (auto &e : entries)
|
||||
extract_entry(e, e.first.data());
|
||||
for (auto &e : entries)
|
||||
extract_entry(e, e.first.data());
|
||||
}
|
||||
|
||||
bool cpio::extract(const char *name, const char *file) {
|
||||
auto it = entries.find(name);
|
||||
if (it != entries.end()) {
|
||||
extract_entry(*it, file);
|
||||
return true;
|
||||
}
|
||||
fprintf(stderr, "Cannot find the file entry [%s]\n", name);
|
||||
return false;
|
||||
auto it = entries.find(name);
|
||||
if (it != entries.end()) {
|
||||
extract_entry(*it, file);
|
||||
return true;
|
||||
}
|
||||
fprintf(stderr, "Cannot find the file entry [%s]\n", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cpio::exists(const char *name) {
|
||||
return entries.count(name) != 0;
|
||||
return entries.count(name) != 0;
|
||||
}
|
||||
|
||||
#define do_out(buf, len) pos += fwrite(buf, 1, len, out);
|
||||
#define out_align() do_out(zeros, align_off(pos, 4))
|
||||
void cpio::dump(FILE *out) {
|
||||
size_t pos = 0;
|
||||
unsigned inode = 300000;
|
||||
char header[111];
|
||||
char zeros[4] = {0};
|
||||
for (auto &e : entries) {
|
||||
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||
inode++, // e->ino
|
||||
e.second->mode,
|
||||
e.second->uid,
|
||||
e.second->gid,
|
||||
1, // e->nlink
|
||||
0, // e->mtime
|
||||
e.second->filesize,
|
||||
0, // e->devmajor
|
||||
0, // e->devminor
|
||||
0, // e->rdevmajor
|
||||
0, // e->rdevminor
|
||||
(uint32_t) e.first.size() + 1,
|
||||
0 // e->check
|
||||
);
|
||||
do_out(header, 110);
|
||||
do_out(e.first.data(), e.first.size() + 1);
|
||||
out_align();
|
||||
if (e.second->filesize) {
|
||||
do_out(e.second->data, e.second->filesize);
|
||||
out_align();
|
||||
}
|
||||
}
|
||||
// Write trailer
|
||||
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||
inode++, 0755, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0);
|
||||
do_out(header, 110);
|
||||
do_out("TRAILER!!!\0", 11);
|
||||
out_align();
|
||||
fclose(out);
|
||||
size_t pos = 0;
|
||||
unsigned inode = 300000;
|
||||
char header[111];
|
||||
char zeros[4] = {0};
|
||||
for (auto &e : entries) {
|
||||
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||
inode++, // e->ino
|
||||
e.second->mode,
|
||||
e.second->uid,
|
||||
e.second->gid,
|
||||
1, // e->nlink
|
||||
0, // e->mtime
|
||||
e.second->filesize,
|
||||
0, // e->devmajor
|
||||
0, // e->devminor
|
||||
0, // e->rdevmajor
|
||||
0, // e->rdevminor
|
||||
(uint32_t) e.first.size() + 1,
|
||||
0 // e->check
|
||||
);
|
||||
do_out(header, 110);
|
||||
do_out(e.first.data(), e.first.size() + 1);
|
||||
out_align();
|
||||
if (e.second->filesize) {
|
||||
do_out(e.second->data, e.second->filesize);
|
||||
out_align();
|
||||
}
|
||||
}
|
||||
// Write trailer
|
||||
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||
inode++, 0755, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0);
|
||||
do_out(header, 110);
|
||||
do_out("TRAILER!!!\0", 11);
|
||||
out_align();
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
cpio_rw::cpio_rw(const char *file) {
|
||||
load_cpio(file);
|
||||
load_cpio(file);
|
||||
}
|
||||
|
||||
void cpio_rw::load_cpio(const char *file) {
|
||||
char *buf;
|
||||
size_t sz;
|
||||
mmap_ro(file, buf, sz);
|
||||
fprintf(stderr, "Loading cpio: [%s]\n", file);
|
||||
load_cpio(buf, sz);
|
||||
munmap(buf, sz);
|
||||
char *buf;
|
||||
size_t sz;
|
||||
mmap_ro(file, buf, sz);
|
||||
fprintf(stderr, "Loading cpio: [%s]\n", file);
|
||||
load_cpio(buf, sz);
|
||||
munmap(buf, sz);
|
||||
}
|
||||
|
||||
void cpio_rw::insert(cpio_entry *e) {
|
||||
auto ex = entries.extract(e->filename);
|
||||
if (!ex) {
|
||||
entries[e->filename].reset(e);
|
||||
} else {
|
||||
ex.key() = e->filename;
|
||||
ex.mapped().reset(e);
|
||||
entries.insert(std::move(ex));
|
||||
}
|
||||
auto ex = entries.extract(e->filename);
|
||||
if (!ex) {
|
||||
entries[e->filename].reset(e);
|
||||
} else {
|
||||
ex.key() = e->filename;
|
||||
ex.mapped().reset(e);
|
||||
entries.insert(std::move(ex));
|
||||
}
|
||||
}
|
||||
|
||||
void cpio_rw::add(mode_t mode, const char *name, const char *file) {
|
||||
void *buf;
|
||||
size_t sz;
|
||||
mmap_ro(file, buf, sz);
|
||||
auto e = new cpio_entry(name, S_IFREG | mode);
|
||||
e->filesize = sz;
|
||||
e->data = xmalloc(sz);
|
||||
memcpy(e->data, buf, sz);
|
||||
munmap(buf, sz);
|
||||
insert(e);
|
||||
fprintf(stderr, "Add entry [%s] (%04o)\n", name, mode);
|
||||
void *buf;
|
||||
size_t sz;
|
||||
mmap_ro(file, buf, sz);
|
||||
auto e = new cpio_entry(name, S_IFREG | mode);
|
||||
e->filesize = sz;
|
||||
e->data = xmalloc(sz);
|
||||
memcpy(e->data, buf, sz);
|
||||
munmap(buf, sz);
|
||||
insert(e);
|
||||
fprintf(stderr, "Add entry [%s] (%04o)\n", name, mode);
|
||||
}
|
||||
|
||||
void cpio_rw::mkdir(mode_t mode, const char *name) {
|
||||
insert(new cpio_entry(name, S_IFDIR | mode));
|
||||
fprintf(stderr, "Create directory [%s] (%04o)\n", name, mode);
|
||||
insert(new cpio_entry(name, S_IFDIR | mode));
|
||||
fprintf(stderr, "Create directory [%s] (%04o)\n", name, mode);
|
||||
}
|
||||
|
||||
void cpio_rw::ln(const char *target, const char *name) {
|
||||
auto e = new cpio_entry(name, S_IFLNK);
|
||||
e->filesize = strlen(target);
|
||||
e->data = strdup(target);
|
||||
insert(e);
|
||||
fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target);
|
||||
auto e = new cpio_entry(name, S_IFLNK);
|
||||
e->filesize = strlen(target);
|
||||
e->data = strdup(target);
|
||||
insert(e);
|
||||
fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target);
|
||||
}
|
||||
|
||||
void cpio_rw::mv(entry_map::iterator &it, const char *to) {
|
||||
fprintf(stderr, "Move [%s] -> [%s]\n", it->first.data(), to);
|
||||
auto ex = entries.extract(it);
|
||||
auto &name = static_cast<cpio_entry*>(ex.mapped().get())->filename;
|
||||
name = to;
|
||||
ex.key() = name;
|
||||
entries.erase(name);
|
||||
entries.insert(std::move(ex));
|
||||
fprintf(stderr, "Move [%s] -> [%s]\n", it->first.data(), to);
|
||||
auto ex = entries.extract(it);
|
||||
auto &name = static_cast<cpio_entry*>(ex.mapped().get())->filename;
|
||||
name = to;
|
||||
ex.key() = name;
|
||||
entries.erase(name);
|
||||
entries.insert(std::move(ex));
|
||||
}
|
||||
|
||||
bool cpio_rw::mv(const char *from, const char *to) {
|
||||
auto it = entries.find(from);
|
||||
if (it != entries.end()) {
|
||||
mv(it, to);
|
||||
return true;
|
||||
}
|
||||
fprintf(stderr, "Cannot find entry %s\n", from);
|
||||
return false;
|
||||
auto it = entries.find(from);
|
||||
if (it != entries.end()) {
|
||||
mv(it, to);
|
||||
return true;
|
||||
}
|
||||
fprintf(stderr, "Cannot find entry %s\n", from);
|
||||
return false;
|
||||
}
|
||||
|
||||
#define pos_align(p) p = do_align(p, 4)
|
||||
|
||||
void cpio_rw::load_cpio(const char *buf, size_t sz) {
|
||||
size_t pos = 0;
|
||||
const cpio_newc_header *header;
|
||||
unique_ptr<cpio_entry> entry;
|
||||
while (pos < sz) {
|
||||
header = reinterpret_cast<const cpio_newc_header *>(buf + pos);
|
||||
entry = make_unique<cpio_entry>(header);
|
||||
pos += sizeof(*header);
|
||||
string_view name_view(buf + pos);
|
||||
pos += x8u(header->namesize);
|
||||
pos_align(pos);
|
||||
if (name_view == "." || name_view == "..")
|
||||
continue;
|
||||
if (name_view == "TRAILER!!!")
|
||||
break;
|
||||
entry->filename = name_view;
|
||||
entry->data = xmalloc(entry->filesize);
|
||||
memcpy(entry->data, buf + pos, entry->filesize);
|
||||
pos += entry->filesize;
|
||||
entries[entry->filename] = std::move(entry);
|
||||
pos_align(pos);
|
||||
}
|
||||
size_t pos = 0;
|
||||
const cpio_newc_header *header;
|
||||
unique_ptr<cpio_entry> entry;
|
||||
while (pos < sz) {
|
||||
header = reinterpret_cast<const cpio_newc_header *>(buf + pos);
|
||||
entry = make_unique<cpio_entry>(header);
|
||||
pos += sizeof(*header);
|
||||
string_view name_view(buf + pos);
|
||||
pos += x8u(header->namesize);
|
||||
pos_align(pos);
|
||||
if (name_view == "." || name_view == "..")
|
||||
continue;
|
||||
if (name_view == "TRAILER!!!")
|
||||
break;
|
||||
entry->filename = name_view;
|
||||
entry->data = xmalloc(entry->filesize);
|
||||
memcpy(entry->data, buf + pos, entry->filesize);
|
||||
pos += entry->filesize;
|
||||
entries[entry->filename] = std::move(entry);
|
||||
pos_align(pos);
|
||||
}
|
||||
}
|
||||
|
||||
cpio_mmap::cpio_mmap(const char *file) {
|
||||
mmap_ro(file, buf, sz);
|
||||
fprintf(stderr, "Loading cpio: [%s]\n", file);
|
||||
size_t pos = 0;
|
||||
cpio_newc_header *header;
|
||||
unique_ptr<cpio_entry_base> entry;
|
||||
while (pos < sz) {
|
||||
header = (cpio_newc_header *)(buf + pos);
|
||||
entry = make_unique<cpio_entry_base>(header);
|
||||
pos += sizeof(*header);
|
||||
string_view name_view(buf + pos);
|
||||
pos += x8u(header->namesize);
|
||||
pos_align(pos);
|
||||
if (name_view == "." || name_view == "..")
|
||||
continue;
|
||||
if (name_view == "TRAILER!!!")
|
||||
break;
|
||||
entry->data = buf + pos;
|
||||
pos += entry->filesize;
|
||||
entries[name_view] = std::move(entry);
|
||||
pos_align(pos);
|
||||
}
|
||||
mmap_ro(file, buf, sz);
|
||||
fprintf(stderr, "Loading cpio: [%s]\n", file);
|
||||
size_t pos = 0;
|
||||
cpio_newc_header *header;
|
||||
unique_ptr<cpio_entry_base> entry;
|
||||
while (pos < sz) {
|
||||
header = (cpio_newc_header *)(buf + pos);
|
||||
entry = make_unique<cpio_entry_base>(header);
|
||||
pos += sizeof(*header);
|
||||
string_view name_view(buf + pos);
|
||||
pos += x8u(header->namesize);
|
||||
pos_align(pos);
|
||||
if (name_view == "." || name_view == "..")
|
||||
continue;
|
||||
if (name_view == "TRAILER!!!")
|
||||
break;
|
||||
entry->data = buf + pos;
|
||||
pos += entry->filesize;
|
||||
entries[name_view] = std::move(entry);
|
||||
pos_align(pos);
|
||||
}
|
||||
}
|
||||
|
||||
cpio_mmap::~cpio_mmap() {
|
||||
munmap(buf, sz);
|
||||
munmap(buf, sz);
|
||||
}
|
||||
|
@@ -13,427 +13,427 @@
|
||||
using namespace std;
|
||||
|
||||
ssize_t fd_path(int fd, char *path, size_t size) {
|
||||
snprintf(path, size, "/proc/self/fd/%d", fd);
|
||||
return xreadlink(path, path, size);
|
||||
snprintf(path, size, "/proc/self/fd/%d", fd);
|
||||
return xreadlink(path, path, size);
|
||||
}
|
||||
|
||||
int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
|
||||
if (fd_path(dirfd, path, size) < 0)
|
||||
return -1;
|
||||
auto len = strlen(path);
|
||||
path[len] = '/';
|
||||
strlcpy(path + len + 1, name, size - len - 1);
|
||||
return 0;
|
||||
if (fd_path(dirfd, path, size) < 0)
|
||||
return -1;
|
||||
auto len = strlen(path);
|
||||
path[len] = '/';
|
||||
strlcpy(path + len + 1, name, size - len - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkdirs(string path, mode_t mode) {
|
||||
errno = 0;
|
||||
for (char *p = path.data() + 1; *p; ++p) {
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (mkdir(path.data(), mode) == -1) {
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
if (mkdir(path.data(), mode) == -1) {
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
errno = 0;
|
||||
for (char *p = path.data() + 1; *p; ++p) {
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (mkdir(path.data(), mode) == -1) {
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
if (mkdir(path.data(), mode) == -1) {
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static void post_order_walk(int dirfd, const Func &fn) {
|
||||
auto dir = xopen_dir(dirfd);
|
||||
if (!dir) return;
|
||||
auto dir = xopen_dir(dirfd);
|
||||
if (!dir) return;
|
||||
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (entry->d_type == DT_DIR)
|
||||
post_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), fn);
|
||||
fn(dirfd, entry);
|
||||
}
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (entry->d_type == DT_DIR)
|
||||
post_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), fn);
|
||||
fn(dirfd, entry);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static void pre_order_walk(int dirfd, const Func &fn) {
|
||||
auto dir = xopen_dir(dirfd);
|
||||
if (!dir) return;
|
||||
auto dir = xopen_dir(dirfd);
|
||||
if (!dir) return;
|
||||
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (!fn(dirfd, entry))
|
||||
continue;
|
||||
if (entry->d_type == DT_DIR)
|
||||
pre_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), fn);
|
||||
}
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (!fn(dirfd, entry))
|
||||
continue;
|
||||
if (entry->d_type == DT_DIR)
|
||||
pre_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), fn);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_at(int dirfd, struct dirent *entry) {
|
||||
unlinkat(dirfd, entry->d_name, entry->d_type == DT_DIR ? AT_REMOVEDIR : 0);
|
||||
unlinkat(dirfd, entry->d_name, entry->d_type == DT_DIR ? AT_REMOVEDIR : 0);
|
||||
}
|
||||
|
||||
void rm_rf(const char *path) {
|
||||
struct stat st;
|
||||
if (lstat(path, &st) < 0)
|
||||
return;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
frm_rf(xopen(path, O_RDONLY | O_CLOEXEC));
|
||||
remove(path);
|
||||
struct stat st;
|
||||
if (lstat(path, &st) < 0)
|
||||
return;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
frm_rf(xopen(path, O_RDONLY | O_CLOEXEC));
|
||||
remove(path);
|
||||
}
|
||||
|
||||
void frm_rf(int dirfd) {
|
||||
post_order_walk(dirfd, remove_at);
|
||||
post_order_walk(dirfd, remove_at);
|
||||
}
|
||||
|
||||
void mv_path(const char *src, const char *dest) {
|
||||
file_attr attr;
|
||||
getattr(src, &attr);
|
||||
if (S_ISDIR(attr.st.st_mode)) {
|
||||
if (access(dest, F_OK) != 0) {
|
||||
xmkdirs(dest, 0);
|
||||
setattr(dest, &attr);
|
||||
}
|
||||
mv_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
} else{
|
||||
xrename(src, dest);
|
||||
}
|
||||
rmdir(src);
|
||||
file_attr attr;
|
||||
getattr(src, &attr);
|
||||
if (S_ISDIR(attr.st.st_mode)) {
|
||||
if (access(dest, F_OK) != 0) {
|
||||
xmkdirs(dest, 0);
|
||||
setattr(dest, &attr);
|
||||
}
|
||||
mv_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
} else{
|
||||
xrename(src, dest);
|
||||
}
|
||||
rmdir(src);
|
||||
}
|
||||
|
||||
void mv_dir(int src, int dest) {
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([=]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
if (faccessat(dest, entry->d_name, F_OK, 0) == 0) {
|
||||
// Destination folder exists, needs recursive move
|
||||
int newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
mv_dir(newsrc, newdest);
|
||||
unlinkat(src, entry->d_name, AT_REMOVEDIR);
|
||||
break;
|
||||
}
|
||||
// Else fall through
|
||||
case DT_LNK:
|
||||
case DT_REG:
|
||||
renameat(src, entry->d_name, dest, entry->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([=]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
if (faccessat(dest, entry->d_name, F_OK, 0) == 0) {
|
||||
// Destination folder exists, needs recursive move
|
||||
int newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
mv_dir(newsrc, newdest);
|
||||
unlinkat(src, entry->d_name, AT_REMOVEDIR);
|
||||
break;
|
||||
}
|
||||
// Else fall through
|
||||
case DT_LNK:
|
||||
case DT_REG:
|
||||
renameat(src, entry->d_name, dest, entry->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cp_afc(const char *src, const char *dest) {
|
||||
file_attr a;
|
||||
getattr(src, &a);
|
||||
file_attr a;
|
||||
getattr(src, &a);
|
||||
|
||||
if (S_ISDIR(a.st.st_mode)) {
|
||||
xmkdirs(dest, 0);
|
||||
clone_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
} else{
|
||||
unlink(dest);
|
||||
if (S_ISREG(a.st.st_mode)) {
|
||||
int sfd = xopen(src, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopen(dest, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
|
||||
xsendfile(dfd, sfd, nullptr, a.st.st_size);
|
||||
close(sfd);
|
||||
close(dfd);
|
||||
} else if (S_ISLNK(a.st.st_mode)) {
|
||||
char buf[4096];
|
||||
xreadlink(src, buf, sizeof(buf));
|
||||
xsymlink(buf, dest);
|
||||
}
|
||||
}
|
||||
setattr(dest, &a);
|
||||
if (S_ISDIR(a.st.st_mode)) {
|
||||
xmkdirs(dest, 0);
|
||||
clone_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
} else{
|
||||
unlink(dest);
|
||||
if (S_ISREG(a.st.st_mode)) {
|
||||
int sfd = xopen(src, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopen(dest, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
|
||||
xsendfile(dfd, sfd, nullptr, a.st.st_size);
|
||||
close(sfd);
|
||||
close(dfd);
|
||||
} else if (S_ISLNK(a.st.st_mode)) {
|
||||
char buf[4096];
|
||||
xreadlink(src, buf, sizeof(buf));
|
||||
xsymlink(buf, dest);
|
||||
}
|
||||
}
|
||||
setattr(dest, &a);
|
||||
}
|
||||
|
||||
void clone_dir(int src, int dest) {
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([&]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
file_attr a;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR: {
|
||||
xmkdirat(dest, entry->d_name, 0);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dst = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
clone_dir(sfd, dst);
|
||||
break;
|
||||
}
|
||||
case DT_REG: {
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
|
||||
xsendfile(dfd, sfd, nullptr, a.st.st_size);
|
||||
fsetattr(dfd, &a);
|
||||
close(dfd);
|
||||
close(sfd);
|
||||
break;
|
||||
}
|
||||
case DT_LNK: {
|
||||
char buf[4096];
|
||||
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
||||
xsymlinkat(buf, dest, entry->d_name);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([&]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
file_attr a;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR: {
|
||||
xmkdirat(dest, entry->d_name, 0);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dst = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
clone_dir(sfd, dst);
|
||||
break;
|
||||
}
|
||||
case DT_REG: {
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
|
||||
xsendfile(dfd, sfd, nullptr, a.st.st_size);
|
||||
fsetattr(dfd, &a);
|
||||
close(dfd);
|
||||
close(sfd);
|
||||
break;
|
||||
}
|
||||
case DT_LNK: {
|
||||
char buf[4096];
|
||||
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
||||
xsymlinkat(buf, dest, entry->d_name);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void link_path(const char *src, const char *dest) {
|
||||
link_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
link_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
}
|
||||
|
||||
void link_dir(int src, int dest) {
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([&]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
file_attr a;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
xmkdirat(dest, entry->d_name, 0);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
link_dir(sfd, dfd);
|
||||
} else {
|
||||
xlinkat(src, entry->d_name, dest, entry->d_name, 0);
|
||||
}
|
||||
}
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([&]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
file_attr a;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
xmkdirat(dest, entry->d_name, 0);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
link_dir(sfd, dfd);
|
||||
} else {
|
||||
xlinkat(src, entry->d_name, dest, entry->d_name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getattr(const char *path, file_attr *a) {
|
||||
if (xlstat(path, &a->st) == -1)
|
||||
return -1;
|
||||
char *con;
|
||||
if (lgetfilecon(path, &con) == -1)
|
||||
return -1;
|
||||
strcpy(a->con, con);
|
||||
freecon(con);
|
||||
return 0;
|
||||
if (xlstat(path, &a->st) == -1)
|
||||
return -1;
|
||||
char *con;
|
||||
if (lgetfilecon(path, &con) == -1)
|
||||
return -1;
|
||||
strcpy(a->con, con);
|
||||
freecon(con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getattrat(int dirfd, const char *name, file_attr *a) {
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
return getattr(path, a);
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
return getattr(path, a);
|
||||
}
|
||||
|
||||
int fgetattr(int fd, file_attr *a) {
|
||||
if (xfstat(fd, &a->st) < 0)
|
||||
return -1;
|
||||
char *con;
|
||||
if (fgetfilecon(fd, &con) < 0)
|
||||
return -1;
|
||||
strcpy(a->con, con);
|
||||
freecon(con);
|
||||
return 0;
|
||||
if (xfstat(fd, &a->st) < 0)
|
||||
return -1;
|
||||
char *con;
|
||||
if (fgetfilecon(fd, &con) < 0)
|
||||
return -1;
|
||||
strcpy(a->con, con);
|
||||
freecon(con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setattr(const char *path, file_attr *a) {
|
||||
if (chmod(path, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (chown(path, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
if (a->con[0] && lsetfilecon(path, a->con) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
if (chmod(path, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (chown(path, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
if (a->con[0] && lsetfilecon(path, a->con) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setattrat(int dirfd, const char *name, file_attr *a) {
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
return setattr(path, a);
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
return setattr(path, a);
|
||||
}
|
||||
|
||||
int fsetattr(int fd, file_attr *a) {
|
||||
if (fchmod(fd, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
if (a->con[0] && fsetfilecon(fd, a->con) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
if (fchmod(fd, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
if (a->con[0] && fsetfilecon(fd, a->con) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clone_attr(const char *src, const char *dest) {
|
||||
file_attr a;
|
||||
getattr(src, &a);
|
||||
setattr(dest, &a);
|
||||
file_attr a;
|
||||
getattr(src, &a);
|
||||
setattr(dest, &a);
|
||||
}
|
||||
|
||||
void fclone_attr(int src, int dest) {
|
||||
file_attr a;
|
||||
fgetattr(src, &a);
|
||||
fsetattr(dest, &a);
|
||||
file_attr a;
|
||||
fgetattr(src, &a);
|
||||
fsetattr(dest, &a);
|
||||
}
|
||||
|
||||
void *__mmap(const char *filename, size_t *size, bool rw) {
|
||||
int fd = xopen(filename, (rw ? O_RDWR : O_RDONLY) | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
*size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
struct stat st;
|
||||
void *buf;
|
||||
if (fstat(fd, &st)) {
|
||||
*size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
if (S_ISBLK(st.st_mode))
|
||||
ioctl(fd, BLKGETSIZE64, size);
|
||||
else
|
||||
*size = st.st_size;
|
||||
buf = *size > 0 ? xmmap(nullptr, *size, PROT_READ | (rw ? PROT_WRITE : 0), MAP_SHARED, fd, 0) : nullptr;
|
||||
close(fd);
|
||||
return buf;
|
||||
int fd = xopen(filename, (rw ? O_RDWR : O_RDONLY) | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
*size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
struct stat st;
|
||||
void *buf;
|
||||
if (fstat(fd, &st)) {
|
||||
*size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
if (S_ISBLK(st.st_mode))
|
||||
ioctl(fd, BLKGETSIZE64, size);
|
||||
else
|
||||
*size = st.st_size;
|
||||
buf = *size > 0 ? xmmap(nullptr, *size, PROT_READ | (rw ? PROT_WRITE : 0), MAP_SHARED, fd, 0) : nullptr;
|
||||
close(fd);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void fd_full_read(int fd, void **buf, size_t *size) {
|
||||
*size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
*buf = xmalloc(*size + 1);
|
||||
xxread(fd, *buf, *size);
|
||||
((char *) *buf)[*size] = '\0';
|
||||
*size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
*buf = xmalloc(*size + 1);
|
||||
xxread(fd, *buf, *size);
|
||||
((char *) *buf)[*size] = '\0';
|
||||
}
|
||||
|
||||
void full_read(const char *filename, void **buf, size_t *size) {
|
||||
int fd = xopen(filename, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
*buf = nullptr;
|
||||
*size = 0;
|
||||
return;
|
||||
}
|
||||
fd_full_read(fd, buf, size);
|
||||
close(fd);
|
||||
int fd = xopen(filename, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
*buf = nullptr;
|
||||
*size = 0;
|
||||
return;
|
||||
}
|
||||
fd_full_read(fd, buf, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
string fd_full_read(int fd) {
|
||||
char buf[4096];
|
||||
string str;
|
||||
for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;)
|
||||
str.insert(str.end(), buf, buf + len);
|
||||
return str;
|
||||
char buf[4096];
|
||||
string str;
|
||||
for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;)
|
||||
str.insert(str.end(), buf, buf + len);
|
||||
return str;
|
||||
}
|
||||
|
||||
string full_read(const char *filename) {
|
||||
int fd = xopen(filename, O_RDONLY | O_CLOEXEC);
|
||||
run_finally f([=]{ close(fd); });
|
||||
return fd < 0 ? "" : fd_full_read(fd);
|
||||
int fd = xopen(filename, O_RDONLY | O_CLOEXEC);
|
||||
run_finally f([=]{ close(fd); });
|
||||
return fd < 0 ? "" : fd_full_read(fd);
|
||||
}
|
||||
|
||||
void write_zero(int fd, size_t size) {
|
||||
char buf[4096] = {0};
|
||||
size_t len;
|
||||
while (size > 0) {
|
||||
len = sizeof(buf) > size ? size : sizeof(buf);
|
||||
write(fd, buf, len);
|
||||
size -= len;
|
||||
}
|
||||
char buf[4096] = {0};
|
||||
size_t len;
|
||||
while (size > 0) {
|
||||
len = sizeof(buf) > size ? size : sizeof(buf);
|
||||
write(fd, buf, len);
|
||||
size -= len;
|
||||
}
|
||||
}
|
||||
|
||||
void file_readline(bool trim, const char *file, const function<bool(string_view)> &fn) {
|
||||
FILE *fp = xfopen(file, "re");
|
||||
if (fp == nullptr)
|
||||
return;
|
||||
size_t len = 1024;
|
||||
char *buf = (char *) malloc(len);
|
||||
char *start;
|
||||
ssize_t read;
|
||||
while ((read = getline(&buf, &len, fp)) >= 0) {
|
||||
start = buf;
|
||||
if (trim) {
|
||||
while (read && "\n\r "sv.find(buf[read - 1]) != string::npos)
|
||||
--read;
|
||||
buf[read] = '\0';
|
||||
while (*start == ' ')
|
||||
++start;
|
||||
}
|
||||
if (!fn(start))
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
FILE *fp = xfopen(file, "re");
|
||||
if (fp == nullptr)
|
||||
return;
|
||||
size_t len = 1024;
|
||||
char *buf = (char *) malloc(len);
|
||||
char *start;
|
||||
ssize_t read;
|
||||
while ((read = getline(&buf, &len, fp)) >= 0) {
|
||||
start = buf;
|
||||
if (trim) {
|
||||
while (read && "\n\r "sv.find(buf[read - 1]) != string::npos)
|
||||
--read;
|
||||
buf[read] = '\0';
|
||||
while (*start == ' ')
|
||||
++start;
|
||||
}
|
||||
if (!fn(start))
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void parse_prop_file(const char *file, const function<bool(string_view, string_view)> &fn) {
|
||||
file_readline(true, file, [&](string_view line_view) -> bool {
|
||||
char *line = (char *) line_view.data();
|
||||
if (line[0] == '#')
|
||||
return true;
|
||||
char *eql = strchr(line, '=');
|
||||
if (eql == nullptr || eql == line)
|
||||
return true;
|
||||
*eql = '\0';
|
||||
return fn(line, eql + 1);
|
||||
});
|
||||
file_readline(true, file, [&](string_view line_view) -> bool {
|
||||
char *line = (char *) line_view.data();
|
||||
if (line[0] == '#')
|
||||
return true;
|
||||
char *eql = strchr(line, '=');
|
||||
if (eql == nullptr || eql == line)
|
||||
return true;
|
||||
*eql = '\0';
|
||||
return fn(line, eql + 1);
|
||||
});
|
||||
}
|
||||
|
||||
void parse_mnt(const char *file, const function<bool(mntent*)> &fn) {
|
||||
auto fp = sFILE(setmntent(file, "re"), endmntent);
|
||||
if (fp) {
|
||||
mntent mentry{};
|
||||
char buf[4096];
|
||||
while (getmntent_r(fp.get(), &mentry, buf, sizeof(buf))) {
|
||||
if (!fn(&mentry))
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto fp = sFILE(setmntent(file, "re"), endmntent);
|
||||
if (fp) {
|
||||
mntent mentry{};
|
||||
char buf[4096];
|
||||
while (getmntent_r(fp.get(), &mentry, buf, sizeof(buf))) {
|
||||
if (!fn(&mentry))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void backup_folder(const char *dir, vector<raw_file> &files) {
|
||||
char path[4096];
|
||||
xrealpath(dir, path);
|
||||
int len = strlen(path);
|
||||
pre_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> bool {
|
||||
int fd = xopenat(dfd, entry->d_name, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
run_finally f([&]{ close(fd); });
|
||||
if (fd_path(fd, path, sizeof(path)) < 0)
|
||||
return false;
|
||||
raw_file file;
|
||||
file.path = path + len + 1;
|
||||
if (fgetattr(fd, &file.attr) < 0)
|
||||
return false;
|
||||
if (entry->d_type == DT_REG) {
|
||||
fd_full_read(fd, file.buf, file.sz);
|
||||
} else if (entry->d_type == DT_LNK) {
|
||||
xreadlinkat(dfd, entry->d_name, path, sizeof(path));
|
||||
file.sz = strlen(path) + 1;
|
||||
file.buf = (uint8_t *) xmalloc(file.sz);
|
||||
memcpy(file.buf, path, file.sz);
|
||||
}
|
||||
files.emplace_back(std::move(file));
|
||||
return true;
|
||||
});
|
||||
char path[4096];
|
||||
xrealpath(dir, path);
|
||||
int len = strlen(path);
|
||||
pre_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> bool {
|
||||
int fd = xopenat(dfd, entry->d_name, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
run_finally f([&]{ close(fd); });
|
||||
if (fd_path(fd, path, sizeof(path)) < 0)
|
||||
return false;
|
||||
raw_file file;
|
||||
file.path = path + len + 1;
|
||||
if (fgetattr(fd, &file.attr) < 0)
|
||||
return false;
|
||||
if (entry->d_type == DT_REG) {
|
||||
fd_full_read(fd, file.buf, file.sz);
|
||||
} else if (entry->d_type == DT_LNK) {
|
||||
xreadlinkat(dfd, entry->d_name, path, sizeof(path));
|
||||
file.sz = strlen(path) + 1;
|
||||
file.buf = (uint8_t *) xmalloc(file.sz);
|
||||
memcpy(file.buf, path, file.sz);
|
||||
}
|
||||
files.emplace_back(std::move(file));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void restore_folder(const char *dir, vector<raw_file> &files) {
|
||||
string base(dir);
|
||||
// Pre-order means folders will always be first
|
||||
for (raw_file &file : files) {
|
||||
string path = base + "/" + file.path;
|
||||
if (S_ISDIR(file.attr.st.st_mode)) {
|
||||
mkdirs(path.data(), 0);
|
||||
} else if (S_ISREG(file.attr.st.st_mode)) {
|
||||
auto fp = xopen_file(path.data(), "we");
|
||||
fwrite(file.buf, 1, file.sz, fp.get());
|
||||
} else if (S_ISLNK(file.attr.st.st_mode)) {
|
||||
symlink((char *)file.buf, path.data());
|
||||
}
|
||||
setattr(path.data(), &file.attr);
|
||||
}
|
||||
string base(dir);
|
||||
// Pre-order means folders will always be first
|
||||
for (raw_file &file : files) {
|
||||
string path = base + "/" + file.path;
|
||||
if (S_ISDIR(file.attr.st.st_mode)) {
|
||||
mkdirs(path.data(), 0);
|
||||
} else if (S_ISREG(file.attr.st.st_mode)) {
|
||||
auto fp = xopen_file(path.data(), "we");
|
||||
fwrite(file.buf, 1, file.sz, fp.get());
|
||||
} else if (S_ISLNK(file.attr.st.st_mode)) {
|
||||
symlink((char *)file.buf, path.data());
|
||||
}
|
||||
setattr(path.data(), &file.attr);
|
||||
}
|
||||
}
|
||||
|
||||
sDIR make_dir(DIR *dp) {
|
||||
return sDIR(dp, [](DIR *dp){ return dp ? closedir(dp) : 1; });
|
||||
return sDIR(dp, [](DIR *dp){ return dp ? closedir(dp) : 1; });
|
||||
}
|
||||
|
||||
sFILE make_file(FILE *fp) {
|
||||
return sFILE(fp, [](FILE *fp){ return fp ? fclose(fp) : 1; });
|
||||
return sFILE(fp, [](FILE *fp){ return fp ? fclose(fp) : 1; });
|
||||
}
|
||||
|
@@ -14,29 +14,29 @@
|
||||
#define align_off(p, a) (do_align(p, a) - (p))
|
||||
|
||||
struct file_attr {
|
||||
struct stat st;
|
||||
char con[128];
|
||||
struct stat st;
|
||||
char con[128];
|
||||
};
|
||||
|
||||
struct raw_file {
|
||||
std::string path;
|
||||
file_attr attr;
|
||||
uint8_t *buf = nullptr;
|
||||
size_t sz = 0;
|
||||
std::string path;
|
||||
file_attr attr;
|
||||
uint8_t *buf = nullptr;
|
||||
size_t sz = 0;
|
||||
|
||||
raw_file() = default;
|
||||
raw_file(const raw_file&) = delete;
|
||||
raw_file(raw_file &&d) {
|
||||
path = std::move(d.path);
|
||||
attr = d.attr;
|
||||
buf = d.buf;
|
||||
sz = d.sz;
|
||||
d.buf = nullptr;
|
||||
d.sz = 0;
|
||||
}
|
||||
~raw_file() {
|
||||
free(buf);
|
||||
}
|
||||
raw_file() = default;
|
||||
raw_file(const raw_file&) = delete;
|
||||
raw_file(raw_file &&d) {
|
||||
path = std::move(d.path);
|
||||
attr = d.attr;
|
||||
buf = d.buf;
|
||||
sz = d.sz;
|
||||
d.buf = nullptr;
|
||||
d.sz = 0;
|
||||
}
|
||||
~raw_file() {
|
||||
free(buf);
|
||||
}
|
||||
};
|
||||
|
||||
ssize_t fd_path(int fd, char *path, size_t size);
|
||||
@@ -63,11 +63,11 @@ std::string full_read(const char *filename);
|
||||
void write_zero(int fd, size_t size);
|
||||
void file_readline(bool trim, const char *file, const std::function<bool(std::string_view)> &fn);
|
||||
static inline void file_readline(const char *file,
|
||||
const std::function<bool(std::string_view)> &fn) {
|
||||
file_readline(false, file, fn);
|
||||
const std::function<bool(std::string_view)> &fn) {
|
||||
file_readline(false, file, fn);
|
||||
}
|
||||
void parse_prop_file(const char *file,
|
||||
const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
void *__mmap(const char *filename, size_t *size, bool rw);
|
||||
void frm_rf(int dirfd);
|
||||
void clone_dir(int src, int dest);
|
||||
@@ -77,38 +77,38 @@ void restore_folder(const char *dir, std::vector<raw_file> &files);
|
||||
|
||||
template <typename T>
|
||||
void full_read(const char *filename, T &buf, size_t &size) {
|
||||
static_assert(std::is_pointer<T>::value);
|
||||
full_read(filename, reinterpret_cast<void**>(&buf), &size);
|
||||
static_assert(std::is_pointer<T>::value);
|
||||
full_read(filename, reinterpret_cast<void**>(&buf), &size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fd_full_read(int fd, T &buf, size_t &size) {
|
||||
static_assert(std::is_pointer<T>::value);
|
||||
fd_full_read(fd, reinterpret_cast<void**>(&buf), &size);
|
||||
static_assert(std::is_pointer<T>::value);
|
||||
fd_full_read(fd, reinterpret_cast<void**>(&buf), &size);
|
||||
}
|
||||
|
||||
template <typename B>
|
||||
void mmap_ro(const char *filename, B &buf, size_t &sz) {
|
||||
buf = (B) __mmap(filename, &sz, false);
|
||||
buf = (B) __mmap(filename, &sz, false);
|
||||
}
|
||||
|
||||
template <typename B, typename L>
|
||||
void mmap_ro(const char *filename, B &buf, L &sz) {
|
||||
size_t __sz;
|
||||
buf = (B) __mmap(filename, &__sz, false);
|
||||
sz = __sz;
|
||||
size_t __sz;
|
||||
buf = (B) __mmap(filename, &__sz, false);
|
||||
sz = __sz;
|
||||
}
|
||||
|
||||
template <typename B>
|
||||
void mmap_rw(const char *filename, B &buf, size_t &sz) {
|
||||
buf = (B) __mmap(filename, &sz, true);
|
||||
buf = (B) __mmap(filename, &sz, true);
|
||||
}
|
||||
|
||||
template <typename B, typename L>
|
||||
void mmap_rw(const char *filename, B &buf, L &sz) {
|
||||
size_t __sz;
|
||||
buf = (B) __mmap(filename, &__sz, true);
|
||||
sz = __sz;
|
||||
size_t __sz;
|
||||
buf = (B) __mmap(filename, &__sz, true);
|
||||
sz = __sz;
|
||||
}
|
||||
|
||||
using sFILE = std::unique_ptr<FILE, decltype(&fclose)>;
|
||||
@@ -117,25 +117,25 @@ sDIR make_dir(DIR *dp);
|
||||
sFILE make_file(FILE *fp);
|
||||
|
||||
static inline sDIR open_dir(const char *path) {
|
||||
return make_dir(opendir(path));
|
||||
return make_dir(opendir(path));
|
||||
}
|
||||
|
||||
static inline sDIR xopen_dir(const char *path) {
|
||||
return make_dir(xopendir(path));
|
||||
return make_dir(xopendir(path));
|
||||
}
|
||||
|
||||
static inline sDIR xopen_dir(int dirfd) {
|
||||
return make_dir(xfdopendir(dirfd));
|
||||
return make_dir(xfdopendir(dirfd));
|
||||
}
|
||||
|
||||
static inline sFILE open_file(const char *path, const char *mode) {
|
||||
return make_file(fopen(path, mode));
|
||||
return make_file(fopen(path, mode));
|
||||
}
|
||||
|
||||
static inline sFILE xopen_file(const char *path, const char *mode) {
|
||||
return make_file(xfopen(path, mode));
|
||||
return make_file(xfopen(path, mode));
|
||||
}
|
||||
|
||||
static inline sFILE xopen_file(int fd, const char *mode) {
|
||||
return make_file(xfdopen(fd, mode));
|
||||
return make_file(xfdopen(fd, mode));
|
||||
}
|
||||
|
@@ -11,67 +11,67 @@
|
||||
struct cpio_newc_header;
|
||||
|
||||
struct cpio_entry_base {
|
||||
uint32_t mode = 0;
|
||||
uint32_t uid = 0;
|
||||
uint32_t gid = 0;
|
||||
uint32_t filesize = 0;
|
||||
uint32_t mode = 0;
|
||||
uint32_t uid = 0;
|
||||
uint32_t gid = 0;
|
||||
uint32_t filesize = 0;
|
||||
|
||||
void *data = nullptr;
|
||||
void *data = nullptr;
|
||||
|
||||
cpio_entry_base() : mode(0), uid(0), gid(0), filesize(0) {};
|
||||
explicit cpio_entry_base(const cpio_newc_header *h);
|
||||
virtual ~cpio_entry_base() = default;
|
||||
cpio_entry_base() : mode(0), uid(0), gid(0), filesize(0) {};
|
||||
explicit cpio_entry_base(const cpio_newc_header *h);
|
||||
virtual ~cpio_entry_base() = default;
|
||||
};
|
||||
|
||||
struct cpio_entry : public cpio_entry_base {
|
||||
std::string filename;
|
||||
std::string filename;
|
||||
|
||||
cpio_entry() = default;
|
||||
explicit cpio_entry(const char *name, uint32_t mode) : filename(name) {
|
||||
this->mode = mode;
|
||||
}
|
||||
explicit cpio_entry(const cpio_newc_header *h) : cpio_entry_base(h) {}
|
||||
cpio_entry() = default;
|
||||
explicit cpio_entry(const char *name, uint32_t mode) : filename(name) {
|
||||
this->mode = mode;
|
||||
}
|
||||
explicit cpio_entry(const cpio_newc_header *h) : cpio_entry_base(h) {}
|
||||
|
||||
~cpio_entry() override { free(data); };
|
||||
~cpio_entry() override { free(data); };
|
||||
};
|
||||
|
||||
typedef std::map<std::string_view, std::unique_ptr<cpio_entry_base>> entry_map;
|
||||
|
||||
class cpio {
|
||||
public:
|
||||
void dump(const char *file);
|
||||
void rm(const char *name, bool r = false);
|
||||
void extract();
|
||||
bool extract(const char *name, const char *file);
|
||||
bool exists(const char *name);
|
||||
void dump(const char *file);
|
||||
void rm(const char *name, bool r = false);
|
||||
void extract();
|
||||
bool extract(const char *name, const char *file);
|
||||
bool exists(const char *name);
|
||||
|
||||
protected:
|
||||
entry_map entries;
|
||||
void rm(entry_map::iterator &it);
|
||||
void dump(FILE *out);
|
||||
entry_map entries;
|
||||
void rm(entry_map::iterator &it);
|
||||
void dump(FILE *out);
|
||||
};
|
||||
|
||||
class cpio_rw : public cpio {
|
||||
public:
|
||||
cpio_rw() = default;
|
||||
explicit cpio_rw(const char *file);
|
||||
void load_cpio(const char *file);
|
||||
void add(mode_t mode, const char *name, const char *file);
|
||||
void mkdir(mode_t mode, const char *name);
|
||||
void ln(const char *target, const char *name);
|
||||
bool mv(const char *from, const char *to);
|
||||
cpio_rw() = default;
|
||||
explicit cpio_rw(const char *file);
|
||||
void load_cpio(const char *file);
|
||||
void add(mode_t mode, const char *name, const char *file);
|
||||
void mkdir(mode_t mode, const char *name);
|
||||
void ln(const char *target, const char *name);
|
||||
bool mv(const char *from, const char *to);
|
||||
|
||||
protected:
|
||||
void insert(cpio_entry *e);
|
||||
void mv(entry_map::iterator &it, const char *to);
|
||||
void load_cpio(const char *buf, size_t sz);
|
||||
void insert(cpio_entry *e);
|
||||
void mv(entry_map::iterator &it, const char *to);
|
||||
void load_cpio(const char *buf, size_t sz);
|
||||
};
|
||||
|
||||
class cpio_mmap : public cpio {
|
||||
public:
|
||||
explicit cpio_mmap(const char *file);
|
||||
~cpio_mmap();
|
||||
explicit cpio_mmap(const char *file);
|
||||
~cpio_mmap();
|
||||
private:
|
||||
char *buf;
|
||||
size_t sz;
|
||||
char *buf;
|
||||
size_t sz;
|
||||
};
|
||||
|
@@ -7,10 +7,10 @@
|
||||
|
||||
class stream {
|
||||
public:
|
||||
virtual int read(void *buf, size_t len);
|
||||
virtual int write(const void *buf, size_t len);
|
||||
virtual off_t seek(off_t off, int whence);
|
||||
virtual ~stream() = default;
|
||||
virtual int read(void *buf, size_t len);
|
||||
virtual int write(const void *buf, size_t len);
|
||||
virtual off_t seek(off_t off, int whence);
|
||||
virtual ~stream() = default;
|
||||
};
|
||||
|
||||
using stream_ptr = std::unique_ptr<stream>;
|
||||
@@ -18,44 +18,44 @@ using stream_ptr = std::unique_ptr<stream>;
|
||||
// Delegates all operations to base stream
|
||||
class filter_stream : public stream {
|
||||
public:
|
||||
filter_stream(stream_ptr &&base) : base(std::move(base)) {}
|
||||
filter_stream(stream_ptr &&base) : base(std::move(base)) {}
|
||||
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
|
||||
protected:
|
||||
stream_ptr base;
|
||||
stream_ptr base;
|
||||
};
|
||||
|
||||
// Byte stream that dynamically allocates memory
|
||||
class byte_stream : public stream {
|
||||
public:
|
||||
byte_stream(uint8_t *&buf, size_t &len);
|
||||
template <class byte>
|
||||
byte_stream(byte *&buf, size_t &len) : byte_stream(reinterpret_cast<uint8_t *&>(buf), len) {}
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
byte_stream(uint8_t *&buf, size_t &len);
|
||||
template <class byte>
|
||||
byte_stream(byte *&buf, size_t &len) : byte_stream(reinterpret_cast<uint8_t *&>(buf), len) {}
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
|
||||
private:
|
||||
uint8_t *&_buf;
|
||||
size_t &_len;
|
||||
size_t _pos = 0;
|
||||
size_t _cap = 0;
|
||||
uint8_t *&_buf;
|
||||
size_t &_len;
|
||||
size_t _pos = 0;
|
||||
size_t _cap = 0;
|
||||
|
||||
void resize(size_t new_pos, bool zero = false);
|
||||
void resize(size_t new_pos, bool zero = false);
|
||||
};
|
||||
|
||||
// File stream but does not close the file descriptor at any time
|
||||
class fd_stream : public stream {
|
||||
public:
|
||||
fd_stream(int fd) : fd(fd) {}
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
fd_stream(int fd) : fd(fd) {}
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
|
||||
private:
|
||||
int fd;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* ****************************************
|
||||
@@ -65,14 +65,14 @@ private:
|
||||
// sFILE -> stream_ptr
|
||||
class fp_stream final : public stream {
|
||||
public:
|
||||
fp_stream(FILE *fp = nullptr) : fp(fp, fclose) {}
|
||||
fp_stream(sFILE &&fp) : fp(std::move(fp)) {}
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
fp_stream(FILE *fp = nullptr) : fp(fp, fclose) {}
|
||||
fp_stream(sFILE &&fp) : fp(std::move(fp)) {}
|
||||
int read(void *buf, size_t len) override;
|
||||
int write(const void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
|
||||
private:
|
||||
sFILE fp;
|
||||
sFILE fp;
|
||||
};
|
||||
|
||||
// stream_ptr -> sFILE
|
||||
@@ -80,5 +80,5 @@ sFILE make_stream_fp(stream_ptr &&strm);
|
||||
|
||||
template <class T, class... Args>
|
||||
sFILE make_stream_fp(Args &&... args) {
|
||||
return make_stream_fp(stream_ptr(new T(std::forward<Args>(args)...)));
|
||||
return make_stream_fp(stream_ptr(new T(std::forward<Args>(args)...)));
|
||||
}
|
||||
|
@@ -11,48 +11,48 @@ int nop_log(const char *, va_list) { return 0; }
|
||||
void nop_ex(int) {}
|
||||
|
||||
log_callback log_cb = {
|
||||
.d = nop_log,
|
||||
.i = nop_log,
|
||||
.w = nop_log,
|
||||
.e = nop_log,
|
||||
.ex = nop_ex
|
||||
.d = nop_log,
|
||||
.i = nop_log,
|
||||
.w = nop_log,
|
||||
.e = nop_log,
|
||||
.ex = nop_ex
|
||||
};
|
||||
|
||||
void no_logging() {
|
||||
log_cb.d = nop_log;
|
||||
log_cb.i = nop_log;
|
||||
log_cb.w = nop_log;
|
||||
log_cb.e = nop_log;
|
||||
log_cb.ex = nop_ex;
|
||||
log_cb.d = nop_log;
|
||||
log_cb.i = nop_log;
|
||||
log_cb.w = nop_log;
|
||||
log_cb.e = nop_log;
|
||||
log_cb.ex = nop_ex;
|
||||
}
|
||||
|
||||
static int vprintfe(const char *fmt, va_list ap) {
|
||||
return vfprintf(stderr, fmt, ap);
|
||||
return vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
|
||||
void cmdline_logging() {
|
||||
log_cb.d = vprintfe;
|
||||
log_cb.i = vprintf;
|
||||
log_cb.w = vprintfe;
|
||||
log_cb.e = vprintfe;
|
||||
log_cb.ex = exit;
|
||||
log_cb.d = vprintfe;
|
||||
log_cb.i = vprintf;
|
||||
log_cb.w = vprintfe;
|
||||
log_cb.e = vprintfe;
|
||||
log_cb.ex = exit;
|
||||
}
|
||||
|
||||
template <int type>
|
||||
void log_handler(const char *fmt, ...) {
|
||||
va_list argv;
|
||||
va_start(argv, fmt);
|
||||
if constexpr (type == L_DEBUG) {
|
||||
log_cb.d(fmt, argv);
|
||||
} else if constexpr (type == L_INFO) {
|
||||
log_cb.i(fmt, argv);
|
||||
} else if constexpr (type == L_WARN) {
|
||||
log_cb.w(fmt, argv);
|
||||
} else if constexpr (type == L_ERR) {
|
||||
log_cb.e(fmt, argv);
|
||||
log_cb.ex(1);
|
||||
}
|
||||
va_end(argv);
|
||||
va_list argv;
|
||||
va_start(argv, fmt);
|
||||
if constexpr (type == L_DEBUG) {
|
||||
log_cb.d(fmt, argv);
|
||||
} else if constexpr (type == L_INFO) {
|
||||
log_cb.i(fmt, argv);
|
||||
} else if constexpr (type == L_WARN) {
|
||||
log_cb.w(fmt, argv);
|
||||
} else if constexpr (type == L_ERR) {
|
||||
log_cb.e(fmt, argv);
|
||||
log_cb.ex(1);
|
||||
}
|
||||
va_end(argv);
|
||||
}
|
||||
|
||||
template void log_handler<L_INFO>(const char *fmt, ...);
|
||||
|
@@ -5,18 +5,18 @@
|
||||
#include <cstring>
|
||||
|
||||
enum {
|
||||
L_DEBUG,
|
||||
L_INFO,
|
||||
L_WARN,
|
||||
L_ERR
|
||||
L_DEBUG,
|
||||
L_INFO,
|
||||
L_WARN,
|
||||
L_ERR
|
||||
};
|
||||
|
||||
struct log_callback {
|
||||
int (*d)(const char* fmt, va_list ap);
|
||||
int (*i)(const char* fmt, va_list ap);
|
||||
int (*w)(const char* fmt, va_list ap);
|
||||
int (*e)(const char* fmt, va_list ap);
|
||||
void (*ex)(int code);
|
||||
int (*d)(const char* fmt, va_list ap);
|
||||
int (*i)(const char* fmt, va_list ap);
|
||||
int (*w)(const char* fmt, va_list ap);
|
||||
int (*e)(const char* fmt, va_list ap);
|
||||
void (*ex)(int code);
|
||||
};
|
||||
|
||||
extern log_callback log_cb;
|
||||
|
@@ -14,23 +14,23 @@
|
||||
using namespace std;
|
||||
|
||||
int fork_dont_care() {
|
||||
if (int pid = xfork()) {
|
||||
waitpid(pid, nullptr, 0);
|
||||
return pid;
|
||||
} else if (xfork()) {
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
if (int pid = xfork()) {
|
||||
waitpid(pid, nullptr, 0);
|
||||
return pid;
|
||||
} else if (xfork()) {
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fork_no_orphan() {
|
||||
int pid = xfork();
|
||||
if (pid)
|
||||
return pid;
|
||||
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
if (getppid() == 1)
|
||||
exit(1);
|
||||
return 0;
|
||||
int pid = xfork();
|
||||
if (pid)
|
||||
return pid;
|
||||
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
if (getppid() == 1)
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr char ALPHANUM[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
@@ -38,111 +38,111 @@ static bool seeded = false;
|
||||
static std::mt19937 gen;
|
||||
static std::uniform_int_distribution<int> dist(0, sizeof(ALPHANUM) - 2);
|
||||
int gen_rand_str(char *buf, int len, bool varlen) {
|
||||
if (!seeded) {
|
||||
if (access("/dev/urandom", F_OK) != 0)
|
||||
mknod("/dev/urandom", 0600 | S_IFCHR, makedev(1, 9));
|
||||
int fd = xopen("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
unsigned seed;
|
||||
xxread(fd, &seed, sizeof(seed));
|
||||
gen.seed(seed);
|
||||
close(fd);
|
||||
seeded = true;
|
||||
}
|
||||
if (varlen) {
|
||||
std::uniform_int_distribution<int> len_dist(len / 2, len);
|
||||
len = len_dist(gen);
|
||||
}
|
||||
for (int i = 0; i < len - 1; ++i)
|
||||
buf[i] = ALPHANUM[dist(gen)];
|
||||
buf[len - 1] = '\0';
|
||||
return len - 1;
|
||||
if (!seeded) {
|
||||
if (access("/dev/urandom", F_OK) != 0)
|
||||
mknod("/dev/urandom", 0600 | S_IFCHR, makedev(1, 9));
|
||||
int fd = xopen("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
unsigned seed;
|
||||
xxread(fd, &seed, sizeof(seed));
|
||||
gen.seed(seed);
|
||||
close(fd);
|
||||
seeded = true;
|
||||
}
|
||||
if (varlen) {
|
||||
std::uniform_int_distribution<int> len_dist(len / 2, len);
|
||||
len = len_dist(gen);
|
||||
}
|
||||
for (int i = 0; i < len - 1; ++i)
|
||||
buf[i] = ALPHANUM[dist(gen)];
|
||||
buf[len - 1] = '\0';
|
||||
return len - 1;
|
||||
}
|
||||
|
||||
int exec_command(exec_t &exec) {
|
||||
int pipefd[] = {-1, -1};
|
||||
int outfd = -1;
|
||||
int pipefd[] = {-1, -1};
|
||||
int outfd = -1;
|
||||
|
||||
if (exec.fd == -1) {
|
||||
if (xpipe2(pipefd, O_CLOEXEC) == -1)
|
||||
return -1;
|
||||
outfd = pipefd[1];
|
||||
} else if (exec.fd >= 0) {
|
||||
outfd = exec.fd;
|
||||
}
|
||||
if (exec.fd == -1) {
|
||||
if (xpipe2(pipefd, O_CLOEXEC) == -1)
|
||||
return -1;
|
||||
outfd = pipefd[1];
|
||||
} else if (exec.fd >= 0) {
|
||||
outfd = exec.fd;
|
||||
}
|
||||
|
||||
int pid = exec.fork();
|
||||
if (pid < 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
} else if (pid) {
|
||||
if (exec.fd == -1) {
|
||||
exec.fd = pipefd[0];
|
||||
close(pipefd[1]);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
int pid = exec.fork();
|
||||
if (pid < 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
} else if (pid) {
|
||||
if (exec.fd == -1) {
|
||||
exec.fd = pipefd[0];
|
||||
close(pipefd[1]);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
// Unblock all signals
|
||||
sigset_t set;
|
||||
sigfillset(&set);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
|
||||
// Unblock all signals
|
||||
sigset_t set;
|
||||
sigfillset(&set);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
|
||||
|
||||
if (outfd >= 0) {
|
||||
xdup2(outfd, STDOUT_FILENO);
|
||||
if (exec.err)
|
||||
xdup2(outfd, STDERR_FILENO);
|
||||
close(outfd);
|
||||
}
|
||||
if (outfd >= 0) {
|
||||
xdup2(outfd, STDOUT_FILENO);
|
||||
if (exec.err)
|
||||
xdup2(outfd, STDERR_FILENO);
|
||||
close(outfd);
|
||||
}
|
||||
|
||||
// Call the pre-exec callback
|
||||
if (exec.pre_exec)
|
||||
exec.pre_exec();
|
||||
// Call the pre-exec callback
|
||||
if (exec.pre_exec)
|
||||
exec.pre_exec();
|
||||
|
||||
execve(exec.argv[0], (char **) exec.argv, environ);
|
||||
PLOGE("execve %s", exec.argv[0]);
|
||||
exit(-1);
|
||||
execve(exec.argv[0], (char **) exec.argv, environ);
|
||||
PLOGE("execve %s", exec.argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int exec_command_sync(exec_t &exec) {
|
||||
int pid = exec_command(exec);
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
return WEXITSTATUS(status);
|
||||
int pid = exec_command(exec);
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
int new_daemon_thread(thread_entry entry, void *arg, const pthread_attr_t *attr) {
|
||||
pthread_t thread;
|
||||
int ret = xpthread_create(&thread, attr, entry, arg);
|
||||
if (ret == 0)
|
||||
pthread_detach(thread);
|
||||
return ret;
|
||||
pthread_t thread;
|
||||
int ret = xpthread_create(&thread, attr, entry, arg);
|
||||
if (ret == 0)
|
||||
pthread_detach(thread);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *proxy_routine(void *fp) {
|
||||
auto fn = reinterpret_cast<std::function<void()>*>(fp);
|
||||
(*fn)();
|
||||
delete fn;
|
||||
return nullptr;
|
||||
auto fn = reinterpret_cast<std::function<void()>*>(fp);
|
||||
(*fn)();
|
||||
delete fn;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int new_daemon_thread(std::function<void()> &&entry) {
|
||||
return new_daemon_thread(proxy_routine, new std::function<void()>(std::move(entry)));
|
||||
return new_daemon_thread(proxy_routine, new std::function<void()>(std::move(entry)));
|
||||
}
|
||||
|
||||
static char *argv0;
|
||||
static size_t name_len;
|
||||
void init_argv0(int argc, char **argv) {
|
||||
argv0 = argv[0];
|
||||
name_len = (argv[argc - 1] - argv[0]) + strlen(argv[argc - 1]) + 1;
|
||||
argv0 = argv[0];
|
||||
name_len = (argv[argc - 1] - argv[0]) + strlen(argv[argc - 1]) + 1;
|
||||
}
|
||||
|
||||
void set_nice_name(const char *name) {
|
||||
memset(argv0, 0, name_len);
|
||||
strlcpy(argv0, name, name_len);
|
||||
prctl(PR_SET_NAME, name);
|
||||
memset(argv0, 0, name_len);
|
||||
strlcpy(argv0, name, name_len);
|
||||
prctl(PR_SET_NAME, name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,52 +150,52 @@ void set_nice_name(const char *name) {
|
||||
* Use our own implementation for faster conversion.
|
||||
*/
|
||||
int parse_int(const char *s) {
|
||||
int val = 0;
|
||||
char c;
|
||||
while ((c = *(s++))) {
|
||||
if (c > '9' || c < '0')
|
||||
return -1;
|
||||
val = val * 10 + c - '0';
|
||||
}
|
||||
return val;
|
||||
int val = 0;
|
||||
char c;
|
||||
while ((c = *(s++))) {
|
||||
if (c > '9' || c < '0')
|
||||
return -1;
|
||||
val = val * 10 + c - '0';
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t binary_gcd(uint32_t u, uint32_t v) {
|
||||
if (u == 0) return v;
|
||||
if (v == 0) return u;
|
||||
auto shift = __builtin_ctz(u | v);
|
||||
u >>= __builtin_ctz(u);
|
||||
do {
|
||||
v >>= __builtin_ctz(v);
|
||||
if (u > v) {
|
||||
auto t = v;
|
||||
v = u;
|
||||
u = t;
|
||||
}
|
||||
v -= u;
|
||||
} while (v != 0);
|
||||
return u << shift;
|
||||
if (u == 0) return v;
|
||||
if (v == 0) return u;
|
||||
auto shift = __builtin_ctz(u | v);
|
||||
u >>= __builtin_ctz(u);
|
||||
do {
|
||||
v >>= __builtin_ctz(v);
|
||||
if (u > v) {
|
||||
auto t = v;
|
||||
v = u;
|
||||
u = t;
|
||||
}
|
||||
v -= u;
|
||||
} while (v != 0);
|
||||
return u << shift;
|
||||
}
|
||||
|
||||
int switch_mnt_ns(int pid) {
|
||||
char mnt[32];
|
||||
snprintf(mnt, sizeof(mnt), "/proc/%d/ns/mnt", pid);
|
||||
if (access(mnt, R_OK) == -1) return 1; // Maybe process died..
|
||||
char mnt[32];
|
||||
snprintf(mnt, sizeof(mnt), "/proc/%d/ns/mnt", pid);
|
||||
if (access(mnt, R_OK) == -1) return 1; // Maybe process died..
|
||||
|
||||
int fd, ret;
|
||||
fd = xopen(mnt, O_RDONLY);
|
||||
if (fd < 0) return 1;
|
||||
// Switch to its namespace
|
||||
ret = xsetns(fd, 0);
|
||||
close(fd);
|
||||
return ret;
|
||||
int fd, ret;
|
||||
fd = xopen(mnt, O_RDONLY);
|
||||
if (fd < 0) return 1;
|
||||
// Switch to its namespace
|
||||
ret = xsetns(fd, 0);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string &replace_all(string &str, string_view from, string_view to) {
|
||||
size_t pos = 0;
|
||||
while((pos = str.find(from, pos)) != string::npos) {
|
||||
str.replace(pos, from.length(), to);
|
||||
pos += to.length();
|
||||
}
|
||||
return str;
|
||||
size_t pos = 0;
|
||||
while((pos = str.find(from, pos)) != string::npos) {
|
||||
str.replace(pos, from.length(), to);
|
||||
pos += to.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
@@ -10,48 +10,48 @@
|
||||
|
||||
class mutex_guard {
|
||||
public:
|
||||
explicit mutex_guard(pthread_mutex_t &m): mutex(&m) {
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
explicit mutex_guard(pthread_mutex_t &m): mutex(&m) {
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
explicit mutex_guard(pthread_mutex_t *m): mutex(m) {
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
explicit mutex_guard(pthread_mutex_t *m): mutex(m) {
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
~mutex_guard() {
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
~mutex_guard() {
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t *mutex;
|
||||
pthread_mutex_t *mutex;
|
||||
};
|
||||
|
||||
template <class Func>
|
||||
class run_finally {
|
||||
public:
|
||||
explicit run_finally(const Func &fn) : fn(fn) {}
|
||||
~run_finally() { fn(); }
|
||||
explicit run_finally(const Func &fn) : fn(fn) {}
|
||||
~run_finally() { fn(); }
|
||||
private:
|
||||
const Func &fn;
|
||||
const Func &fn;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class reversed_container {
|
||||
public:
|
||||
reversed_container(T &base) : base(base) {}
|
||||
decltype(std::declval<T>().rbegin()) begin() { return base.rbegin(); }
|
||||
decltype(std::declval<T>().crbegin()) begin() const { return base.crbegin(); }
|
||||
decltype(std::declval<T>().crbegin()) cbegin() const { return base.crbegin(); }
|
||||
decltype(std::declval<T>().rend()) end() { return base.rend(); }
|
||||
decltype(std::declval<T>().crend()) end() const { return base.crend(); }
|
||||
decltype(std::declval<T>().crend()) cend() const { return base.crend(); }
|
||||
reversed_container(T &base) : base(base) {}
|
||||
decltype(std::declval<T>().rbegin()) begin() { return base.rbegin(); }
|
||||
decltype(std::declval<T>().crbegin()) begin() const { return base.crbegin(); }
|
||||
decltype(std::declval<T>().crbegin()) cbegin() const { return base.crbegin(); }
|
||||
decltype(std::declval<T>().rend()) end() { return base.rend(); }
|
||||
decltype(std::declval<T>().crend()) end() const { return base.crend(); }
|
||||
decltype(std::declval<T>().crend()) cend() const { return base.crend(); }
|
||||
private:
|
||||
T &base;
|
||||
T &base;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
reversed_container<T> reversed(T &base) {
|
||||
return reversed_container<T>(base);
|
||||
return reversed_container<T>(base);
|
||||
}
|
||||
|
||||
int parse_int(const char *s);
|
||||
@@ -63,13 +63,13 @@ int new_daemon_thread(thread_entry entry, void *arg = nullptr, const pthread_att
|
||||
int new_daemon_thread(std::function<void()> &&entry);
|
||||
|
||||
static inline bool str_contains(std::string_view s, std::string_view ss) {
|
||||
return s.find(ss) != std::string::npos;
|
||||
return s.find(ss) != std::string::npos;
|
||||
}
|
||||
static inline bool str_starts(std::string_view s, std::string_view ss) {
|
||||
return s.rfind(ss, 0) == 0;
|
||||
return s.rfind(ss, 0) == 0;
|
||||
}
|
||||
static inline bool str_ends(std::string_view s, std::string_view ss) {
|
||||
return s.size() >= ss.size() && s.compare(s.size() - ss.size(), std::string::npos, ss) == 0;
|
||||
return s.size() >= ss.size() && s.compare(s.size() - ss.size(), std::string::npos, ss) == 0;
|
||||
}
|
||||
|
||||
int fork_dont_care();
|
||||
@@ -82,38 +82,38 @@ int gen_rand_str(char *buf, int len, bool varlen = true);
|
||||
std::string &replace_all(std::string &str, std::string_view from, std::string_view to);
|
||||
|
||||
struct exec_t {
|
||||
bool err = false;
|
||||
int fd = -2;
|
||||
void (*pre_exec)() = nullptr;
|
||||
int (*fork)() = xfork;
|
||||
const char **argv = nullptr;
|
||||
bool err = false;
|
||||
int fd = -2;
|
||||
void (*pre_exec)() = nullptr;
|
||||
int (*fork)() = xfork;
|
||||
const char **argv = nullptr;
|
||||
};
|
||||
|
||||
int exec_command(exec_t &exec);
|
||||
template <class ...Args>
|
||||
int exec_command(exec_t &exec, Args &&...args) {
|
||||
const char *argv[] = {args..., nullptr};
|
||||
exec.argv = argv;
|
||||
return exec_command(exec);
|
||||
const char *argv[] = {args..., nullptr};
|
||||
exec.argv = argv;
|
||||
return exec_command(exec);
|
||||
}
|
||||
int exec_command_sync(exec_t &exec);
|
||||
template <class ...Args>
|
||||
int exec_command_sync(exec_t &exec, Args &&...args) {
|
||||
const char *argv[] = {args..., nullptr};
|
||||
exec.argv = argv;
|
||||
return exec_command_sync(exec);
|
||||
const char *argv[] = {args..., nullptr};
|
||||
exec.argv = argv;
|
||||
return exec_command_sync(exec);
|
||||
}
|
||||
template <class ...Args>
|
||||
int exec_command_sync(Args &&...args) {
|
||||
exec_t exec{};
|
||||
return exec_command_sync(exec, args...);
|
||||
exec_t exec{};
|
||||
return exec_command_sync(exec, args...);
|
||||
}
|
||||
template <class ...Args>
|
||||
void exec_command_async(Args &&...args) {
|
||||
const char *argv[] = {args..., nullptr};
|
||||
exec_t exec {
|
||||
.argv = argv,
|
||||
.fork = fork_dont_care
|
||||
};
|
||||
exec_command(exec);
|
||||
const char *argv[] = {args..., nullptr};
|
||||
exec_t exec {
|
||||
.argv = argv,
|
||||
.fork = fork_dont_care
|
||||
};
|
||||
exec_command(exec);
|
||||
}
|
||||
|
@@ -14,96 +14,96 @@
|
||||
* License: BSD, full copyright notice please check original source */
|
||||
|
||||
ssize_t compat_getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) {
|
||||
char *ptr, *eptr;
|
||||
char *ptr, *eptr;
|
||||
|
||||
if (*buf == nullptr || *bufsiz == 0) {
|
||||
*bufsiz = BUFSIZ;
|
||||
if ((*buf = (char *) malloc(*bufsiz)) == nullptr)
|
||||
return -1;
|
||||
}
|
||||
if (*buf == nullptr || *bufsiz == 0) {
|
||||
*bufsiz = BUFSIZ;
|
||||
if ((*buf = (char *) malloc(*bufsiz)) == nullptr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
|
||||
int c = fgetc(fp);
|
||||
if (c == -1) {
|
||||
if (feof(fp))
|
||||
return ptr == *buf ? -1 : ptr - *buf;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
*ptr++ = c;
|
||||
if (c == delimiter) {
|
||||
*ptr = '\0';
|
||||
return ptr - *buf;
|
||||
}
|
||||
if (ptr + 2 >= eptr) {
|
||||
char *nbuf;
|
||||
size_t nbufsiz = *bufsiz * 2;
|
||||
ssize_t d = ptr - *buf;
|
||||
if ((nbuf = (char *) realloc(*buf, nbufsiz)) == nullptr)
|
||||
return -1;
|
||||
*buf = nbuf;
|
||||
*bufsiz = nbufsiz;
|
||||
eptr = nbuf + nbufsiz;
|
||||
ptr = nbuf + d;
|
||||
}
|
||||
}
|
||||
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
|
||||
int c = fgetc(fp);
|
||||
if (c == -1) {
|
||||
if (feof(fp))
|
||||
return ptr == *buf ? -1 : ptr - *buf;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
*ptr++ = c;
|
||||
if (c == delimiter) {
|
||||
*ptr = '\0';
|
||||
return ptr - *buf;
|
||||
}
|
||||
if (ptr + 2 >= eptr) {
|
||||
char *nbuf;
|
||||
size_t nbufsiz = *bufsiz * 2;
|
||||
ssize_t d = ptr - *buf;
|
||||
if ((nbuf = (char *) realloc(*buf, nbufsiz)) == nullptr)
|
||||
return -1;
|
||||
*buf = nbuf;
|
||||
*bufsiz = nbufsiz;
|
||||
eptr = nbuf + nbufsiz;
|
||||
ptr = nbuf + d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t compat_getline(char **buf, size_t *bufsiz, FILE *fp) {
|
||||
return getdelim(buf, bufsiz, '\n', fp);
|
||||
return getdelim(buf, bufsiz, '\n', fp);
|
||||
}
|
||||
|
||||
/* Original source: https://android.googlesource.com/platform/bionic/+/master/libc/bionic/mntent.cpp
|
||||
* License: AOSP, full copyright notice please check original source */
|
||||
|
||||
struct mntent *compat_getmntent_r(FILE* fp, struct mntent* e, char* buf, int buf_len) {
|
||||
memset(e, 0, sizeof(*e));
|
||||
while (fgets(buf, buf_len, fp) != nullptr) {
|
||||
// Entries look like "proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0".
|
||||
// That is: mnt_fsname mnt_dir mnt_type mnt_opts 0 0.
|
||||
int fsname0, fsname1, dir0, dir1, type0, type1, opts0, opts1;
|
||||
if (sscanf(buf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
|
||||
&fsname0, &fsname1, &dir0, &dir1, &type0, &type1, &opts0, &opts1,
|
||||
&e->mnt_freq, &e->mnt_passno) == 2) {
|
||||
e->mnt_fsname = &buf[fsname0];
|
||||
buf[fsname1] = '\0';
|
||||
e->mnt_dir = &buf[dir0];
|
||||
buf[dir1] = '\0';
|
||||
e->mnt_type = &buf[type0];
|
||||
buf[type1] = '\0';
|
||||
e->mnt_opts = &buf[opts0];
|
||||
buf[opts1] = '\0';
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
memset(e, 0, sizeof(*e));
|
||||
while (fgets(buf, buf_len, fp) != nullptr) {
|
||||
// Entries look like "proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0".
|
||||
// That is: mnt_fsname mnt_dir mnt_type mnt_opts 0 0.
|
||||
int fsname0, fsname1, dir0, dir1, type0, type1, opts0, opts1;
|
||||
if (sscanf(buf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
|
||||
&fsname0, &fsname1, &dir0, &dir1, &type0, &type1, &opts0, &opts1,
|
||||
&e->mnt_freq, &e->mnt_passno) == 2) {
|
||||
e->mnt_fsname = &buf[fsname0];
|
||||
buf[fsname1] = '\0';
|
||||
e->mnt_dir = &buf[dir0];
|
||||
buf[dir1] = '\0';
|
||||
e->mnt_type = &buf[type0];
|
||||
buf[type1] = '\0';
|
||||
e->mnt_opts = &buf[opts0];
|
||||
buf[opts1] = '\0';
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FILE *compat_setmntent(const char* path, const char* mode) {
|
||||
return fopen(path, mode);
|
||||
return fopen(path, mode);
|
||||
}
|
||||
|
||||
int compat_endmntent(FILE* fp) {
|
||||
if (fp != nullptr) {
|
||||
fclose(fp);
|
||||
}
|
||||
return 1;
|
||||
if (fp != nullptr) {
|
||||
fclose(fp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *compat_hasmntopt(const struct mntent* mnt, const char* opt) {
|
||||
char* token = mnt->mnt_opts;
|
||||
char* const end = mnt->mnt_opts + strlen(mnt->mnt_opts);
|
||||
const size_t optLen = strlen(opt);
|
||||
while (token) {
|
||||
char* const tokenEnd = token + optLen;
|
||||
if (tokenEnd > end) break;
|
||||
if (memcmp(token, opt, optLen) == 0 &&
|
||||
(*tokenEnd == '\0' || *tokenEnd == ',' || *tokenEnd == '=')) {
|
||||
return token;
|
||||
}
|
||||
token = strchr(token, ',');
|
||||
if (token) token++;
|
||||
}
|
||||
return nullptr;
|
||||
char* token = mnt->mnt_opts;
|
||||
char* const end = mnt->mnt_opts + strlen(mnt->mnt_opts);
|
||||
const size_t optLen = strlen(opt);
|
||||
while (token) {
|
||||
char* const tokenEnd = token + optLen;
|
||||
if (tokenEnd > end) break;
|
||||
if (memcmp(token, opt, optLen) == 0 &&
|
||||
(*tokenEnd == '\0' || *tokenEnd == ',' || *tokenEnd == '=')) {
|
||||
return token;
|
||||
}
|
||||
token = strchr(token, ',');
|
||||
if (token) token++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@@ -31,38 +31,38 @@ int compat_endmntent(FILE* fp);
|
||||
char *compat_hasmntopt(const struct mntent* mnt, const char* opt);
|
||||
|
||||
static inline int compat_setns(int fd, int nstype) {
|
||||
return syscall(__NR_setns, fd, nstype);
|
||||
return syscall(__NR_setns, fd, nstype);
|
||||
}
|
||||
|
||||
static inline int compat_unshare(int flags) {
|
||||
return syscall(__NR_unshare, flags);
|
||||
return syscall(__NR_unshare, flags);
|
||||
}
|
||||
|
||||
static inline int compat_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
|
||||
return syscall(__NR_accept4, sockfd, addr, addrlen, flags);
|
||||
return syscall(__NR_accept4, sockfd, addr, addrlen, flags);
|
||||
}
|
||||
|
||||
static inline int compat_dup3(int oldfd, int newfd, int flags) {
|
||||
return syscall(__NR_dup3, oldfd, newfd, flags);
|
||||
return syscall(__NR_dup3, oldfd, newfd, flags);
|
||||
}
|
||||
|
||||
static inline ssize_t compat_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) {
|
||||
return syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz);
|
||||
return syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz);
|
||||
}
|
||||
|
||||
static inline int compat_symlinkat(const char *target, int newdirfd, const char *linkpath) {
|
||||
return syscall(__NR_symlinkat, target, newdirfd, linkpath);
|
||||
return syscall(__NR_symlinkat, target, newdirfd, linkpath);
|
||||
}
|
||||
|
||||
static inline int compat_linkat(int olddirfd, const char *oldpath,
|
||||
int newdirfd, const char *newpath, int flags) {
|
||||
return syscall(__NR_linkat, olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
int newdirfd, const char *newpath, int flags) {
|
||||
return syscall(__NR_linkat, olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
}
|
||||
|
||||
static inline int compat_inotify_init1(int flags) {
|
||||
return syscall(__NR_inotify_init1, flags);
|
||||
return syscall(__NR_inotify_init1, flags);
|
||||
}
|
||||
|
||||
static inline int compat_faccessat(int dirfd, const char *pathname, int mode, int flags) {
|
||||
return syscall(__NR_faccessat, dirfd, pathname, mode, flags);
|
||||
return syscall(__NR_faccessat, dirfd, pathname, mode, flags);
|
||||
}
|
||||
|
@@ -12,67 +12,67 @@ static int stub(const char *) { return 0; }
|
||||
static int stub(const char *, const char *) { return 0; }
|
||||
|
||||
static int stub(const char *, char **ctx) {
|
||||
*ctx = strdup("");
|
||||
return 0;
|
||||
*ctx = strdup("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stub(int, const char *) { return 0; }
|
||||
|
||||
static int stub(int, char **ctx) {
|
||||
*ctx = strdup("");
|
||||
return 0;
|
||||
*ctx = strdup("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Builtin implementation
|
||||
|
||||
static void __freecon(char *s) {
|
||||
free(s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
static int __setcon(const char *ctx) {
|
||||
int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
size_t len = strlen(ctx) + 1;
|
||||
int rc = write(fd, ctx, len);
|
||||
close(fd);
|
||||
return rc != len;
|
||||
int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
size_t len = strlen(ctx) + 1;
|
||||
int rc = write(fd, ctx, len);
|
||||
close(fd);
|
||||
return rc != len;
|
||||
}
|
||||
|
||||
static int __getfilecon(const char *path, char **ctx) {
|
||||
char buf[1024];
|
||||
int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
|
||||
if (rc >= 0)
|
||||
*ctx = strdup(buf);
|
||||
return rc;
|
||||
char buf[1024];
|
||||
int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
|
||||
if (rc >= 0)
|
||||
*ctx = strdup(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __lgetfilecon(const char *path, char **ctx) {
|
||||
char buf[1024];
|
||||
int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
|
||||
if (rc >= 0)
|
||||
*ctx = strdup(buf);
|
||||
return rc;
|
||||
char buf[1024];
|
||||
int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
|
||||
if (rc >= 0)
|
||||
*ctx = strdup(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __fgetfilecon(int fd, char **ctx) {
|
||||
char buf[1024];
|
||||
int rc = syscall(__NR_fgetxattr, fd, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
|
||||
if (rc >= 0)
|
||||
*ctx = strdup(buf);
|
||||
return rc;
|
||||
char buf[1024];
|
||||
int rc = syscall(__NR_fgetxattr, fd, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
|
||||
if (rc >= 0)
|
||||
*ctx = strdup(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __setfilecon(const char *path, const char *ctx) {
|
||||
return syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
|
||||
return syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
|
||||
}
|
||||
|
||||
static int __lsetfilecon(const char *path, const char *ctx) {
|
||||
return syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
|
||||
return syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
|
||||
}
|
||||
|
||||
static int __fsetfilecon(int fd, const char *ctx) {
|
||||
return syscall(__NR_fsetxattr, fd, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
|
||||
return syscall(__NR_fsetxattr, fd, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
|
||||
}
|
||||
|
||||
// Function pointers
|
||||
@@ -87,34 +87,34 @@ int (*lsetfilecon)(const char *, const char *) = stub;
|
||||
int (*fsetfilecon)(int, const char *) = stub;
|
||||
|
||||
void getfilecon_at(int dirfd, const char *name, char **con) {
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
if (lgetfilecon(path, con))
|
||||
*con = strdup("");
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
if (lgetfilecon(path, con))
|
||||
*con = strdup("");
|
||||
}
|
||||
|
||||
void setfilecon_at(int dirfd, const char *name, const char *con) {
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
lsetfilecon(path, con);
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
lsetfilecon(path, con);
|
||||
}
|
||||
|
||||
void selinux_builtin_impl() {
|
||||
setcon = __setcon;
|
||||
getfilecon = __getfilecon;
|
||||
lgetfilecon = __lgetfilecon;
|
||||
fgetfilecon = __fgetfilecon;
|
||||
setfilecon = __setfilecon;
|
||||
lsetfilecon = __lsetfilecon;
|
||||
fsetfilecon = __fsetfilecon;
|
||||
setcon = __setcon;
|
||||
getfilecon = __getfilecon;
|
||||
lgetfilecon = __lgetfilecon;
|
||||
fgetfilecon = __fgetfilecon;
|
||||
setfilecon = __setfilecon;
|
||||
lsetfilecon = __lsetfilecon;
|
||||
fsetfilecon = __fsetfilecon;
|
||||
}
|
||||
|
||||
void dload_selinux() {
|
||||
if (access("/system/lib/libselinux.so", F_OK))
|
||||
return;
|
||||
/* We only check whether libselinux.so exists but don't dlopen.
|
||||
* For some reason calling symbols returned from dlsym
|
||||
* will result to SEGV_ACCERR on some devices.
|
||||
* Always use builtin implementations for SELinux stuffs. */
|
||||
selinux_builtin_impl();
|
||||
if (access("/system/lib/libselinux.so", F_OK))
|
||||
return;
|
||||
/* We only check whether libselinux.so exists but don't dlopen.
|
||||
* For some reason calling symbols returned from dlsym
|
||||
* will result to SEGV_ACCERR on some devices.
|
||||
* Always use builtin implementations for SELinux stuffs. */
|
||||
selinux_builtin_impl();
|
||||
}
|
||||
|
@@ -2,128 +2,128 @@
|
||||
#include <stream.hpp>
|
||||
|
||||
static int strm_read(void *v, char *buf, int len) {
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
return strm->read(buf, len);
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
return strm->read(buf, len);
|
||||
}
|
||||
|
||||
static int strm_write(void *v, const char *buf, int len) {
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
return strm->write(buf, len);
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
return strm->write(buf, len);
|
||||
}
|
||||
|
||||
static fpos_t strm_seek(void *v, fpos_t off, int whence) {
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
return strm->seek(off, whence);
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
return strm->seek(off, whence);
|
||||
}
|
||||
|
||||
static int strm_close(void *v) {
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
delete strm;
|
||||
return 0;
|
||||
auto strm = reinterpret_cast<stream *>(v);
|
||||
delete strm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sFILE make_stream_fp(stream_ptr &&strm) {
|
||||
auto fp = make_file(funopen(strm.release(), strm_read, strm_write, strm_seek, strm_close));
|
||||
setbuf(fp.get(), nullptr);
|
||||
return fp;
|
||||
auto fp = make_file(funopen(strm.release(), strm_read, strm_write, strm_seek, strm_close));
|
||||
setbuf(fp.get(), nullptr);
|
||||
return fp;
|
||||
}
|
||||
|
||||
int stream::read(void *buf, size_t len) {
|
||||
LOGE("This stream does not support read\n");
|
||||
return -1;
|
||||
LOGE("This stream does not support read\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int stream::write(const void *buf, size_t len) {
|
||||
LOGE("This stream does not support write\n");
|
||||
return -1;
|
||||
LOGE("This stream does not support write\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t stream::seek(off_t off, int whence) {
|
||||
LOGE("This stream does not support seek\n");
|
||||
return -1;
|
||||
LOGE("This stream does not support seek\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fp_stream::read(void *buf, size_t len) {
|
||||
return fread(buf, 1, len, fp.get());
|
||||
return fread(buf, 1, len, fp.get());
|
||||
}
|
||||
|
||||
int fp_stream::write(const void *buf, size_t len) {
|
||||
return fwrite(buf, 1, len, fp.get());
|
||||
return fwrite(buf, 1, len, fp.get());
|
||||
}
|
||||
|
||||
off_t fp_stream::seek(off_t off, int whence) {
|
||||
return fseek(fp.get(), off, whence);
|
||||
return fseek(fp.get(), off, whence);
|
||||
}
|
||||
|
||||
int filter_stream::read(void *buf, size_t len) {
|
||||
return base->read(buf, len);
|
||||
return base->read(buf, len);
|
||||
}
|
||||
|
||||
int filter_stream::write(const void *buf, size_t len) {
|
||||
return base->write(buf, len);
|
||||
return base->write(buf, len);
|
||||
}
|
||||
|
||||
byte_stream::byte_stream(uint8_t *&buf, size_t &len) : _buf(buf), _len(len) {
|
||||
buf = nullptr;
|
||||
len = 0;
|
||||
buf = nullptr;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
int byte_stream::read(void *buf, size_t len) {
|
||||
len = std::min(len, _len - _pos);
|
||||
memcpy(buf, _buf + _pos, len);
|
||||
return len;
|
||||
len = std::min(len, _len - _pos);
|
||||
memcpy(buf, _buf + _pos, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
int byte_stream::write(const void *buf, size_t len) {
|
||||
resize(_pos + len);
|
||||
memcpy(_buf + _pos, buf, len);
|
||||
_pos += len;
|
||||
_len = std::max(_len, _pos);
|
||||
return len;
|
||||
resize(_pos + len);
|
||||
memcpy(_buf + _pos, buf, len);
|
||||
_pos += len;
|
||||
_len = std::max(_len, _pos);
|
||||
return len;
|
||||
}
|
||||
|
||||
off_t byte_stream::seek(off_t off, int whence) {
|
||||
off_t np;
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
np = _pos + off;
|
||||
break;
|
||||
case SEEK_END:
|
||||
np = _len + off;
|
||||
break;
|
||||
case SEEK_SET:
|
||||
np = off;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
resize(np, true);
|
||||
_pos = np;
|
||||
return np;
|
||||
off_t np;
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
np = _pos + off;
|
||||
break;
|
||||
case SEEK_END:
|
||||
np = _len + off;
|
||||
break;
|
||||
case SEEK_SET:
|
||||
np = off;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
resize(np, true);
|
||||
_pos = np;
|
||||
return np;
|
||||
}
|
||||
|
||||
void byte_stream::resize(size_t new_pos, bool zero) {
|
||||
bool resize = false;
|
||||
size_t old_cap = _cap;
|
||||
while (new_pos > _cap) {
|
||||
_cap = _cap ? (_cap << 1) - (_cap >> 1) : 1 << 12;
|
||||
resize = true;
|
||||
}
|
||||
if (resize) {
|
||||
_buf = (uint8_t *) xrealloc(_buf, _cap);
|
||||
if (zero)
|
||||
memset(_buf + old_cap, 0, _cap - old_cap);
|
||||
}
|
||||
bool resize = false;
|
||||
size_t old_cap = _cap;
|
||||
while (new_pos > _cap) {
|
||||
_cap = _cap ? (_cap << 1) - (_cap >> 1) : 1 << 12;
|
||||
resize = true;
|
||||
}
|
||||
if (resize) {
|
||||
_buf = (uint8_t *) xrealloc(_buf, _cap);
|
||||
if (zero)
|
||||
memset(_buf + old_cap, 0, _cap - old_cap);
|
||||
}
|
||||
}
|
||||
|
||||
int fd_stream::read(void *buf, size_t len) {
|
||||
return ::read(fd, buf, len);
|
||||
return ::read(fd, buf, len);
|
||||
}
|
||||
|
||||
int fd_stream::write(const void *buf, size_t len) {
|
||||
return ::write(fd, buf, len);
|
||||
return ::write(fd, buf, len);
|
||||
}
|
||||
|
||||
off_t fd_stream::seek(off_t off, int whence) {
|
||||
return lseek(fd, off, whence);
|
||||
return lseek(fd, off, whence);
|
||||
}
|
||||
|
@@ -15,458 +15,458 @@
|
||||
using namespace std;
|
||||
|
||||
FILE *xfopen(const char *pathname, const char *mode) {
|
||||
FILE *fp = fopen(pathname, mode);
|
||||
if (fp == nullptr) {
|
||||
PLOGE("fopen: %s", pathname);
|
||||
}
|
||||
return fp;
|
||||
FILE *fp = fopen(pathname, mode);
|
||||
if (fp == nullptr) {
|
||||
PLOGE("fopen: %s", pathname);
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
FILE *xfdopen(int fd, const char *mode) {
|
||||
FILE *fp = fdopen(fd, mode);
|
||||
if (fp == nullptr) {
|
||||
PLOGE("fopen");
|
||||
}
|
||||
return fp;
|
||||
FILE *fp = fdopen(fd, mode);
|
||||
if (fp == nullptr) {
|
||||
PLOGE("fopen");
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
int xopen(const char *pathname, int flags) {
|
||||
int fd = open(pathname, flags);
|
||||
if (fd < 0) {
|
||||
PLOGE("open: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
int fd = open(pathname, flags);
|
||||
if (fd < 0) {
|
||||
PLOGE("open: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xopen(const char *pathname, int flags, mode_t mode) {
|
||||
int fd = open(pathname, flags, mode);
|
||||
if (fd < 0) {
|
||||
PLOGE("open: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
int fd = open(pathname, flags, mode);
|
||||
if (fd < 0) {
|
||||
PLOGE("open: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xopenat(int dirfd, const char *pathname, int flags) {
|
||||
int fd = openat(dirfd, pathname, flags);
|
||||
if (fd < 0) {
|
||||
PLOGE("openat: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
int fd = openat(dirfd, pathname, flags);
|
||||
if (fd < 0) {
|
||||
PLOGE("openat: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xopenat(int dirfd, const char *pathname, int flags, mode_t mode) {
|
||||
int fd = openat(dirfd, pathname, flags, mode);
|
||||
if (fd < 0) {
|
||||
PLOGE("openat: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
int fd = openat(dirfd, pathname, flags, mode);
|
||||
if (fd < 0) {
|
||||
PLOGE("openat: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ssize_t xwrite(int fd, const void *buf, size_t count) {
|
||||
int ret = write(fd, buf, count);
|
||||
if (count != ret) {
|
||||
PLOGE("write");
|
||||
}
|
||||
return ret;
|
||||
int ret = write(fd, buf, count);
|
||||
if (count != ret) {
|
||||
PLOGE("write");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read error other than EOF
|
||||
ssize_t xread(int fd, void *buf, size_t count) {
|
||||
int ret = read(fd, buf, count);
|
||||
if (ret < 0) {
|
||||
PLOGE("read");
|
||||
}
|
||||
return ret;
|
||||
int ret = read(fd, buf, count);
|
||||
if (ret < 0) {
|
||||
PLOGE("read");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read exact same size as count
|
||||
ssize_t xxread(int fd, void *buf, size_t count) {
|
||||
int ret = read(fd, buf, count);
|
||||
if (count != ret) {
|
||||
PLOGE("read (%zu != %d)", count, ret);
|
||||
}
|
||||
return ret;
|
||||
int ret = read(fd, buf, count);
|
||||
if (count != ret) {
|
||||
PLOGE("read (%zu != %d)", count, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xpipe2(int pipefd[2], int flags) {
|
||||
int ret = pipe2(pipefd, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("pipe2");
|
||||
}
|
||||
return ret;
|
||||
int ret = pipe2(pipefd, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("pipe2");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xsetns(int fd, int nstype) {
|
||||
int ret = setns(fd, nstype);
|
||||
if (ret < 0) {
|
||||
PLOGE("setns");
|
||||
}
|
||||
return ret;
|
||||
int ret = setns(fd, nstype);
|
||||
if (ret < 0) {
|
||||
PLOGE("setns");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xunshare(int flags) {
|
||||
int ret = unshare(flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("unshare");
|
||||
}
|
||||
return ret;
|
||||
int ret = unshare(flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("unshare");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
DIR *xopendir(const char *name) {
|
||||
DIR *d = opendir(name);
|
||||
if (d == nullptr) {
|
||||
PLOGE("opendir: %s", name);
|
||||
}
|
||||
return d;
|
||||
DIR *d = opendir(name);
|
||||
if (d == nullptr) {
|
||||
PLOGE("opendir: %s", name);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
DIR *xfdopendir(int fd) {
|
||||
DIR *d = fdopendir(fd);
|
||||
if (d == nullptr) {
|
||||
PLOGE("fdopendir");
|
||||
}
|
||||
return d;
|
||||
DIR *d = fdopendir(fd);
|
||||
if (d == nullptr) {
|
||||
PLOGE("fdopendir");
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
struct dirent *xreaddir(DIR *dirp) {
|
||||
errno = 0;
|
||||
for (dirent *e;;) {
|
||||
e = readdir(dirp);
|
||||
if (e == nullptr) {
|
||||
if (errno)
|
||||
PLOGE("readdir");
|
||||
return nullptr;
|
||||
} else if (e->d_name == "."sv || e->d_name == ".."sv) {
|
||||
// Filter . and .. for users
|
||||
continue;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
errno = 0;
|
||||
for (dirent *e;;) {
|
||||
e = readdir(dirp);
|
||||
if (e == nullptr) {
|
||||
if (errno)
|
||||
PLOGE("readdir");
|
||||
return nullptr;
|
||||
} else if (e->d_name == "."sv || e->d_name == ".."sv) {
|
||||
// Filter . and .. for users
|
||||
continue;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t xsetsid() {
|
||||
pid_t pid = setsid();
|
||||
if (pid < 0) {
|
||||
PLOGE("setsid");
|
||||
}
|
||||
return pid;
|
||||
pid_t pid = setsid();
|
||||
if (pid < 0) {
|
||||
PLOGE("setsid");
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
int xsocket(int domain, int type, int protocol) {
|
||||
int fd = socket(domain, type, protocol);
|
||||
if (fd < 0) {
|
||||
PLOGE("socket");
|
||||
}
|
||||
return fd;
|
||||
int fd = socket(domain, type, protocol);
|
||||
if (fd < 0) {
|
||||
PLOGE("socket");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
int ret = bind(sockfd, addr, addrlen);
|
||||
if (ret < 0) {
|
||||
PLOGE("bind");
|
||||
}
|
||||
return ret;
|
||||
int ret = bind(sockfd, addr, addrlen);
|
||||
if (ret < 0) {
|
||||
PLOGE("bind");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xlisten(int sockfd, int backlog) {
|
||||
int ret = listen(sockfd, backlog);
|
||||
if (ret < 0) {
|
||||
PLOGE("listen");
|
||||
}
|
||||
return ret;
|
||||
int ret = listen(sockfd, backlog);
|
||||
if (ret < 0) {
|
||||
PLOGE("listen");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int accept4_compat(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
|
||||
int fd = accept(sockfd, addr, addrlen);
|
||||
if (fd < 0) {
|
||||
PLOGE("accept");
|
||||
} else {
|
||||
if (flags & SOCK_CLOEXEC)
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
if (flags & SOCK_NONBLOCK) {
|
||||
int i = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, i | O_NONBLOCK);
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
int fd = accept(sockfd, addr, addrlen);
|
||||
if (fd < 0) {
|
||||
PLOGE("accept");
|
||||
} else {
|
||||
if (flags & SOCK_CLOEXEC)
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
if (flags & SOCK_NONBLOCK) {
|
||||
int i = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, i | O_NONBLOCK);
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
|
||||
int fd = accept4(sockfd, addr, addrlen, flags);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOSYS)
|
||||
return accept4_compat(sockfd, addr, addrlen, flags);
|
||||
PLOGE("accept4");
|
||||
}
|
||||
return fd;
|
||||
int fd = accept4(sockfd, addr, addrlen, flags);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOSYS)
|
||||
return accept4_compat(sockfd, addr, addrlen, flags);
|
||||
PLOGE("accept4");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void *xmalloc(size_t size) {
|
||||
void *p = malloc(size);
|
||||
if (p == nullptr) {
|
||||
PLOGE("malloc");
|
||||
}
|
||||
return p;
|
||||
void *p = malloc(size);
|
||||
if (p == nullptr) {
|
||||
PLOGE("malloc");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *xcalloc(size_t nmemb, size_t size) {
|
||||
void *p = calloc(nmemb, size);
|
||||
if (p == nullptr) {
|
||||
PLOGE("calloc");
|
||||
}
|
||||
return p;
|
||||
void *p = calloc(nmemb, size);
|
||||
if (p == nullptr) {
|
||||
PLOGE("calloc");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *xrealloc(void *ptr, size_t size) {
|
||||
void *p = realloc(ptr, size);
|
||||
if (p == nullptr) {
|
||||
PLOGE("realloc");
|
||||
}
|
||||
return p;
|
||||
void *p = realloc(ptr, size);
|
||||
if (p == nullptr) {
|
||||
PLOGE("realloc");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) {
|
||||
int sent = sendmsg(sockfd, msg, flags);
|
||||
if (sent < 0) {
|
||||
PLOGE("sendmsg");
|
||||
}
|
||||
return sent;
|
||||
int sent = sendmsg(sockfd, msg, flags);
|
||||
if (sent < 0) {
|
||||
PLOGE("sendmsg");
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
|
||||
int rec = recvmsg(sockfd, msg, flags);
|
||||
if (rec < 0) {
|
||||
PLOGE("recvmsg");
|
||||
}
|
||||
return rec;
|
||||
int rec = recvmsg(sockfd, msg, flags);
|
||||
if (rec < 0) {
|
||||
PLOGE("recvmsg");
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg) {
|
||||
errno = pthread_create(thread, attr, start_routine, arg);
|
||||
if (errno) {
|
||||
PLOGE("pthread_create");
|
||||
}
|
||||
return errno;
|
||||
void *(*start_routine) (void *), void *arg) {
|
||||
errno = pthread_create(thread, attr, start_routine, arg);
|
||||
if (errno) {
|
||||
PLOGE("pthread_create");
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
|
||||
int xstat(const char *pathname, struct stat *buf) {
|
||||
int ret = stat(pathname, buf);
|
||||
if (ret < 0) {
|
||||
PLOGE("stat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
int ret = stat(pathname, buf);
|
||||
if (ret < 0) {
|
||||
PLOGE("stat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xlstat(const char *pathname, struct stat *buf) {
|
||||
int ret = lstat(pathname, buf);
|
||||
if (ret < 0) {
|
||||
PLOGE("lstat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
int ret = lstat(pathname, buf);
|
||||
if (ret < 0) {
|
||||
PLOGE("lstat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xfstat(int fd, struct stat *buf) {
|
||||
int ret = fstat(fd, buf);
|
||||
if (ret < 0) {
|
||||
PLOGE("fstat %d", fd);
|
||||
}
|
||||
return ret;
|
||||
int ret = fstat(fd, buf);
|
||||
if (ret < 0) {
|
||||
PLOGE("fstat %d", fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xdup(int fd) {
|
||||
int ret = dup(fd);
|
||||
if (ret < 0) {
|
||||
PLOGE("dup");
|
||||
}
|
||||
return ret;
|
||||
int ret = dup(fd);
|
||||
if (ret < 0) {
|
||||
PLOGE("dup");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xdup2(int oldfd, int newfd) {
|
||||
int ret = dup2(oldfd, newfd);
|
||||
if (ret < 0) {
|
||||
PLOGE("dup2");
|
||||
}
|
||||
return ret;
|
||||
int ret = dup2(oldfd, newfd);
|
||||
if (ret < 0) {
|
||||
PLOGE("dup2");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xdup3(int oldfd, int newfd, int flags) {
|
||||
int ret = dup3(oldfd, newfd, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("dup3");
|
||||
}
|
||||
return ret;
|
||||
int ret = dup3(oldfd, newfd, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("dup3");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) {
|
||||
ssize_t ret = readlink(pathname, buf, bufsiz);
|
||||
if (ret < 0) {
|
||||
PLOGE("readlink %s", pathname);
|
||||
} else {
|
||||
buf[ret] = '\0';
|
||||
}
|
||||
return ret;
|
||||
ssize_t ret = readlink(pathname, buf, bufsiz);
|
||||
if (ret < 0) {
|
||||
PLOGE("readlink %s", pathname);
|
||||
} else {
|
||||
buf[ret] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) {
|
||||
// readlinkat() may fail on x86 platform, returning random value
|
||||
// instead of number of bytes placed in buf (length of link)
|
||||
// readlinkat() may fail on x86 platform, returning random value
|
||||
// instead of number of bytes placed in buf (length of link)
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
memset(buf, 0, bufsiz);
|
||||
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
|
||||
if (ret < 0) {
|
||||
PLOGE("readlinkat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
memset(buf, 0, bufsiz);
|
||||
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
|
||||
if (ret < 0) {
|
||||
PLOGE("readlinkat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
#else
|
||||
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
|
||||
if (ret < 0) {
|
||||
PLOGE("readlinkat %s", pathname);
|
||||
} else {
|
||||
buf[ret] = '\0';
|
||||
}
|
||||
return ret;
|
||||
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
|
||||
if (ret < 0) {
|
||||
PLOGE("readlinkat %s", pathname);
|
||||
} else {
|
||||
buf[ret] = '\0';
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int xsymlink(const char *target, const char *linkpath) {
|
||||
int ret = symlink(target, linkpath);
|
||||
if (ret < 0) {
|
||||
PLOGE("symlink %s->%s", target, linkpath);
|
||||
}
|
||||
return ret;
|
||||
int ret = symlink(target, linkpath);
|
||||
if (ret < 0) {
|
||||
PLOGE("symlink %s->%s", target, linkpath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xsymlinkat(const char *target, int newdirfd, const char *linkpath) {
|
||||
int ret = symlinkat(target, newdirfd, linkpath);
|
||||
if (ret < 0) {
|
||||
PLOGE("symlinkat %s->%s", target, linkpath);
|
||||
}
|
||||
return ret;
|
||||
int ret = symlinkat(target, newdirfd, linkpath);
|
||||
if (ret < 0) {
|
||||
PLOGE("symlinkat %s->%s", target, linkpath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xlinkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) {
|
||||
int ret = linkat(olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("linkat %s->%s", oldpath, newpath);
|
||||
}
|
||||
return ret;
|
||||
int ret = linkat(olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("linkat %s->%s", oldpath, newpath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmount(const char *source, const char *target,
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data) {
|
||||
int ret = mount(source, target, filesystemtype, mountflags, data);
|
||||
if (ret < 0) {
|
||||
PLOGE("mount %s->%s", source, target);
|
||||
}
|
||||
return ret;
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data) {
|
||||
int ret = mount(source, target, filesystemtype, mountflags, data);
|
||||
if (ret < 0) {
|
||||
PLOGE("mount %s->%s", source, target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xumount(const char *target) {
|
||||
int ret = umount(target);
|
||||
if (ret < 0) {
|
||||
PLOGE("umount %s", target);
|
||||
}
|
||||
return ret;
|
||||
int ret = umount(target);
|
||||
if (ret < 0) {
|
||||
PLOGE("umount %s", target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xumount2(const char *target, int flags) {
|
||||
int ret = umount2(target, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("umount2 %s", target);
|
||||
}
|
||||
return ret;
|
||||
int ret = umount2(target, flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("umount2 %s", target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xrename(const char *oldpath, const char *newpath) {
|
||||
int ret = rename(oldpath, newpath);
|
||||
if (ret < 0) {
|
||||
PLOGE("rename %s->%s", oldpath, newpath);
|
||||
}
|
||||
return ret;
|
||||
int ret = rename(oldpath, newpath);
|
||||
if (ret < 0) {
|
||||
PLOGE("rename %s->%s", oldpath, newpath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmkdir(const char *pathname, mode_t mode) {
|
||||
int ret = mkdir(pathname, mode);
|
||||
if (ret < 0 && errno != EEXIST) {
|
||||
PLOGE("mkdir %s %u", pathname, mode);
|
||||
}
|
||||
return ret;
|
||||
int ret = mkdir(pathname, mode);
|
||||
if (ret < 0 && errno != EEXIST) {
|
||||
PLOGE("mkdir %s %u", pathname, mode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmkdirs(const char *pathname, mode_t mode) {
|
||||
int ret = mkdirs(pathname, mode);
|
||||
if (ret < 0) {
|
||||
PLOGE("mkdirs %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
int ret = mkdirs(pathname, mode);
|
||||
if (ret < 0) {
|
||||
PLOGE("mkdirs %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmkdirat(int dirfd, const char *pathname, mode_t mode) {
|
||||
int ret = mkdirat(dirfd, pathname, mode);
|
||||
if (ret < 0 && errno != EEXIST) {
|
||||
PLOGE("mkdirat %s %u", pathname, mode);
|
||||
}
|
||||
return ret;
|
||||
int ret = mkdirat(dirfd, pathname, mode);
|
||||
if (ret < 0 && errno != EEXIST) {
|
||||
PLOGE("mkdirat %s %u", pathname, mode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *xmmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset) {
|
||||
void *ret = mmap(addr, length, prot, flags, fd, offset);
|
||||
if (ret == MAP_FAILED) {
|
||||
PLOGE("mmap");
|
||||
}
|
||||
return ret;
|
||||
int fd, off_t offset) {
|
||||
void *ret = mmap(addr, length, prot, flags, fd, offset);
|
||||
if (ret == MAP_FAILED) {
|
||||
PLOGE("mmap");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
|
||||
ssize_t ret = sendfile(out_fd, in_fd, offset, count);
|
||||
if (count != ret) {
|
||||
PLOGE("sendfile");
|
||||
}
|
||||
return ret;
|
||||
ssize_t ret = sendfile(out_fd, in_fd, offset, count);
|
||||
if (count != ret) {
|
||||
PLOGE("sendfile");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
pid_t xfork() {
|
||||
int ret = fork();
|
||||
if (ret < 0) {
|
||||
PLOGE("fork");
|
||||
}
|
||||
return ret;
|
||||
int ret = fork();
|
||||
if (ret < 0) {
|
||||
PLOGE("fork");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xpoll(struct pollfd *fds, nfds_t nfds, int timeout) {
|
||||
int ret = poll(fds, nfds, timeout);
|
||||
if (ret < 0) {
|
||||
PLOGE("poll");
|
||||
}
|
||||
return ret;
|
||||
int ret = poll(fds, nfds, timeout);
|
||||
if (ret < 0) {
|
||||
PLOGE("poll");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xinotify_init1(int flags) {
|
||||
int ret = inotify_init1(flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("inotify_init1");
|
||||
}
|
||||
return ret;
|
||||
int ret = inotify_init1(flags);
|
||||
if (ret < 0) {
|
||||
PLOGE("inotify_init1");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *xrealpath(const char *path, char *resolved_path) {
|
||||
char buf[PATH_MAX];
|
||||
char *ret = realpath(path, buf);
|
||||
if (ret == nullptr) {
|
||||
PLOGE("xrealpath");
|
||||
} else {
|
||||
strcpy(resolved_path, buf);
|
||||
}
|
||||
return ret;
|
||||
char buf[PATH_MAX];
|
||||
char *ret = realpath(path, buf);
|
||||
if (ret == nullptr) {
|
||||
PLOGE("xrealpath");
|
||||
} else {
|
||||
strcpy(resolved_path, buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmknod(const char *pathname, mode_t mode, dev_t dev) {
|
||||
int ret = mknod(pathname, mode, dev);
|
||||
if (ret < 0) {
|
||||
PLOGE("mknod");
|
||||
}
|
||||
return ret;
|
||||
int ret = mknod(pathname, mode, dev);
|
||||
if (ret < 0) {
|
||||
PLOGE("mknod");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ extern "C" void *xrealloc(void *ptr, size_t size);
|
||||
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags);
|
||||
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags);
|
||||
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg);
|
||||
void *(*start_routine) (void *), void *arg);
|
||||
int xstat(const char *pathname, struct stat *buf);
|
||||
int xlstat(const char *pathname, struct stat *buf);
|
||||
int xfstat(int fd, struct stat *buf);
|
||||
@@ -45,8 +45,8 @@ int xsymlink(const char *target, const char *linkpath);
|
||||
int xsymlinkat(const char *target, int newdirfd, const char *linkpath);
|
||||
int xlinkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags);
|
||||
int xmount(const char *source, const char *target,
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data);
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data);
|
||||
int xumount(const char *target);
|
||||
int xumount2(const char *target, int flags);
|
||||
int xrename(const char *oldpath, const char *newpath);
|
||||
|
Reference in New Issue
Block a user