13 #include <sys/types.h>
14 #include <sys/stat.h> /* OS/2 needs this after sys/types.h */
16 #include <dirent.h> /* OS/2 needs this after sys/types.h */
19 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
28 #ifdef TIME_WITH_SYS_TIME
29 #ifdef HAVE_SYS_TIME_H
36 #if defined(TM_IN_SYS_TIME) && defined(HAVE_SYS_TIME_H)
38 #elif defined(HAVE_TIME_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. */
57 file_exists(const unsigned char *filename
)
60 return access(filename
, F_OK
) >= 0;
64 return stat(filename
, &buf
) >= 0;
69 file_can_read(const unsigned char *filename
)
72 return access(filename
, R_OK
) >= 0;
74 FILE *f
= fopen(filename
, "rb");
83 file_is_dir(const unsigned char *filename
)
87 if (stat(filename
, &st
))
90 return S_ISDIR(st
.st_mode
);
94 get_filename_position(unsigned char *filename
)
99 if_assert_failed
return NULL
;
101 for (pos
= filename
; *pos
; pos
++)
102 if (dir_sep(*pos
)) filename
= pos
+ 1;
108 expand_tilde(unsigned char *filename
)
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");
119 add_to_string(&file
, home
);
124 struct passwd
*passwd
= NULL
;
125 unsigned char *user
= filename
+ 1;
128 while (user
[userlen
] && !dir_sep(user
[userlen
]))
131 user
= memacpy(user
, userlen
);
133 passwd
= getpwnam(user
);
137 if (passwd
&& passwd
->pw_dir
) {
138 add_to_string(&file
, passwd
->pw_dir
);
139 filename
+= 1 + userlen
;
145 add_to_string(&file
, filename
);
151 get_unique_name(unsigned char *fileprefix
)
153 unsigned char *file
= fileprefix
;
154 int fileprefixlen
= strlen(fileprefix
);
159 while (file_exists(file
)) {
160 if (!(suffix
< memtrigger
)) {
162 INTERNAL("Too big suffix in get_unique_name().");
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);
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
);
195 file_read_line(unsigned char *line
, size_t *size
, FILE *file
, int *lineno
)
200 line
= mem_alloc(MAX_STR_LEN
);
207 while (fgets(line
+ offset
, *size
- offset
, file
)) {
208 unsigned char *linepos
= strchr(line
+ offset
, '\n');
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
);
217 /* We are on the last line. */
222 /* Undo our dammage */
225 *size
+= MAX_STR_LEN
;
227 newline
= mem_realloc(line
, *size
);
234 /* A whole line was read. Fetch next into the buffer if
235 * the line is 'continued'. */
238 while (line
< linepos
&& isspace(*linepos
))
241 if (*linepos
!= '\\') {
242 *(linepos
+ 1) = '\0';
245 offset
= linepos
- line
- 1;
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:
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).
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
);
279 int fd
= mkstemp(template);
280 #ifndef CONFIG_OS_WIN32
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. */
303 file_visible(unsigned char *name
, int get_hidden_files
, int is_root_directory
)
305 /* Always show everything not beginning with a dot. */
309 /* Always hide the "." directory. */
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
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
;
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
;
340 struct string attrib
;
342 if (!file_visible(entry
->d_name
, get_hidden
, is_root_directory
))
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
352 name
= straconcat(dirname
, entry
->d_name
,
353 (unsigned char *) NULL
);
356 if (!init_string(&attrib
)) {
361 #ifdef FS_UNIX_SOFTLINKS
362 stp
= (lstat(name
, &st
)) ? NULL
: &st
;
364 stp
= (stat(name
, &st
)) ? NULL
: &st
;
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
;
383 /* We may have allocated space for entries but added none. */
384 mem_free_if(entries
);
388 qsort(entries
, size
, sizeof(*entries
), compare_dir_entries
);
390 memset(&entries
[size
], 0, sizeof(*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;
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;
410 memcpy(p
, path
, len
);
412 for (pos
= 1; p
[pos
]; pos
++) {
413 unsigned char separator
= p
[pos
];
415 if (!dir_sep(separator
))
420 ret
= mkdir(p
, S_IRWXU
);
425 if (errno
!= EEXIST
) break;