💾 Archived View for gemini.rmf-dev.com › repo › Vaati › mz › files › d620cd9acbb98fff3d67864910c0424… captured on 2023-03-20 at 18:35:54. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

0 /*

1 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>

2 *

3 * Permission to use, copy, modify, and distribute this software for any

4 * purpose with or without fee is hereby granted, provided that the above

5 * copyright notice and this permission notice appear in all copies.

6 *

7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES

8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES

11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN

12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF

13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

14 */

15 #ifdef __linux__

16 #define _GNU_SOURCE

17 #else

18 #define _BSD_SOURCE

19 #endif

20 #include <stdio.h>

21 #include <stdlib.h>

22 #include <fcntl.h>

23 #include <errno.h>

24 #include <string.h>

25 #include <pwd.h>

26 #include <unistd.h>

27 #include <sys/stat.h>

28 #include <sys/types.h>

29 #include <fts.h>

30 #include "client.h"

31 #include "strlcpy.h"

32 #include "file.h"

33 #include "view.h"

34 #include "trash.h"

35 #include "util.h"

36

37 #define TRASH "/.trash"

38 #define ID_LENGTH 32

39

40 static int gethome(char *buf, size_t length) {

41

42 struct passwd *pw;

43 char *home;

44 int fd;

45

46 home = getenv("HOME");

47 if (home) {

48 fd = open(home, O_DIRECTORY);

49 if (fd > -1) {

50 close(fd);

51 return strlcpy(buf, home, length);

52 }

53 }

54

55 pw = getpwuid(geteuid());

56 if (!pw) return -1;

57 fd = open(pw->pw_dir, O_DIRECTORY);

58 if (fd < 0) {

59 close(fd);

60 return -1;

61 }

62 return strlcpy(buf, pw->pw_dir, length);

63 }

64

65 static int trash_path(char *path, size_t length) {

66

67 char buf[1024];

68

69 int len = gethome(buf, length);

70 if (len == -1 || len + sizeof(TRASH) >= length) goto clean;

71

72 len = strlcpy(path, buf, length);

73 strlcpy(&path[len], TRASH, sizeof(path) - length);

74

75 if (!strncmp(path, buf, length)) goto clean;

76

77 return 0;

78 clean: /* make sure we're not deleting a whole folder by accident */

79 memset(path, 0, length);

80 strlcpy(path, "/nonexistent/folder", sizeof(path));

81 return -1;

82 }

83

84 int trash_init() {

85 char path[PATH_MAX];

86 int home, trash;

87

88 if (gethome(V(path)) == -1) return -1;

89

90 home = open(path, O_DIRECTORY);

91 if (home < 0) goto fail;

92

93 trash = openat(home, ".trash", O_DIRECTORY);

94 if (trash > -1) {

95 close(home);

96 return trash;

97 }

98

99 if (mkdirat(home, ".trash", 0700)) goto fail;

100

101 trash = openat(home, ".trash", O_DIRECTORY);

102 if (trash < 0) goto fail;

103

104 return trash;

105 fail:

106 if (home > -1)

107 close(home);

108 return -1;

109 }

110

111 int trash_send(int fd, char *path, char *name) {

112

113 char buf[PATH_MAX * 2], id[ID_LENGTH + 1];

114 int info, len, error;

115

116 info = openat(client.trash, "info", O_WRONLY|O_CREAT|O_APPEND, 0600);

117 if (info < 0)

118 return -1;

119

120 do {

121 size_t i;

122 int try;

123

124 i = 0;

125 while (i < sizeof(id) - 1) {

126 id[i] = 'a' + rand() % 26;

127 i++;

128 }

129 id[sizeof(id) - 1] = '\0';

130

131 /* check if there's not already a file with that id */

132 try = openat(client.trash, id, O_RDONLY);

133 if (try < 0) break;

134 close(i);

135 } while (1);

136

137 trash_path(V(buf));

138 error = file_move(path, fd, name, client.trash, buf, id);

139 if (!error) {

140 len = snprintf(V(buf), "%s %s/%s\n", id, path, name);

141 error = -(write(info, buf, len) != len);

142 }

143 close(info);

144

145 return error;

146 }

147

148 int trash_clear() {

149

150 char path[PATH_MAX], cmd[PATH_MAX * 2];

151

152 if (trash_path(V(path))) return -1;

153 snprintf(V(cmd), "rm -r %s", path);

154 if (system(cmd)) return -1;

155

156 close(client.trash);

157 client.trash = trash_init();

158 if (client.trash < 0) return -1;

159

160 return 0;

161 }

162

163 int trash_restore(struct view *view) {

164

165 size_t i;

166 char path[PATH_MAX];

167 int error = 0;

168

169 if (view->fd != TRASH_FD) {

170 errno = EINVAL;

171 return -1;

172 }

173

174 if (trash_path(V(path))) return -1;

175

176 i = 0;

177 while (i < view->length) {

178

179 char src[PATH_MAX];

180 char id[ID_LENGTH + 1];

181 size_t j = i++;

182 int fd;

183

184 if (!view->entries[j].selected) continue;

185 memcpy(id, &((char*)view->other)[j * ID_LENGTH], ID_LENGTH);

186 id[ID_LENGTH] = '\0';

187 snprintf(V(src), "%s/%s", path, id);

188

189 /* check if file exist before using rename */

190 fd = open(view->entries[j].name, 0);

191 if (fd > -1) {

192 close(fd);

193 errno = EEXIST;

194 error = -1;

195 continue;

196 }

197

198 if (rename(src, view->entries[j].name)) {

199 char *name;

200 if (errno != EXDEV) return -1;

201 sstrcpy(src, view->entries[j].name);

202 name = strrchr(src, '/');

203 if (!name) return -1;

204 *name = '\0';

205 name++;

206 fd = open(src, O_DIRECTORY);

207 if (fd < 0) return -1;

208 if (file_move(path, client.trash, id, fd, src, name))

209 return -1;

210 }

211 view->entries[j].selected = -1;

212 }

213 return error;

214 }

215

216 int trash_refresh(struct view *view) {

217

218 void *next, *prev;

219 size_t i;

220 int fd, rewrite;

221

222 i = 0;

223 rewrite = 0;

224 while (i < view->length) {

225 switch (view->entries[i].selected) {

226 case -1:

227 rewrite = 1;

228 break;

229 case 1:

230 view->entries[i].selected = 0;

231 break;

232 }

233 i++;

234 }

235 if (!rewrite) return 0;

236

237 /* rewrite info file */

238 fd = openat(client.trash, "info", O_CREAT|O_WRONLY|O_TRUNC);

239 if (!fd) return -1;

240

241 i = 0;

242 while (i < view->length) {

243

244 char c;

245 size_t j = i++;

246

247 if (view->entries[j].selected == -1) continue;

248

249 write(fd, &((char*)view->other)[j * ID_LENGTH], ID_LENGTH);

250 c = ' ';

251 write(fd, &c, 1);

252 write(fd, view->entries[j].name,

253 strnlen(V(view->entries[j].name)));

254 c = '\n';

255 write(fd, &c, 1);

256 }

257 close(fd);

258

259 free(view->other);

260 free(view->entries);

261

262 next = view->next;

263 prev = view->prev;

264 trash_view(view);

265 view->next = next;

266 view->prev = prev;

267

268 return 0;

269 }

270

271 int trash_view(struct view* view) {

272

273 int fd;

274 size_t i;

275 char buf[PATH_MAX * 2];

276

277 PZERO(view);

278 sstrcpy(view->path, "Trash");

279 view->fd = TRASH_FD;

280

281 fd = openat(client.trash, "info", O_RDONLY);

282 if (fd < 0) return 0;

283

284 i = 0;

285 while (i < sizeof(buf)) {

286

287 void *ptr;

288 char id[ID_LENGTH];

289 char c;

290 size_t j;

291

292 j = read(fd, V(id));

293 if (!j) { /* success : end of file */

294 close(fd);

295 return 0;

296 }

297 if (j != sizeof(id)) break;

298

299 j = 0;

300 while (j < sizeof(id)) {

301 if (id[j] > 'z' || id[j] < 'a') break;

302 j++;

303 }

304 if (j != sizeof(id)) break;

305

306 if (read(fd, &c, 1) != 1 || c != ' ') break;

307

308 j = 0;

309 while (j < sizeof(buf)) {

310 if (read(fd, &c, 1) != 1) break;

311 if (c == '\n') {

312 buf[j] = 0;

313 break;

314 }

315 buf[j] = c;

316 j++;

317 }

318

319 ptr = realloc(view->entries, sizeof(struct entry) * (i + 1));

320 if (!ptr) break;

321 view->entries = ptr;

322 RZERO(view->entries[i]);

323

324 sstrcpy(view->entries[i].name, buf);

325 view->entries[i].type = 0;

326 view->length = i + 1;

327

328 ptr = realloc(view->other, (i + 1) * ID_LENGTH + 1);

329 if (!ptr) break;

330 view->other = ptr;

331 memcpy(&((char*)view->other)[i * ID_LENGTH], V(id));

332

333 i++;

334 }

335

336 free(view->other);

337 free(view->entries);

338 close(fd);

339 return -1;

340 }

341