You are here

Bug? Portable Firefox deletes normal Firefox AppData dir if it's a junction

17 posts / 0 new
Last post
wh
Offline
Last seen: 15 years 12 months ago
Joined: 2008-04-03 10:10
Bug? Portable Firefox deletes normal Firefox AppData dir if it's a junction

Hi,

I have my normal firefox installation set up with a junction in Application Data\Mozilla\Firefox pointing to a directory on another disk (So my config is seperate in case of reinstallation). Whenever I install and use FX Portable, this junction is deleted!

This happened in fx3 betas 3, 4 and 5.

There must be more ppl out there who use junctions -- has anybody else encountered this? It's pretty annoying Blum

tia,
Wouter

edit: the deleting of the junction happens when closing the portable version

wh
Offline
Last seen: 15 years 12 months ago
Joined: 2008-04-03 10:10
Some more info on this: If I

Some more info on this:

If I do not have a junction set up (I.e. no Mozilla\Firefox directory at all), the following files are created upon startup of fxportable:

%APPDATA%\Mozilla\Firefox\Crash Reports\InstallTime2008032620
%APPDATA%\Mozilla\Firefox\Crash Reports\UserID

The Crash Reports dir with contents, together with the Mozilla\Firefox directory is then deleted when fxportable is closed.

If I have a normal fx profile (ie with no junction) the Crash Reports dir is created and removed, but the rest is left intact.

Why does deleting the Crash Reports dir also delete its parent dir if it's a junction?

SteffenS
Offline
Last seen: 15 years 2 months ago
Joined: 2009-01-19 07:41
Does it on my installation, too

Hi,
we have the same situation on our office PCs. The directory C:\Users\user-id\AppData\Roaming\Mozilla is 'junctioned' to a second partition, exactly for the same reason (keep the config separate). We're using Vista SP1 and the client setup and SW distribution is highly automated, so as to be able to re-install a client machine very quickly without touching user data and specific settings.

I wanted to try out Firefox Portable and found the same problem as Wouter - after closing Firefox Portable the junction is gone ...
I found this very annoying - shouldn't a portable app avoid to write into a - possibly - existing directory, where deletion of directories or files could do harm?

Apart from that, I like Firefox Portable (and other portable apps) a lot, since I can use them without installing.

Cheers,
Steffen.

John T. Haller
John T. Haller's picture
Offline
Last seen: 1 hour 6 min ago
AdminDeveloperModeratorTranslator
Joined: 2005-11-28 22:21
As Discussed

As discussed, this appears to be an issue on the part of Windows as a simple check for existence of the directory and whether there are files in it returns an incorrect answer. As an admin, you should not be using junctions within the APPDATA hierarchy. If you as a user were to install standard Firefox on that machine, it would similarly mess up. Your admins, when they setup your distribution, did not heed the Microsoft's usage recommendations, the first two points of which are: (1) Use NTFS ACLs to protect junction points from inadvertent deletion. (2) Use NTFS ACLs to protect files and directories that are targeted by junction points from inadvertent deletion or other file system operations.

Unfortunately, there's not much we can do to fix a poorly-setup configuration like this. We use an unaltered copy of the official Firefox builds with Mozilla's permission which does not permit us to alter pieces within Firefox. So, we have to clean up after it closes.

Sometimes, the impossible can become possible, if you're awesome!

rab040ma
Offline
Last seen: 4 months 3 weeks ago
Joined: 2007-08-27 13:35
Workaround

It looks like there's at least one NSIS plugin ( see GetFileAttributes) that returns REPARSE_POINT status. I'd have to play with it some to see how it works, but something like that might let you test the folder before your launcher cleans up after Firefox. There might also be a way to test for existence of a file in a folder that is the target of a junction, if testing for an empty directory isn't reliable. Not for every directory, perhaps, but it might be worth it for one like this that has shown itself to be a junction in these cases. (Is this sort of thing a problem for symlinks, which I've heard are the same thing only different?)

An extra layer of complexity, but maybe it would be a workaround for sloppy admins.

I suppose another option would be for an optional and obscure configuration element that would tell the launcher to skip that cleanup step.

Perhaps this is something that the NSIS folks should anticipate too. I'd expect that an installer might encounter that sort of sloppy admin, and at least stop or prompt if a normal install would break the way the filesystem is set up on a computer.

MC

rab040ma
Offline
Last seen: 4 months 3 weeks ago
Joined: 2007-08-27 13:35
Odd

It looks like the offending code is

RMDir "$APPDATA\Mozilla\Firefox\" ;=== Will only delete if empty (no /r switch)
RMDir "$APPDATA\Mozilla\" ;=== Will only delete if empty (no /r switch)

One might conclude that NSIS considers a junction to be "empty".

If you want it to stop before John figures out a solution, you could remove those two lines and recompile the launcher. I think.

One solution might be to test for existence of files, rather than rely on RMDir to work.

MC

John T. Haller
John T. Haller's picture
Offline
Last seen: 1 hour 6 min ago
AdminDeveloperModeratorTranslator
Joined: 2005-11-28 22:21
I doubt it

I highly doubt that anyone else is doing this as it only works on Windows Vista and to manually create a junction in a specific Application Data directory is highly unusual. Firefox itself creates those directories on launch and will usually leave them empty. On exit, the FirefoxPortable.exe launcher will remove the crash data and then remove the Application Data\Mozilla\Firefox directory only if it is empty. It would appear that Vista is incorrectly reporting that directory as empty instead of having the files in it that it should have. In short, Windows *should* be telling the launcher that there are fils in it.

It would appear that junctions are rather poorly implemented (read: essentially tacked onto NTFS without being fully thought out or working with most software) and don't work right with several tools as there are many warnings and such around them. For more details, see the wikipedia article here:
http://en.wikipedia.org/wiki/NTFS_junction_point

You should heed the warnings and set an ACL permission so it can't be deleted. Or, if possible (I'm not sure as I don't use Vista) just place a single text file within that directory. Since it isn't a directory, I don't think it will work, though. And since Vista isn't properly reporting the contents of that path, there's nothing we can do from our end.

Sometimes, the impossible can become possible, if you're awesome!

Bruce Pascoe
Offline
Last seen: 12 years 2 months ago
Joined: 2006-01-15 16:14
Only on Vista?

According to Wikipedia, junctions existed as early as NTFS 3.0--that is to say, Windows 2000.

John T. Haller
John T. Haller's picture
Offline
Last seen: 1 hour 6 min ago
AdminDeveloperModeratorTranslator
Joined: 2005-11-28 22:21
Ah, quite right

Hmm, you're right. I guess I just never heard of them before. Either way, it seems they don't work right if an app checks to see if a directory is empty and Windows says it is when it's a junction with files in it (which is why there are all those warnings).

Sometimes, the impossible can become possible, if you're awesome!

zpangwin
zpangwin's picture
Offline
Last seen: 9 years 6 months ago
Joined: 2014-08-15 13:35
simple solution...?

Let me start off by saying that I know this is an incredibly old (ancient? :P) post and some people frown on what they consider "reviving dead threads", but I would like to point out that once something is cached in google sometimes it is better to add current information so that others stumbling in from the web get a mix of the old and the new. I myself stumbled on this one while googling "firefox and appdata junctions" it seemed relevant to my issue (essentially the same as explained in the OP)

But, that said, I would like to offer a very simple and elegant fix that I think would work for everyone Smile ... I believe the root cause of this issue is that whatever API Windows uses for RmDir considers symlinks and junctions to be the same as empty directories (you will see the exact same behavior if you run RMDIR command from cmd). What if we just add a parameter to the ini file that allows the user to "opt out" of removing the empty directories? This seems like it would allow the use of symlinks/junctions for those that want to use them in appdata folders (but either don't want to/aren't able to set ACL's), without disrupting the defaults for everybody else. Plus it seems pretty easy to implement.

I'm not at home so I can't link to a download (maybe I will add later but here is a snippet that should do what I am proposing:

FirefoxPortableU.nsi changes:

Var CLEANEMPTYAPPDATADIRS
...
;== Default to true (remove empty appdata dirs)
${ReadINIStrWithDefault} $CLEANEMPTYAPPDATADIRS "$INIPATH\${NAME}.ini" "${NAME}" "CleanEmptyAppDataDirs" "true"
...
	RemoveLocalFiles3:
		Delete "$APPDATA\Mozilla\Firefox\pluginreg.dat"
		StrCmp $CLEANEMPTYAPPDATADIRS "false" RemoveLocalFiles4
		RMDir "$APPDATA\Mozilla\Firefox\Profiles\" ;=== Will only delete if empty (no /r switch)
		RMDir "$APPDATA\Mozilla\Firefox\Profile\" ;=== Will only delete if empty (no /r switch)
		RMDir "$APPDATA\Mozilla\Firefox\" ;=== Will only delete if empty (no /r switch)
		RMDir "$APPDATA\Mozilla\" ;=== Will only delete if empty (no /r switch)
		RMDir "$LOCALAPPDATA\Mozilla\Firefox\firefox\updates\0" ;=== Will only delete if empty (no /r switch)
		RMDir "$LOCALAPPDATA\Mozilla\Firefox\firefox\updates" ;=== Will only delete if empty (no /r switch)
		RMDir "$LOCALAPPDATA\Mozilla\Firefox\firefox" ;=== Will only delete if empty (no /r switch)
		RMDir "$LOCALAPPDATA\Mozilla\Firefox\" ;=== Will only delete if empty (no /r switch)
		RMDir "$LOCALAPPDATA\Mozilla\" ;=== Will only delete if empty (no /r switch)

	RemoveLocalFiles4:
		StrCmp $MOZILLAORGKEYEXISTS "true" RemoveMachineRegistryKey
			${registry::DeleteKey} "HKEY_CURRENT_USER\Software\mozilla.org" $R0
		RemoveMachineRegistryKey:
...

FirefoxPortable.ini changes (using default value -aka delete is ON):

CleanEmptyAppDataDirs=true

I would be happy to unit-test/add this into a sourceforge repo or post somewhere else as well if that would make it more likely to get added. If so, please let me know.

John T. Haller
John T. Haller's picture
Offline
Last seen: 1 hour 6 min ago
AdminDeveloperModeratorTranslator
Joined: 2005-11-28 22:21
Gets Messy, Likely detect and close if anything

The problem with this is that it gets messy. Most people use the PA.c Platform. So, do we allow it to be shut off for all apps? And then only use it on certain PCs? And what about when we transition to the PA.c Launcher and ditch this custom code. Will we update it to support a turnoff for all APPDATA move backs? And, again, should it be per PC or everywhere (leaving data behind on every PC) and per app or for all apps?

Setting a junction on a specific app's section of APPDATA is just a bad thing to do, considering how badly supported junctions are within Windows.

One thing I am debating is having the launcher detect if a junction is in use on any affected directories and simply refusing to run, since we can't be sure what will and will not work right, since the Windows APIs and commands don't function correctly with junctions. I found some code from a few years back that may help us detect them, but it's not something built into NSIS (or anything else for that matter): http://forums.winamp.com/showthread.php?t=325143

Sometimes, the impossible can become possible, if you're awesome!

zpangwin
zpangwin's picture
Offline
Last seen: 9 years 6 months ago
Joined: 2014-08-15 13:35
Thanks for the fast reply. :)

I get the impression that you may not be a fan of junctions ... Even if this case, they do work very solidly in Windows/NTFS; the main problem is just that MS didn't provide good ways for detection/removal and RMDIR handles them poorly. Aside from that, I've never seen any scenarios where junctions did not work correctly with Windows APIs due to them being junctions (I have seen some issues which occur with folders - such as locking -- happen for junctions as well). As for using them in APPDATA, I've never seen any recommendations for or against using junctions there... and while it may not be a traditional approach on Windows, this is done frequently by many many people (usually for storage reasons or to make scripted backups easier). I have seen many cases of this on the web, including in a technet.microsoft.com thread. And similar usage is quite common under Linux systems where MS took the idea from Smile

While I can't speak for PA.c Platform/Launcher (not sure if those are still using NSIS), I would hope that those still support per-app settings (such as allow multiple instances/disable splash) as those settings are important to many in the community. Even if the new setup were in C++/Java/etc, I don't think it would be too bad... and I would be more than willing to help if you are open-minded towards the idea.

I think the problem we've run into here is literally just in the cleanup method and can be handled safely without a lot of changes. In my previous post, I was suggesting to have a flag which would just bypass the need to detect/handle linked dirs entirely and instead just let the user have an INI setting for it (e.g. "change it at your own risk").

And while you could certainly detect linked dirs and then refuse to run, I would hope that you wouldn't do it that way... At the point where you have added the detection logic, you would have everything you need to fix the issue and it would be very trivial to do so. Refusing to run after detecting junctions would only hurt end users and for no real reason or benefit.

If you were going to add detection logic, it would be just as easy if not easier to avoid the problem altogether. Here is a psuedo-NSIS snippet showing this with the function you had linked to.

;-- sample using the function you linked to
${IsSoftLink} "${Path}" ${outVar} 
StrCmp $outVar 1 skipdelete
;-- delete empty folders like usual

:skipdelete
;--continue cleanup

If that doesn't work for you (I had to tweak it slightly to get it working under nsis v3.0b0), then here is another version that should work with less dependencies and technically should be slightly faster due to more focused attribute checking (although we're talking milliseconds and I doubt the difference would be noticeable):

;--------------------------------------------------------------------------
; -- Usage:
;--    ${IsLinkedDir} "$Path" $OutputVar
;-- Returns (OutputVar):
;--   -1 - Encountered an error (such as invalid path/does not exist)
;--    0 - Path is NOT a junction/symbolic link
;--    1 - Path IS a junction/symbolic link
;--------------------------------------------------------------------------
Function IsLinkedDir
	!define IsLinkedDir `!insertmacro IsLinkedDirMacro`

	!macro IsLinkedDirMacro _PATH _RESULT
		Push `${_PATH}`
		Call IsLinkedDir
		Pop ${_RESULT}
	!macroend
	
	Exch $0
	System::Call 'kernel32::GetFileAttributes(t r0)i .r1'
	StrCmp $1 -1 error
	IntOp $0 $1 & 0x0400
	IntCmp $0 0 +2
	StrCpy $0 1
	goto end

	error:
	SetErrors
	StrCpy $0 $1

	end:
	Exch $0
FunctionEnd

Anyway, I hope I'm not coming off as argumentative or disagreeable. As you already pointed out in your earlier posts, there are other ways to do this including ACLs. I think there is also a way to have the non-portable FF install look for its profile data in another folder (but IIRC, this may require manual setup), so that in theory you could get them to play nice that way. There may be other methods too.

I'm just trying to point out another usage pattern and an easy way to allow it. I think fixing it here has several advantages, such as being less complicated, being independent of one's permissions to change ACLs, and potentially allowing easy automation/scripting for profile setup tasks).

Either way, I like portableapps a lot and have a lot of respect for all the time and work it must take you to do all of this. And for that I would like to say, Thank You! For any of the rest in this thread, I am happy to help if I can and you are open to it, but if you have already made up your mind then it is what is.

John T. Haller
John T. Haller's picture
Offline
Last seen: 1 hour 6 min ago
AdminDeveloperModeratorTranslator
Joined: 2005-11-28 22:21
We Already Do That

We already use -profile to ensure the Firefox profile is contained on the portable device. Unfortunately, Firefox still leaves multiple things behind on the local machine within APPDATA\Firefox even when used with this switch. The profile manager only works for a local profile database set and is inapplicable to our needs.

The issue here is that this is an extreme edge case... as in maybe 3 users over the last 10 years and 20 million downloads of Firefox Portable. Unfortunately, junctions are buggy and Windows' own built-in tools and APIs don't work properly with them, as we've already proven with RMDir. So, it's a lot of extra work on our part to support those 3 users in the extreme edge case (as in rewriting PAL and the custom launchers and rebuilding 300+ app packages) just to work around a Windows bug with junctions+RMDir that Microsoft doesn't think is worth fixing.

The example code is just random code on the Winamp forum I found for NSIS. I'm unsure how buggy/stable it is. And I'm unsure how well it detects a linked dir vs a sub-directory of a linked dir nor how RMDir performs on a sub-directory of a linked dir. Additionally, if your junction point is on APPDATA\Mozilla, would APPDATA\Mozilla\Firefox (which firefox.exe will create no matter what) be detected as a linked dir? Knowing that is a critical piece of the puzzle and could throw a wrench in whether this is even feasible.

Setting it up as an INI entry to skip cleanup is a bad idea, as you'll wind up leaving stuff behind on every PC as you move around. If you're only using it on your own PC, then you would not have a junction on APPDATA\Mozilla (or similar) in the first place.

The only proper way to handle it is to detect whether that specific directory will break as it's being removed due to the unfixed junction+RMDir bug and then not remove it. That means wrapping RMDir into a function that first checks for a junction and replacing all instances of RMDir throughout all the custom launchers as well as PAL in every single app. At the moment, that is WELL beyond my unpaid available development time.

If you're interested in testing it, I'll put together a wrapped RMDir function and test it out with a custom Firefox Portable launcher to see if it's even feasible. I'll set it to do an RMDir unless the function says it's a link.

Sometimes, the impossible can become possible, if you're awesome!

zpangwin
zpangwin's picture
Offline
Last seen: 9 years 6 months ago
Joined: 2014-08-15 13:35
ok

ah, sorry hadn't meant to imply that PA/FF should use -profile, just that it could (maybe) be used for someone looking for a way to have a non-portable FF install, with data stored outside appdata, while also running PA/FF. (disclaimer: I have not tested this :P)

Anyway, I'm at work (waiting for a dev server to come back up) but I would be happy to test. I might even get some time this weekend to write/test a wrapped RMDir function. I had already tested both the function from your link and the IsLinkedDir function I threw together (above) - both were correctly detecting junctions/symlinked dirs vs regular ones. IsLinkedDir used 0 (regular) or 1 (junction/symlink)... I forget that the other one used.

I hadn't thought to test for a dir within a junction at the time. I assume it will be reported as a dir based on what I've encountered in batch files/scripting/etc, but I will confirm and report back.

bege10
Offline
Last seen: 6 years 8 months ago
Joined: 2017-07-07 09:36
Three years after the last

Three years after the last post - and I am horrified. The same issue happens on my system finding it only here in this old thread. I imagine this had happened on the machine of I friend I am visiting using my portable Firefox!
There must be a warning on the download page that this is NOT a portable app but still writing in the AppData of the local machine! The hole discussion about good Admin behavior is not the issue. Firefox "portable" writing into the AppData of the local machine is the issue. I definitely cannot use it on other people machines Sad
Important to know, tomorrow I will leave for a journey.

John T. Haller
John T. Haller's picture
Offline
Last seen: 1 hour 6 min ago
AdminDeveloperModeratorTranslator
Joined: 2005-11-28 22:21
Data Is Fine

If you encounter the extreme edge case of manually creating a junction specifically for Firefox within AppData and Firefox Portable interfering, you just need to recreate the junction. All the local data is completely untouched. The junction is removed due to a bug in the Windows API regarding junctions.

Nearly all portable apps write data locally, at least temporarily. The only way around that is to fully sandbox them which introduces its own set of issues or run them within a full Windows virtual machine. It is currently impossible to run Firefox without writing some data locally unless you use a virtual machine or sandbox. If you'd like it to do otherwise, you'd need to file a bug with Mozilla. If you encounter some other site claiming they have portable software like Firefox that doesn't temporarily write to the local machine that isn't using a virtual machine or sandbox, they are outright lying.

Sometimes, the impossible can become possible, if you're awesome!

bege10
Offline
Last seen: 6 years 8 months ago
Joined: 2017-07-07 09:36
Thank you for your answer.

Thank you for your answer.
For now I also take Palemoon portable with me because it doesn't write to the Firefox AppData, of course. But you are right, Palemoon also writes to the local AppData.
But I am still concerned that portable apps write to the AppData folder instead of only to the Temp folder.

Log in or register to post comments