mirror of
https://github.com/rkd77/elinks.git
synced 2025-06-30 22:19:29 -04:00
SMB directory listing looks like normal directory listing.
This commit is contained in:
parent
a9898eab51
commit
00ebb8ef4b
@ -34,24 +34,10 @@
|
|||||||
#include "protocol/smb/smb.h"
|
#include "protocol/smb/smb.h"
|
||||||
#include "protocol/uri.h"
|
#include "protocol/uri.h"
|
||||||
#include "util/conv.h"
|
#include "util/conv.h"
|
||||||
|
#include "util/file.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
/* These options are not used. */
|
|
||||||
#if 0
|
|
||||||
struct option_info smb_options[] = {
|
|
||||||
INIT_OPT_TREE("protocol", N_("SMB"),
|
|
||||||
"smb", 0,
|
|
||||||
N_("SAMBA specific options.")),
|
|
||||||
|
|
||||||
INIT_OPT_STRING("protocol.smb", N_("Credentials"),
|
|
||||||
"credentials", 0, "",
|
|
||||||
N_("Credentials file passed to smbclient via -A option.")),
|
|
||||||
|
|
||||||
NULL_OPTION_INFO,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct module smb_protocol_module = struct_module(
|
struct module smb_protocol_module = struct_module(
|
||||||
/* name: */ N_("SMB"),
|
/* name: */ N_("SMB"),
|
||||||
/* options: */ NULL,
|
/* options: */ NULL,
|
||||||
@ -81,179 +67,167 @@ smb_error(struct connection_state error)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/** First information such as permissions is gathered for each directory entry.
|
||||||
compare(const void *a, const void *b)
|
* All entries are then sorted. */
|
||||||
|
static struct directory_entry *
|
||||||
|
get_smb_directory_entries(int dir, struct string *prefix)
|
||||||
{
|
{
|
||||||
const struct smbc_dirent **da = (const struct smbc_dirent **)a;
|
struct directory_entry *entries = NULL;
|
||||||
const struct smbc_dirent **db = (const struct smbc_dirent **)b;
|
|
||||||
int res = (*da)->smbc_type - (*db)->smbc_type;
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return strcmp((*da)->name, (*db)->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
smb_add_link(struct string *string, const struct smbc_dirent *entry,
|
|
||||||
const unsigned char *text, const unsigned char dircolor[])
|
|
||||||
{
|
|
||||||
struct string uri_string;
|
|
||||||
|
|
||||||
if (!init_string(&uri_string)) return;
|
|
||||||
encode_uri_string(&uri_string, entry->name, entry->namelen, 0);
|
|
||||||
|
|
||||||
add_to_string(string, "<a href=\"");
|
|
||||||
add_html_to_string(string, uri_string.source, uri_string.length);
|
|
||||||
done_string(&uri_string);
|
|
||||||
|
|
||||||
add_to_string(string, "\">");
|
|
||||||
if (*dircolor) {
|
|
||||||
add_to_string(string, "<font color=\"");
|
|
||||||
add_to_string(string, dircolor);
|
|
||||||
add_to_string(string, "\"><b>");
|
|
||||||
}
|
|
||||||
add_html_to_string(string, entry->name, entry->namelen);
|
|
||||||
if (*dircolor) {
|
|
||||||
add_to_string(string, "</b></font>");
|
|
||||||
}
|
|
||||||
add_to_string(string, "</a>");
|
|
||||||
if (text) add_to_string(string, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
display_entry(const struct smbc_dirent *entry, const unsigned char dircolor[])
|
|
||||||
{
|
|
||||||
static const unsigned char zero = '\0';
|
|
||||||
struct string string;
|
|
||||||
|
|
||||||
if (!init_string(&string)) return;
|
|
||||||
|
|
||||||
switch (entry->smbc_type) {
|
|
||||||
case SMBC_WORKGROUP:
|
|
||||||
smb_add_link(&string, entry, " WORKGROUP ", dircolor);
|
|
||||||
break;
|
|
||||||
case SMBC_SERVER:
|
|
||||||
smb_add_link(&string, entry, " SERVER ", dircolor);
|
|
||||||
if (entry->comment) {
|
|
||||||
add_html_to_string(&string, entry->comment, entry->commentlen);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SMBC_FILE_SHARE:
|
|
||||||
smb_add_link(&string, entry, " FILE SHARE ", dircolor);
|
|
||||||
if (entry->comment) {
|
|
||||||
add_html_to_string(&string, entry->comment, entry->commentlen);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SMBC_PRINTER_SHARE:
|
|
||||||
add_html_to_string(&string, entry->name, entry->namelen);
|
|
||||||
add_to_string(&string, " PRINTER ");
|
|
||||||
if (entry->comment) {
|
|
||||||
add_html_to_string(&string, entry->comment, entry->commentlen);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SMBC_COMMS_SHARE:
|
|
||||||
add_bytes_to_string(&string, entry->name, entry->namelen);
|
|
||||||
add_to_string(&string, " COMM");
|
|
||||||
break;
|
|
||||||
case SMBC_IPC_SHARE:
|
|
||||||
add_bytes_to_string(&string, entry->name, entry->namelen);
|
|
||||||
add_to_string(&string, " IPC");
|
|
||||||
break;
|
|
||||||
case SMBC_DIR:
|
|
||||||
smb_add_link(&string, entry, NULL, dircolor);
|
|
||||||
break;
|
|
||||||
case SMBC_LINK:
|
|
||||||
smb_add_link(&string, entry, " Link", &zero);
|
|
||||||
break;
|
|
||||||
case SMBC_FILE:
|
|
||||||
smb_add_link(&string, entry, NULL, &zero);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* unknown type */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fputs(string.source, data_out);
|
|
||||||
fputc('\n', data_out);
|
|
||||||
done_string(&string);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sort_and_display_entries(int dir, const unsigned char dircolor[])
|
|
||||||
{
|
|
||||||
struct smbc_dirent *fentry, **table = NULL;
|
|
||||||
int size = 0;
|
int size = 0;
|
||||||
int i;
|
struct smbc_dirent *entry;
|
||||||
|
|
||||||
while ((fentry = smbc_readdir(dir))) {
|
while ((entry = smbc_readdir(dir))) {
|
||||||
struct smbc_dirent **new_table, *new_entry;
|
struct stat st, *stp;
|
||||||
unsigned int commentlen = fentry->commentlen;
|
struct directory_entry *new_entries;
|
||||||
unsigned int namelen = fentry->namelen;
|
struct string attrib;
|
||||||
|
struct string name;
|
||||||
|
|
||||||
if (!strcmp(fentry->name, "."))
|
if (!strcmp(entry->name, "."))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* In libsmbclient 3.0.10, @smbc_dirent.namelen and
|
new_entries = mem_realloc(entries, (size + 2) * sizeof(*new_entries));
|
||||||
* @smbc_dirent.commentlen include the null characters
|
if (!new_entries) continue;
|
||||||
* (tested with GDB). In libsmbclient 3.0.24, they
|
entries = new_entries;
|
||||||
* don't. This is related to Samba bug 3030. Adjust
|
|
||||||
* the lengths to exclude the null characters, so that
|
|
||||||
* other code need not care.
|
|
||||||
*
|
|
||||||
* Make all changes to local copies rather than
|
|
||||||
* directly to *@fentry, so that there's no chance of
|
|
||||||
* ELinks messing up whatever mechanism libsmbclient
|
|
||||||
* will use to free @fentry. */
|
|
||||||
if (commentlen > 0 && fentry->comment[commentlen - 1] == '\0')
|
|
||||||
commentlen--;
|
|
||||||
if (namelen > 0 && fentry->name[namelen - 1] == '\0')
|
|
||||||
namelen--;
|
|
||||||
|
|
||||||
/* libsmbclient seems to place the struct smbc_dirent,
|
if (!init_string(&attrib)) {
|
||||||
* the name string, and the comment string all in one
|
|
||||||
* block of memory, which then is smbc_dirent.dirlen
|
|
||||||
* bytes long. This has however not been really
|
|
||||||
* documented, so ELinks should not assume copying
|
|
||||||
* fentry->dirlen bytes will copy the comment too.
|
|
||||||
* Yet, it would be wasteful to copy both dirlen bytes
|
|
||||||
* and then the comment string separately. What we do
|
|
||||||
* here is ignore fentry->dirlen and recompute the
|
|
||||||
* size based on namelen. */
|
|
||||||
new_entry = (struct smbc_dirent *)
|
|
||||||
memacpy((const unsigned char *) fentry,
|
|
||||||
offsetof(struct smbc_dirent, name)
|
|
||||||
+ namelen); /* memacpy appends '\0' */
|
|
||||||
if (!new_entry)
|
|
||||||
continue;
|
continue;
|
||||||
new_entry->namelen = namelen;
|
}
|
||||||
new_entry->commentlen = commentlen;
|
|
||||||
if (fentry->comment)
|
|
||||||
new_entry->comment = memacpy(fentry->comment, commentlen);
|
|
||||||
if (!new_entry->comment)
|
|
||||||
new_entry->commentlen = 0;
|
|
||||||
|
|
||||||
new_table = mem_realloc(table, (size + 1) * sizeof(*table));
|
if (!init_string(&name)) {
|
||||||
if (!new_table)
|
done_string(&attrib);
|
||||||
continue;
|
continue;
|
||||||
table = new_table;
|
}
|
||||||
table[size] = new_entry;
|
|
||||||
|
add_string_to_string(&name, prefix);
|
||||||
|
add_to_string(&name, entry->name);
|
||||||
|
|
||||||
|
stp = (smbc_stat(name.source, &st)) ? NULL : &st;
|
||||||
|
|
||||||
|
stat_type(&attrib, stp);
|
||||||
|
stat_mode(&attrib, stp);
|
||||||
|
stat_links(&attrib, stp);
|
||||||
|
stat_user(&attrib, stp);
|
||||||
|
stat_group(&attrib, stp);
|
||||||
|
stat_size(&attrib, stp);
|
||||||
|
stat_date(&attrib, stp);
|
||||||
|
|
||||||
|
entries[size].name = stracpy(entry->name);
|
||||||
|
entries[size].attrib = attrib.source;
|
||||||
|
done_string(&name);
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
/* If size==0, then table==NULL. According to ISO/IEC 9899:1999
|
smbc_closedir(dir);
|
||||||
* 7.20.5p1, the NULL must not be given to qsort. */
|
|
||||||
if (size > 0)
|
|
||||||
qsort(table, size, sizeof(*table), compare);
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
if (!size) {
|
||||||
display_entry(table[i], dircolor);
|
/* We may have allocated space for entries but added none. */
|
||||||
|
mem_free_if(entries);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
qsort(entries, size, sizeof(*entries), compare_dir_entries);
|
||||||
|
memset(&entries[size], 0, sizeof(*entries));
|
||||||
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
smb_directory(int dir, struct uri *uri)
|
add_smb_dir_entry(struct directory_entry *entry, struct string *page,
|
||||||
|
int pathlen, unsigned char *dircolor)
|
||||||
|
{
|
||||||
|
unsigned char *lnk = NULL;
|
||||||
|
struct string html_encoded_name;
|
||||||
|
struct string uri_encoded_name;
|
||||||
|
|
||||||
|
if (!init_string(&html_encoded_name)) return;
|
||||||
|
if (!init_string(&uri_encoded_name)) {
|
||||||
|
done_string(&html_encoded_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
encode_uri_string(&uri_encoded_name, entry->name + pathlen, -1, 1);
|
||||||
|
add_html_to_string(&html_encoded_name, entry->name + pathlen,
|
||||||
|
strlen(entry->name) - pathlen);
|
||||||
|
|
||||||
|
/* add_to_string(&fragment, &fragmentlen, " "); */
|
||||||
|
add_html_to_string(page, entry->attrib, strlen(entry->attrib));
|
||||||
|
add_to_string(page, "<a href=\"");
|
||||||
|
add_string_to_string(page, &uri_encoded_name);
|
||||||
|
|
||||||
|
if (entry->attrib[0] == 'd') {
|
||||||
|
add_char_to_string(page, '/');
|
||||||
|
|
||||||
|
#ifdef FS_UNIX_SOFTLINKS
|
||||||
|
} else if (entry->attrib[0] == 'l') {
|
||||||
|
struct stat st;
|
||||||
|
unsigned char buf[MAX_STR_LEN];
|
||||||
|
int readlen = readlink(entry->name, buf, MAX_STR_LEN);
|
||||||
|
|
||||||
|
if (readlen > 0 && readlen != MAX_STR_LEN) {
|
||||||
|
buf[readlen] = '\0';
|
||||||
|
lnk = straconcat(" -> ", buf, (unsigned char *) NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stat(entry->name, &st) && S_ISDIR(st.st_mode))
|
||||||
|
add_char_to_string(page, '/');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_string(page, "\">");
|
||||||
|
|
||||||
|
if (entry->attrib[0] == 'd' && *dircolor) {
|
||||||
|
/* The <b> is for the case when use_document_colors is off. */
|
||||||
|
string_concat(page, "<font color=\"", dircolor, "\"><b>",
|
||||||
|
(unsigned char *) NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_string_to_string(page, &html_encoded_name);
|
||||||
|
done_string(&uri_encoded_name);
|
||||||
|
done_string(&html_encoded_name);
|
||||||
|
|
||||||
|
if (entry->attrib[0] == 'd' && *dircolor) {
|
||||||
|
add_to_string(page, "</b></font>");
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_string(page, "</a>");
|
||||||
|
if (lnk) {
|
||||||
|
add_html_to_string(page, lnk, strlen(lnk));
|
||||||
|
mem_free(lnk);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_char_to_string(page, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First information such as permissions is gathered for each directory entry.
|
||||||
|
* Finally the sorted entries are added to the @data->fragment one by one. */
|
||||||
|
static void
|
||||||
|
add_smb_dir_entries(struct directory_entry *entries, unsigned char *dirpath,
|
||||||
|
struct string *page)
|
||||||
|
{
|
||||||
|
unsigned char dircolor[8];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Setup @dircolor so it's easy to check if we should color dirs. */
|
||||||
|
if (get_opt_bool("document.browse.links.color_dirs", NULL)) {
|
||||||
|
color_to_string(get_opt_color("document.colors.dirs", NULL),
|
||||||
|
(unsigned char *) &dircolor);
|
||||||
|
} else {
|
||||||
|
dircolor[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; entries[i].name; i++) {
|
||||||
|
add_smb_dir_entry(&entries[i], page, 0, dircolor);
|
||||||
|
mem_free(entries[i].attrib);
|
||||||
|
mem_free(entries[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We may have allocated space for entries but added none. */
|
||||||
|
mem_free_if(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_directory(int dir, struct string *prefix, struct uri *uri)
|
||||||
{
|
{
|
||||||
struct string buf;
|
struct string buf;
|
||||||
unsigned char dircolor[8] = "";
|
struct directory_entry *entries;
|
||||||
|
|
||||||
if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) {
|
if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) {
|
||||||
smb_error(connection_state(S_OUT_OF_MEM));
|
smb_error(connection_state(S_OUT_OF_MEM));
|
||||||
@ -262,17 +236,12 @@ smb_directory(int dir, struct uri *uri)
|
|||||||
fputs("text/html", header_out);
|
fputs("text/html", header_out);
|
||||||
fclose(header_out);
|
fclose(header_out);
|
||||||
|
|
||||||
|
entries = get_smb_directory_entries(dir, prefix);
|
||||||
|
add_smb_dir_entries(entries, NULL, &buf);
|
||||||
|
add_to_string(&buf, "</pre><hr/></body></html>\n");
|
||||||
|
|
||||||
fputs(buf.source, data_out);
|
fputs(buf.source, data_out);
|
||||||
fputc('\n', data_out);
|
done_string(&buf);
|
||||||
|
|
||||||
if (get_opt_bool("document.browse.links.color_dirs", NULL)) {
|
|
||||||
color_to_string(get_opt_color("document.colors.dirs", NULL),
|
|
||||||
dircolor);
|
|
||||||
}
|
|
||||||
|
|
||||||
sort_and_display_entries(dir, dircolor);
|
|
||||||
fputs("</pre><hr/></body></html>\n", data_out);
|
|
||||||
smbc_closedir(dir);
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,9 +298,16 @@ do_smb(struct connection *conn)
|
|||||||
smb_error(connection_state_for_errno(errno));
|
smb_error(connection_state_for_errno(errno));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
dir = smbc_opendir(url);
|
dir = smbc_opendir(url);
|
||||||
if (dir >= 0) {
|
if (dir >= 0) {
|
||||||
smb_directory(dir, conn->uri);
|
struct string prefix;
|
||||||
|
|
||||||
|
init_string(&prefix);
|
||||||
|
add_to_string(&prefix, url);
|
||||||
|
add_char_to_string(&prefix, '/');
|
||||||
|
smb_directory(dir, &prefix, conn->uri);
|
||||||
|
done_string(&prefix);
|
||||||
} else {
|
} else {
|
||||||
const int errno_from_opendir = errno;
|
const int errno_from_opendir = errno;
|
||||||
char buf[READ_SIZE];
|
char buf[READ_SIZE];
|
||||||
|
200
src/util/file.c
200
src/util/file.c
@ -283,206 +283,8 @@ safe_mkstemp(unsigned char *template)
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @name The stat_* functions set the various attributes for directory entries.
|
|
||||||
* @{ */
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
stat_type(struct string *string, struct stat *stp)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
stat_mode(struct string *string, struct stat *stp)
|
|
||||||
{
|
|
||||||
#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
|
|
||||||
stat_links(struct string *string, struct stat *stp)
|
|
||||||
{
|
|
||||||
#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
|
|
||||||
stat_user(struct string *string, struct stat *stp)
|
|
||||||
{
|
|
||||||
#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. */
|
|
||||||
sprintf(last_user, "%-8d", (int) stp->st_uid);
|
|
||||||
else
|
|
||||||
sprintf(last_user, "%-8.8s", pwd->pw_name);
|
|
||||||
|
|
||||||
last_uid = stp->st_uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_to_string(string, last_user);
|
|
||||||
add_char_to_string(string, ' ');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
stat_group(struct string *string, struct stat *stp)
|
|
||||||
{
|
|
||||||
#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. */
|
|
||||||
sprintf(last_group, "%-8d", (int) stp->st_gid);
|
|
||||||
else
|
|
||||||
sprintf(last_group, "%-8.8s", grp->gr_name);
|
|
||||||
|
|
||||||
last_gid = stp->st_gid;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_to_string(string, last_group);
|
|
||||||
add_char_to_string(string, ' ');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
stat_size(struct string *string, struct stat *stp)
|
|
||||||
{
|
|
||||||
/* 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
|
|
||||||
stat_date(struct string *string, struct stat *stp)
|
|
||||||
{
|
|
||||||
#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, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
|
|
||||||
/* comparison function for qsort() */
|
/* comparison function for qsort() */
|
||||||
static int
|
int
|
||||||
compare_dir_entries(const void *v1, const void *v2)
|
compare_dir_entries(const void *v1, const void *v2)
|
||||||
{
|
{
|
||||||
const struct directory_entry *d1 = v1, *d2 = v2;
|
const struct directory_entry *d1 = v1, *d2 = v2;
|
||||||
|
202
src/util/file.h
202
src/util/file.h
@ -3,6 +3,9 @@
|
|||||||
#define EL__UTIL_FILE_H
|
#define EL__UTIL_FILE_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "util/conv.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
/** Data read about an entry in a directory.
|
/** Data read about an entry in a directory.
|
||||||
* The strings pointed to by this structure are in the system
|
* The strings pointed to by this structure are in the system
|
||||||
@ -59,4 +62,203 @@ int safe_mkstemp(unsigned char *template);
|
|||||||
* taken to be a filename, and simply ignored */
|
* taken to be a filename, and simply ignored */
|
||||||
int mkalldirs(const unsigned char *path);
|
int mkalldirs(const unsigned char *path);
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
stat_type(struct string *string, struct stat *stp)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
stat_mode(struct string *string, struct stat *stp)
|
||||||
|
{
|
||||||
|
#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
|
||||||
|
stat_links(struct string *string, struct stat *stp)
|
||||||
|
{
|
||||||
|
#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
|
||||||
|
stat_user(struct string *string, struct stat *stp)
|
||||||
|
{
|
||||||
|
#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. */
|
||||||
|
sprintf(last_user, "%-8d", (int) stp->st_uid);
|
||||||
|
else
|
||||||
|
sprintf(last_user, "%-8.8s", pwd->pw_name);
|
||||||
|
|
||||||
|
last_uid = stp->st_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_string(string, last_user);
|
||||||
|
add_char_to_string(string, ' ');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
stat_group(struct string *string, struct stat *stp)
|
||||||
|
{
|
||||||
|
#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. */
|
||||||
|
sprintf(last_group, "%-8d", (int) stp->st_gid);
|
||||||
|
else
|
||||||
|
sprintf(last_group, "%-8.8s", grp->gr_name);
|
||||||
|
|
||||||
|
last_gid = stp->st_gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_string(string, last_group);
|
||||||
|
add_char_to_string(string, ' ');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
stat_size(struct string *string, struct stat *stp)
|
||||||
|
{
|
||||||
|
/* 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
|
||||||
|
stat_date(struct string *string, struct stat *stp)
|
||||||
|
{
|
||||||
|
#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, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user