#include "file-64.h" /* must appear before fcntl & unistd */ #include #include #include #include #include #include "exceptions.h" #include "ti-gc.h" #include "java_string.h" #include "mem-local.h" #include "native-file-utils.h" #include "native-utils.h" #include "runtime-options.h" #include "primitives.h" #include "T11NativeUtils4lang2ti.h" #include "layout!PT14FileDescriptor2io4java.h" #include "layout!PTAjbyte.h" #include "layout!Pjbyte.h" #include "layout!Pjint.h" #include "layout!T14FileDescriptor2io4java.h" typedef PT14FileDescriptor2io4java GP_FileDescriptor; static Pjint getFdPtr( const GP_FileDescriptor descriptor ) { Pjint fdPtr; CHECK_NULL_GLOBAL( descriptor ); FIELD_ADDR_GLOBAL( fdPtr, descriptor, f2fdT14FileDescriptor2io4java ); /* none of our distributed platforms support global file descriptors, so we need to detect this situation and prevent non-local file descriptors from being passed to a local file system call, which could result in an error return or even silent incorrect behavior if the integer descriptor happens to alias an unrelated local file descriptor. It can be proven that every FileDescriptor object referring to an explicitly opened file (i.e. not including stdin/stdout/stderr or network sockets) will always be local to the processor which called open() for it and assigned its consituent fd field. */ if (!isDirectlyAddressable(fdPtr)) tossIOException_str("File operation attempted on non-local file descriptor"); return fdPtr; } int getFd( const GP_FileDescriptor descriptor ) { jint fd; const Pjint fdPtr = getFdPtr( descriptor ); FENCE_PRE_READ(); DEREF_GLOBAL_jint( fd, fdPtr ); FENCE_POST_READ(); return fd; } /**********************************************************************/ void jclose( const GP_FileDescriptor descriptor ) { if (close( getFd( descriptor ) )) tossIOException(); } void jopen( const GP_FileDescriptor descriptor, const GP_JString name, int flags ) { const char *bytes; int fd; CHECK_NULL_GLOBAL( descriptor ); bytes = globalJstringToCstring( name ); #ifdef __CYGWIN__ flags = flags | O_BINARY; /* prevent CRLF -> LF translation */ #endif fd = open64( bytes, flags | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); if (fd == -1) tossIOException(); else { Pjint field = getFdPtr( descriptor ); jint jfd = (jint)fd; assert(((int)jfd) == fd); /* be careful for 64-bit platforms */ FENCE_PRE_WRITE(); ASSIGN_GLOBAL_jint( field, jfd ); FENCE_POST_WRITE(); } } jint jread( GP_FileDescriptor descriptor ) { unsigned char byte; switch (read( getFd( descriptor ), &byte, 1 )) { case 0: return -1; case 1: return byte; default: tossIOException(); } } jint jreadBytes( GP_FileDescriptor descriptor, PTAjbyte b, jint off, jint len ) { const int fd = getFd( descriptor ); JAVA_ARRAY_CHECK_GLOBAL( b, off, len, "in jreadBytes()" ); if (isDirectlyAddressable(b)) { /* read into local array */ jint received; jbyte* localbuf; /* we could use JAVA_ARRAY_ADDR_GLOBAL here, but that includes a redundant check */ FIELD_ADDR_LOCAL( localbuf, (TAjbyte *)TO_LOCAL(b), data[0] ); INDEX_LOCAL( localbuf, localbuf, off ); received = read( fd, localbuf, len ); if (received < 0) tossIOException(); else if (received == 0) return -1; else return received; } else { /* read into global array */ VARARRAY_DECLARE( jbyte, buffer, len ); jint received; VARARRAY_CREATE( jbyte, buffer, len ); received = read( fd, buffer, len ); if (received < 0) { VARARRAY_DESTROY( buffer ); tossIOException(); } else if (received == 0) { /* reached EOF */ VARARRAY_DESTROY( buffer ); return -1; } else { Pjbyte rem_buf; /* we could use JAVA_ARRAY_ADDR_GLOBAL here, but that includes a redundant check */ FIELD_ADDR_GLOBAL( rem_buf, b, data[0] ); INDEX_GLOBAL( rem_buf, rem_buf, off ); local_to_global_copy( buffer, rem_buf, received ); VARARRAY_DESTROY( buffer ); return received; } } } void jwrite( GP_FileDescriptor descriptor, char byte ) { /* We expect that write() of one byte will never return 0. */ if (write( getFd( descriptor ), &byte, 1 ) <= 0) tossIOException(); } void jwriteBytes( GP_FileDescriptor descriptor, PTAjbyte b, jint off, jint len ) { const int fd = getFd( descriptor ); JAVA_ARRAY_CHECK_GLOBAL( b, off, len, "in jwriteBytes()" ); if (isDirectlyAddressable(b)) { /* write from local array */ jbyte* current; /* we could use JAVA_ARRAY_ADDR_GLOBAL here, but that includes a redundant check */ FIELD_ADDR_LOCAL( current, (TAjbyte *)TO_LOCAL(b), data[0] ); INDEX_LOCAL( current, current, off ); while (len > 0) { const ssize_t chunk = write( fd, current, len ); if (chunk <= 0) tossIOException(); else { len -= chunk; current += chunk; } } } else { /* write from global array */ VARARRAY_DECLARE( jbyte, buffer, len ); Pjbyte rem_buf; const jbyte *current; VARARRAY_CREATE( jbyte, buffer, len ); current = buffer; /* we could use JAVA_ARRAY_ADDR_GLOBAL here, but that includes a redundant check */ FIELD_ADDR_GLOBAL( rem_buf, b, data[0] ); INDEX_GLOBAL( rem_buf, rem_buf, off ); global_to_local_copy( rem_buf, buffer, len ); while (len > 0) { const ssize_t chunk = write( fd, current, len ); if (chunk <= 0) { VARARRAY_DESTROY( buffer ); tossIOException(); } else { len -= chunk; current += chunk; } } VARARRAY_DESTROY( buffer ); } } jlong jseek( GP_FileDescriptor descriptor, jlong offset, int whence ) { const jlong result = (jlong) CONVERT_OFF64_TO_LONG_LONG(lseek64(getFd(descriptor), CONVERT_LSEEK64_OFFSET(offset), whence)); if (result == -1) tossIOException(); else return result; } /**********************************************************************/ void tossIOException() { char * const ascii = strerror( errno ); const LP_JString message = java_string_build_8( ascii ); m16throwIOExceptionLT6String4lang4javamT11NativeUtils4lang2ti( message ); abort(); /* should never be reached */ } void tossIOException_str(char * const ascii) { const LP_JString message = java_string_build_8( ascii ); m16throwIOExceptionLT6String4lang4javamT11NativeUtils4lang2ti( message ); abort(); /* should never be reached */ }