1 /*
2  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /* @test
25  * @bug 4429043 4493595 6332756 6709457
26  * @summary The FileChannel file locking
27  */
28 
29 import java.io.*;
30 import java.nio.channels.*;
31 import static java.nio.file.StandardOpenOption.*;
32 
33 /**
34  * Testing FileChannel's lock method.
35  */
36 
37 public class Lock {
38 
main(String[] args)39     public static void main(String[] args) throws Exception {
40         if (args.length > 0) {
41             if(args[0].equals("1")) {
42                 MadWriter mw = new MadWriter(args[1], false);
43             } else {
44                 MadWriter mw = new MadWriter(args[1], true);
45             }
46             return;
47         }
48         File blah = File.createTempFile("blah", null);
49         blah.deleteOnExit();
50         RandomAccessFile raf = new RandomAccessFile(blah, "rw");
51         raf.write(1);
52         raf.close();
53         test1(blah, "1");
54         test1(blah, "2");
55         test2(blah, true);
56         test2(blah, false);
57         test3(blah);
58         test4(blah);
59         blah.delete();
60     }
61 
test2(File blah, boolean b)62     private static void test2(File blah, boolean b) throws Exception {
63         RandomAccessFile raf = new RandomAccessFile(blah, "rw");
64         FileChannel channel = raf.getChannel();
65         FileLock lock;
66         if (b)
67             lock = channel.lock();
68         else
69             lock = channel.tryLock();
70         lock.release();
71         channel.close();
72     }
73 
test1(File blah, String str)74     static void test1(File blah, String str) throws Exception {
75 
76         // Grab the lock
77         RandomAccessFile fis = new RandomAccessFile(blah, "rw");
78         FileChannel fc = fis.getChannel();
79         FileLock lock = null;
80 
81         if (str.equals("1")) {
82             lock = fc.lock(0, 10, false);
83             if (lock == null)
84                 throw new RuntimeException("Lock should not return null");
85             try {
86                 FileLock lock2 = fc.lock(5, 10, false);
87                 throw new RuntimeException("Overlapping locks allowed");
88             } catch (OverlappingFileLockException e) {
89                 // Correct result
90             }
91         }
92 
93         // Exec the tamperer
94         String command = System.getProperty("java.home") +
95             File.separator + "bin" + File.separator + "java";
96         String testClasses = System.getProperty("test.classes");
97         if (testClasses != null)
98             command += " -cp " + testClasses;
99         command += " Lock " + str + " " + blah;
100         Process p = Runtime.getRuntime().exec(command);
101 
102         BufferedReader in = new BufferedReader
103             (new InputStreamReader(p.getInputStream()));
104 
105         String s;
106         int count = 0;
107         while ((s = in.readLine()) != null) {
108             if (!s.equals("good")) {
109                 if (File.separatorChar == '/') {
110                     // Fails on windows over NFS...
111                     throw new RuntimeException("Failed: "+s);
112                 }
113             }
114             count++;
115         }
116 
117         if (count == 0) {
118             in = new BufferedReader(new InputStreamReader(p.getErrorStream()));
119             while ((s = in.readLine()) != null) {
120                 System.err.println("Error output: " + s);
121             }
122             throw new RuntimeException("Failed, no output");
123         }
124 
125         // Clean up
126         if (lock != null) {
127             /* Check multiple releases */
128             lock.release();
129             lock.release();
130         }
131         fc.close();
132         fis.close();
133     }
134 
135     // The overlap check for file locks should be JVM-wide
test3(File blah)136     private static void test3(File blah) throws Exception {
137         FileChannel fc1 = new RandomAccessFile(blah, "rw").getChannel();
138         FileChannel fc2 = new RandomAccessFile(blah, "rw").getChannel();
139 
140         // lock via one channel, and then attempt to lock the same file
141         // using a second channel
142         FileLock fl1 = fc1.lock();
143         try {
144             fc2.tryLock();
145             throw new RuntimeException("Overlapping locks allowed");
146         } catch (OverlappingFileLockException x) {
147         }
148         try {
149             fc2.lock();
150             throw new RuntimeException("Overlapping locks allowed");
151         } catch (OverlappingFileLockException x) {
152         }
153 
154         // release lock and the attempt to lock with the second channel
155         // should succeed.
156         fl1.release();
157         FileLock fl2 = fc2.lock();
158         try {
159             fc1.lock();
160             throw new RuntimeException("Overlapping locks allowed");
161         } catch (OverlappingFileLockException x) {
162         }
163 
164         fc1.close();
165         fc2.close();
166     }
167 
168     /**
169      * Test file locking when file is opened for append
170      */
test4(File blah)171     static void test4(File blah) throws Exception {
172         try (FileChannel fc = new FileOutputStream(blah, true).getChannel()) {
173             fc.tryLock().release();
174             fc.tryLock(0L, 1L, false).release();
175             fc.lock().release();
176             fc.lock(0L, 1L, false).release();
177         }
178         try (FileChannel fc = FileChannel.open(blah.toPath(), APPEND)) {
179             fc.tryLock().release();
180             fc.tryLock(0L, 1L, false).release();
181             fc.lock().release();
182             fc.lock(0L, 1L, false).release();
183         }
184     }
185 }
186 
187 class MadWriter {
MadWriter(String s, boolean b)188     public MadWriter(String s, boolean b) throws Exception {
189         File f = new File(s);
190         RandomAccessFile fos = new RandomAccessFile(f, "rw");
191         FileChannel fc = fos.getChannel();
192         if (fc.tryLock(10, 10, false) == null) {
193             System.out.println("bad: Failed to grab adjacent lock");
194         }
195         FileLock lock = fc.tryLock(0, 10, false);
196         if (lock == null) {
197             if (b)
198                 System.out.println("bad");
199             else
200                 System.out.println("good");
201         } else {
202             if (b)
203                 System.out.println("good");
204             else
205                 System.out.println("bad");
206         }
207         fc.close();
208         fos.close();
209     }
210 
211 }
212