/*
** $Id: os.c,v 1.8 2008/12/18 04:18:43 dredd Exp $
**
** $Source: /cvsroot/swlpc/swlpc/modules/os.c,v $
** $Revision: 1.8 $
** $Date: 2008/12/18 04:18:43 $
** $State: Exp $
**
** Author: Mike McGaughey & Geoff Wong, 1993-2001
**
** See the file "Copying" distributed with this file.
**
** OS modules: provide an interface to file system
** and other generic operating system specific
** services.
**
** FIX: probably should set umask on copies (etc)
** Note: Scurrent() needs to be replaced with Scaller() for
** the module ..
*/
#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 "stack.h"
//#define MUD_SECURE
#ifdef __WIN32__
#define mkdir(A,B) mkdir(A)
#endif
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.
*
* 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 * lpc_list_files(Val * 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];
#ifdef MUD_SECURE
if (!o_dir_read_ok(Scaller(), path->u.string)) return Const(0);
#endif
if (path->u.string->length >= PATH_SIZE)
{
efun_error("Path too long for ls(). Path was (%s)\n", path->u.string);
return Const(0);
}
if (path->u.string->str[0] == '/')
{
efun_error("Invalid use of ls() efun. Illegal leading slash.\n");
return Const(0);
}
if (path->u.string->str[0] == '\0')
strcpy(path2, ".");
else
strcpy(path2, path->u.string->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 Const(0);
}
dirp = opendir(path2);
if (dirp == NULL)
{
efun_error("No such directory '%s'\n", path2);
return Const(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]);
}
#ifndef __WIN32__
if (truncated) add_message("***TRUNCATED***\n");
#endif
free((LSFILES **) names);
closedir(dirp);
return ret;
}
Val * lpc_remove_file(Val * path)
{
#ifdef MUD_SECURE
if (!o_write_ok(Scaller(), path->u.string)) return Const(0);
#endif
if (unlink(path->u.string->str) == -1)
{
/* add_message("No such file: %s\n", path); */
return Const(0);
}
return Const(1);
}
Val * lpc_copy_file(Val * src, Val * dst)
{
FILE *src_f, *dst_f;
int c;
#ifdef MUD_SECURE
if (!o_read_ok(Scaller(), src->u.string)) return Const(0);
if (!o_write_ok(Scaller(), dst->u.string)) return Const(0);
#endif
src_f = fopen(src->u.string->str, "r");
if (src_f == 0) return Const(0);
dst_f = fopen(dst->u.string->str, "w");
if (dst_f == 0)
{
fclose(src_f);
return Const(0);
}
while ((c = fgetc(src_f)) != EOF)
fputc(c, dst_f);
fclose(src_f);
fclose(dst_f);
return Const(1);
}
Val * lpc_rename_file(Val * src, Val * dst)
{
extern int sys_nerr;
/* extern char *sys_errlist[]; */
#ifdef MUD_SECURE
if (!o_read_ok(Scaller(), src->u.string)) return Const(0);
if (!o_write_ok(Scaller(), dst->u.string)) return Const(0);
#endif
if (rename(src->u.string->str, dst->u.string->str) == -1)
{
efun_error("rename: %s\n",
errno < sys_nerr ? sys_errlist[errno] : "unknown error");
return Const(0);
}
return Const(1);
}
Val * lpc_write_file(Val * file, Val * str)
{
FILE *f;
#ifdef MUD_SECURE
if (!o_write_ok(Scaller(), file->u.string)) return Const(0);
#endif
f = fopen(file->u.string->str, "a");
if (f == 0) return Const(0);
fwrite(str->u.string->str, str->u.string->length, 1, f);
fclose(f);
return Const(1);
}
Val * lpc_file_size(Val * file)
{
struct stat st;
#ifdef MUD_SECURE
if (!o_read_ok(Scaller(), file)) return Const(0);
#endif
if (stat(file->u.string->str, &st) == -1) return make_number(-1);
if (S_IFDIR & st.st_mode) return make_number(-2);
return make_number(st.st_size);
}
/*
* grab_file changed to return a string
*/
#define READ_FILE_MAX_SIZE 500000
Val * lpc_char_grab_file(Val * file, Val * fromV, Val * toV)
{
FILE *f;
char *buf = 0;
int i, from, to;
Val *ret;
if (!file->u.string) return Const(0);
#ifdef MUD_SECURE
if (!o_read_ok(Scaller(), file->u.string)) return Const(0);
#endif
from = fromV->u.number;
to = toV->u.number;
if (from < 0) from = 0;
if (to <= 0) to = from + READ_FILE_MAX_SIZE - 1;
i = lpc_file_size(file)->u.number;
if (i < 0) return Const(0);
if (i < to) to = i;
if (from > to) from = to;
f = fopen(file->u.string->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));
// cause we don't want 2 refs to it?
ret->u.string->refs--;
free(buf);
return ret;
}
Val * lpc_mkdir(Val * path)
{
#ifdef MUD_SECURE
if (!o_write_ok(Scaller(), path->u.string)) return Const(0);
#endif
if (mkdir(path->u.string->str, 0770) == -1)
{
efun_error("mkdir(): invalid path\n");
return Const(0);
}
return Const(1);
}
Val * lpc_rmdir(Val * path)
{
#ifdef MUD_SECURE
if (!o_write_ok(Scaller(), path->u.string)) return Const(0);
#endif
if (rmdir(path->u.string->str) == -1) return Const(0);
return Const(1);
}
Val * lpc_chmod(Val * path, Val * mode)
{
return Const(0);
}
#if 0
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;
}
#endif
Val * lpc_time()
{
return make_number(time(0));
}
Val * lpc_stat(Val * name)
{
struct stat info;
Val * ret;
if (!name->u.string) return Const(0);
if (stat(name->u.string->str, &info) == -1) return Const(0);
ret = allocate_array(4);
ret->u.vec->item[0].type = T_NUMBER;
ret->u.vec->item[0].u.number = info.st_size;
ret->u.vec->item[1].type = T_NUMBER;
ret->u.vec->item[1].u.number = info.st_atime;
ret->u.vec->item[2].type = T_NUMBER;
ret->u.vec->item[2].u.number = info.st_mtime;
ret->u.vec->item[3].type = T_NUMBER;
ret->u.vec->item[3].u.number = info.st_ctime;
return ret;
}
#define HOST_NAME_LEN 256
Val * lpc_query_host_name()
{
static char name[HOST_NAME_LEN];
#ifdef __WIN32__
strcpy(name, "Windoze box");
#else
gethostname(name, sizeof name);
#endif
name[sizeof name - 1] = '\0'; /* Just to make sure */
return make_string(name);
}