Skip to content
⌘ NSIS Forum Archive

Back up and restore files

12 posts

moho9#

Back up and restore files

Let me preface this post the same as my other. I apologize for my ignorance. I've already spent a few days researching and attempting rectify my issue, without success.

I'm attempting to make my installer backup the present file and then restore it upon uninstall, but I cannot get this to work correctly. I'm modeling my script using a sample script from another installer that I know works (I've used the installer).

I know the problem has something to do with how I've set up the directories. I know that because I can get both the backup/rename/uninstall features to work if I don't use a relative path, and instead simply point to a specific directory (in my case, H:\ME3_dummy).

Here are some snippets of the sample code I'm working off :

InstallDir "$PROGRAMFILES"
InstallDirRegKey HKLM "Software\BioWare\Mass Effect 3" "Install Dir"

DetailPrint "copying remaining files..."
SetOverwrite on
SetOutPath "$INSTDIR\BIOGame"

IfFileExists "$INSTDIR\BIOGame\PCConsoleTOC.bin.bup" +2 0
Rename "$INSTDIR\BIOGame\PCConsoleTOC.bin" "$INSTDIR\BIOGame\PCConsoleTOC.bin.bup"
File "BIOGame\PCConsoleTOC.bin"
Uninstall looks like this (the program previous used .bak files, but now uses .bup files):

IfFileExists "$INSTDIR\BIOGame\PCConsoleTOC.bin.bup" 0 +4
Delete "$INSTDIR\BIOGame\PCConsoleTOC.bin"
Rename "$INSTDIR\BIOGame\PCConsoleTOC.bin.bup" "$INSTDIR\BIOGame\PCConsoleTOC.bin"
Goto +4
IfFileExists "$INSTDIR\BIOGame\PCConsoleTOC.bin.bak" 0 +3
Delete "$INSTDIR\BIOGame\PCConsoleTOC.bin"
Rename "$INSTDIR\BIOGame\PCConsoleTOC.bin.bak" "$INSTDIR\BIOGame\PCConsoleTOC.bin"
And, here's a sample of what mine looks like. In my case, the new files are copied over, but backups are not made.

InstallDir "$PROGRAMFILES"
InstallDirRegKey HKLM "Software\BioWare\Mass Effect 3" "Install Dir"

Section "Expanded Core Module for EC" SEC01
SectionIn RO
SetOutPath "$INSTDIR\BIOGame\CookedPCConsole"
SetOverwrite on

IfFileExists "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" +2 0
Rename "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2"
File "Conditionals.cnd"
And, here's a portion of my uninstall. When it comes time to uninstall, there are not any .bu2 files created, so it makes sense the new files wouldn't get uninstalled. However, the files that are simply copied/created without backups being made, also aren't being uninstalled.

Section Uninstall
IfFileExists "$INSTDIR\BIOGame\UNINSTALL_ThaneMOD_v1B.exe" 0 +2
Delete "$INSTDIR\BIOGame\UNINSTALL_ThaneMOD_v1B.exe"

IfFileExists "$INSTDIR\BIOGame\CookedPCConsole\BioD_CitHub_HospitalP2_LOC_INT.pcc.bu2" 0 +2
Delete "$INSTDIR\BIOGame\CookedPCConsole\BioD_CitHub_HospitalP2_LOC_INT.pcc"
Rename "$INSTDIR\BIOGame\CookedPCConsole\BioD_CitHub_HospitalP2_LOC_INT.pcc.bu2" "$INSTDIR\BIOGame\CookedPCConsole\BioD_CitHub_HospitalP2_LOC_INT.pcc"
If anyone is willing to take the time to help, I'd very much appreciate it.

If it is helpful, here's a pastebin of the full installer: http://pastebin.com/jy7ppHeU

Thanks much.
JasonFriday13#
You're close, the problem is that in the sample code, it's checking for the backup file, while in yours it's checking for the main file (the relative vs absolute thing is not the problem).
Originally Posted by Sample code
IfFileExists "$INSTDIR\BIOGame\PCConsoleTOC.bin.bup" +2 0
Rename "$INSTDIR\BIOGame\PCConsoleTOC.bin" "$INSTDIR\BIOGame\PCConsoleTOC.bin.bup"
File "BIOGame\PCConsoleTOC.bin"
And this basically says that if the file exists, skip it (it's checking the main file, not the backup):
Originally Posted by Your code
IfFileExists "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" +2 0
Rename "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2"
File "Conditionals.cnd"
It should look like this (this mirrors the sample code):
IfFileExists "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2" +2 0
Rename "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2"
File "Conditionals.cnd"
Or you can change the logic so that the file is renamed if it exists:
IfFileExists "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" 0 +2
Rename "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2"
File "Conditionals.cnd"
Looks like the uninstall code is ok, I haven't looked at the full installer code though. Logic errors can be a pain to track down, hope this helps.
moho9#
@JasonFriday13 --

Thank you so very much for your help!

That swap of the 0 +2 to +2 0 for the backup got it working. So, now a snippet of the install section looks like this:

Section "Core Module for EC" SEC01
SectionIn RO
SetOutPath "$INSTDIR\BIOGame\CookedPCConsole"
SetOverwrite on

IfFileExists "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" 0 +2
Rename "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd" "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2"
File "Conditionals.cnd"
It renames the original file to the ".bu2" extension and copies over the new file, just as intended. The uninstall is still failing though -- it "completes successfully", but none of the files are removed or renamed as they should. Nothing happens short of the message box popping up. What should be happening is the new file gets deleted and the original, backed up file with the .bu2 extension should have that extension dropped (restoring the original name).

Similar uninstall code for the above file looks like:

Section Uninstall
IfFileExists "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2" 0 +2
Delete "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd"
Rename "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd.bu2" "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd"
I tried reversing the 0 +2, but that didn't work, either. Obviously I am still missing something. Any other ideas?
Afrow UK#
Instead of using relative jumps (such as +2 which can be confusing) I would use LogicLib instead.
${If} ${FileExists} `path`
[do this]
${EndIf}
If it still does not work then check your paths (file names) are correct.

Stu
moho9#
Thanks for the input, Stu.

I'm still not having any luck, unfortunately. I've been messing with it all day. The file paths themselves are correct, the only issue I could be maybe something with the relative path? But, this also seems ok to me.

If you are willing to take a look, I've put up the entire installer script on a pastebin. Everything works except for the uninstall. I don't get any compiling errors, but it still does the same thing upon uninstallation -- the new files stick around and the old ones don't get renamed. You'll see files with your scheme and others using the other scheme. Nothing is uninstalled, regardless of what scheme is used.

moho9#
Yeah, it's something with the relative path of the Install Directory. Well, that's what I thought with the install and backing up, also, but it wasn't that.

The only way I can get the uninstall to work correctly, though, is if I define an exact file path. For example:

"C:\Program Files (x86)\Origin Games\Mass Effect 3\BIOGame\CookedPCConsole\File_01.txt"

${If} ${FileExists} "C:\Program Files (x86)\Origin Games\Mass Effect 3\BIOGame\CookedPCConsole\File_01.txt"
Rename "C:\Program Files (x86)\Origin Games\Mass Effect 3\BIOGame\CookedPCConsole\File_01.txt" "C:\Program Files (x86)\Origin Games\Mass Effect 3\BIOGame\CookedPCConsole\File_01.txt.bu2"
File "C:\Users\User\Desktop\File_01.txt"
${EndIf}
But, not everyone will have the program installed in this location. So, instead I use:

"$INSTDIR\BIOGame\CookedPCConsole\File_01.txt"

But if I use this in the uninstall section it doesn't work. Yet it works in the install section.

How can that be?
Afrow UK#
FYI
Note that in uninstaller code, $INSTDIR contains the directory where the uninstaller lies. It does not necessarily contain the same value it contained in the installer. For example, if you write the uninstaller to $WINDIR and the user doesn't move it, $INSTDIR will be $WINDIR in the uninstaller. If you write the uninstaller to another location, you should keep the installer's $INSTDIR in the registry or an alternative storing facility and read it in the uninstaller.
Stu
moho9#
@Stu -- I read that snippet in the documentation, but as far as I can tell, the installer is already doing that in this part:

Section -Post
WriteUninstaller "$INSTDIR\BIOGame\UNINSTALL_ThaneMOD_v1A.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\BIOGame\UNINSTALL_ThaneMOD_v1A.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
SectionEnd
And, isn't the uninstaller supposed to be reading this information by default when the user launches it?

The only other thing I can think of is maybe this line in the installer is the problem?

InstallDirRegKey HKLM "Software\BioWare\Mass Effect 3" "Install Dir"
I took this line from another installer's script. My understanding was it was supposed to help detect the default install location of the game. Note, that the $INSTDIR for the installer is:

InstallDir "$PROGRAMFILES\Origin Games\Mass Effect 3"
JasonFriday13#
Try putting this in your uninstall section to see what it says:
DetailPrint "$INSTDIR\BIOGame\CookedPCConsole\Conditionals.cnd"

From what Afrow UK said, if you write your uninstaller to "$INSTDIR\BIOGame\uninstall.exe", then in the uninstaller $INSTDIR will be "C:\Program Files (x86)\Origin Games\Mass Effect 3\BIOGame". Your uninstaller will work properly if it's written to $INSTDIR, ie: WriteUninstaller "$INSTDIR\uninstall.exe", but the uninstaller filename should be more descriptive than that.
moho9#
Well, I found a solution, though I'm not sure it's what either of you were saying.

Taking a closer look at the simplest default installer/uninstaller I could make with HM NIS Edit, I figured out that if I simply left the uninstaller .exe in the $INSTDIR, that the uninstaller worked perfectly. While I wanted it in a different subdirectory, it wasn't critical that it be there, so I just changed the location in my script. It was the easiest solution, and since I basically don't know what I'm doing, that works just fine, lol.

The obvious problem is that if the user moves the uninstaller, then it won't delete the files (or itself) -- it will simply delete the registry entries and proceed to tell the user the uninstallation worked "successfully". I thought about perhaps creating a function that would use an "IfFileExists" to detect if it's in the proper location and abort the install if it isn't, but that seems to be part of the problem I was originally having so I don't anticipate being successful.

The only other complication I see is if the user actually deletes the uninstall .exe. This will be a problem as I have a function that prevents installation over an existing one by reading the registry. So, I haven't thought of a way around that yet.

Again, I appreciate your help.
JasonFriday13#
Originally Posted by moho9 View Post
Well, I found a solution, though I'm not sure it's what either of you were saying.

Taking a closer look at the simplest default installer/uninstaller I could make with HM NIS Edit, I figured out that if I simply left the uninstaller .exe in the $INSTDIR, that the uninstaller worked perfectly. While I wanted it in a different subdirectory, it wasn't critical that it be there, so I just changed the location in my script. It was the easiest solution, and since I basically don't know what I'm doing, that works just fine, lol.
This is exactly what we were talking about, the uninstaller uses the directory it's in for $INSTDIR, which is why your uninstaller didn't work. $INSTDIR can be different between the installer and the uninstaller (usually they are the same), in your case they are different because the uninstaller wasn't written to $INSTDIR.

Originally Posted by moho9
The obvious problem is that if the user moves the uninstaller, then it won't delete the files (or itself) -- it will simply delete the registry entries and proceed to tell the user the uninstallation worked "successfully". I thought about perhaps creating a function that would use an "IfFileExists" to detect if it's in the proper location and abort the install if it isn't, but that seems to be part of the problem I was originally having so I don't anticipate being successful.
One way to fix this is to write the install directory to the registry (using WriteRegStr) during the install. Then if the uninstaller is moved it's not such a big problem because in 'Function un.onInit' you can read this install dir from the registry (with ReadRegStr) and use 'StrCpy $INSTDIR $variable_containing_instdir', or whatever variable you read the path into.

For deleting the uninstaller executable, there's a script on the wiki that gets the uninstallers filename, then just use 'Delete $EXEDIR\$variable_containing_the_filename'.
Afrow UK#
Originally Posted by moho9 View Post
And, isn't the uninstaller supposed to be reading this information by default when the user launches it?
InstallDirRegKey is for the installer only and it sets the initial value of $INSTDIR; the uninstaller does not use it. It is up to you to save $INSTDIR somewhere and then read it in the uninstaller. The uninstaller's location is used as the initial value for $INSTDIR.

Stu