Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 332178

Summary: FileDialog overwrites file without prompt.
Product: [Eclipse Project] Platform Reporter: Alex Ignácio da Silva <alexignaciodasilva>
Component: SWTAssignee: Sravan Kumar Lakkimsetti <sravankumarl>
Status: RESOLVED FIXED QA Contact: Arun Thondapu <arunkumar.thondapu>
Severity: normal    
Priority: P3 CC: arunkumar.thondapu, carolynmacleod4, eclipse, gheorghe, loskutov, markus.kell.r, remy.suen, sravankumarl
Version: 3.6.1Flags: arunkumar.thondapu: review+
Target Milestone: 4.4 M6   
Hardware: PC   
OS: Linux   
Whiteboard:
Attachments:
Description Flags
Simple patch reverting 3.6 changes
none
Revised Patch
none
Updated Patch based on the review comments none

Description Alex Ignácio da Silva CLA 2010-12-08 18:37:30 EST
Build Identifier: 20100917-0705

When using the FileDialog to save a file with a name without extension ("file"), and the dialog extension filter is set to some extension ("Text Files"), the file will be saved with that extension ("file.txt"), and if a file with the same name already exists in the specified directory it will be overwritten without prompt, even if setOverwrite(true) was called.

Reproducible: Always

Steps to Reproduce:
- run the snippet below,
- hit the save button and navigate to a directory with an already existing file named "file.txt" and press OK,
- the dialog won't warn the user about the existing file.

public class Test {

    public static void main(String[] args) {
        Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new GridLayout(1, false));

        Button button = new Button(shell, SWT.PUSH);
        button.setText("Save");
        button.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                FileDialog dialog = new FileDialog(shell, SWT.SAVE);
                dialog.setFilterExtensions(new String[] {"*.txt"});
                dialog.setFilterNames(new String[] {"Text Files"});
                dialog.setFilterIndex(0);
                dialog.setText("Save");
                dialog.setFileName("file");
                dialog.setOverwrite(true);
                String filePath = dialog.open();
                if((filePath != null) && filePath.endsWith("file.txt")) {
                    System.out.println(dialog.getFileName());
                    MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
                    messageBox.setText("Oops");
                    messageBox.setMessage("File was overwritten!");
                    messageBox.open();
                }
            }
        });

        shell.setSize(150, 100);
        shell.open();
        while(!shell.isDisposed()) {
            if(!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
    
}
Comment 1 Alex Ignácio da Silva CLA 2010-12-08 18:52:48 EST
I've seen this bug in Ubuntu 10.04. Perhaps it's not a GTK bug, as when I try the same situation using gedit the file gets saved without the extension ("file"), therefore not overwriting the already existing file ("file.txt").

Running the snippet above on Windows XP produces the expected behavior of the dialog displaying the overwrite warning.

On Windows the file names returned by both open() and getFileName() have the extension ("file.txt"). On Linux the return value of open() has the extension and the return of getFileName() has not, so a workaround could be implemented by using the directory returned by open() with the file name returned by getFileName(). On Linux the dialog will warn the user if she tries to save the file in a directory with an already existing file without the extension ("file").
Comment 2 Arun Thondapu CLA 2011-04-11 11:31:02 EDT
I understand the situation described below but after more in depth testing, I think it is actually a GTK bug.
To explain further, the GTKFileChooser dialog (which is used by FileDialog) checks whether a file with the name specified by the user already exists only by using the name that is entered by the user. As you already noticed in this case, if the name is entered as "file" and a file already exists with that name, the confirmation dialog will appear. Similarly, if you try to save a file by entering the name as "file.txt" and a file with that name exists, it will warn you. However, it fails to handle the case where the filename is entered as "file" with a "*.txt" extension filter because GTK's check only ensures that there is no file named "file" in the specified directory and no check is done for "file.txt" at all.
Regarding the difference in handling you noticed between gedit and FileDialog, this is because gedit accepts the filename exactly as it is returned by GTK whereas the FileDialog code explicitly appends the extension filter to the filename if no extension is specified by the user.
This is what is causing an SWT application using FileDialog to overwrite the file in this case.

I'm still contemplating whether to file a bug with GTK for this issue or if it is possible to find some workaround for the same. Will update soon.

Thanks!

(In reply to comment #1)
> I've seen this bug in Ubuntu 10.04. Perhaps it's not a GTK bug, as when I try
> the same situation using gedit the file gets saved without the extension
> ("file"), therefore not overwriting the already existing file ("file.txt").
> 
> Running the snippet above on Windows XP produces the expected behavior of the
> dialog displaying the overwrite warning.
> 
> On Windows the file names returned by both open() and getFileName() have the
> extension ("file.txt"). On Linux the return value of open() has the extension
> and the return of getFileName() has not, so a workaround could be implemented
> by using the directory returned by open() with the file name returned by
> getFileName(). On Linux the dialog will warn the user if she tries to save the
> file in a directory with an already existing file without the extension
> ("file").
Comment 3 Andrey Loskutov CLA 2012-03-02 03:02:18 EST
I can confirm this too.

The bug was introduced in FileDialog.computeResultChooserDialog() method after 3.5.1.

We observe it right now on 3.7.1 in a slightly different way, but the common part is that the FileDialog now appends the file filter to the file name if the file name does not contains "." and filter is not "*" or "*.*".

For us if we set the filter to "[^.]*" (to hide dot files) the filter string will be always added to the file name.


This is the bad code added after 3.5.1 which breaks FileDialog behavior on Linux.

	if (fullPath != null) {
		int separatorIndex = fullPath.lastIndexOf (SEPARATOR);
		fileName = fullPath.substring (separatorIndex + 1);
		filterPath = fullPath.substring (0, separatorIndex);
		int fileExtensionIndex = fileName.indexOf(FILE_EXTENSION_SEPARATOR);
		if ((style & SWT.SAVE) != 0 && fileExtensionIndex == -1 && filterIndex != -1) {
			if (filterExtensions.length > filterIndex) {
				String selection = filterExtensions [filterIndex];
				int length = selection.length ();
				int index = selection.indexOf (EXTENSION_SEPARATOR);
				if (index == -1) index = length;
				String extension = selection.substring (0, index).trim ();
				if (!extension.equals ("*") && !extension.equals ("*.*")) {
					if (extension.startsWith ("*.")) extension = extension.substring (1);
					fullPath = fullPath + extension;
				}	
			}
		}
	}
	return fullPath;

The fix should be changed to NOT append filter anymore. 

At least the first assumption 

int separatorIndex = fullPath.lastIndexOf (SEPARATOR);
fileName = fullPath.substring (separatorIndex + 1);

is plain wrong as for files without suffix the code below will now add suffixes.
It should probably do 

int separatorIndex = fullPath.lastIndexOf (SEPARATOR);
if(separatorIndex <= 0)
return fullPath; 
fileName = fullPath.substring (separatorIndex + 1);
Comment 4 Andrey Loskutov CLA 2012-03-08 02:26:29 EST
Created attachment 212276 [details]
Simple patch reverting 3.6 changes

Attached the simplest possible patch which makes SAVE dialog working on Linux again.

The code in 3.6 SWT stream was changed to append filter suffixes to file names in some cases. Unfortunately there is no comment why it was done, but I suspect that this probably should fix some issues with latest? GTK releases. I may imagine that it could be that for some reason the filter suffix was removed in native code from selected files (initially containing suffix), and the 3.6 change should fix that. As I'm not aware in which GTK version this problem exists, I can't add the platform filter. Anyway, the 3.6 code is just buggy as it breaks the SAVE dialog behavior for ALL files without suffix if filter is set.

Proper patch would need:

1) Document, why the 3.6 addition of suffix from filter was needed.
2) Specify on which GTK version this addition of the suffix is required.
3) Check GTK version used and accordingly enable/disable this behavior.
4) Provide a working solution for newer GTK versions if the user didn't specified suffix for selected file. 

The proposed patch based on the 3.7.2 swt version (org.eclipse.swt.gtk.linux.x86_64_3.7.2.v3740f) makes the recent 3.6 change mostly obsolete and so the code just works as before.

On my RH 5.6 Linux we have following GTK version:
 
$ rpm -qa | grep libgtk
libgtk-java-2.8.7-3.el5
libgtk-java-devel-2.8.7-3.el5
libgtk-java-devel-2.8.7-3.el5
libgtk-java-2.8.7-3.el5

and 

uname -a
Linux socbl593 2.6.18-238.el5 #1 SMP Sun Dec 19 14:22:44 EST 2010 x86_64 x86_64 x86_64 GNU/Linux

Regards,
Andrey
Comment 5 Andrey Loskutov CLA 2012-03-08 02:29:10 EST
P.S. just to make sure my gtk version is documented properly:

rpm -qa | grep gtk2
gtk2-engines-2.8.0-3.el5
gtk2-devel-2.10.4-21.el5_7.7
gtk2-2.10.4-21.el5_7.7
gtk2-devel-2.10.4-21.el5_7.7
gtk2-engines-2.8.0-3.el5
gtk2-2.10.4-21.el5_7.7
Comment 6 Andrey Loskutov CLA 2012-04-13 04:33:38 EDT
Ping.
Given patch works for us with no issues reported so far.
Anybody to integrate it to 3.8?
Comment 7 Doug M CLA 2012-05-02 19:33:57 EDT
This same problem exists now for OS X: FileDialog for save, with extension list. When the typed filename has extension, the overwrite warning appears; when the extension is implicit, overwrite is not detected and a path is returned to the existing file (with extension).

Do I need to file a separate report for OS X platform?
Comment 8 Andrey Loskutov CLA 2012-05-04 15:22:54 EDT
Ping #2.

The patch is there. It just works. All what you need is to look at it (and integrate :-)).

*Anybody* to integrate it to 3.8 before it's too late for the release?
Comment 9 Carolyn MacLeod CLA 2012-06-04 15:59:20 EDT
Changing target milestone to 4.3 so that this will not get missed for the next round.
Comment 10 Arun Thondapu CLA 2013-12-16 10:43:50 EST
Sravan, can you please try to reproduce this problem on your Linux setup and test the attached patch (check whether it works in all kinds of scenarios with different combinations of filenames and extension filters and also that it doesn't break any expected behavior) ? You can work on improving the patch or suggesting a different fix if needed. Thanks!
Comment 11 Sravan Kumar Lakkimsetti CLA 2014-01-02 01:12:36 EST
This behaviour was changed as part of bug 285641. In this the code change was done to mimic the behaviour as Windows.

The code change done as a part of 285641 is that after GTK returns the file name we are adding extension to it.

So the behaviour we have created is 
1. Open the GTK file chooser dialog
2. GTK dialog will check for the existence of file and warns if it about to overwritten and returns the new file
3. Add the extension
4. Write the contents in to the file

Here if we closely see the steps you may notice that the filename on which we got overwrite warning and file name we used to write the contents are two different files. This is leading to overwrite of different file altogether.

In my opinion there are two ways of dealing with this
1. After adding the extension verify whether the file exists. and modify the documentation to avoid setOverwrite(true) on the dialog so that the gtk will not check for the file name. and we do overwrite warning ourselves.

2. Reverting back the changes done in 285641. This will make the file chooser dialog behaviour across other gtk applications.

I prefer the send solution as it will make the behaviour consistent across GTK applications
Comment 12 Sravan Kumar Lakkimsetti CLA 2014-01-03 03:10:35 EST
The approach I am taking is reverting the chages done in bug 285641. The attached patch also works, but it will result in dead code. So I believe the correct approach would be reverting the changes for adding the extension as this is inconsistenent with other linux applications
Comment 13 Markus Keller CLA 2014-01-06 13:49:23 EST
Playing ping-pong with bug 285641 / bug 277323 is not a sustainable solution.

SWT has two kinds of consistency requirements:
1) implement platform behavior so that SWT apps feel like native apps
2) offer a portable (and stable!) API that shields client code from platform differences

A common use case for the Save dialog is that there's a default file extension that should be used unless the user specifies a different extension. The user shouldn't have to enter the default extension manually. This use case is currently supported on all 3 platforms with the same application code (first filter extension is used by default). The only problem for this use case is that setOverwrite(true) doesn't seem to be implemented correctly on all platforms.

If you want to support other use cases, then you should document those use cases and add APIs to implement them.
Comment 14 Sravan Kumar Lakkimsetti CLA 2014-01-30 00:05:47 EST
Created attachment 239460 [details]
Revised Patch
Comment 15 Sravan Kumar Lakkimsetti CLA 2014-01-30 00:07:11 EST
Hi Markus,

The current implementation sets a empty file name in the save dialog. My approach is to have default filename set in the savedialog with extension(first filter extension). This will solve the original problem of not adding the file extension to the file.

The code changes are revert the changes done for bug 285641. and set a default filename with extension in the save dialog and highlight the filename portion so that filename can be edited. If the user needs a different extension he needs to type the extension explicitly. Also if the filter contains any regular expressions we do not add the extension.

Thanks
Sravan
Comment 16 Markus Keller CLA 2014-01-31 15:00:19 EST
(In reply to Sravan Kumar Lakkimsetti from comment #14)
> Created attachment 239460 [details] [diff]
> Revised Patch

'if (fileName == "")' looks wrong. Shouldn't it use '"".equals(fileName)'?

New code should adopt the formatting of surrounding code (here: space before method arguments list, but not after 'if (' ).

isRegexExt(..) should be called isGlobExt and doc comments should also be fixed. The OS.gtk_file_filter_add_pattern(..) function takes glob patterns, but not regular expressions.
Comment 17 Sravan Kumar Lakkimsetti CLA 2014-02-05 05:51:50 EST
(In reply to Markus Keller from comment #16)
> (In reply to Sravan Kumar Lakkimsetti from comment #14)
> > Created attachment 239460 [details] [diff]
> > Revised Patch
> 
> 'if (fileName == "")' looks wrong. Shouldn't it use '"".equals(fileName)'?
> 
> New code should adopt the formatting of surrounding code (here: space before
> method arguments list, but not after 'if (' ).
> 
> isRegexExt(..) should be called isGlobExt and doc comments should also be
> fixed. The OS.gtk_file_filter_add_pattern(..) function takes glob patterns,
> but not regular expressions.

Hi Markus,

Based on your comments I made changes and uploaded to gerrit https://git.eclipse.org/r/21306

Please review the changes and let me know your comments

Thanks
Sravan
Comment 18 Sravan Kumar Lakkimsetti CLA 2014-02-05 05:53:54 EST
Created attachment 239653 [details]
Updated Patch based on the review comments
Comment 19 Markus Keller CLA 2014-02-05 06:18:49 EST
Passing the review ball over to Arun.

I mainly jumped in to prevent a fix that just reopens bug 285641, and because the term "regular expressions" in this context looked suspicious.
Comment 20 Arun Thondapu CLA 2014-02-17 06:38:59 EST
GtkFileChooserDialog behavior seems to have changed in GTK 3 to append the default filter extension to the file name by itself, which means FileDialog may not need to append the extension explicitly. However, I'm not sure if this still solves the overwrite problem completely. Can you please test the patch with GTK 3 and update? Thanks!
Comment 21 Sravan Kumar Lakkimsetti CLA 2014-02-21 06:56:38 EST
The bug has been committed in the following commit
http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=b647d62c5bdcee9c1d9104cd6245d80b8fca31e7