Retry only for https protocol
[elinks.git] / src / util / file.c
blob90882eed24efd4bcc6b462d8b8861b114a7d0c42
1 /** File utilities
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/stat.h> /* OS/2 needs this after sys/types.h */
15 #ifdef HAVE_DIRENT_H
16 #include <dirent.h> /* OS/2 needs this after sys/types.h */
17 #endif
18 #ifdef HAVE_FCNTL_H
19 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
20 #endif
21 #ifdef HAVE_PWD_H
22 #include <pwd.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
28 #ifdef TIME_WITH_SYS_TIME
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32 #ifdef HAVE_TIME_H
33 #include <time.h>
34 #endif
35 #else
36 #if defined(TM_IN_SYS_TIME) && defined(HAVE_SYS_TIME_H)
37 #include <sys/time.h>
38 #elif defined(HAVE_TIME_H)
39 #include <time.h>
40 #endif
41 #endif
43 #include "elinks.h"
45 #include "osdep/osdep.h"
46 #include "util/conv.h"
47 #include "util/error.h"
48 #include "util/file.h"
49 #include "util/memory.h"
50 #include "util/string.h"
53 /* Not that these two would be so useful for portability (they are ANSI C) but
54 * they encapsulate the lowlevel stuff (need for <unistd.h>) nicely. */
56 int
57 file_exists(const unsigned char *filename)
59 #ifdef HAVE_ACCESS
60 return access(filename, F_OK) >= 0;
61 #else
62 struct stat buf;
64 return stat(filename, &buf) >= 0;
65 #endif
68 int
69 file_can_read(const unsigned char *filename)
71 #ifdef HAVE_ACCESS
72 return access(filename, R_OK) >= 0;
73 #else
74 FILE *f = fopen(filename, "rb");
75 int ok = !!f;
77 if (f) fclose(f);
78 return ok;
79 #endif
82 int
83 file_is_dir(const unsigned char *filename)
85 struct stat st;
87 if (stat(filename, &st))
88 return 0;
90 return S_ISDIR(st.st_mode);
93 unsigned char *
94 get_filename_position(unsigned char *filename)
96 unsigned char *pos;
98 assert(filename);
99 if_assert_failed return NULL;
101 for (pos = filename; *pos; pos++)
102 if (dir_sep(*pos)) filename = pos + 1;
104 return filename;
107 unsigned char *
108 expand_tilde(unsigned char *filename)
110 struct string file;
112 if (!init_string(&file)) return NULL;
114 if (filename[0] == '~') {
115 if (!filename[1] || dir_sep(filename[1])) {
116 unsigned char *home = getenv("HOME");
118 if (home) {
119 add_to_string(&file, home);
120 filename++;
122 #ifdef HAVE_GETPWNAM
123 } else {
124 struct passwd *passwd = NULL;
125 unsigned char *user = filename + 1;
126 int userlen = 0;
128 while (user[userlen] && !dir_sep(user[userlen]))
129 userlen++;
131 user = memacpy(user, userlen);
132 if (user) {
133 passwd = getpwnam(user);
134 mem_free(user);
137 if (passwd && passwd->pw_dir) {
138 add_to_string(&file, passwd->pw_dir);
139 filename += 1 + userlen;
141 #endif
145 add_to_string(&file, filename);
147 return file.source;
150 unsigned char *
151 get_unique_name(unsigned char *fileprefix)
153 unsigned char *file = fileprefix;
154 int fileprefixlen = strlen(fileprefix);
155 int memtrigger = 1;
156 int suffix = 1;
157 int digits = 0;
159 while (file_exists(file)) {
160 if (!(suffix < memtrigger)) {
161 if (suffix >= 10000)
162 INTERNAL("Too big suffix in get_unique_name().");
163 memtrigger *= 10;
164 digits++;
166 if (file != fileprefix) mem_free(file);
167 file = mem_alloc(fileprefixlen + 2 + digits);
168 if (!file) return NULL;
170 memcpy(file, fileprefix, fileprefixlen);
171 file[fileprefixlen] = '.';
174 longcat(&file[fileprefixlen + 1], NULL, suffix, digits + 1, 0);
175 suffix++;
178 return file;
181 unsigned char *
182 get_tempdir_filename(unsigned char *name)
184 unsigned char *tmpdir = getenv("TMPDIR");
186 if (!tmpdir || !*tmpdir) tmpdir = getenv("TMP");
187 if (!tmpdir || !*tmpdir) tmpdir = getenv("TEMPDIR");
188 if (!tmpdir || !*tmpdir) tmpdir = getenv("TEMP");
189 if (!tmpdir || !*tmpdir) tmpdir = "/tmp";
191 return straconcat(tmpdir, "/", name, (unsigned char *) NULL);
194 unsigned char *
195 file_read_line(unsigned char *line, size_t *size, FILE *file, int *lineno)
197 size_t offset = 0;
199 if (!line) {
200 line = mem_alloc(MAX_STR_LEN);
201 if (!line)
202 return NULL;
204 *size = MAX_STR_LEN;
207 while (fgets(line + offset, *size - offset, file)) {
208 unsigned char *linepos = strchr((const char *)(line + offset), '\n');
210 if (!linepos) {
211 /* Test if the line buffer should be increase because
212 * it was continued and could not fit. */
213 unsigned char *newline;
214 int next = getc(file);
216 if (next == EOF) {
217 /* We are on the last line. */
218 (*lineno)++;
219 return line;
222 /* Undo our dammage */
223 ungetc(next, file);
224 offset = *size - 1;
225 *size += MAX_STR_LEN;
227 newline = mem_realloc(line, *size);
228 if (!newline)
229 break;
230 line = newline;
231 continue;
234 /* A whole line was read. Fetch next into the buffer if
235 * the line is 'continued'. */
236 (*lineno)++;
238 while (line < linepos && isspace(*linepos))
239 linepos--;
241 if (*linepos != '\\') {
242 *(linepos + 1) = '\0';
243 return line;
245 offset = linepos - line - 1;
248 mem_free_if(line);
249 return NULL;
253 /* Some mkstemp() implementations do not set safe permissions,
254 * so it may result in temporary files readable by all users.
255 * This may be a problem when textarea fields are edited through
256 * an external editor (see src/viewer/text/textarea.c).
258 * From 2001-12-23 mkstemp(3) gnu man page:
260 * ...
261 * The file is then created with mode read/write and permissions 0666
262 * (glibc 2.0.6 and earlier), 0600 (glibc 2.0.7 and later).
263 * ...
265 * NOTES:
266 * The old behaviour (creating a file with mode 0666) may be a security
267 * risk, especially since other Unix flavours use 0600, and somebody
268 * might overlook this detail when porting programs.
269 * More generally, the POSIX specification does not say anything
270 * about file modes, so the application should make sure its umask is
271 * set appropriately before calling mkstemp.
274 safe_mkstemp(unsigned char *template_)
276 #ifndef CONFIG_OS_WIN32
277 mode_t saved_mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
278 #endif
279 int fd = mkstemp(template_);
280 #ifndef CONFIG_OS_WIN32
281 umask(saved_mask);
282 #endif
283 return fd;
286 /* comparison function for qsort() */
288 compare_dir_entries(const void *v1, const void *v2)
290 const struct directory_entry *d1 = v1, *d2 = v2;
292 if (d1->name[0] == '.' && d1->name[1] == '.' && !d1->name[2]) return -1;
293 if (d2->name[0] == '.' && d2->name[1] == '.' && !d2->name[2]) return 1;
294 if (d1->attrib[0] == 'd' && d2->attrib[0] != 'd') return -1;
295 if (d1->attrib[0] != 'd' && d2->attrib[0] == 'd') return 1;
296 return strcmp(d1->name, d2->name);
300 /** This function decides whether a file should be shown in directory
301 * listing or not. @returns according boolean value. */
302 static inline int
303 file_visible(unsigned char *name, int get_hidden_files, int is_root_directory)
305 /* Always show everything not beginning with a dot. */
306 if (name[0] != '.')
307 return 1;
309 /* Always hide the "." directory. */
310 if (name[1] == '\0')
311 return 0;
313 /* Always show the ".." directory (but for root directory). */
314 if (name[1] == '.' && name[2] == '\0')
315 return !is_root_directory;
317 /* Others like ".x" or "..foo" are shown if get_hidden_files
318 * == 1. */
319 return get_hidden_files;
322 /** First information such as permissions is gathered for each directory entry.
323 * All entries are then sorted. */
324 struct directory_entry *
325 get_directory_entries(unsigned char *dirname, int get_hidden)
327 struct directory_entry *entries = NULL;
328 DIR *directory;
329 int size = 0;
330 struct dirent *entry;
331 int is_root_directory = dirname[0] == '/' && !dirname[1];
333 directory = opendir(dirname);
334 if (!directory) return NULL;
336 while ((entry = readdir(directory))) {
337 struct stat st, *stp;
338 struct directory_entry *new_entries;
339 unsigned char *name;
340 struct string attrib;
342 if (!file_visible(entry->d_name, get_hidden, is_root_directory))
343 continue;
345 new_entries = mem_realloc(entries, (size + 2) * sizeof(*new_entries));
346 if (!new_entries) continue;
347 entries = new_entries;
349 /* We allocate the full path because it is used in a few places
350 * which means less allocation although a bit more short term
351 * memory usage. */
352 name = straconcat(dirname, entry->d_name,
353 (unsigned char *) NULL);
354 if (!name) continue;
356 if (!init_string(&attrib)) {
357 mem_free(name);
358 continue;
361 #ifdef FS_UNIX_SOFTLINKS
362 stp = (lstat(name, &st)) ? NULL : &st;
363 #else
364 stp = (stat(name, &st)) ? NULL : &st;
365 #endif
367 stat_type(&attrib, stp);
368 stat_mode(&attrib, stp);
369 stat_links(&attrib, stp);
370 stat_user(&attrib, stp);
371 stat_group(&attrib, stp);
372 stat_size(&attrib, stp);
373 stat_date(&attrib, stp);
375 entries[size].name = name;
376 entries[size].attrib = attrib.source;
377 size++;
380 closedir(directory);
382 if (!size) {
383 /* We may have allocated space for entries but added none. */
384 mem_free_if(entries);
385 return NULL;
388 qsort(entries, size, sizeof(*entries), compare_dir_entries);
390 memset(&entries[size], 0, sizeof(*entries));
392 return entries;
395 /** Recursively create directories in @a path. The last element in the path is
396 * taken to be a filename, and simply ignored */
398 mkalldirs(const unsigned char *path)
400 int pos, len, ret = 0;
401 unsigned char *p;
403 if (!*path) return -1;
405 /* Make a copy of path, to be able to write to it. Otherwise, the
406 * function is unsafe if called with a read-only char *argument. */
407 len = strlen(path) + 1;
408 p = fmem_alloc(len);
409 if (!p) return -1;
410 memcpy(p, path, len);
412 for (pos = 1; p[pos]; pos++) {
413 unsigned char separator = p[pos];
415 if (!dir_sep(separator))
416 continue;
418 p[pos] = 0;
420 ret = mkdir(p, S_IRWXU);
422 p[pos] = separator;
424 if (ret < 0) {
425 if (errno != EEXIST) break;
426 ret = 0;
430 fmem_free(p);
431 return ret;