diff options
Diffstat (limited to 'erts/emulator/drivers/unix/bin_drv.c')
-rw-r--r-- | erts/emulator/drivers/unix/bin_drv.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/erts/emulator/drivers/unix/bin_drv.c b/erts/emulator/drivers/unix/bin_drv.c new file mode 100644 index 0000000000..1827187d57 --- /dev/null +++ b/erts/emulator/drivers/unix/bin_drv.c @@ -0,0 +1,224 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* Purpose: Binary file driver interface , used for code loading */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sys.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "erl_driver.h" +#include <errno.h> + +#ifdef NO_UMASK +#define FILE_MODE 0644 +#else +#define FILE_MODE 0666 +#endif + +static int this_port; + +static long bin_start(); +static int bin_init(),bin_stop(),bin_erlang_read(); +static int read_fill(), write_fill(); + +const struct erl_drv_entry bin_driver_entry = { + bin_init, + bin_start, + bin_stop, + bin_erlang_read, + NULL, + NULL, + "binary_filer" +}; + + + +static int bin_init() +{ + this_port = -1; + return 0; +} + + +static long bin_start(port,buf) +int port; +char *buf; +{ + + if (this_port != -1) + return(-1); + this_port = port; + return(port); +} + + +static int bin_stop() +{ + this_port = -1; +} + + +static int bin_erlang_read(port,buf,count) +long port; +char *buf; +int count; + +{ + struct stat statbuf; + int i,size,fd,rval; + char *t,*rbuf; + + buf[count] = '\0'; + switch (*buf) { + case 'c' : + if (chdir(buf+1) == 0) /* sucsess */ + driver_output(this_port,"y",1); + else + driver_output(this_port,"n",1); + return 0; + case 'f': +#ifdef MSDOS + if ((fd = open(buf+1,O_RDONLY|O_BINARY)) < 0) { +#else + if ((fd = open(buf+1,O_RDONLY, 0)) < 0) { +#endif + driver_output(this_port,"n",1); + return 0; + } + if (stat(buf+1,&statbuf) < 0) { + driver_output(this_port,"n",1); + close(fd); + return 0; + } + if (S_ISREG(statbuf.st_mode)) + size = statbuf.st_size; + else + size = BUFSIZ; + + if ((rbuf = (char*) driver_alloc(1 + size)) == NULL) { + fprintf(stderr,"Out of memory\n"); + close(fd); + driver_output(this_port,"n",1); + return 0; + } + if (S_ISREG(statbuf.st_mode)) { + if (read_fill(fd,1+rbuf,size) != size) { + driver_free(rbuf); + close(fd); + driver_output(this_port,"n",1); + return 0;; + } + } + /* The idea here is that if it's a regular file read the entire + * entire file and if it's a device file or a tty try to read + * until errno != EINTR + */ + + else { + while (1) { + rval = read(fd,1+rbuf,size); + if (rval < 0 && errno == EINTR) + continue; + if (rval < 0) { + driver_free(rbuf); + close(fd); + driver_output(this_port,"n",1); + return 0; + } + size = rval; + break; + } + } + rbuf[0] = 'y'; + driver_output(this_port,rbuf,1+size); + driver_free(rbuf); + close(fd); + return 0; + case 'w': +#ifdef MSDOS + if ((fd = open(buf+1, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + FILE_MODE)) < 0) { +#else + if ((fd = open(buf+1, O_WRONLY | O_CREAT | O_TRUNC, FILE_MODE)) < 0) { +#endif + driver_output(this_port,"n",1); + return 0; + } + t = buf+1; i = 1; + while(*t && i++ < count) t++; + t++; + /* t now points to the contents of what we shall write */ + size = count - 1 - i; + + /* gotta write_fill if we are writing to a slow device + such as /dev/audio */ + + if (write_fill (fd,t,size) != size) { + driver_output(this_port,"n",1); + close(fd); + return 0; + } + driver_output(this_port,"y",1); + close(fd); + return 0; + default: + driver_failure(this_port,-1); + return 0; + } +} + + +static int write_fill(fd, buf, len) +char *buf; +{ + int i, done = 0; + + do { + if ((i = write(fd, buf+done, len-done)) < 0) { + if (errno != EINTR) + return (i); + i = 0; + } + done += i; + } while (done < len); + return (len); +} + + +static int read_fill(fd, buf, len) +char *buf; +{ + int i, got = 0; + + do { + if ((i = read(fd, buf+got, len-got)) <= 0) { + if (i == 0 || errno != EINTR) + return (i); + i = 0; + } + got += i; + } while (got < len); + return (len); +} + |