mirror of https://github.com/Cisco-Talos/clamav
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1018 lines
24 KiB
1018 lines
24 KiB
/*
|
|
* The builtin File object.
|
|
* Copyright (c) 1998-1999 New Generation Software (NGS) Oy
|
|
*
|
|
* Author: Markku Rossi <mtr@ngs.fi>
|
|
*/
|
|
|
|
/*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
* MA 02111-1307, USA
|
|
*/
|
|
|
|
/*
|
|
* $Source: /tmp/cvsroot-15-2-2007/clamav-devel/libclamav/js/b_file.c,v $
|
|
* $Id: b_file.c,v 1.2 2006/10/28 11:27:44 njh Exp $
|
|
*/
|
|
|
|
/*
|
|
* Static methods.
|
|
*
|
|
* byteToString (BYTE) => string
|
|
* + chmod (string, int) => boolean
|
|
* + lstat (PATH) => array / boolean
|
|
* + remove (PATH) => boolean
|
|
* + rename (FROM, TO) => boolean
|
|
* + stat (PATH) => array / boolean
|
|
* stringToByte (STRING) => number
|
|
*
|
|
* Methods:
|
|
*
|
|
* open (MODE) => boolean
|
|
* close () => boolean
|
|
* setPosition (POSITION [, WHENCE]) => boolean
|
|
* getPosition () => integer
|
|
* eof () => boolean
|
|
* read (SIZE) => string
|
|
* readln () => string
|
|
* readByte () => integer
|
|
* write (STRING) => boolean
|
|
* writeln (STRING) => boolean
|
|
* writeByte (INTEGER) => boolean
|
|
* + ungetByte (BYTE) => boolean
|
|
* flush () => boolean
|
|
* getLength () => integer
|
|
* exists () => boolean
|
|
* error () => integer
|
|
* clearError () => true
|
|
*
|
|
* Properties:
|
|
*
|
|
* autoFlush boolean mutable
|
|
* bufferSize integer mutable
|
|
*/
|
|
#if HAVE_CONFIG_H
|
|
#include "clamav-config.h"
|
|
#endif
|
|
|
|
#ifdef CL_EXPERIMENTAL
|
|
|
|
#include "jsint.h"
|
|
|
|
#include <sys/stat.h>
|
|
|
|
/*
|
|
* Types and definitions.
|
|
*/
|
|
|
|
#define INSECURE() \
|
|
do { \
|
|
if (secure_mode) \
|
|
goto insecure_feature; \
|
|
} while (0)
|
|
|
|
/* Class context. */
|
|
struct file_ctx_st
|
|
{
|
|
/* Static methods. */
|
|
JSSymbol s_byteToString;
|
|
JSSymbol s_chmod;
|
|
JSSymbol s_lstat;
|
|
JSSymbol s_remove;
|
|
JSSymbol s_rename;
|
|
JSSymbol s_stat;
|
|
JSSymbol s_stringToByte;
|
|
|
|
/* Methods */
|
|
JSSymbol s_open;
|
|
JSSymbol s_close;
|
|
JSSymbol s_setPosition;
|
|
JSSymbol s_getPosition;
|
|
JSSymbol s_eof;
|
|
JSSymbol s_read;
|
|
JSSymbol s_readln;
|
|
JSSymbol s_readByte;
|
|
JSSymbol s_write;
|
|
JSSymbol s_writeln;
|
|
JSSymbol s_writeByte;
|
|
JSSymbol s_ungetByte;
|
|
JSSymbol s_flush;
|
|
JSSymbol s_getLength;
|
|
JSSymbol s_exists;
|
|
JSSymbol s_error;
|
|
JSSymbol s_clearError;
|
|
|
|
/* Properties. */
|
|
JSSymbol s_autoFlush;
|
|
JSSymbol s_bufferSize;
|
|
};
|
|
|
|
typedef struct file_ctx_st FileCtx;
|
|
|
|
/* Instance context. */
|
|
struct file_instance_ctx_st
|
|
{
|
|
/* Flags. */
|
|
unsigned int dont_close : 1;
|
|
|
|
char *path;
|
|
JSIOStream *stream;
|
|
|
|
/* Needed for the delete_proc. */
|
|
JSVirtualMachine *vm;
|
|
};
|
|
|
|
typedef struct file_instance_ctx_st FileInstanceCtx;
|
|
|
|
|
|
/*
|
|
* Static functions.
|
|
*/
|
|
|
|
/* Method proc. */
|
|
static int
|
|
method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
|
|
void *instance_context, JSSymbol method, JSNode *result_return,
|
|
JSNode *args)
|
|
{
|
|
FileCtx *ctx = builtin_info->obj_context;
|
|
FileInstanceCtx *ictx = instance_context;
|
|
char buf[256];
|
|
long int li = 0;
|
|
int i = 0;
|
|
char *cp;
|
|
int secure_mode = vm->security & JS_VM_SECURE_FILE;
|
|
|
|
/* The default result is false. */
|
|
result_return->type = JS_BOOLEAN;
|
|
result_return->u.vboolean = 0;
|
|
|
|
/*
|
|
* Static methods.
|
|
*/
|
|
if (method == ctx->s_byteToString)
|
|
{
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
|
|
i = -1;
|
|
if (args[1].type == JS_INTEGER)
|
|
{
|
|
i = args[1].u.vinteger;
|
|
if (i < 0 || i > 255)
|
|
i = -1;
|
|
}
|
|
|
|
js_vm_make_string (vm, result_return, NULL, 1);
|
|
|
|
if (i < 0)
|
|
result_return->u.vstring->len = 0;
|
|
else
|
|
result_return->u.vstring->data[0] = i;
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == ctx->s_chmod)
|
|
{
|
|
INSECURE ();
|
|
|
|
if (args->u.vinteger != 2)
|
|
goto argument_error;
|
|
if (args[1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
if (args[2].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
result_return->type= JS_BOOLEAN;
|
|
|
|
cp = js_string_to_c_string (vm, &args[1]);
|
|
result_return->u.vboolean = (chmod (cp, args[2].u.vinteger) == 0);
|
|
js_free (cp);
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == ctx->s_lstat || method == ctx->s_stat)
|
|
{
|
|
char *path;
|
|
struct stat stat_st;
|
|
int result;
|
|
|
|
INSECURE ();
|
|
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
|
|
path = js_string_to_c_string (vm, &args[1]);
|
|
|
|
#if HAVE_LSTAT
|
|
if (method == ctx->s_lstat)
|
|
result = lstat (path, &stat_st);
|
|
else
|
|
#endif /* HAVE_LSTAT */
|
|
result = stat (path, &stat_st);
|
|
|
|
js_free (path);
|
|
|
|
if (result >= 0)
|
|
{
|
|
JSNode *node;
|
|
|
|
/* Success. */
|
|
js_vm_make_array (vm, result_return, 13);
|
|
node = result_return->u.varray->data;
|
|
|
|
/* dev */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_dev;
|
|
node++;
|
|
|
|
/* ino */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_ino;
|
|
node++;
|
|
|
|
/* mode */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_mode;
|
|
node++;
|
|
|
|
/* nlink */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_nlink;
|
|
node++;
|
|
|
|
/* uid */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_uid;
|
|
node++;
|
|
|
|
/* gid */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_gid;
|
|
node++;
|
|
|
|
/* rdev */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_rdev;
|
|
node++;
|
|
|
|
/* size */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_size;
|
|
node++;
|
|
|
|
/* atime */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_atime;
|
|
node++;
|
|
|
|
/* mtime */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_mtime;
|
|
node++;
|
|
|
|
/* ctime */
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = stat_st.st_ctime;
|
|
node++;
|
|
|
|
/* blksize */
|
|
node->type = JS_INTEGER;
|
|
#if HAVE_STAT_ST_ST_BLKSIZE
|
|
node->u.vinteger = stat_st.st_blksize;
|
|
#else /* not HAVE_STAT_ST_ST_BLKSIZE */
|
|
node->u.vinteger = 0;
|
|
#endif /* not HAVE_STAT_ST_ST_BLKSIZE */
|
|
node++;
|
|
|
|
/* blocks */
|
|
node->type = JS_INTEGER;
|
|
#if HAVE_STAT_ST_ST_BLOCKS
|
|
node->u.vinteger = stat_st.st_blocks;
|
|
#else /* not HAVE_STAT_ST_ST_BLOCKS */
|
|
node->u.vinteger = 0;
|
|
#endif /* not HAVE_STAT_ST_ST_BLOCKS */
|
|
}
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == ctx->s_remove)
|
|
{
|
|
char *path;
|
|
|
|
INSECURE ();
|
|
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
path = js_string_to_c_string (vm, &args[1]);
|
|
i = remove (path);
|
|
js_free (path);
|
|
|
|
result_return->u.vboolean = (i == 0);
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == ctx->s_rename)
|
|
{
|
|
char *path1;
|
|
char *path2;
|
|
|
|
INSECURE ();
|
|
|
|
if (args->u.vinteger != 2)
|
|
goto argument_error;
|
|
|
|
if (args[1].type != JS_STRING || args[2].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
path1 = js_string_to_c_string (vm, &args[1]);
|
|
path2 = js_string_to_c_string (vm, &args[2]);
|
|
|
|
i = rename (path1, path2);
|
|
|
|
js_free (path1);
|
|
js_free (path2);
|
|
|
|
result_return->u.vboolean = (i == 0);
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == ctx->s_stringToByte)
|
|
{
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
|
|
result_return->type = JS_INTEGER;
|
|
|
|
if (args[1].type == JS_STRING && args[1].u.vstring->len > 0)
|
|
result_return->u.vinteger = args[i].u.vstring->data[0];
|
|
else
|
|
result_return->u.vinteger = 0;
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (method == vm->syms.s_toString)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
if (ictx)
|
|
js_vm_make_string (vm, result_return, ictx->path, strlen (ictx->path));
|
|
else
|
|
js_vm_make_static_string (vm, result_return, "File", 4);
|
|
}
|
|
/* ********************************************************************** */
|
|
else if (ictx)
|
|
{
|
|
/*
|
|
* Instance methods.
|
|
*/
|
|
|
|
if (method == ctx->s_open)
|
|
{
|
|
int readp = 0;
|
|
int writep = 0;
|
|
|
|
INSECURE ();
|
|
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_STRING
|
|
|| args[1].u.vstring->len == 0
|
|
|| args[1].u.vstring->len > 3)
|
|
goto argument_type_error;
|
|
|
|
i = args[1].u.vstring->len;
|
|
memcpy (buf, args[1].u.vstring->data, i);
|
|
|
|
if (buf[i - 1] != 'b')
|
|
buf[i++] = 'b';
|
|
buf[i] = '\0';
|
|
|
|
/* Check that the mode is valid. */
|
|
if (strcmp (buf, "rb") == 0)
|
|
readp = 1;
|
|
else if (strcmp (buf, "wb") == 0)
|
|
writep = 1;
|
|
else if (strcmp (buf, "ab") == 0)
|
|
writep = 1;
|
|
else if (strcmp (buf, "r+b") == 0)
|
|
readp = writep = 1;
|
|
else if (strcmp (buf, "w+b") == 0)
|
|
readp = writep = 1;
|
|
else if (strcmp (buf, "a+b") == 0)
|
|
readp = writep = 1;
|
|
else
|
|
{
|
|
sprintf (vm->error, "File.%s(): illegal open mode \"%s\"",
|
|
js_vm_symname (vm, method), buf);
|
|
js_vm_error (vm);
|
|
}
|
|
|
|
if (ictx->stream == NULL)
|
|
{
|
|
/* Do open. */
|
|
JS_VM_ALLOCATE_FD (vm, "File.open()");
|
|
ictx->stream = js_iostream_file (fopen (ictx->path, buf), readp,
|
|
writep, 1);
|
|
if (ictx->stream == NULL)
|
|
JS_VM_FREE_FD (vm);
|
|
else
|
|
result_return->u.vboolean = 1;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_close)
|
|
{
|
|
if (ictx->stream != NULL)
|
|
{
|
|
int result = 0;
|
|
|
|
if (!ictx->dont_close)
|
|
{
|
|
result = js_iostream_close (ictx->stream);
|
|
JS_VM_FREE_FD (vm);
|
|
}
|
|
|
|
ictx->stream = NULL;
|
|
result_return->u.vboolean = result >= 0;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_setPosition)
|
|
{
|
|
if (args->u.vinteger == 1)
|
|
{
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
li = args[1].u.vinteger;
|
|
i = SEEK_SET;
|
|
}
|
|
else if (args->u.vinteger == 2)
|
|
{
|
|
if (args[2].type == JS_INTEGER)
|
|
{
|
|
switch (args[2].u.vinteger)
|
|
{
|
|
case 1:
|
|
i = SEEK_CUR;
|
|
break;
|
|
|
|
case 2:
|
|
i = SEEK_END;
|
|
break;
|
|
|
|
default:
|
|
i = SEEK_SET;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
i = SEEK_SET;
|
|
}
|
|
else
|
|
goto argument_error;
|
|
|
|
if (ictx->stream && js_iostream_seek (ictx->stream, li, i) >= 0)
|
|
result_return->u.vboolean = 1;
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_getPosition)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
result_return->type = JS_INTEGER;
|
|
if (ictx->stream == NULL)
|
|
result_return->u.vinteger = -1;
|
|
else
|
|
result_return->u.vinteger
|
|
= js_iostream_get_position (ictx->stream);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_eof)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
if (ictx->stream != NULL)
|
|
result_return->u.vboolean = ictx->stream->at_eof;
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_read)
|
|
{
|
|
size_t got;
|
|
char *buffer;
|
|
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_INTEGER || args[1].u.vinteger < 0)
|
|
goto argument_type_error;
|
|
|
|
if (ictx->stream != NULL)
|
|
{
|
|
buffer = js_vm_alloc (vm, args[1].u.vinteger + 1);
|
|
|
|
got = js_iostream_read (ictx->stream, buffer,
|
|
args[1].u.vinteger);
|
|
if (got < 0)
|
|
got = 0;
|
|
|
|
js_vm_make_static_string (vm, result_return, buffer, got);
|
|
result_return->u.vstring->staticp = 0;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_readln)
|
|
{
|
|
int ch;
|
|
unsigned int bufpos = 0;
|
|
unsigned int buflen = 0;
|
|
char *buffer = NULL;
|
|
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
if (ictx->stream != NULL)
|
|
{
|
|
/* Flush all buffered output data. */
|
|
js_iostream_flush (ictx->stream);
|
|
|
|
while (1)
|
|
{
|
|
/* Process all the data we have in the buffer. */
|
|
for (; ictx->stream->bufpos < ictx->stream->data_in_buf
|
|
&& (ictx->stream->buffer[ictx->stream->bufpos]
|
|
!= '\n');
|
|
ictx->stream->bufpos++)
|
|
{
|
|
if (bufpos >= buflen)
|
|
{
|
|
buflen += 1024;
|
|
buffer = js_vm_realloc (vm, buffer, buflen);
|
|
}
|
|
buffer[bufpos++]
|
|
= ictx->stream->buffer[ictx->stream->bufpos];
|
|
}
|
|
|
|
if (ictx->stream->bufpos >= ictx->stream->data_in_buf)
|
|
{
|
|
int result;
|
|
|
|
/* Read past the buffer. */
|
|
if (ictx->stream->at_eof)
|
|
/* EOF seen. */
|
|
break;
|
|
|
|
/* Read more data. */
|
|
js_iostream_fill_buffer (ictx->stream);
|
|
}
|
|
else
|
|
{
|
|
/* Got it. Skip the newline character. */
|
|
ictx->stream->bufpos++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Remove '\r' characters. */
|
|
while (bufpos > 0)
|
|
if (buffer[bufpos - 1] == '\r')
|
|
bufpos--;
|
|
else
|
|
break;
|
|
|
|
if (buffer == NULL)
|
|
/* An empty string. Allocate one byte. */
|
|
buffer = js_vm_alloc (vm, 1);
|
|
|
|
/*
|
|
* Use the data we already had. In maximum, it has only
|
|
* 1023 bytes overhead.
|
|
*/
|
|
js_vm_make_static_string (vm, result_return, buffer, bufpos);
|
|
result_return->u.vstring->staticp = 0;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_readByte)
|
|
{
|
|
result_return->type = JS_INTEGER;
|
|
if (ictx->stream == NULL)
|
|
result_return->u.vinteger = -1;
|
|
else
|
|
{
|
|
retry:
|
|
if (ictx->stream->bufpos < ictx->stream->data_in_buf)
|
|
result_return->u.vinteger
|
|
= ictx->stream->buffer[ictx->stream->bufpos++];
|
|
else
|
|
{
|
|
if (ictx->stream->at_eof)
|
|
result_return->u.vinteger = -1;
|
|
else
|
|
{
|
|
js_iostream_fill_buffer (ictx->stream);
|
|
goto retry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_write || method == ctx->s_writeln)
|
|
{
|
|
size_t wrote;
|
|
int autoflush;
|
|
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_STRING)
|
|
goto argument_type_error;
|
|
|
|
if (ictx->stream != NULL)
|
|
{
|
|
autoflush = ictx->stream->autoflush;
|
|
ictx->stream->autoflush = 0;
|
|
|
|
wrote = js_iostream_write (ictx->stream,
|
|
args[1].u.vstring->data,
|
|
args[1].u.vstring->len);
|
|
if (wrote == args[1].u.vstring->len)
|
|
{
|
|
/* Success. */
|
|
result_return->u.vboolean = 1;
|
|
|
|
if (method == ctx->s_writeln)
|
|
if (js_iostream_write (ictx->stream,
|
|
JS_HOST_LINE_BREAK,
|
|
JS_HOST_LINE_BREAK_LEN) < 0)
|
|
/* No, it was not a success. */
|
|
result_return->u.vboolean = 0;
|
|
}
|
|
|
|
ictx->stream->autoflush = autoflush;
|
|
if (autoflush)
|
|
js_iostream_flush (ictx->stream);
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_writeByte)
|
|
{
|
|
unsigned char buf[1];
|
|
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
buf[0] = args[1].u.vinteger;
|
|
|
|
if (ictx->stream != NULL)
|
|
result_return->u.vboolean
|
|
= js_iostream_write (ictx->stream, buf, 1) >= 0;
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_ungetByte)
|
|
{
|
|
if (args->u.vinteger != 1)
|
|
goto argument_error;
|
|
if (args[1].type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
if (ictx->stream != NULL)
|
|
result_return->u.vboolean
|
|
= js_iostream_unget (ictx->stream, args[1].u.vinteger);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_flush)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
if (ictx->stream != NULL && js_iostream_flush (ictx->stream) >= 0)
|
|
result_return->u.vboolean = 1;
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_getLength)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
/* The default error code is an integer -1. */
|
|
result_return->type = JS_INTEGER;
|
|
result_return->u.vinteger = -1;
|
|
|
|
if (ictx->stream != NULL)
|
|
result_return->u.vinteger
|
|
= js_iostream_get_length (ictx->stream);
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_exists)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
if (ictx->stream)
|
|
{
|
|
/* Since we have opened the file, it must exist. */
|
|
result_return->u.vboolean = 1;
|
|
}
|
|
else
|
|
{
|
|
struct stat stat_st;
|
|
|
|
if (stat (ictx->path, &stat_st) >= 0)
|
|
result_return->u.vboolean = 1;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_error)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
result_return->type = JS_INTEGER;
|
|
if (ictx->stream == NULL)
|
|
result_return->u.vinteger = -1;
|
|
else
|
|
result_return->u.vinteger = ictx->stream->error;
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (method == ctx->s_clearError)
|
|
{
|
|
if (args->u.vinteger != 0)
|
|
goto argument_error;
|
|
|
|
if (ictx->stream != NULL)
|
|
{
|
|
ictx->stream->error = 0;
|
|
result_return->u.vboolean = 1;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else
|
|
return JS_PROPERTY_UNKNOWN;
|
|
}
|
|
else
|
|
return JS_PROPERTY_UNKNOWN;
|
|
|
|
return JS_PROPERTY_FOUND;
|
|
|
|
|
|
/*
|
|
* Error handling.
|
|
*/
|
|
|
|
argument_error:
|
|
sprintf (vm->error, "File.%s(): illegal amount of arguments",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
|
|
argument_type_error:
|
|
sprintf (vm->error, "File.%s(): illegal argument",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
|
|
insecure_feature:
|
|
sprintf (vm->error, "File.%s(): not allowed in secure mode",
|
|
js_vm_symname (vm, method));
|
|
js_vm_error (vm);
|
|
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
/* Property proc. */
|
|
static int
|
|
property (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
|
|
void *instance_context, JSSymbol property, int set, JSNode *node)
|
|
{
|
|
FileCtx *ctx = builtin_info->obj_context;
|
|
FileInstanceCtx *ictx = instance_context;
|
|
|
|
if (ictx)
|
|
{
|
|
/* Instance properties. */
|
|
if (property == ctx->s_autoFlush)
|
|
{
|
|
if (ictx->stream == NULL)
|
|
goto not_open;
|
|
|
|
if (set)
|
|
{
|
|
if (node->type != JS_BOOLEAN)
|
|
goto argument_type_error;
|
|
|
|
ictx->stream->autoflush = node->u.vboolean;
|
|
}
|
|
else
|
|
{
|
|
node->type = JS_BOOLEAN;
|
|
node->u.vboolean = ictx->stream->autoflush;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else if (property == ctx->s_bufferSize)
|
|
{
|
|
if (ictx->stream == NULL)
|
|
goto not_open;
|
|
|
|
if (set)
|
|
{
|
|
unsigned char *buf;
|
|
unsigned int len;
|
|
|
|
if (node->type != JS_INTEGER)
|
|
goto argument_type_error;
|
|
|
|
js_iostream_flush (ictx->stream);
|
|
|
|
len = node->u.vinteger;
|
|
buf = js_realloc (vm, ictx->stream->buffer, len);
|
|
|
|
ictx->stream->buflen = len;
|
|
ictx->stream->buffer = buf;
|
|
}
|
|
else
|
|
{
|
|
node->type = JS_INTEGER;
|
|
node->u.vinteger = ictx->stream->buflen;
|
|
}
|
|
}
|
|
/* ***************************************************************** */
|
|
else
|
|
{
|
|
if (!set)
|
|
node->type = JS_UNDEFINED;
|
|
|
|
return JS_PROPERTY_UNKNOWN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!set)
|
|
node->type = JS_UNDEFINED;
|
|
|
|
return JS_PROPERTY_UNKNOWN;
|
|
}
|
|
|
|
return JS_PROPERTY_FOUND;
|
|
|
|
|
|
/* Error handling. */
|
|
|
|
argument_type_error:
|
|
sprintf (vm->error, "File.%s: illegal value",
|
|
js_vm_symname (vm, property));
|
|
js_vm_error (vm);
|
|
|
|
not_open:
|
|
sprintf (vm->error, "File.%s: the stream is not opened",
|
|
js_vm_symname (vm, property));
|
|
js_vm_error (vm);
|
|
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* New proc. */
|
|
static void
|
|
new_proc (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, JSNode *args,
|
|
JSNode *result_return)
|
|
{
|
|
FileInstanceCtx *instance;
|
|
|
|
if (args->u.vinteger != 1)
|
|
{
|
|
sprintf (vm->error, "new File(): illegal amount of arguments");
|
|
js_vm_error (vm);
|
|
}
|
|
if (args[1].type != JS_STRING)
|
|
{
|
|
sprintf (vm->error, "new File(): illegal argument");
|
|
js_vm_error (vm);
|
|
}
|
|
|
|
instance = js_calloc (vm, 1, sizeof (*instance));
|
|
instance->path = js_string_to_c_string (vm, &args[1]);
|
|
instance->vm = vm;
|
|
|
|
js_vm_builtin_create (vm, result_return, builtin_info, instance);
|
|
}
|
|
|
|
/* Delete proc. */
|
|
static void
|
|
delete_proc (JSBuiltinInfo *builtin_info, void *instance_context)
|
|
{
|
|
FileInstanceCtx *ictx = instance_context;
|
|
|
|
if (ictx)
|
|
{
|
|
if (ictx->stream)
|
|
{
|
|
if (!ictx->dont_close)
|
|
{
|
|
js_iostream_close (ictx->stream);
|
|
JS_VM_FREE_FD (ictx->vm);
|
|
}
|
|
|
|
ictx->stream = NULL;
|
|
}
|
|
|
|
js_free (ictx->path);
|
|
js_free (ictx);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Global functions.
|
|
*/
|
|
|
|
void
|
|
js_builtin_File (JSVirtualMachine *vm)
|
|
{
|
|
JSNode *n;
|
|
JSBuiltinInfo *info;
|
|
FileCtx *ctx;
|
|
|
|
ctx = js_calloc (vm, 1, sizeof (*ctx));
|
|
|
|
ctx->s_byteToString = js_vm_intern (vm, "byteToString");
|
|
ctx->s_chmod = js_vm_intern (vm, "chmod");
|
|
ctx->s_lstat = js_vm_intern (vm, "lstat");
|
|
ctx->s_remove = js_vm_intern (vm, "remove");
|
|
ctx->s_rename = js_vm_intern (vm, "rename");
|
|
ctx->s_stat = js_vm_intern (vm, "stat");
|
|
ctx->s_stringToByte = js_vm_intern (vm, "stringToByte");
|
|
|
|
ctx->s_open = js_vm_intern (vm, "open");
|
|
ctx->s_close = js_vm_intern (vm, "close");
|
|
ctx->s_setPosition = js_vm_intern (vm, "setPosition");
|
|
ctx->s_getPosition = js_vm_intern (vm, "getPosition");
|
|
ctx->s_eof = js_vm_intern (vm, "eof");
|
|
ctx->s_read = js_vm_intern (vm, "read");
|
|
ctx->s_readln = js_vm_intern (vm, "readln");
|
|
ctx->s_readByte = js_vm_intern (vm, "readByte");
|
|
ctx->s_write = js_vm_intern (vm, "write");
|
|
ctx->s_writeln = js_vm_intern (vm, "writeln");
|
|
ctx->s_writeByte = js_vm_intern (vm, "writeByte");
|
|
ctx->s_ungetByte = js_vm_intern (vm, "ungetByte");
|
|
ctx->s_flush = js_vm_intern (vm, "flush");
|
|
ctx->s_getLength = js_vm_intern (vm, "getLength");
|
|
ctx->s_exists = js_vm_intern (vm, "exists");
|
|
ctx->s_error = js_vm_intern (vm, "error");
|
|
ctx->s_clearError = js_vm_intern (vm, "clearError");
|
|
|
|
ctx->s_autoFlush = js_vm_intern (vm, "autoFlush");
|
|
ctx->s_bufferSize = js_vm_intern (vm, "bufferSize");
|
|
|
|
|
|
/* Object information. */
|
|
|
|
info = js_vm_builtin_info_create (vm);
|
|
|
|
info->method_proc = method;
|
|
info->property_proc = property;
|
|
info->new_proc = new_proc;
|
|
info->delete_proc = delete_proc;
|
|
info->obj_context = ctx;
|
|
info->obj_context_delete = js_free;
|
|
|
|
/* Define it. */
|
|
n = &vm->globals[js_vm_intern (vm, "File")];
|
|
js_vm_builtin_create (vm, n, info, NULL);
|
|
}
|
|
|
|
|
|
void
|
|
js_builtin_File_new (JSVirtualMachine *vm, JSNode *result_return,
|
|
char *path, JSIOStream *stream, int dont_close)
|
|
{
|
|
JSNode *n;
|
|
FileInstanceCtx *ictx;
|
|
|
|
/* Lookup our context. */
|
|
n = &vm->globals[js_vm_intern (vm, "File")];
|
|
|
|
/* Create a file instance. */
|
|
ictx = js_calloc (vm, 1, sizeof (*ictx));
|
|
ictx->path = js_strdup (vm, path);
|
|
ictx->stream = stream;
|
|
ictx->dont_close = dont_close;
|
|
ictx->vm = vm;
|
|
|
|
/* Create the builtin. */
|
|
js_vm_builtin_create (vm, result_return, n->u.vbuiltin->info, ictx);
|
|
}
|
|
#endif /*CL_EXPERIMENTAL*/
|
|
|