locked
Problems with FileStream.Lock(); RRS feed

  • Question

  • User1362 posted

    I have a class that work fine in C# under Windows but not under Monodroid.

    A simplified version of the class is:

    public class LockedStream : FileStream
    {
        ulong LockCount = 0;
        bool _IsNewFile;
    
          LockedStream( bool IsNewFile, string path, FileMode mode, FileAccess access, FileShare share )
                      : base( MakePath( path ), mode, access, share )
             {
               _IsNewFile = IsNewFile;
             }
    
       public LockedStream( string path, FileMode mode, FileAccess access, FileShare share )
                      : this( !File.Exists( path ), path, mode, access, share )
             {
             }
    
       public static internal LockedStream Open( string FilePathName )
            {
               return ( new LockedStream( FilePathName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite ) );
            }
    
        public void Lock()
            {
                if( LockCount++ == 0 )
                {
                     int SleepCount = 1;
    
                        while( true )
                        {
                            try
                            {
                                base.Lock( 0, Int64.MaxValue );
                                break;
                             }
                             catch( Exception E )
                             {
                                  Thread.Sleep( SleepCount++ );
                             }
                         }
                 }
            }
    
       public void UnLock()
              {
                  if( LockCount > 0 )
                  {
                      if( --LockCount == 0 )
                      {
                          try
                          {
                              base.Unlock( 0, Int64.MaxValue );
                          }
                          catch( Exception )
                          {
                          }
                       }
                   }
               }
    
    }
    

    Now when I do:

    LockedStream Stream = LockedStream.Open( "Some Path/file name" );
         Stream.Lock();
    

    I get the file created when I call the Open(); but when I call Stream.Lock(); I hangs in the lock routine forever because base.Lock( 0, Int64.MaxValue ); throws a lock violation exception even though the file isn't locked.

    Does anybody know why this is happening on Android?

    Thanks in advance.

    Terry

    Monday, January 7, 2013 2:00 PM

All replies

  • User48 posted

    The problem appears to be due to using long.MaxValue for the length parameter:

    System.IO.IOException: Lock violation on path /data/data/Scratch.FileLocking/files/foo.dat
      at System.IO.FileStream.Lock (Int64 position, Int64 length)
      at Scratch.FileLocking.Activity1.OnCreate (Android.OS.Bundle bundle)
      at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState)
      at (wrapper dynamic-method) object:bb4be693-3135-413b-9702-5891d1dcae64 (intptr,intptr,intptr)
    

    However, if you instead use int.MaxValue, it works w/o error.

    The actual problem appears to be that LockFile is implemented incorrectly, particularly in conjunction with vesicallSystemIOMonoIO_Lock:

    ret=LockFile (handle, position & 0xFFFFFFFF, position >> 32,
              length & 0xFFFFFFFF, length >> 32);
    

    We know that length is long.MaxValue, thus within LockFile() both length_low and length_high will be 0xFFFFFFFF. This breaks on platforms without large file support (64-bit file size/offset support), because LockFile() does:

    length = length_low;
    

    This doesn't look bad, but length is a signed type (off_t), while length_low is an unsigned type; when we hit wapilockfileregion(), the unsigned 0xFFFFFFFF value has now become the signed value of -1:

    lock_data.l_len = length;
    

    The result is that we're passing a negative value for the lock length, starting at offset 0, which fcntl(2) doesn't like. Boom, game over.

    This has been filed as bug 9411.

    Wednesday, January 9, 2013 5:18 AM