]>
Commit | Line | Data |
---|---|---|
1 | /* Cydia - iPhone UIKit Front-End for Debian APT | |
2 | * Copyright (C) 2008-2015 Jay Freeman (saurik) | |
3 | */ | |
4 | ||
5 | /* GNU General Public License, Version 3 {{{ */ | |
6 | /* | |
7 | * Cydia is free software: you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published | |
9 | * by the Free Software Foundation, either version 3 of the License, | |
10 | * or (at your option) any later version. | |
11 | * | |
12 | * Cydia is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Cydia. If not, see <http://www.gnu.org/licenses/>. | |
19 | **/ | |
20 | /* }}} */ | |
21 | ||
22 | #include <fcntl.h> | |
23 | #include <dirent.h> | |
24 | #include <unistd.h> | |
25 | #include <stdio.h> | |
26 | #include <errno.h> | |
27 | #include <string.h> | |
28 | #include <sys/stat.h> | |
29 | ||
30 | #define _syscall(expr) ({ typeof(expr) _value; for (;;) { \ | |
31 | _value = (expr); \ | |
32 | if ((long) _value != -1) \ | |
33 | break; \ | |
34 | if (errno != EINTR) { \ | |
35 | perror(#expr); \ | |
36 | return -1; \ | |
37 | } \ | |
38 | } _value; }) | |
39 | ||
40 | extern "C" int __getdirentries64(int, char *, int, long *); | |
41 | ||
42 | enum Recurse { | |
43 | RecurseYes, | |
44 | RecurseNo, | |
45 | RecurseMaybe, | |
46 | }; | |
47 | ||
48 | struct File { | |
49 | int fd_; | |
50 | ||
51 | File(int fd); | |
52 | ~File(); | |
53 | ||
54 | operator int() const; | |
55 | }; | |
56 | ||
57 | File::File(int fd) : | |
58 | fd_(fd) | |
59 | { | |
60 | } | |
61 | ||
62 | File::~File() { | |
63 | close(fd_); | |
64 | } | |
65 | ||
66 | File::operator int() const { | |
67 | return fd_; | |
68 | } | |
69 | ||
70 | static int setnsfpn(const char *path, size_t before, Recurse recurse) { | |
71 | File fd(_syscall(open_dprotected_np(path, O_RDONLY | O_SYMLINK, 0, O_DP_GETRAWENCRYPTED))); | |
72 | ||
73 | if (recurse == RecurseMaybe) { | |
74 | struct stat stat; | |
75 | _syscall(fstat(fd, &stat)); | |
76 | switch (stat.st_mode & S_IFMT) { | |
77 | case S_IFLNK: | |
78 | return 0; | |
79 | default: | |
80 | return -1; | |
81 | ||
82 | case S_IFDIR: | |
83 | recurse = RecurseYes; | |
84 | break; | |
85 | case S_IFREG: | |
86 | recurse = RecurseNo; | |
87 | break; | |
88 | } | |
89 | } | |
90 | ||
91 | int mode(_syscall(fcntl(fd, F_GETPROTECTIONCLASS))); | |
92 | if (mode == 4) | |
93 | return 0; | |
94 | ||
95 | if (recurse == RecurseYes) | |
96 | for (long address(0);;) { | |
97 | char buffer[4096]; | |
98 | int size(_syscall(__getdirentries64(fd, buffer, sizeof(buffer), &address))); | |
99 | if (size == 0) | |
100 | break; | |
101 | ||
102 | const char *next(buffer), *stop(next + size); | |
103 | while (next != stop) { | |
104 | const dirent *dir(reinterpret_cast<const dirent *>(next)); | |
105 | const char *name(dir->d_name); | |
106 | size_t after(strlen(name)); | |
107 | ||
108 | if (dir->d_ino == 0); | |
109 | else if (after == 1 && name[0] == '.'); | |
110 | else if (after == 2 && name[0] == '.' && name[1] == '.'); | |
111 | else { | |
112 | size_t both(before + 1 + after); | |
113 | char sub[both + 1]; | |
114 | memcpy(sub, path, before); | |
115 | sub[before] = '/'; | |
116 | memcpy(sub + before + 1, name, after); | |
117 | sub[both] = '\0'; | |
118 | ||
119 | switch (dir->d_type) { | |
120 | case DT_LNK: | |
121 | break; | |
122 | default: | |
123 | return -1; | |
124 | ||
125 | case DT_DIR: | |
126 | if (setnsfpn(sub, both, RecurseYes) != 0) | |
127 | return -1; | |
128 | break; | |
129 | case DT_REG: | |
130 | if (setnsfpn(sub, both, RecurseNo) != 0) | |
131 | return -1; | |
132 | break; | |
133 | } | |
134 | } | |
135 | ||
136 | next += dir->d_reclen; | |
137 | } | |
138 | } | |
139 | ||
140 | _syscall(fcntl(fd, F_SETPROTECTIONCLASS, 4)); | |
141 | return 0; | |
142 | } | |
143 | ||
144 | int main(int argc, const char *argv[]) { | |
145 | return setnsfpn(argv[1], strlen(argv[1]), RecurseMaybe); | |
146 | } |