Archive: backup file on copy if differ


backup file on copy if differ
  Hello All,

I want to make a backup copy of file only in case when it is different from installed version and then overwrite it.

Here is a macro I wrote to do this:

!macro CopyFileEx LOCAL_DIR DEST_DIR FILE_NAME
SetOverwrite ifdiff
DetailPrint "Backup file path ${DEST_DIR}${FILE_NAME}.old"
GetFileTimeLocal "${LOCAL_DIR}${FILE_NAME}" $R0 $R1
IfFileExists ${FILE_NAME} 0 +10
GetFileTime ${FILE_NAME} $R2 $R3
DetailPrint "LOW_LOCAL=$R1 LOW=$R3 HIGH_LOCAL=$R0 HIGH=$R2"
IntCmp $R0 $R2 0 +4 +4
DetailPrint "HIGH_LOCAL=$R0 equal HIGH=$R2"
IntCmp $R1 $R3 +5 0 0
DetailPrint "LOW_LOCAL=$R1 not equal LOW=$R3"
IfFileExists "${FILE_NAME}.old" 0 +2
Delete "${DEST_DIR}${FILE_NAME}.old"
Rename "${FILE_NAME}" "${FILE_NAME}.old"
File "${LOCAL_DIR}${FILE_NAME}"
;nothing changed
!macroend

!insertmacro CopyFileEx "${_DATA_DIR}\syntax\" "$INSTDIR\data\" "xml_user.xml"


but generally it does not work.
File time is always different (event after reinstall),
existing .old files are not deleted and rename in this case does not work, File command says skipped even when file time read from GetFileTime and GetFileTimeLocal is different.

For me coding looks correct and I dont know what to check more.
Maybe some has idea how to make this working or maybe better solutions for backup of files which differ exist?

Thanks a lot for help!

Regards,
Kefira

What about this xml file?
Is it dynamically created at runtime and/or writing/updating it at application usage?


No this is normal static file, not dynamically created, which contais configuration for xml highlighting in my editor.
File is not chnaged during script execution. No file attributes changed also.
I think result would be the same for any other file.

The installation log can looks like this:


Output folder: C:\Program Files\HippoEdit\data\syntax
Backup file path C:\Program Files\HippoEdit\data\xml_spec.xml.old
LOW_LOCAL=1979421442 LOW=1973640192 HIGH_LOCAL=29856398 HIGH=29856398
HIGH_LOCAL=29856398 equal HIGH=29856398
LOW_LOCAL=1979421442 not equal LOW=1973640192
Skipped: xml_spec.xml

Well, wouldn't be easier to add an entry in the file which identifies its version so reading this entry e.g. in function .onInit would allow you to backup the file if necessary?


No. I dont think that this is a solution, because file can be changed by user manually, and he whould not think about increasing of some "version". Last modified date is most suitable thing, because it changes allways and as I have noticed NSIS would set date/time of installed file as date/time of original.
The idea is to not overwrite user changes in configuration files and merge them, on first start of updated application, with updated configuration file.


hmm, I think you're using improperly the GetFileTimeLocal instruction, probably you need to run another script which generates a header with those 2 values as defines.


And what is correct usage for this function?
What I have found with it, that GetFileTimeLocal does not accept any variable as file name. It only works when it is inline string or macro with inline string..
Using of the external tool for generating of time stamp would be rather complicated, because I need to do this for all (more then 30) configuration fles which are installed...


I don't see a problem with the way you use GetFileTimeLocal. It won't allow a variable for the file name or path because it executes strictly during compile time, when the variables don't yet have any values.

Are you installing onto the same type of file system as the setup is built on (NTFS or FAT32 for both)? The file times depend upon the resolution of the file system; it looks like the LOW word differs by about a half second for the two files - close enough that the FS could be the cause.

Don


Hello Don,

The installation is executed in the same machine where it is build. From drive D to drive C, both have NTFS, on XP.
The strange thing you can see in the log:

LOW_LOCAL=1979421442 not equal LOW=1973640192
Skipped: xml_spec.xml

The File function skipes copying, but time low time is different, and this is when overwrite settings for File is ifdiff.

Regards,
Kefir


Someone familiar with the NSIS source might be a better person to provide this answer, but it looks like NSIS expects the file time to have no better than 2 seconds resolution, and any difference less than that is considered to be matching times. Your file times differ by 0.58 seconds, so the script thinks they match and it skips the extraction of the new one.

The GetFileTime / GetFileTimeLocal commands give you the Windows FILETIME data type, the number of seconds since 1/1/1601, expressed in units of 100 nanoseconds. The low word only goes up to (2^32 / 10^7 seconds, about 4 minutes); put a decimal point in the value with 7 digits to the right of it: 1979421442 -> 197.9421442. Since both the target and the build file times' low words start 197..., the difference is less than one second.

Don


Someone familiar with the NSIS source might be a better person to provide this answer, but it looks like NSIS expects the file time to have no better than 2 seconds resolution, and any difference less than that is considered to be matching times. Your file times differ by 0.58 seconds, so the script thinks they match and it skips the extraction of the new one.
Indeed. That's done to avoid issues between FAT and NTFS, because FAT uses a 2 seconds resolution.

Hello guys,

thanks a lot for help! This description helps to make working solution. I have corrected the script to skip changes if time difference less then 3 seconds (to be safe ;) ). I submit it here, maybe would be helpful to somebody.

!macro CopyFileEx LOCAL_DIR FILE_NAME

SetOverwrite ifdiff
IfFileExists${FILE_NAME} 0 +11
GetFileTimeLocal"${LOCAL_DIR}${FILE_NAME}" $R0 $R1
GetFileTime${FILE_NAME} $R2 $R3
IntCmp $R0 $R2 0+7 +7
IntOp $R1 $R1/ 10000000
IntOp $R3 $R3/ 10000000
IntOp $R5 $R1- $R3
IntCmp $R5 0+2 0 +2
IntOp $R5 $R5* -1
IntCmp $R5 3+2 +2 0
Rename "${FILE_NAME}" "${FILE_NAME}.old"
File "${LOCAL_DIR}${FILE_NAME}"
>!macroend
>
can be used like this:

"${FILE_DIR}" "${FILE_NAME}" 

Best regards,
Kefir.

work around for 2 second file modified date resolution
  Is there any way to work around the 2 second resolution of file modified dates? I'm creating a CD installer for a Java WebStart application, which compares the file dates with ones on a web server to see if an update is required. The problem I'm having is that the installer is setting the file date on one of the files to Friday, June 15, 2007, 11:22:04 PM but the original file date was Friday, June 15, 2007, 11:22:05 PM... this causes the auto update feature of Java Web Start to kick in every time... negating the benefits of an off line CD install.

If it helps, here's the relevant portion of the script:

Function .onInit

InitPluginsDir
SetOutPath $PLUGINSDIR
>...
Function InstallLSGAM
File/a "LSGAM\*"
ExecWait '"javaws" -shortcut -codebase file:. -import LSGAM40.jnlp' $0
>...
It finds and installs the files just fine, its only the modified dates that are off.

As an alternate solution, is there a way to get the drive letter of the CD the installer is running from? I'm sure this is a n00b question, so I apologize if this question has been answered before...

Any help would be greatly appreciated!

Thanks,
Nick

You could use $EXEDIR to get the directory where the installer is located. You can then use GetRoot to get the root drive of that directory.


Exactly what I needed. thanks! Kinda out of place, but if it helps anyone else, here's the modified code:


ExecWait '"javaws" -shortcut -codebase file:"$EXEDIR\LSGAM" -import "$EXEDIR\LSGAM\LSGAM40.jnlp"' $0 

>

Oops, the slashes went away in my last post


ExecWait '"javaws" -shortcut -codebase file:"$EXEDIR\\LSGAM" -import "$EXEDIR\\LSGAM\\LSGAM40.jnlp"' $0 

>

Use [code] not [php] :p

Stu