summaryrefslogtreecommitdiff
path: root/setnsfpn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'setnsfpn.cpp')
-rw-r--r--setnsfpn.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/setnsfpn.cpp b/setnsfpn.cpp
new file mode 100644
index 0000000..6dc80c7
--- /dev/null
+++ b/setnsfpn.cpp
@@ -0,0 +1,158 @@
+/* Cydia - iPhone UIKit Front-End for Debian APT
+ * Copyright (C) 2008-2014 Jay Freeman (saurik)
+*/
+
+/* GNU General Public License, Version 3 {{{ */
+/*
+ * Cydia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * Cydia is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cydia. If not, see <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#define _syscall(expr) ({ typeof(expr) _value; for (;;) { \
+ _value = (expr); \
+ if ((long) _value != -1) \
+ break; \
+ if (errno != EINTR) { \
+ perror(#expr); \
+ return -1; \
+ } \
+} _value; })
+
+int $getdirentries(int, char *, int, long *) __asm("_getdirentries");
+
+struct $dirent {
+ __uint32_t d_ino;
+ __uint16_t d_reclen;
+ __uint8_t d_type;
+ __uint8_t d_namlen;
+ char d_name[__DARWIN_MAXNAMLEN + 1];
+};
+
+#define getdirentries $getdirentries
+#define dirent $dirent
+
+enum Recurse {
+ RecurseYes,
+ RecurseNo,
+ RecurseMaybe,
+};
+
+struct File {
+ int fd_;
+
+ File(int fd);
+ ~File();
+
+ operator int() const;
+};
+
+File::File(int fd) :
+ fd_(fd)
+{
+}
+
+File::~File() {
+ close(fd_);
+}
+
+File::operator int() const {
+ return fd_;
+}
+
+static int setnsfpn(const char *path, size_t before, Recurse recurse) {
+ File fd(_syscall(open_dprotected_np(path, O_RDONLY | O_SYMLINK, 0, O_DP_GETRAWENCRYPTED)));
+
+ if (recurse == RecurseMaybe) {
+ struct stat stat;
+ _syscall(fstat(fd, &stat));
+ switch (stat.st_mode & S_IFMT) {
+ case S_IFLNK:
+ return 0;
+ default:
+ return -1;
+
+ case S_IFDIR:
+ recurse = RecurseYes;
+ break;
+ case S_IFREG:
+ recurse = RecurseNo;
+ break;
+ }
+ }
+
+ int mode(_syscall(fcntl(fd, F_GETPROTECTIONCLASS)));
+ if (mode != -1 && mode != 4) {
+ if (recurse == RecurseYes) {
+ long address(0);
+
+ for (;;) {
+ char buffer[4096];
+ int size(_syscall(getdirentries(fd, buffer, sizeof(buffer), &address)));
+ if (size == 0)
+ break;
+
+ const char *next(buffer), *stop(next + size);
+ while (next != stop) {
+ const dirent *dir(reinterpret_cast<const dirent *>(next));
+ const char *name(dir->d_name);
+ size_t after(strlen(name));
+
+ if (false);
+ else if (after == 1 && name[0] == '.');
+ else if (after == 2 && name[0] == '.' && name[1] == '.');
+ else {
+ size_t both(before + 1 + after);
+ char sub[both + 1];
+ memcpy(sub, path, before);
+ sub[before] = '/';
+ memcpy(sub + before + 1, name, after);
+ sub[both] = '\0';
+
+ switch (dir->d_type) {
+ case DT_LNK:
+ break;
+ default:
+ return -1;
+
+ case DT_DIR:
+ setnsfpn(sub, both, RecurseYes);
+ break;
+ case DT_REG:
+ setnsfpn(sub, both, RecurseNo);
+ break;
+ }
+ }
+
+ next += dir->d_reclen;
+ }
+ }
+ }
+
+ _syscall(fcntl(fd, F_SETPROTECTIONCLASS, 4));
+ }
+
+ return 0;
+}
+
+int main(int argc, const char *argv[]) {
+ return setnsfpn(argv[1], strlen(argv[1]), RecurseMaybe);
+}