2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
#ifndef EL__UTIL_FILE_H
|
|
|
|
#define EL__UTIL_FILE_H
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2010-09-06 12:38:36 -04:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include "util/conv.h"
|
|
|
|
#include "util/string.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2020-10-05 14:14:55 -04:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Data read about an entry in a directory.
|
|
|
|
* The strings pointed to by this structure are in the system
|
|
|
|
* charset (i.e. LC_CTYPE) and must be freed with mem_free(). */
|
2005-09-15 09:58:31 -04:00
|
|
|
struct directory_entry {
|
2007-07-27 05:35:13 -04:00
|
|
|
/** The various attribute info collected with the @c stat_* functions. */
|
2005-09-15 09:58:31 -04:00
|
|
|
unsigned char *attrib;
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** The full path of the dir entry. */
|
2005-09-15 09:58:31 -04:00
|
|
|
unsigned char *name;
|
|
|
|
};
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** First information such as permissions is gathered for each directory entry.
|
2005-09-15 09:58:31 -04:00
|
|
|
* All entries are then sorted. */
|
|
|
|
struct directory_entry *
|
|
|
|
get_directory_entries(unsigned char *dirname, int get_hidden_files);
|
|
|
|
|
|
|
|
int file_exists(const unsigned char *filename);
|
|
|
|
int file_can_read(const unsigned char *filename);
|
|
|
|
int file_is_dir(const unsigned char *filename);
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Strips all directory stuff from @a filename and returns the
|
2005-09-15 09:58:31 -04:00
|
|
|
* position of where the actual filename starts */
|
|
|
|
unsigned char *get_filename_position(unsigned char *filename);
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Tilde is only expanded for the current users homedir (~/).
|
|
|
|
* The returned file name is allocated. */
|
2005-09-15 09:58:31 -04:00
|
|
|
unsigned char *expand_tilde(unsigned char *filename);
|
|
|
|
|
2007-07-31 06:38:00 -04:00
|
|
|
/*! @brief Generate a unique file name by trial and error based on the
|
2007-07-27 05:35:13 -04:00
|
|
|
* @a fileprefix by adding suffix counter (e.g. '.42').
|
|
|
|
*
|
|
|
|
* The returned file name is allocated if @a fileprefix is not unique. */
|
2005-09-15 09:58:31 -04:00
|
|
|
unsigned char *get_unique_name(unsigned char *fileprefix);
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Checks various environment variables to get the name of the temp dir.
|
2005-09-15 09:58:31 -04:00
|
|
|
* Returns a filename by concatenating "<tmpdir>/<name>". */
|
|
|
|
unsigned char *get_tempdir_filename(unsigned char *name);
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Read a line from @a file into the dynamically allocated @a line,
|
|
|
|
* increasing @a line if necessary. Ending whitespace is trimmed.
|
|
|
|
* If a line ends with "\" the next line is read too.
|
|
|
|
* If @a line is NULL the returned line is allocated and if file
|
|
|
|
* reading fails @a line is free()d. */
|
2005-09-15 09:58:31 -04:00
|
|
|
unsigned char *file_read_line(unsigned char *line, size_t *linesize,
|
|
|
|
FILE *file, int *linenumber);
|
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Safe wrapper for mkstemp().
|
2005-09-15 09:58:31 -04:00
|
|
|
* It enforces permissions by calling umask(0177), call mkstemp(), then
|
|
|
|
* restore previous umask(). */
|
2016-04-20 12:05:00 -04:00
|
|
|
int safe_mkstemp(unsigned char *template_);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Recursively create directories in @a path. The last element in the path is
|
2006-01-05 04:49:05 -05:00
|
|
|
* taken to be a filename, and simply ignored */
|
2006-01-04 15:43:42 -05:00
|
|
|
int mkalldirs(const unsigned char *path);
|
|
|
|
|
2010-09-06 12:38:36 -04:00
|
|
|
/* comparison function for qsort() */
|
|
|
|
int compare_dir_entries(const void *v1, const void *v2);
|
|
|
|
|
|
|
|
|
|
|
|
/** @name The stat_* functions set the various attributes for directory entries.
|
|
|
|
* @{ */
|
|
|
|
|
|
|
|
static inline void
|
2019-04-21 06:27:40 -04:00
|
|
|
stat_type(struct string *string, struct stat *stp)
|
2010-09-06 12:38:36 -04:00
|
|
|
{
|
|
|
|
unsigned char c = '?';
|
|
|
|
|
|
|
|
if (stp) {
|
|
|
|
if (S_ISDIR(stp->st_mode)) c = 'd';
|
|
|
|
else if (S_ISREG(stp->st_mode)) c = '-';
|
|
|
|
#ifdef S_ISBLK
|
|
|
|
else if (S_ISBLK(stp->st_mode)) c = 'b';
|
|
|
|
#endif
|
|
|
|
#ifdef S_ISCHR
|
|
|
|
else if (S_ISCHR(stp->st_mode)) c = 'c';
|
|
|
|
#endif
|
|
|
|
#ifdef S_ISFIFO
|
|
|
|
else if (S_ISFIFO(stp->st_mode)) c = 'p';
|
|
|
|
#endif
|
|
|
|
#ifdef S_ISLNK
|
|
|
|
else if (S_ISLNK(stp->st_mode)) c = 'l';
|
|
|
|
#endif
|
|
|
|
#ifdef S_ISSOCK
|
|
|
|
else if (S_ISSOCK(stp->st_mode)) c = 's';
|
|
|
|
#endif
|
|
|
|
#ifdef S_ISNWK
|
|
|
|
else if (S_ISNWK(stp->st_mode)) c = 'n';
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
add_char_to_string(string, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-04-21 06:27:40 -04:00
|
|
|
stat_mode(struct string *string, struct stat *stp)
|
2010-09-06 12:38:36 -04:00
|
|
|
{
|
|
|
|
#ifdef FS_UNIX_RIGHTS
|
|
|
|
unsigned char rwx[10] = "---------";
|
|
|
|
|
|
|
|
if (stp) {
|
|
|
|
mode_t mode = stp->st_mode;
|
|
|
|
unsigned int shift;
|
|
|
|
|
|
|
|
/* Set permissions attributes for user, group and other */
|
|
|
|
for (shift = 0; shift <= 6; shift += 3) {
|
|
|
|
mode_t m = mode << shift;
|
|
|
|
|
|
|
|
if (m & S_IRUSR) rwx[shift + 0] = 'r';
|
|
|
|
if (m & S_IWUSR) rwx[shift + 1] = 'w';
|
|
|
|
if (m & S_IXUSR) rwx[shift + 2] = 'x';
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef S_ISUID
|
|
|
|
if (mode & S_ISUID)
|
|
|
|
rwx[2] = (mode & S_IXUSR) ? 's' : 'S';
|
|
|
|
#endif
|
|
|
|
#ifdef S_ISGID
|
|
|
|
if (mode & S_ISGID)
|
|
|
|
rwx[5] = (mode & S_IXGRP) ? 's' : 'S';
|
|
|
|
#endif
|
|
|
|
#ifdef S_ISVTX
|
|
|
|
if (mode & S_ISVTX)
|
|
|
|
rwx[8] = (mode & S_IXOTH) ? 't' : 'T';
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
add_to_string(string, rwx);
|
|
|
|
#endif
|
|
|
|
add_char_to_string(string, ' ');
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-04-21 06:27:40 -04:00
|
|
|
stat_links(struct string *string, struct stat *stp)
|
2010-09-06 12:38:36 -04:00
|
|
|
{
|
|
|
|
#ifdef FS_UNIX_HARDLINKS
|
|
|
|
if (!stp) {
|
|
|
|
add_to_string(string, " ");
|
|
|
|
} else {
|
|
|
|
unsigned char lnk[64];
|
|
|
|
|
|
|
|
ulongcat(lnk, NULL, stp->st_nlink, 3, ' ');
|
|
|
|
add_to_string(string, lnk);
|
|
|
|
add_char_to_string(string, ' ');
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-04-21 06:27:40 -04:00
|
|
|
stat_user(struct string *string, struct stat *stp)
|
2010-09-06 12:38:36 -04:00
|
|
|
{
|
|
|
|
#ifdef FS_UNIX_USERS
|
|
|
|
static unsigned char last_user[64];
|
|
|
|
static int last_uid = -1;
|
|
|
|
|
|
|
|
if (!stp) {
|
|
|
|
add_to_string(string, " ");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stp->st_uid != last_uid) {
|
|
|
|
struct passwd *pwd = getpwuid(stp->st_uid);
|
|
|
|
|
|
|
|
if (!pwd || !pwd->pw_name)
|
|
|
|
/* ulongcat() can't pad from right. */
|
2010-09-19 08:13:28 -04:00
|
|
|
snprintf(last_user, 64, "%-8d", (int) stp->st_uid);
|
2010-09-06 12:38:36 -04:00
|
|
|
else
|
2010-09-19 08:13:28 -04:00
|
|
|
snprintf(last_user, 64, "%-8.8s", pwd->pw_name);
|
2010-09-06 12:38:36 -04:00
|
|
|
|
|
|
|
last_uid = stp->st_uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_to_string(string, last_user);
|
|
|
|
add_char_to_string(string, ' ');
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-04-21 06:27:40 -04:00
|
|
|
stat_group(struct string *string, struct stat *stp)
|
2010-09-06 12:38:36 -04:00
|
|
|
{
|
|
|
|
#ifdef FS_UNIX_USERS
|
|
|
|
static unsigned char last_group[64];
|
|
|
|
static int last_gid = -1;
|
|
|
|
|
|
|
|
if (!stp) {
|
|
|
|
add_to_string(string, " ");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stp->st_gid != last_gid) {
|
|
|
|
struct group *grp = getgrgid(stp->st_gid);
|
|
|
|
|
|
|
|
if (!grp || !grp->gr_name)
|
|
|
|
/* ulongcat() can't pad from right. */
|
2010-09-19 08:13:28 -04:00
|
|
|
snprintf(last_group, 64, "%-8d", (int) stp->st_gid);
|
2010-09-06 12:38:36 -04:00
|
|
|
else
|
2010-09-19 08:13:28 -04:00
|
|
|
snprintf(last_group, 64, "%-8.8s", grp->gr_name);
|
2010-09-06 12:38:36 -04:00
|
|
|
|
|
|
|
last_gid = stp->st_gid;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_to_string(string, last_group);
|
|
|
|
add_char_to_string(string, ' ');
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-04-21 06:27:40 -04:00
|
|
|
stat_size(struct string *string, struct stat *stp)
|
2010-09-06 12:38:36 -04:00
|
|
|
{
|
|
|
|
/* Check if st_size will cause overflow. */
|
|
|
|
/* FIXME: See bug 497 for info about support for big files. */
|
|
|
|
if (!stp || stp->st_size != (unsigned long) stp->st_size) {
|
|
|
|
add_to_string(string, " ");
|
|
|
|
|
|
|
|
} else {
|
|
|
|
unsigned char size[64];
|
|
|
|
int width = 9;
|
|
|
|
|
|
|
|
/* First try to fit the file size into 8 digits ... */
|
|
|
|
width = ulongcat(size, NULL, stp->st_size, width, ' ');
|
|
|
|
if (0 < width && width < sizeof(size)) {
|
|
|
|
/* ... if that is not enough expand the size buffer.
|
|
|
|
* This will only break the column alignment of the size
|
|
|
|
* attribute if really needed. */
|
|
|
|
ulongcat(size, NULL, stp->st_size, width, ' ');
|
|
|
|
}
|
|
|
|
|
|
|
|
add_to_string(string, size);
|
|
|
|
add_char_to_string(string, ' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-04-21 06:27:40 -04:00
|
|
|
stat_date(struct string *string, struct stat *stp)
|
2010-09-06 12:38:36 -04:00
|
|
|
{
|
|
|
|
#ifdef HAVE_STRFTIME
|
|
|
|
if (stp) {
|
|
|
|
time_t current_time = time(NULL);
|
|
|
|
time_t when = stp->st_mtime;
|
|
|
|
unsigned char *fmt;
|
|
|
|
|
|
|
|
if (current_time > when + 6L * 30L * 24L * 60L * 60L
|
|
|
|
|| current_time < when - 60L * 60L)
|
|
|
|
fmt = "%b %e %Y";
|
|
|
|
else
|
|
|
|
fmt = "%b %e %H:%M";
|
|
|
|
|
|
|
|
add_date_to_string(string, fmt, &when);
|
|
|
|
add_char_to_string(string, ' ');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
add_to_string(string, " ");
|
|
|
|
}
|
|
|
|
|
2020-10-05 14:14:55 -04:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-09-06 12:38:36 -04:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
#endif
|