mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			510 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			510 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
// natFile.cc - Native part of File class for POSIX.
 | 
						|
 | 
						|
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006, 2008, 2012
 | 
						|
   Free Software Foundation
 | 
						|
 | 
						|
   This file is part of libgcj.
 | 
						|
 | 
						|
This software is copyrighted work licensed under the terms of the
 | 
						|
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
 | 
						|
details.  */
 | 
						|
 | 
						|
#include <config.h>
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <sys/param.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#ifdef HAVE_UNISTD_H
 | 
						|
#include <unistd.h>
 | 
						|
#endif
 | 
						|
#include <stdlib.h>
 | 
						|
#ifdef HAVE_DIRENT_H
 | 
						|
#include <dirent.h>
 | 
						|
#endif
 | 
						|
#include <string.h>
 | 
						|
#include <utime.h>
 | 
						|
 | 
						|
#include <gcj/cni.h>
 | 
						|
#include <jvm.h>
 | 
						|
#include <java/io/File.h>
 | 
						|
#include <java/io/IOException.h>
 | 
						|
#include <java/util/ArrayList.h>
 | 
						|
#include <java/lang/String.h>
 | 
						|
#include <java/io/FilenameFilter.h>
 | 
						|
#include <java/io/FileFilter.h>
 | 
						|
#include <java/lang/System.h>
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::access (jint query)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
  JvAssert (query == READ || query == WRITE || query == EXISTS
 | 
						|
	    || query == EXEC);
 | 
						|
#ifdef HAVE_ACCESS
 | 
						|
  int mode;
 | 
						|
  if (query == READ)
 | 
						|
    mode = R_OK;
 | 
						|
  else if (query == WRITE)
 | 
						|
    mode = W_OK;
 | 
						|
  else if (query == EXISTS)
 | 
						|
    mode = F_OK;
 | 
						|
  else
 | 
						|
    mode = X_OK;
 | 
						|
  return ::access (buf, mode) == 0;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::stat (jint query)
 | 
						|
{
 | 
						|
  if (query == ISHIDDEN)
 | 
						|
    return getName()->charAt(0) == '.';
 | 
						|
 | 
						|
#ifdef HAVE_STAT
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
 | 
						|
  struct stat sb;
 | 
						|
  if (::stat (buf, &sb))
 | 
						|
    return false;
 | 
						|
  
 | 
						|
  JvAssert (query == DIRECTORY || query == ISFILE);
 | 
						|
  jboolean r = S_ISDIR (sb.st_mode);
 | 
						|
  return query == DIRECTORY ? r : ! r;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
jlong
 | 
						|
java::io::File::attr (jint query)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
 | 
						|
#ifdef HAVE_STAT
 | 
						|
  struct stat sb;
 | 
						|
  // FIXME: not sure about return value here.
 | 
						|
  if (::stat (buf, &sb))
 | 
						|
    return 0;
 | 
						|
 | 
						|
  JvAssert (query == MODIFIED || query == LENGTH);
 | 
						|
  return query == MODIFIED ? (jlong)sb.st_mtime * 1000 : sb.st_size;
 | 
						|
#else
 | 
						|
  // There's no good choice here.
 | 
						|
  return 23;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
// These two methods are used to maintain dynamically allocated
 | 
						|
// buffers for getCanonicalPath without the overhead of calling
 | 
						|
// realloc every time a buffer is modified.  Buffers are sized
 | 
						|
// at the smallest multiple of CHUNKSIZ that is greater than or
 | 
						|
// equal to the desired length.  The default CHUNKSIZ is 256,
 | 
						|
// longer than most paths, so in most cases a getCanonicalPath
 | 
						|
// will require only one malloc per buffer.
 | 
						|
 | 
						|
#define CHUNKLOG 8
 | 
						|
#define CHUNKSIZ (1 << CHUNKLOG)
 | 
						|
 | 
						|
static int
 | 
						|
nextChunkSize (int size)
 | 
						|
{
 | 
						|
  return ((size >> CHUNKLOG) + ((size & (CHUNKSIZ - 1)) ? 1 : 0)) << CHUNKLOG;
 | 
						|
}
 | 
						|
 | 
						|
static char *
 | 
						|
maybeGrowBuf (char *buf, int *size, int required)
 | 
						|
{
 | 
						|
  if (required > *size)
 | 
						|
    {
 | 
						|
      *size = nextChunkSize (required);
 | 
						|
      buf = (char *) _Jv_Realloc (buf, *size);
 | 
						|
    }
 | 
						|
  return buf;
 | 
						|
}
 | 
						|
 | 
						|
// Return a canonical representation of the pathname of this file.  On
 | 
						|
// the GNU system this involves the removal of redundant separators,
 | 
						|
// references to "." and "..", and symbolic links.
 | 
						|
//
 | 
						|
// The conversion proceeds on a component-by-component basis: symbolic
 | 
						|
// links and references to ".."  are resolved as and when they occur.
 | 
						|
// This means that if "/foo/bar" is a symbolic link to "/baz" then the
 | 
						|
// canonical form of "/foo/bar/.." is "/" and not "/foo".
 | 
						|
//
 | 
						|
// In order to mimic the behaviour of proprietary JVMs, non-existant
 | 
						|
// path components are allowed (a departure from the normal GNU system
 | 
						|
// convention).  This means that if "/foo/bar" is a symbolic link to
 | 
						|
// "/baz", the canonical form of "/non-existant-directory/../foo/bar"
 | 
						|
// is "/baz".
 | 
						|
 | 
						|
jstring
 | 
						|
java::io::File::getCanonicalPath (void)
 | 
						|
{
 | 
						|
  jstring path = getAbsolutePath ();
 | 
						|
 | 
						|
  int len = JvGetStringUTFLength (path);
 | 
						|
  int srcl = nextChunkSize (len + 1);
 | 
						|
  char *src = (char *) _Jv_Malloc (srcl);
 | 
						|
  JvGetStringUTFRegion (path, 0, path->length(), src);
 | 
						|
  src[len] = '\0';
 | 
						|
  int srci = 1;
 | 
						|
 | 
						|
  int dstl = nextChunkSize (2);  
 | 
						|
  char *dst = (char *) _Jv_Malloc (dstl);
 | 
						|
  dst[0] = '/';
 | 
						|
  int dsti = 1;
 | 
						|
 | 
						|
  bool fschecks = true;
 | 
						|
 | 
						|
  while (src[srci] != '\0')
 | 
						|
    {
 | 
						|
      // Skip slashes.
 | 
						|
      while (src[srci] == '/')
 | 
						|
	srci++;
 | 
						|
      int tmpi = srci;
 | 
						|
      // Find next slash.
 | 
						|
      while (src[srci] != '/' && src[srci] != '\0')
 | 
						|
	srci++;
 | 
						|
      if (srci == tmpi)
 | 
						|
	// We hit the end.
 | 
						|
	break;
 | 
						|
      len = srci - tmpi;
 | 
						|
 | 
						|
      // Handle "." and "..".
 | 
						|
      if (len == 1 && src[tmpi] == '.')
 | 
						|
	continue;
 | 
						|
      if (len == 2 && src[tmpi] == '.' && src[tmpi + 1] == '.')
 | 
						|
	{
 | 
						|
	  while (dsti > 1 && dst[dsti - 1] != '/')
 | 
						|
	    dsti--;
 | 
						|
	  if (dsti != 1)
 | 
						|
	    dsti--;
 | 
						|
	  // Reenable filesystem checking if disabled, as we might
 | 
						|
	  // have reversed over whatever caused the problem before.
 | 
						|
	  // At least one proprietary JVM has inconsistencies because
 | 
						|
	  // it does not do this.
 | 
						|
	  fschecks = true;
 | 
						|
	  continue;
 | 
						|
	}
 | 
						|
 | 
						|
      // Handle real path components.
 | 
						|
      dst = maybeGrowBuf (dst, &dstl, dsti + (dsti > 1 ? 1 : 0) + len + 1);
 | 
						|
      int dsti_save = dsti;
 | 
						|
      if (dsti > 1)
 | 
						|
	dst[dsti++] = '/';
 | 
						|
      strncpy (&dst[dsti], &src[tmpi], len);
 | 
						|
      dsti += len;
 | 
						|
      if (fschecks == false)
 | 
						|
	continue;
 | 
						|
 | 
						|
#if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
 | 
						|
      struct stat sb;
 | 
						|
      dst[dsti] = '\0';
 | 
						|
      if (::lstat (dst, &sb) == 0)
 | 
						|
	{
 | 
						|
	  if (S_ISLNK (sb.st_mode))
 | 
						|
	    {
 | 
						|
	      int tmpl = CHUNKSIZ;
 | 
						|
	      char *tmp = (char *) _Jv_Malloc (tmpl);
 | 
						|
 | 
						|
	      while (1)
 | 
						|
		{
 | 
						|
		  tmpi = ::readlink (dst, tmp, tmpl);
 | 
						|
		  if (tmpi < 1)
 | 
						|
		    {
 | 
						|
		      _Jv_Free (src);
 | 
						|
		      _Jv_Free (dst);
 | 
						|
		      _Jv_Free (tmp);
 | 
						|
		      throw new IOException (
 | 
						|
			JvNewStringLatin1 ("readlink failed"));
 | 
						|
		    }
 | 
						|
		  if (tmpi < tmpl)
 | 
						|
		    break;
 | 
						|
		  tmpl += CHUNKSIZ;
 | 
						|
		  tmp = (char *) _Jv_Realloc (tmp, tmpl);
 | 
						|
		}
 | 
						|
 | 
						|
	      // Prepend the link's path to src.
 | 
						|
	      tmp = maybeGrowBuf (tmp, &tmpl, tmpi + strlen (&src[srci]) + 1);
 | 
						|
	      strcpy(&tmp[tmpi], &src[srci]);
 | 
						|
	      _Jv_Free (src);
 | 
						|
	      src = tmp;
 | 
						|
	      srcl = tmpl;
 | 
						|
	      srci = 0;
 | 
						|
 | 
						|
	      // Either replace or append dst depending on whether the
 | 
						|
	      // link is relative or absolute.
 | 
						|
	      dsti = src[0] == '/' ? 1 : dsti_save;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  // Something doesn't exist, or we don't have permission to
 | 
						|
	  // read it, or a previous path component is a directory, or
 | 
						|
	  // a symlink is looped.  Whatever, we can't check the
 | 
						|
	  // filesystem any more.
 | 
						|
	  fschecks = false;
 | 
						|
	}
 | 
						|
#endif // HAVE_LSTAT && HAVE_READLINK
 | 
						|
    }
 | 
						|
  dst[dsti] = '\0';
 | 
						|
 | 
						|
  // FIXME: what encoding to assume for file names?  This affects many
 | 
						|
  // calls.
 | 
						|
  path = JvNewStringUTF (dst);
 | 
						|
  _Jv_Free (src);
 | 
						|
  _Jv_Free (dst);
 | 
						|
  return path;
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::isAbsolute (void)
 | 
						|
{
 | 
						|
  return path->length() > 0 && path->charAt(0) == '/';
 | 
						|
}
 | 
						|
 | 
						|
jobjectArray
 | 
						|
java::io::File::performList (java::io::FilenameFilter *filter, 
 | 
						|
			     java::io::FileFilter *fileFilter, 
 | 
						|
			     java::lang::Class *result_type)
 | 
						|
{
 | 
						|
  /* Some systems have dirent.h, but no directory reading functions like
 | 
						|
     opendir.  */
 | 
						|
#if defined(HAVE_DIRENT_H) && defined(HAVE_OPENDIR)
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
 | 
						|
  DIR *dir = opendir (buf);
 | 
						|
  if (! dir)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  java::util::ArrayList *list = new java::util::ArrayList ();
 | 
						|
  struct dirent *d;
 | 
						|
  while ((d = readdir (dir)) != NULL)
 | 
						|
    {
 | 
						|
      // Omit "." and "..".
 | 
						|
      if (d->d_name[0] == '.'
 | 
						|
	  && (d->d_name[1] == '\0'
 | 
						|
	      || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
 | 
						|
	continue;
 | 
						|
 | 
						|
      jstring name = JvNewStringUTF (d->d_name);
 | 
						|
      if (filter && ! filter->accept(this, name))
 | 
						|
	continue;
 | 
						|
 | 
						|
      if (result_type == &java::io::File::class$)
 | 
						|
        {
 | 
						|
	  java::io::File *file = new java::io::File (this, name);
 | 
						|
	  if (fileFilter && ! fileFilter->accept(file))
 | 
						|
	    continue;
 | 
						|
 | 
						|
	  list->add(file);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	list->add(name);
 | 
						|
    }
 | 
						|
 | 
						|
  closedir (dir);
 | 
						|
 | 
						|
  jobjectArray ret = JvNewObjectArray (list->size(), result_type, NULL);
 | 
						|
  list->toArray(ret);
 | 
						|
  return ret;
 | 
						|
#else /* HAVE_DIRENT_H && HAVE_OPENDIR */
 | 
						|
  return NULL;
 | 
						|
#endif /* HAVE_DIRENT_H && HAVE_OPENDIR */
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::performMkdir (void)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
 | 
						|
#ifdef HAVE_MKDIR
 | 
						|
  return ::mkdir (buf, 0755) == 0;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::setFilePermissions (jboolean enable,
 | 
						|
				    jboolean ownerOnly,
 | 
						|
				    jint permissions)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
  JvAssert (permissions == READ || permissions == WRITE || permissions == EXEC);
 | 
						|
#if defined (HAVE_STAT) && defined (HAVE_CHMOD)
 | 
						|
  mode_t mode = 0;
 | 
						|
 | 
						|
  struct stat sb;
 | 
						|
  if (::stat (buf, &sb))
 | 
						|
    return false;
 | 
						|
 | 
						|
  if (ownerOnly)
 | 
						|
    {
 | 
						|
      if (permissions == READ)
 | 
						|
        mode |= S_IRUSR;
 | 
						|
      else if (permissions == WRITE)
 | 
						|
        mode |= S_IWUSR;
 | 
						|
      else if (permissions == EXEC)
 | 
						|
        mode |= S_IXUSR;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      if (permissions == READ)
 | 
						|
        mode |= (S_IRUSR | S_IRGRP | S_IROTH);
 | 
						|
      else if (permissions == WRITE)
 | 
						|
        mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
 | 
						|
      else if (permissions == EXEC)
 | 
						|
        mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (enable)
 | 
						|
    mode = sb.st_mode | mode;
 | 
						|
  else
 | 
						|
    mode = sb.st_mode & ~mode;
 | 
						|
  
 | 
						|
  if (::chmod(buf, mode) < 0)
 | 
						|
    return false;
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::performSetReadOnly (void)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
 | 
						|
#if defined (HAVE_STAT) && defined (HAVE_CHMOD)
 | 
						|
  struct stat sb;
 | 
						|
  if (::stat (buf, &sb))
 | 
						|
    return false;
 | 
						|
 | 
						|
  if (::chmod(buf, sb.st_mode & 0555))
 | 
						|
    return false;  
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
JArray< ::java::io::File *>*
 | 
						|
java::io::File::performListRoots ()
 | 
						|
{
 | 
						|
  ::java::io::File *f = new ::java::io::File (JvNewStringLatin1 ("/"));
 | 
						|
  JArray<java::io::File *> *unixroot
 | 
						|
    = reinterpret_cast <JArray<java::io::File *>*> 
 | 
						|
          (JvNewObjectArray (1, &java::io::File::class$, f));
 | 
						|
  elements (unixroot) [0] = f;
 | 
						|
  return unixroot;
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::performRenameTo (File *dest)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
  char *buf2
 | 
						|
    = (char *) __builtin_alloca (JvGetStringUTFLength (dest->path) + 1);
 | 
						|
  total = JvGetStringUTFRegion (dest->path, 0, dest->path->length(), buf2);
 | 
						|
  buf2[total] = '\0';
 | 
						|
 | 
						|
#ifdef HAVE_RENAME
 | 
						|
  return ::rename (buf, buf2) == 0;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::performSetLastModified (jlong time)
 | 
						|
{
 | 
						|
#ifdef HAVE_UTIME
 | 
						|
  utimbuf tb;
 | 
						|
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
  
 | 
						|
  tb.actime = time / 1000;
 | 
						|
  tb.modtime = time / 1000;
 | 
						|
  return (::utime (buf, &tb) == 0);
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::performCreate (void)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
 | 
						|
  int fd = ::open (buf, O_CREAT | O_EXCL, 0644);
 | 
						|
 | 
						|
  if (fd < 0)
 | 
						|
    {
 | 
						|
      if (errno == EEXIST)
 | 
						|
        return false;
 | 
						|
      throw new IOException (JvNewStringLatin1 (strerror (errno)));
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      ::close (fd);
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
jboolean
 | 
						|
java::io::File::performDelete (void)
 | 
						|
{
 | 
						|
  char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1);
 | 
						|
  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
 | 
						|
  buf[total] = '\0';
 | 
						|
 | 
						|
#ifdef HAVE_UNLINK
 | 
						|
#ifdef HAVE_RMDIR
 | 
						|
  if (! ::rmdir (buf))
 | 
						|
    return true;
 | 
						|
  if (errno == ENOTDIR)
 | 
						|
#endif // HAVE_RMDIR
 | 
						|
    return ::unlink (buf) == 0;
 | 
						|
#endif // HAVE_UNLINK
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
java::io::File::init_native ()
 | 
						|
{
 | 
						|
#ifdef MAXPATHLEN
 | 
						|
  maxPathLen = MAXPATHLEN;
 | 
						|
#else
 | 
						|
  /* Some systems do not have a limit on the length of a file name,
 | 
						|
     the GNU system is one such example.  */
 | 
						|
  maxPathLen = 0;
 | 
						|
#endif
 | 
						|
  caseSensitive = true;
 | 
						|
}
 |