]>
Commit | Line | Data |
---|---|---|
e40620ab | 1 | /* Cydia - iPhone UIKit Front-End for Debian APT |
4c66fad9 | 2 | * Copyright (C) 2008-2015 Jay Freeman (saurik) |
e40620ab JF |
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) ({ decltype(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 bool DiskUsage(size_t &total, 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 | struct stat stat; | |
74 | _syscall(fstat(fd, &stat)); | |
75 | total += stat.st_blocks * 512; | |
76 | ||
77 | if (recurse == RecurseMaybe) | |
78 | switch (stat.st_mode & S_IFMT) { | |
79 | case S_IFLNK: | |
80 | return true; | |
81 | default: | |
82 | return false; | |
83 | ||
84 | case S_IFDIR: | |
85 | recurse = RecurseYes; | |
86 | break; | |
87 | case S_IFREG: | |
88 | recurse = RecurseNo; | |
89 | break; | |
90 | } | |
91 | ||
92 | if (recurse == RecurseNo) { | |
93 | } else for (long address(0);;) { | |
94 | char buffer[4096]; | |
95 | int size(_syscall(__getdirentries64(fd, buffer, sizeof(buffer), &address))); | |
96 | if (size == 0) | |
97 | break; | |
98 | ||
99 | const char *next(buffer), *stop(next + size); | |
100 | while (next != stop) { | |
101 | const dirent *dir(reinterpret_cast<const dirent *>(next)); | |
102 | const char *name(dir->d_name); | |
103 | size_t after(strlen(name)); | |
104 | ||
105 | if (dir->d_ino == 0); | |
106 | else if (after == 1 && name[0] == '.'); | |
107 | else if (after == 2 && name[0] == '.' && name[1] == '.'); | |
108 | else { | |
109 | size_t both(before + 1 + after); | |
110 | char sub[both + 1]; | |
111 | memcpy(sub, path, before); | |
112 | sub[before] = '/'; | |
113 | memcpy(sub + before + 1, name, after); | |
114 | sub[both] = '\0'; | |
115 | ||
116 | switch (dir->d_type) { | |
117 | case DT_DIR: | |
118 | if (!DiskUsage(total, sub, both, RecurseYes)) | |
119 | return false; | |
120 | break; | |
121 | ||
122 | case DT_LNK: | |
123 | case DT_REG: | |
124 | if (!DiskUsage(total, sub, both, RecurseNo)) | |
125 | return false; | |
126 | break; | |
127 | ||
128 | default: | |
129 | return false; | |
130 | } | |
131 | } | |
132 | ||
133 | next += dir->d_reclen; | |
134 | } | |
135 | } | |
136 | ||
137 | return true; | |
138 | } | |
139 | ||
140 | ssize_t DiskUsage(const char *path) { | |
141 | size_t total(0); | |
142 | if (!DiskUsage(total, path, strlen(path), RecurseMaybe)) | |
143 | return -1; | |
144 | return total; | |
145 | } |