💾 Archived View for gemini.rmf-dev.com › repo › Vaati › mz › files › bf77f035f6d90fbc62cc179e733aab3… captured on 2023-03-20 at 18:35:19. 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 <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 sstrcpy(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 = sstrcpy(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 sstrcpy(view->path, buf);

97 view->selected = 0;

98 return 0;

99 }

100

101 void file_free(struct view *view) {

102 free(view->entries);

103 view->length = 0;

104 view->entries = NULL;

105 }

106

107 int sort(const void* a, const void* b)

108 {

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

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

111 int i = 0, j = 0;

112

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

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

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

116 }

117 while (1) {

118 uint32_t c1, c2;

119 do {

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

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

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

123 do {

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

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

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

127 c1 = tolower(c1);

128 c2 = tolower(c2);

129 if (c1 != c2)

130 return c1 < c2 ? -1 : 1;

131 }

132 return 0;

133 }

134

135 int file_reload(struct view *view) {

136 close(view->fd);

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

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

139 return file_ls(view);

140 }

141

142 int file_ls(struct view *view) {

143 struct dirent *entry;

144 DIR *dp;

145 int length, i, fd;

146

147 fd = dup(view->fd);

148 dp = fdopendir(fd);

149 if (dp == NULL)

150 return -1;

151

152 length = 0;

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

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

155 continue;

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

157 length++;

158 }

159 if (length == 0) {

160 closedir(dp);

161 file_free(view);

162 return 0;

163 }

164

165 rewinddir(dp);

166 file_free(view);

167 view->entries = malloc(sizeof(struct entry) * length);

168 i = 0;

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

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

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

172 continue;

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

174 continue;

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

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

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

178

179 #ifndef sun

180 if (entry->d_type == DT_LNK) {

181 #endif

182 struct stat buf;

183 view->entries[i].type =

184 fstatat(view->fd, entry->d_name, &buf, 0);

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

186 DT_DIR : DT_REG;

187 #ifndef sun

188 } else

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

190 #endif

191 i++;

192 }

193

194 qsort(view->entries, length, sizeof(struct entry), sort);

195

196 closedir(dp);

197 close(fd);

198 view->length = length;

199 view->scroll = 0;

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

201 return 0;

202 }

203

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

205 size_t i = 0;

206 while (i < view->length) {

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

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

209 view->selected = i;

210 return 0;

211 }

212 i++;

213 }

214 return -1;

215 }

216

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

218

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

220 if (fd < 0) return -1;

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

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

223 }

224

225 #ifdef __linux__

226 #define lseek lseek64

227 #define off_t off64_t

228 #endif

229

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

231 #define NO_COPY_FILE_RANGE

232 #endif

233

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

235

236 struct stat st;

237 int fd, dstfd, srcfd;

238

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

240 if (fd > -1) {

241 close(fd);

242 errno = EEXIST;

243 return -1;

244 }

245

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

247 if (fd < 0) return -1;

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

249 close(fd);

250 if (srcfd < 0) return -1;

251

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

253 close(srcfd);

254 return -1;

255 }

256

257 if (S_ISDIR(st.st_mode)) {

258 char buf[PATH_MAX];

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

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

261 return system(buf);

262 }

263

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

265 if (dstfd < 0) return -1;

266

267 return file_copy(srcfd, dstfd, 0);

268 }

269

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

271

272 size_t length, ret;

273

274 #ifdef NO_COPY_FILE_RANGE

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

276 #endif

277

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

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

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

281 close(dst);

282 close(src);

283 return -1;

284 }

285

286 ret = 0;

287 while (1) {

288 ssize_t i;

289 char buf[4096];

290 #ifndef NO_COPY_FILE_RANGE

291 if (usebuf) {

292 #endif

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

294 if (i <= 0) break;

295 write(dst, buf, i);

296 #ifndef NO_COPY_FILE_RANGE

297 } else {

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

299 if (i <= 0) break;

300 }

301 #endif

302 ret += i;

303 }

304

305 #ifndef NO_COPY_FILE_RANGE

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

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

308 #endif

309

310 close(dst);

311 close(src);

312 if (ret != length) {

313 return -1;

314 }

315

316 return 0;

317 }

318

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

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

321

322 int error, fd;

323

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

325 if (fd > -1) {

326 errno = EEXIST;

327 close(fd);

328 return -1;

329 }

330

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

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

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

334 int src, dst;

335 struct stat st;

336

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

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

339 if (S_ISDIR(st.st_mode)) {

340 char buf[PATH_MAX * 3];

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

342 oldpath, oldname,

343 newpath, newname);

344 return system(buf);

345 }

346

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

348 if (src < 0) return -1;

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

350 if (dst < 0) {

351 close(src);

352 return -1;

353 }

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

355 char buf[2048];

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

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

358 }

359 close(src);

360 close(dst);

361 }

362 return error;

363 }

364