curlftpfs/ftpfs-ls.c

281 lines
6.8 KiB
C

/*
FTP file system
Copyright (C) 2006 Robson Braga Araujo <robsonbraga@gmail.com>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#ifndef __FreeBSD__
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE
#endif
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include "ftpfs.h"
#include "charset_utils.h"
#include "ftpfs-ls.h"
static int parse_dir_unix(const char *line,
struct stat *sbuf,
char *file,
char *link) {
char mode[12];
long nlink = 1;
char user[33];
char group[33];
unsigned long long size;
char month[4];
char day[3];
char year[6];
char date[20];
struct tm tm;
time_t tt;
int res;
memset(file, 0, sizeof(char)*1024);
memset(&tm, 0, sizeof(tm));
memset(&tt, 0, sizeof(tt));
#define SPACES "%*[ \t]"
res = sscanf(line,
"%11s"
"%lu" SPACES
"%32s" SPACES
"%32s" SPACES
"%llu" SPACES
"%3s" SPACES
"%2s" SPACES
"%5s" "%*c"
"%1023c",
mode, &nlink, user, group, &size, month, day, year, file);
if (res < 9) {
res = sscanf(line,
"%11s"
"%32s" SPACES
"%32s" SPACES
"%llu" SPACES
"%3s" SPACES
"%2s" SPACES
"%5s" "%*c"
"%1023c",
mode, user, group, &size, month, day, year, file);
if (res < 8) {
return 0;
}
}
#undef SPACES
char *link_marker = strstr(file, " -> ");
if (link_marker) {
strcpy(link, link_marker + 4);
*link_marker = '\0';
}
int i = 0;
if (mode[i] == 'd') {
sbuf->st_mode |= S_IFDIR;
} else if (mode[i] == 'l') {
sbuf->st_mode |= S_IFLNK;
} else {
sbuf->st_mode |= S_IFREG;
}
for (i = 1; i < 10; ++i) {
if (mode[i] != '-') {
sbuf->st_mode |= 1 << (9 - i);
}
}
sbuf->st_nlink = nlink;
sbuf->st_size = size;
if (ftpfs.blksize) {
sbuf->st_blksize = ftpfs.blksize;
sbuf->st_blocks =
((size + ftpfs.blksize - 1) & ~((unsigned long long) ftpfs.blksize - 1)) >> 9;
}
sprintf(date,"%s,%s,%s", year, month, day);
tt = time(NULL);
gmtime_r(&tt, &tm);
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
if(strchr(year, ':')) {
int cur_mon = tm.tm_mon; // save current month
strptime(date, "%H:%M,%b,%d", &tm);
// Unix systems omit the year for the last six months
if (cur_mon + 5 < tm.tm_mon) { // month from last year
DEBUG(2, "correct year: cur_mon: %d, file_mon: %d\n", cur_mon, tm.tm_mon);
tm.tm_year--; // correct the year
}
} else {
strptime(date, "%Y,%b,%d", &tm);
}
sbuf->st_atime = sbuf->st_ctime = sbuf->st_mtime = mktime(&tm);
return 1;
}
static int parse_dir_win(const char *line,
struct stat *sbuf,
char *file,
char *link) {
char date[9];
char hour[8];
char size[33];
struct tm tm;
time_t tt;
int res;
(void)link;
memset(file, 0, sizeof(char)*1024);
memset(&tm, 0, sizeof(tm));
memset(&tt, 0, sizeof(tt));
res = sscanf(line, "%8s%*[ \t]%7s%*[ \t]%32s%*[ \t]%1023c",
date, hour, size, file);
if (res < 4) {
return 0;
}
DEBUG(2, "date: %s hour: %s size: %s file: %s\n", date, hour, size, file);
tt = time(NULL);
gmtime_r(&tt, &tm);
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
strptime(date, "%m-%d-%y", &tm);
strptime(hour, "%I:%M%p", &tm);
sbuf->st_atime = sbuf->st_ctime = sbuf->st_mtime = mktime(&tm);
sbuf->st_nlink = 1;
if (!strcmp(size, "<DIR>")) {
sbuf->st_mode |= S_IFDIR;
} else {
unsigned long long nsize = strtoull(size, NULL, 0);
sbuf->st_mode |= S_IFREG;
sbuf->st_size = nsize;
if (ftpfs.blksize) {
sbuf->st_blksize = ftpfs.blksize;
sbuf->st_blocks =
((nsize + ftpfs.blksize - 1) & ~((unsigned long long) ftpfs.blksize - 1)) >> 9;
}
}
return 1;
}
static int parse_dir_netware(const char *line,
struct stat *sbuf,
char *file,
char *link) {
(void) line;
(void) sbuf;
(void) file;
(void) link;
return 0;
}
int parse_dir(const char* list, const char* dir,
const char* name, struct stat* sbuf,
char* linkbuf, int linklen,
fuse_cache_dirh_t h, fuse_cache_dirfil_t filler) {
char *file;
char *link;
const char *start = list;
const char *end = list;
char found = 0;
struct stat stat_buf;
if (sbuf) memset(sbuf, 0, sizeof(struct stat));
if (name && sbuf && name[0] == '\0') {
sbuf->st_mode |= S_IFDIR;
sbuf->st_mode |= 0755;
sbuf->st_size = 1024;
sbuf->st_nlink = 1;
return 0;
}
file = (char *)malloc(1024*sizeof(char));
link = (char *)malloc(1024*sizeof(char));
while ((end = strchr(start, '\n')) != NULL) {
char* line;
memset(&stat_buf, 0, sizeof(stat_buf));
if (end > start && *(end-1) == '\r') end--;
line = (char*)malloc(end - start + 1);
strncpy(line, start, end - start);
line[end - start] = '\0';
start = *end == '\r' ? end + 2 : end + 1;
if (ftpfs.codepage) {
convert_charsets(ftpfs.codepage, ftpfs.iocharset, &line);
}
file[0] = link[0] = '\0';
int res = parse_dir_unix(line, &stat_buf, file, link) ||
parse_dir_win(line, &stat_buf, file, link) ||
parse_dir_netware(line, &stat_buf, file, link);
if (res) {
char *full_path = g_strdup_printf("%s%s", dir, file);
if (link[0]) {
char *reallink;
if (link[0] == '/' && ftpfs.symlink_prefix_len) {
reallink = g_strdup_printf("%s%s", ftpfs.symlink_prefix, link);
} else {
reallink = g_strdup(link);
}
int linksize = strlen(reallink);
cache_add_link(full_path, reallink, linksize+1);
DEBUG(1, "cache_add_link: %s %s\n", full_path, reallink);
if (linkbuf && linklen) {
if (linksize > linklen) linksize = linklen - 1;
strncpy(linkbuf, reallink, linksize);
linkbuf[linksize] = '\0';
}
free(reallink);
}
if (h && filler) {
DEBUG(1, "filler: %s\n", file);
filler(h, file, &stat_buf);
} else {
DEBUG(1, "cache_add_attr: %s\n", full_path);
cache_add_attr(full_path, &stat_buf);
}
DEBUG(2, "comparing %s %s\n", name, file);
if (name && !strcmp(name, file)) {
if (sbuf) *sbuf = stat_buf;
found = 1;
}
free(full_path);
}
free(line);
}
free(file);
free(link);
return !found;
}