Lock.java revision 15476:2c68a91dcecf
1/*
2 * Copyright (c) 2001, 2016, 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 7146506
26 * @summary Test FileChannel file locking
27 */
28
29import java.io.*;
30import java.nio.channels.*;
31import static java.nio.file.StandardOpenOption.*;
32
33/**
34 * Testing FileChannel's lock method.
35 */
36public class Lock {
37
38    public static void main(String[] args) throws Exception {
39        if (args.length == 2) {
40            attemptLock(args[1], args[0].equals("2"));
41            return;
42        } else if (args.length != 0) {
43            throw new RuntimeException("Wrong number of parameters.");
44        }
45        File blah = File.createTempFile("blah", null);
46        blah.deleteOnExit();
47        RandomAccessFile raf = new RandomAccessFile(blah, "rw");
48        raf.write(1);
49        raf.close();
50        test1(blah, "1");
51        test1(blah, "2");
52        test2(blah, true);
53        test2(blah, false);
54        test3(blah);
55        test4(blah);
56    }
57
58    /**
59     * Test mutual locking with other process
60     */
61    static void test1(File blah, String str) throws Exception {
62        try (RandomAccessFile fis = new RandomAccessFile(blah, "rw")) {
63            FileChannel fc = fis.getChannel();
64            FileLock lock = null;
65
66            // grab the lock
67            if (str.equals("1")) {
68                lock = fc.lock(0, 10, false);
69                if (lock == null)
70                    throw new RuntimeException("Lock should not return null");
71                try {
72                    fc.lock(5, 10, false);
73                    throw new RuntimeException("Overlapping locks allowed");
74                } catch (OverlappingFileLockException e) {} // correct result
75            }
76
77            // execute the tamperer
78            String command = System.getProperty("java.home") +
79                File.separator + "bin" + File.separator + "java";
80            String testClasses = System.getProperty("test.classes");
81            if (testClasses != null)
82                command += " -cp " + testClasses;
83            command += " Lock " + str + " " + blah;
84            Process p = Runtime.getRuntime().exec(command);
85
86            // evaluate System.out of child process
87            String s;
88            boolean hasOutput = false;
89            InputStreamReader isr;
90            isr = new InputStreamReader(p.getInputStream());
91            BufferedReader br = new BufferedReader(isr);
92            while ((s = br.readLine()) != null) {
93                // only throw on Unix as windows over NFS fails...
94                if ((File.separatorChar == '/') && !s.equals("good")) {
95                    throw new RuntimeException("Failed: " + s);
96                }
97                hasOutput = true;
98            }
99
100            // evaluate System.err in case of System.out of child process
101            // was empty
102            if (!hasOutput) {
103                isr = new InputStreamReader(p.getErrorStream());
104                br = new BufferedReader(isr);
105                if ((s = br.readLine()) != null) {
106                    System.err.println("Error output:");
107                    System.err.println(s);
108                    while ((s = br.readLine()) != null) {
109                        System.err.println(s);
110                    }
111                }
112                throw new RuntimeException("Failed, no output");
113            }
114
115            // clean up, check multiple releases
116            if (lock != null) {
117                lock.release();
118                lock.release();
119            }
120        }
121    }
122
123    /**
124     * Basic test for FileChannel.lock() and FileChannel.tryLock()
125     */
126    static void test2(File blah, boolean b) throws Exception {
127        try (RandomAccessFile raf = new RandomAccessFile(blah, "rw")) {
128            FileChannel channel = raf.getChannel();
129            FileLock lock;
130            if (b)
131                lock = channel.lock();
132            else
133                lock = channel.tryLock();
134            lock.release();
135        }
136    }
137
138    /**
139     * Test that overlapping file locking is not possible when using different
140     * FileChannel objects to the same file path
141     */
142    static void test3(File blah) throws Exception {
143        try (RandomAccessFile raf1 = new RandomAccessFile(blah, "rw");
144             RandomAccessFile raf2 = new RandomAccessFile(blah, "rw"))
145        {
146            FileChannel fc1 = raf1.getChannel();
147            FileChannel fc2 = raf2.getChannel();
148
149            // lock via one channel, and then attempt to lock the same file
150            // using a second channel
151            FileLock fl1 = fc1.lock();
152            try {
153                fc2.tryLock();
154                throw new RuntimeException("Overlapping locks allowed");
155            } catch (OverlappingFileLockException x) {}
156            try {
157                fc2.lock();
158                throw new RuntimeException("Overlapping locks allowed");
159            } catch (OverlappingFileLockException x) {}
160
161            // release lock and the attempt to lock with the second channel
162            // should succeed.
163            fl1.release();
164            fc2.lock();
165            try {
166                fc1.lock();
167                throw new RuntimeException("Overlapping locks allowed");
168            } catch (OverlappingFileLockException x) {}
169        }
170    }
171
172    /**
173     * Test file locking when file is opened for append
174     */
175    static void test4(File blah) throws Exception {
176        try (FileOutputStream fos = new FileOutputStream(blah, true)) {
177            FileChannel fc = fos.getChannel();
178            fc.tryLock().release();
179            fc.tryLock(0L, 1L, false).release();
180            fc.lock().release();
181            fc.lock(0L, 1L, false).release();
182        }
183        try (FileChannel fc = FileChannel.open(blah.toPath(), APPEND)) {
184            fc.tryLock().release();
185            fc.tryLock(0L, 1L, false).release();
186            fc.lock().release();
187            fc.lock(0L, 1L, false).release();
188        }
189    }
190
191    /**
192     * Utility method to be run in secondary process which tries to acquire a
193     * lock on a FileChannel
194     */
195    static void attemptLock(String fileName,
196                            boolean expectsLock) throws Exception
197    {
198        File f = new File(fileName);
199        try (RandomAccessFile raf = new RandomAccessFile(f, "rw")) {
200            FileChannel fc = raf.getChannel();
201            if (fc.tryLock(10, 10, false) == null) {
202                System.out.println("bad: Failed to grab adjacent lock");
203            }
204            if (fc.tryLock(0, 10, false) == null) {
205                if (expectsLock)
206                    System.out.println("bad");
207                else
208                    System.out.println("good");
209            } else {
210                if (expectsLock)
211                    System.out.println("good");
212                else
213                    System.out.println("bad");
214            }
215        }
216    }
217}
218