#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#include <strings.h>
#include <time.h>
#include "security.h"
#include "proto.h"
#include "regexp.h"
#include "lexer.h"
#include "y.tab.h"
#include "opcodes.h"
#include "consts.h"
#include "hash.h"
#include "fsecure.h"
struct list_files_
{
Shared * fname;
int size; /* File size */
int last_written;
};
typedef struct list_files_ LSFILES;
int
pstrcmp(LSFILES ** p1, LSFILES ** p2)
{
return string_cmp((*p1)->fname, (*p2)->fname);
}
/*
* List files in a directory. The standard 'ls' could be used, but it takes
* too much time. Prepared for flag decoding.
*
* Rewritten so that it is much simplier, with the addition of regexp ()
* as an efun :L
* Now returns an array:
* ({ ({files}) , ({ corresponding size }), ({ last time the file was written}) })
* Done this way to allow easy searches on filenames
*/
#define PATH_SIZE 100
#include <limits.h>
Val * list_files(Shared * path)
{
int num, offset, max_files = 128, truncated = 0;
DIR *dirp;
struct dirent *de;
Val *ret;
struct vector *subname, *subsize, *subtime;
LSFILES **names;
struct stat st;
char path2[PATH_SIZE], tmppath[160];
if (!path) return 0;
if (path->length >= PATH_SIZE)
{
efun_error("Path too long for ls(). Path was (%s)\n", path->str);
return 0;
}
if (path->str[0] == '/')
{
efun_error("Invalid use of ls() efun. Illegal leading slash.\n");
return 0;
}
if (path->str[0] == '\0')
strcpy(path2, ".");
else
strcpy(path2, path->str);
offset = strlen(path2) + 1;
if (stat(path2, &st) == -1)
{
extern int sys_nerr;
/* extern char *sys_errlist[]; */
/* Failed. Let them know the errno.
* The likely problem was that the directory didnt exist */
efun_error("stat() failed in ls(). Errmessage was (%s)\n",
errno < sys_nerr ? sys_errlist[errno] : "unknown error");
return 0;
}
dirp = opendir(path2);
if (dirp == NULL)
{
efun_error("No such directory '%s'\n", path2);
return 0;
}
num = 0;
/*
* First step, find the number of file names.
* and copy the names into a space. Also copy in their sizes.
* Its a damn pity we dont know how many there is going to be,
* would make things alot simplier
*/
names = (LSFILES **) malloc(max_files * sizeof(LSFILES *));
strcpy(tmppath, path2);
strcat(tmppath, "/");
for (de = readdir(dirp); de; de = readdir(dirp))
{
if ((strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0))
continue;
strcpy(&tmppath[offset], de->d_name);
if (stat(tmppath, &st) != -1)
{
if (S_IFDIR & st.st_mode)
{ /* Directory */
strcat(tmppath, "/");
}
else if (S_IEXEC & st.st_mode)
{ /* mud file has special permissions */
strcat(tmppath, "*");
}
}
names[num] = (LSFILES *) malloc(sizeof(LSFILES));
names[num]->fname = string_copy(&tmppath[offset]);
names[num]->size = (int) st.st_size / 1024 + ((int) st.st_size % 1024 > 0);
names[num]->last_written = st.st_mtime;
num++;
if (num >= max_files)
{
if (max_files < MAX_ARRAY_SIZE / 2)
{
max_files *= 2; /* Lets just double the space */
}
else
{
truncated = 1;
break;
}
names = (LSFILES **) realloc((LSFILES **) names, max_files *
sizeof(LSFILES *));
}
}
/* Sort the names. */
qsort(names, num, sizeof(LSFILES *), pstrcmp);
ret = allocate_array(3);
ret->u.vec->item[0].type = T_POINTER;
ret->u.vec->item[0].u.vec = create_vector(num, "simulate.c:list_files()");
ret->u.vec->item[1].type = T_POINTER;
ret->u.vec->item[1].u.vec = create_vector(num, "simulate.c:list_files()");
ret->u.vec->item[2].type = T_POINTER;
ret->u.vec->item[2].u.vec = create_vector(num, "simulate.c:list_files()");
subname = ret->u.vec->item[0].u.vec;
subsize = ret->u.vec->item[1].u.vec;
subtime = ret->u.vec->item[2].u.vec;
while (num--)
{
subname->item[num].type = T_STRING;
subname->item[num].u.string = names[num]->fname;
subsize->item[num].type = T_NUMBER;
subsize->item[num].u.number = names[num]->size;
subtime->item[num].type = T_NUMBER;
subtime->item[num].u.number = names[num]->last_written;
free(names[num]);
}
if (truncated)
add_message("***TRUNCATED***\n");
free((LSFILES **) names);
closedir(dirp);
return ret;
}
int remove_file(Shared * path)
{
if (!o_write_ok(Scurrent(), path)) return 0;
if (unlink(path->str) == -1)
{
/* add_message("No such file: %s\n", path); */
return 0;
}
return 1;
}
int copy_file(Shared *src, Shared *dst)
{
FILE *src_f, *dst_f;
int c;
if (!o_read_ok(Scurrent(), src)) return 0;
if (!o_write_ok(Scurrent(), dst)) return 0;
src_f = fopen(src->str, "r");
if (src_f == 0)
return 0;
dst_f = fopen(dst->str, "w");
if (dst_f == 0)
{
fclose(src_f);
return 0;
}
force_no_su(dst);
while ((c = fgetc(src_f)) != EOF)
fputc(c, dst_f);
fclose(src_f);
fclose(dst_f);
return 1;
}
int rename_file(Shared *src, Shared *dst)
{
extern int sys_nerr;
/* extern char *sys_errlist[]; */
if (!o_write_ok(Scurrent(), src)) return 0;
if (!o_write_ok(Scurrent(), dst)) return 0;
if (rename(src->str, dst->str) == -1)
{
add_message("rename: %s\n",
errno < sys_nerr ? sys_errlist[errno] : "unknown error");
return 0;
}
return 1;
}
#if 0
int log_file(char *file, char *str)
{
FILE *f;
char file_name[500];
#ifndef SECURE
if (strchr(file, '/') || file[0] == '.' || strlen(file) > 400)
{
efun_error("Illegal file name to log_file(%s)\n", file);
return 0;
}
sprintf(file_name, "log/%s", file);
#else
if (strlen(file) > 400)
{
efun_error("log_file(%s): filename too long\n", file);
return 0;
}
sprintf(file_name, "log/%s", file);
if (!valid_filename(file_name))
{
efun_error("Illegal file name to log_file(%s)", file);
return 0;
}
#endif
f = fopen(file_name, "a");
if (f == 0)
return 1;
fprintf(f, "%08x: %s", (int) time((long *) 0), str);
force_no_su(file_name);
fclose(f);
return 1;
}
#endif
int write_file(Shared *file, Shared * str)
{
FILE *f;
f = fopen(file->str, "a");
if (f == 0) return 0;
fwrite(str->str, str->length, 1, f);
fclose(f);
force_no_su(file);
return 1;
}
int file_size(Shared *file)
{
struct stat st;
if (stat(file->str, &st) == -1) return -1;
if (S_IFDIR & st.st_mode) return -2;
return st.st_size;
}
/*
* grab_file changed to return a string
*/
#define READ_FILE_MAX_SIZE 60000
Val * char_grab_file(Shared * file, int from, int to)
{
FILE *f;
char *buf = 0;
int i;
Val * ret;
if (!file) return Const(0);
if (from < 0) from = 0;
if (to <= 0) to = from + READ_FILE_MAX_SIZE - 1;
if (from > to) from = to;
i = file_size(file);
if (i < 0)
return Const(0);
if (i < to)
to = i;
f = fopen(file->str, "r");
if (f == 0)
return Const(0);
buf = malloc(to - from + 2);
fseek(f, (long) from, SEEK_SET);
i = fread(buf, 1, (to - from + 1), f);
buf[i] = '\0';
#if 0
printf("grab_file grabbed:\n%s\n", buf);
#endif
fclose(f);
ret = share_string(string_ncopy(buf,i));
free(buf);
return ret;
}
int secure_path(char *path)
{
int HadSlash = 1;
/* check for "." or ".." between slashes or at start */
for (; *path != 0; path++)
{
if ( (HadSlash && *path == '.' && (*(path + 1) == '/') ||
((*(path + 1) == '.') && *(path + 2) == '/')) )
{ /* illegal path */
return 0;
}
}
return 1;
}