[Unison-hackers] Re: [unison-users] read-only files and times=true problem under Windows; Unison crashes

Dmitry Bely dbely at mail.ru
Wed Apr 13 21:39:02 EDT 2005


"mszummer" <szummer-www at media.mit.edu> writes:

>  During four years of using Unison, I have never been able to 
> properly sync files including modification times (the 'times=true' 
> option) between two Windows XP machines both using NTFS filesystems 
> and synchronized clocks.  I use Windows precompiled binaries (for 
> Windows not Cygwin) provided by links on your site.
>
>  In version 2.9.1 and earlier, Unison would falsely list many files 
> as having differing modification times, claiming the difference to be 
> in file modification time by exactly 1 hour (even though the files 
> had been freshly copied from one place to another using standard 
> Windows copy, or also when they had previously been synced with 
> Unison including modification times).
> There are so many files listed as differing by 1 hour that it is 
> difficult to pick out what files have actually changed, making the 
> program less usable.
>
>  In version 2.10.2 this problem has been solved, but another and 
> nastier problem has appeared.  The release notes describe a 'fix to 
> read-only under Windows' sync by Dmitry Bely.  However, I experience 
> more problems in 2.10.2 than in 2.9.1 with regards to read-only 
> files, in fact I resort to 2.9.1 to get around the new problem.  
>
> Specifically, in 2.10.2 synchronization frequently (if not always?) 
> fails when both files are read-only.  I get the error 'Error in 
> setting modification times: Permission denied [utimes()] It does work 
> when any one of them is read-write.

Well I have upgraded my Unison and now also suffer from this. I think the
problem is that Unison developers have improved my old patch (though I
don't know when it had happened)

Let's see. I proposed the following code in props.ml:

	     match Util.osType with
		 `Win32 ->
		   let oldPerms = (Unix.lstat abspath).Unix.st_perm in
		     begin
		       Unix.chmod abspath 0o600;
		       Unix.utimes abspath v v;
		       Unix.chmod abspath oldPerms
		     end
	       | _ ->
		   Unix.utimes abspath v v)

but now we have

let iCanWrite p =
  try
    Unix.access p [Unix.R_OK];
    true
  with
    Unix.Unix_error _ -> false

[...]

           let abspath = Fspath.concatToString fspath path in
           if Util.osType = `Win32 && not (iCanWrite abspath) then
             begin
              (* Nb. This workaround was proposed by Dmitry Bely, to
                 work around the fact that Unix.utimes fails on readonly
                 files under windows.  I'm [bcp] a little bit uncomfortable
                 with it for two reasons: (1) if we crash in the middle,
                 the permissions might be left in a bad state, and (2) I
                 don't understand the Win32 permissions model enough to
                 know whether it will always work -- e.g., what if the
                 UID of the unison process is not the same as that of the
                 file itself (under Unix, this case would fail, but we
                 certainly don't want to make it WORLD-writable, even
                 briefly!). *)
               let oldPerms =
                 (Unix.LargeFile.lstat abspath).Unix.LargeFile.st_perm in
               Util.finalize
                 (fun()->
                    Unix.chmod abspath 0o600;
                    Unix.utimes abspath v v)
                 (fun()-> Unix.chmod abspath oldPerms)
             end
           else Unix.utimes abspath v v)

The comments are completely irrelevant. Windows permissions are ACL-based
and not affected by Unix.chmod (i.e. C runtime chmod()) at all
(see
<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt__chmod.2c_._wchmod.asp>
and note 

#define _S_IREAD        0000400         /* read permission, owner */
#define _S_IWRITE       0000200         /* write permission, owner */

definitons from SYS\STAT.H)

All that chmod() affects is read-only flag which is the separate file attribute
and does not relate to ACL (and thus user/group permissions) in any way.

Next, "Unix.access p [Unix.R_OK];" is probably the typo: it checks if the
file is readable, not writable, and the Win32 specific code in fact is never
executed. "Unix.W_OK" should be used there instead.

So there is no surprise that the r/o files are not synchronized
correctly. I hope Unison developers are reading this and will update the
sources accordingly.

- Dmitry Bely



More information about the Unison-hackers mailing list