Bug 38201 - File locking doesn`t work amount processes
Summary: File locking doesn`t work amount processes
Status: RESOLVED NOT_ON_ROADMAP
Alias: None
Product: Runtime
Classification: Mono
Component: General ()
Version: 4.2.0 (C6)
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-01-29 19:27 UTC by shrimpy
Modified: 2017-08-28 15:05 UTC (History)
3 users (show)

Tags: lock linux
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED NOT_ON_ROADMAP

Description shrimpy 2016-01-29 19:27:04 UTC
Language: C#
Mono version: 4.2.1
OS: Ubuntu 14.04

On windows while one process is holding on a file with stream from below code 
             File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.Read)

and if another process try to open the file
             File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.Read)

exception will be throw

however, on mono, no exception will be throw, and second process can also removed the file while the first process who create the file would still think the file is there (other thread in that process try to open the file will have exception)


Repro:
build below code into an exe, e.g Program.exe
duplicate Program.exe to Program2.exe
Run in two terminal:
mono Program.exe create
mono Program2.exe open



                static void Main(string[] args)
		{
			if (args == null || args.Length != 1) {
				Console.WriteLine ("Program.exe [create|open]");
			}

			string filePath = "[update to a valid file path]";
			string action = args [0];

			Stream s = null;
			try{
				if(string.Equals("create", action, StringComparison.OrdinalIgnoreCase)){
					s = File.Open (filePath, FileMode.Create, FileAccess.Write, FileShare.None);
					Task.Factory.StartNew (() => {
						Console.WriteLine ("checking if file is locked");
						int count =0;
						while(count++ <500){
							try{
								using(File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.None)){}
								Console.WriteLine ("File is not locked");
							}catch{
								Console.WriteLine ("File is locked");
							}

							Thread.Sleep(TimeSpan.FromSeconds(1));
						}
					});
				}else{
					DateTime start = DateTime.Now;
					while((DateTime.Now - start).TotalMinutes < 5){
						try{
							using(File.Open (filePath, FileMode.Open, FileAccess.Write, FileShare.None)){};
							Console.WriteLine ("File is not locked");
							File.Delete(filePath);
							break;
						}catch{
							Console.WriteLine ("File is locked");
							Thread.Sleep(TimeSpan.FromSeconds(1));
						}
					}
				}

				Console.WriteLine ("Enter a line to end program.");
				Console.ReadLine();
			}finally{
				if (s != null) {
					s.Dispose ();
				}
			}
		}
Comment 1 Zoltan Varga 2016-02-01 04:11:25 UTC
We don't support this feature of .net, we used to, but the implementation was very complicated and error prone.
Comment 2 shrimpy 2016-02-16 23:10:28 UTC
Hi Zoltan, 

then how about Advisory lock "FileStream.Lock(long, long)" ? Is it out of the picture as well?
Comment 3 Zoltan Varga 2016-02-17 00:04:54 UTC
That should work, since its supported on unix.
Comment 4 shrimpy 2016-02-17 00:10:03 UTC
Hi Zoltan,

it doesn`t. Tested on ubuntu, two process both try to perform "FileStream.Lock", both of them went thru, i was expecting one of them will throw exception per source code https://github.com/mono/mono/blob/master/mcs/class/corlib/System.IO/FileStream.cs#L862
Comment 5 Zoltan Varga 2016-02-17 03:19:54 UTC
It seems to work for me at least on osx with:

using System;
using System.IO;

public class Tests
{
	public static void Main (String[] args) {
		var f = new FileStream ("foo.txt", FileMode.Open);

		f.Lock (0, 0);

		Console.ReadLine ();
	}
}
Comment 6 shrimpy 2016-02-17 03:44:49 UTC
did you try with multiple process? (open two terminal and run your code)

ran below code on Ubuntu 14.04, first run without parameters, and then run with parameters. i see "file is not locked".

seems like a bug in mono, code only work on certain linux kernal i believe. and osx mostly is using older kernal version. Can you try on a ubuntu machine?




using System;
using System.IO;
using System.Threading.Tasks;

namespace ConsoleTry
{
        class MainClass
        {
                public static void Main (string[] args)
                {
                        string filePath = Path.Combine (Environment.GetEnvironmentVariable ("HOME"), "foo.txt");
                        Console.WriteLine (filePath);
                        FileStream f = null;
                        try {
                                if (args == null || args.Length == 0) {
                                        Console.WriteLine ("lock");
                                        f = File.Open (filePath, FileMode.Open);
                                        f.Lock (0, 0);
                                        Console.WriteLine ("enter to exit");
                                        Console.ReadLine ();
                                        f.Unlock (0, 0);

                                } else {
                                        f = File.Open (filePath, FileMode.Open);
                                        Console.WriteLine ("file is not locked");
                                }
                        } finally {
                                if (f != null)
                                        f.Dispose ();
                        }
                }
        }
}
Comment 7 Zoltan Varga 2016-02-17 07:48:06 UTC
Advisory locking means that both processes need to call f.Lock ().
Comment 8 shrimpy 2016-02-17 17:39:40 UTC
ah, my bad. thanks for spotting that.
Comment 9 shrimpy 2016-02-17 17:44:22 UTC
also, Lock(0,0) seems to have special meaning. tried other len value before that doesn`t work. thanks for your help.