JDK-4722567 : File and File{In,Out}putStream path directories inconsistent if user.dir is set on cmd line
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2002-07-30
  • Updated: 2005-11-29
  • Resolved: 2005-11-29
Related Reports
Duplicate :  
Description
Name: nt126004			Date: 07/29/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :  Microsoft Windows XP
[Version 5.1.2600]


A DESCRIPTION OF THE PROBLEM :
There are serious inconsistencies in the handling of non-
absolute paths in the File and
FileInputStream/FileOutputStream classes in Windows.

The problem arises when the initial current directory (A)
is different to the user.dir directory (B).

new FileInputStream("xxx") always seems to open "xxx" in
dir A.

File f = new File("xxx") sometimes refers to dir A and
sometimes to dir B:
        f.exists() and f.isDirectory() refer to dir A
while
        f.getCanonicalPath() and f.getAbsolutePath()
return dir B

With user entered paths, to avoid confusion, I now have to
use:
        File f = new File(xxx);
        f = new File(rv.getCanonicalPath());
        and always use new FileInputStream(f)
to be sure of referring to the same file/dir all of the
time.

I suggest that File has a
        private String realPath;
which is set to rv.getCanonicalPath() in the constructor,
and is used for all file system accesses.

And that FileInputStream/FileOutputStream (File file)
constructor replaces
	String name = file.getPath();

with
	String name = file.getCanonicalPath();


These constructors will obviously now have to throw
IOException as well.
Or use getAbsolutePath() to avoid throwing this exception.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run source code from directory say D:\dirA which contains
file test.txt with user.dir set to say D:\dirB which is
empty
eg: java -jar -Duser.dir="D:\dirB" d:\dirA\FilesBug.jar


EXPECTED VERSUS ACTUAL BEHAVIOR :
I expect non-absolute paths passed to File and
FileInputStream/FileOutputStream to consistently refer to
the same file/dir.

-----------------
Windows File and FileInputStream/FileOutputStream path
directories inconsistent

user.dir=D:\dirB

Before getAbsolutePath....
....  f.exists: true
....  f.getAbsolutePath(): D:\dirB\test.txt

After getAbsolutePath.....
....  f.exists: false

dir.list() 0 test.txt
dir.list() 1 FilesBug.class
dir.list() 2 FilesBug.jar
dir.list() 3 manifest.txt
dir.list() 4 FilesBug.java
dir.getAbsolutePath(): D:\dirB\.

FileInputStream read: abcdefghijklmnopq


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// Run from directory say D:\dirA which contains file test.txt
// with user.dir set to say D:\dirB which is empty
//
//	java -jar -Duser.dir="D:\dirB" d:\dirA\FilesBug.jar

import java.io.*;

public final class FilesBug
{

public static void main(String[] args)
{
	System.out.println("Windows File and FileInputStream/FileOutputStream
path directories inconsistent");
	System.out.println();

	System.out.println("user.dir="+System.getProperty("user.dir"));
	System.out.println();

	// This test shows that a non-absolute file is in dir A but
getAbsolutePath() returns dir B
	File f = new File("test.txt");
	System.out.println("Before getAbsolutePath....");
	System.out.println("....  f.exists: "+f.exists());
	System.out.println("....  f.getAbsolutePath(): "+f.getAbsolutePath());
	System.out.println();

	// Now check dir B
	f = new File(f.getAbsolutePath());
	System.out.println("After getAbsolutePath.....");
	System.out.println("....  f.exists: "+f.exists());
	System.out.println();

	// This test shows that a directory listing refers to dir A but /
getAbsolutePath() returns dir B
	File dir = new File(".");
	if( dir.isDirectory())
	{
		String[] dirlist = dir.list();
		for( int i=0; i<dirlist.length; i++)
			System.out.println("dir.list() "+i+" "+dirlist[i]);
		System.out.println("dir.getAbsolutePath
(): "+dir.getAbsolutePath());
	}
	else
		System.out.println("dir is not a directory");
	System.out.println();

	// This test shows that new FileInputStream("test.txt") refers to dir A
	try
	{
		DataInputStream ds = new DataInputStream(new FileInputStream
("test.txt"));
		String line = ds.readLine();
		System.out.println("FileInputStream read: "+line);
	}
	catch( Exception e)
	{
		System.out.println("FileInputStream failed: "+e);
	}
}

////
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
With user entered paths, to avoid confusion, I now have to
use:
        File f = new File(xxx);
        f = new File(rv.getCanonicalPath());
        and always use new FileInputStream(f)
to be sure of referring to the same file/dir all of the
time.
(Review ID: 158686) 
======================================================================

Comments
EVALUATION Duplicate of 4117557.
29-11-2005