💾 Archived View for gemini.rmf-dev.com › repo › Vaati › mz › files › 13fc50b575d7d90289b537f3ca45763… captured on 2023-09-08 at 16:43:45. Gemini links have been rewritten to link to archived content

View Raw

More Information

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

Go Back

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 <dirent.h>

21 #include <unistd.h>

22 #include <ctype.h>

23 #include <fcntl.h>

24 #include <stdlib.h>

25 #include <string.h>

26 #include <stdint.h>

27 #include <errno.h>

28 #include <fcntl.h>

29 #include <fts.h>

30 #include <stdio.h>

31 #include <sys/stat.h>

32 #include <sys/types.h>

33 #include "termbox.h"

34 #include "view.h"

35 #include "file.h"

36 #include "strlcpy.h"

37 #include "client.h"

38 #include "util.h"

39

40 int file_init(struct view *view, const char* path) {

41

42 PZERO(view);

43

44 if (path)

45 STRCPY(view->path, path);

46 else if (view->path != getcwd(V(view->path)))

47 return -1;

48

49 view->fd = open(view->path, O_DIRECTORY);

50 if (view->fd < 0)

51 return -1;

52

53 return 0;

54 }

55

56 int file_up(struct view *view) {

57 return file_cd(view, "..");

58 }

59

60 int file_cd(struct view *view, const char *path) {

61

62 char buf[PATH_MAX];

63 int fd, len, back;

64

65 if (!strcmp(path, ".")) return 0;

66

67 len = STRCPY(buf, view->path);

68 back = 0;

69 if (!strcmp(path, "..")) {

70 if (!strcmp(view->path, "/")) {

71 return 0;

72 }

73 len--;

74 while (len >= 0) {

75 if (buf[len] == '/') {

76 buf[AZ(len)] = '\0';

77 back = 1;

78 break;

79 }

80 len--;

81 }

82 if (!back) return 0;

83 } else {

84 if (buf[AZ(len) - 1] != '/') {

85 buf[len] = '/';

86 len++;

87 }

88 strlcpy(&buf[len], path, sizeof(buf) - len);

89 }

90

91 fd = open(buf, O_DIRECTORY);

92 if (fd < 0) return -1;

93 close(view->fd);

94 view->fd = fd;

95 fchdir(fd);

96 STRCPY(view->path, buf);

97 view->selected = 0;

98 return 0;

99 }

100

101 void file_free(struct view *view) {

102 size_t i;

103 for (i = 0; i < view->length; i++) {

104 free(view->entries[i].other);

105 view->entries[i].other = NULL;

106 }

107 free(view->entries);

108 view->length = 0;

109 view->entries = NULL;

110 }

111

112 int file_sort(const void* a, const void* b)

113 {

114 struct entry *first = (struct entry*)a;

115 struct entry *second = (struct entry*)b;

116 int i = 0, j = 0;

117

118 if (first->type != second->type) {

119 if (first->type == DT_DIR) return -1;

120 if (second->type == DT_DIR) return 1;

121 }

122 while (1) {

123 uint32_t c1, c2;

124 do {

125 if (!first->name[i]) return 0;

126 i += tb_utf8_char_to_unicode(&c1, &first->name[i]);

127 } while (c1 == ' ' || c1 == '\t');

128 do {

129 if (!second->name[j]) return 0;

130 j += tb_utf8_char_to_unicode(&c2, &second->name[j]);

131 } while (c2 == ' ' || c2 == '\t');

132 c1 = tolower(c1);

133 c2 = tolower(c2);

134 if (c1 != c2)

135 return c1 < c2 ? -1 : 1;

136 }

137 return 0;

138 }

139

140 int file_reload(struct view *view) {

141 close(view->fd);

142 view->fd = open(view->path, O_DIRECTORY);

143 if (view->fd < 0) return -1;

144 return file_ls(view);

145 }

146

147 int file_ls(struct view *view) {

148 struct dirent *entry;

149 DIR *dp;

150 int length, i, fd;

151

152 fd = dup(view->fd);

153 dp = fdopendir(fd);

154 if (dp == NULL)

155 return -1;

156

157 length = 0;

158 while ((entry = readdir(dp))) {

159 if (!view->showhidden && entry->d_name[0] == '.')

160 continue;

161 if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))

162 length++;

163 }

164 if (length == 0) {

165 closedir(dp);

166 file_free(view);

167 return 0;

168 }

169

170 rewinddir(dp);

171 file_free(view);

172 view->entries = calloc(length, sizeof(struct entry));

173 i = 0;

174 while ((entry = readdir(dp))) {

175 if (!strcmp(entry->d_name, ".") ||

176 !strcmp(entry->d_name, ".."))

177 continue;

178 if (!view->showhidden && entry->d_name[0] == '.')

179 continue;

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

181 strlcpy(view->entries[i].name, entry->d_name,

182 sizeof(view->entries[i].name));

183

184 #ifndef sun

185 if (entry->d_type == DT_LNK || entry->d_type == DT_UNKNOWN) {

186 #endif

187 struct stat buf;

188 if (!fstatat(view->fd, entry->d_name, &buf, 0)) {

189 view->entries[i].type = S_ISDIR(buf.st_mode) ?

190 DT_DIR : DT_REG;

191 } else {

192 view->entries[i].type = DT_REG;

193 }

194 #ifndef sun

195 } else

196 view->entries[i].type = entry->d_type;

197 #endif

198 i++;

199 }

200

201 qsort(view->entries, length, sizeof(struct entry), file_sort);

202

203 closedir(dp);

204 close(fd);

205 view->length = length;

206 view->scroll = 0;

207 lseek(view->fd, 0, SEEK_SET);

208 return 0;

209 }

210

211 int file_select(struct view *view, const char *path) {

212 size_t i = 0;

213 while (i < view->length) {

214 if (!strncmp(view->entries[i].name, path,

215 sizeof(view->entries[i].name))) {

216 view->selected = i;

217 return 0;

218 }

219 i++;

220 }

221 return -1;

222 }

223

224 int file_move_entry(struct view *view, struct entry *entry) {

225

226 int fd = open(client.copy_path, O_DIRECTORY);

227 if (fd < 0) return -1;

228 return file_move(client.copy_path, fd, entry->name,

229 view->fd, view->path, entry->name);

230 }

231

232 #ifdef __linux__

233 #define lseek lseek64

234 #define off_t off64_t

235 #endif

236

237 #if !defined(__linux__) && !defined(__FreeBSD__)

238 #define NO_COPY_FILE_RANGE

239 #endif

240

241 int file_copy_entry(struct view *view, struct entry *entry) {

242

243 struct stat st;

244 int fd, dstfd, srcfd;

245

246 fd = openat(view->fd, entry->name, 0);

247 if (fd > -1) {

248 close(fd);

249 errno = EEXIST;

250 return -1;

251 }

252

253 fd = open(client.copy_path, O_DIRECTORY);

254 if (fd < 0) return -1;

255 srcfd = openat(fd, entry->name, O_RDONLY);

256 close(fd);

257 if (srcfd < 0) return -1;

258

259 if (fstat(srcfd, &st)) {

260 close(srcfd);

261 return -1;

262 }

263

264 if (S_ISDIR(st.st_mode)) {

265 char buf[PATH_MAX];

266 snprintf(V(buf), "cp -r \"%s/%s\" \"%s\"", client.copy_path,

267 client.copy->name, view->path);

268 return system(buf);

269 }

270

271 dstfd = openat(view->fd, entry->name, O_WRONLY|O_CREAT, st.st_mode);

272 if (dstfd < 0) return -1;

273

274 return file_copy(srcfd, dstfd, 0);

275 }

276

277 int file_copy(int src, int dst, int usebuf) {

278

279 size_t length, ret;

280

281 #ifdef NO_COPY_FILE_RANGE

282 if (usebuf == -1) return -1;

283 #endif

284

285 length = lseek(src, 0, SEEK_END);

286 if (length == (size_t)-1 ||

287 lseek(src, 0, SEEK_SET) == (off_t)-1) {

288 close(dst);

289 close(src);

290 return -1;

291 }

292

293 ret = 0;

294 while (1) {

295 ssize_t i;

296 char buf[4096];

297 #ifndef NO_COPY_FILE_RANGE

298 if (usebuf) {

299 #endif

300 i = read(src, buf, sizeof(buf));

301 if (i <= 0) break;

302 write(dst, buf, i);

303 #ifndef NO_COPY_FILE_RANGE

304 } else {

305 i = copy_file_range(src, 0, dst, 0, length - ret, 0);

306 if (i <= 0) break;

307 }

308 #endif

309 ret += i;

310 }

311

312 #ifndef NO_COPY_FILE_RANGE

313 /* retry without copy_file_range if the operation failed */

314 if (ret != length && !usebuf) return file_copy(src, dst, 1);

315 #endif

316

317 close(dst);

318 close(src);

319 if (ret != length) {

320 return -1;

321 }

322

323 return 0;

324 }

325

326 int file_move(const char *oldpath, int srcdir, const char *oldname,

327 int dstdir, const char *newpath, const char *newname) {

328

329 int error, fd;

330

331 fd = openat(dstdir, newname, 0);

332 if (fd > -1) {

333 errno = EEXIST;

334 close(fd);

335 return -1;

336 }

337

338 error = renameat(srcdir, oldname, dstdir, newname);

339 /* EXDEV : when trying to move a file to another file system */

340 if (error && errno == EXDEV) {

341 int src, dst;

342 struct stat st;

343

344 if (fstatat(srcdir, oldname, &st, 0)) return -1;

345 /* use a shell command instead of recursively copying files */

346 if (S_ISDIR(st.st_mode)) {

347 char buf[PATH_MAX * 3];

348 snprintf(V(buf), "mv \"%s/%s\" \"%s/%s\"",

349 oldpath, oldname,

350 newpath, newname);

351 return system(buf);

352 }

353

354 src = openat(srcdir, oldname, O_RDONLY);

355 if (src < 0) return -1;

356 dst = openat(dstdir, newname, O_WRONLY|O_CREAT, st.st_mode);

357 if (dst < 0) {

358 close(src);

359 return -1;

360 }

361 if (!file_copy(src, dst, 1)) {

362 char buf[2048];

363 snprintf(V(buf), "%s/%s", oldpath, oldname);

364 if (!remove(buf)) error = 0;

365 }

366 close(src);

367 close(dst);

368 }

369 return error;

370 }

371