Skip to content

Commit 9bccf90

Browse files
committed
posix module: open create a temp file if DELETE_ON_CLOSE is set
- uses Files.createTempFile until TruffleFile API supports the creation of temp files - explicit logic for creating temporary files in the specified path - files are deleted on jvm exit - add test_tempfile case
1 parent c9742fe commit 9bccf90

File tree

10 files changed

+183
-21
lines changed

10 files changed

+183
-21
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_subprocess.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates.
22
# Copyright (C) 1996-2017 Python Software Foundation
33
#
44
# Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
41+
def assert_raises(err, fn, *args, **kwargs):
42+
raised = False
43+
try:
44+
fn(*args, **kwargs)
45+
except err:
46+
raised = True
47+
assert raised
48+
49+
50+
def test_create():
51+
from tempfile import TemporaryFile
52+
try:
53+
f = TemporaryFile()
54+
assert f is not None
55+
f.close()
56+
except:
57+
assert False
58+

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OSError;
3131
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
3232
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
33+
import static com.oracle.graal.python.util.TempFileUtils.getRandomFilePath;
3334
import static com.oracle.truffle.api.TruffleFile.CREATION_TIME;
3435
import static com.oracle.truffle.api.TruffleFile.IS_DIRECTORY;
3536
import static com.oracle.truffle.api.TruffleFile.IS_REGULAR_FILE;
@@ -541,7 +542,7 @@ public abstract static class StatNode extends PythonBinaryBuiltinNode {
541542

542543
@Specialization
543544
Object doStatPath(VirtualFrame frame, Object path, boolean followSymlinks,
544-
@Cached CastToPathNode cast) {
545+
@Cached CastToPathNode cast) {
545546
return stat(cast.execute(frame, path), followSymlinks);
546547
}
547548

@@ -845,7 +846,7 @@ public abstract static class ScandirIterNode extends PythonBinaryBuiltinNode {
845846

846847
@Specialization
847848
Object doit(VirtualFrame frame, LazyPythonClass cls, Object pathArg,
848-
@Cached CastToPathNode cast) {
849+
@Cached CastToPathNode cast) {
849850
String path = cast.execute(frame, pathArg);
850851
try {
851852
TruffleFile file = getContext().getEnv().getPublicTruffleFile(path);
@@ -865,7 +866,7 @@ public abstract static class DirEntryNode extends PythonTernaryBuiltinNode {
865866

866867
@Specialization
867868
Object doit(VirtualFrame frame, LazyPythonClass cls, String name, Object pathArg,
868-
@Cached CastToPathNode cast) {
869+
@Cached CastToPathNode cast) {
869870
String path = cast.execute(frame, pathArg);
870871
try {
871872
TruffleFile dir = getContext().getEnv().getPublicTruffleFile(path);
@@ -912,19 +913,26 @@ public abstract static class OpenNode extends PythonFileNode {
912913

913914
@Specialization(guards = {"isNoValue(mode)", "isNoValue(dir_fd)"})
914915
Object open(VirtualFrame frame, Object pathname, int flags, @SuppressWarnings("unused") PNone mode, PNone dir_fd,
915-
@Cached CastToPathNode cast) {
916+
@Cached CastToPathNode cast) {
916917
return openMode(frame, pathname, flags, 0777, dir_fd, cast);
917918
}
918919

919920
@Specialization(guards = {"isNoValue(dir_fd)"})
920921
Object openMode(VirtualFrame frame, Object pathArg, int flags, int fileMode, @SuppressWarnings("unused") PNone dir_fd,
921-
@Cached CastToPathNode cast) {
922+
@Cached CastToPathNode cast) {
922923
String pathname = cast.execute(frame, pathArg);
923924
Set<StandardOpenOption> options = flagsToOptions(flags);
924925
FileAttribute<Set<PosixFilePermission>>[] attributes = modeToAttributes(fileMode);
925-
TruffleFile truffleFile = getContext().getPublicTruffleFileRelaxed(pathname, PythonLanguage.DEFAULT_PYTHON_EXTENSIONS);
926+
TruffleFile truffleFile;
926927
try {
927-
SeekableByteChannel fc = truffleFile.newByteChannel(options, attributes);
928+
SeekableByteChannel fc;
929+
if (options.contains(StandardOpenOption.DELETE_ON_CLOSE)) {
930+
// TODO: (cbas) remove patch once the TruffleFile API supports temp file
931+
// creation -> GR-17515
932+
pathname = getRandomFilePath(pathname, options);
933+
}
934+
truffleFile = getContext().getPublicTruffleFileRelaxed(pathname, PythonLanguage.DEFAULT_PYTHON_EXTENSIONS);
935+
fc = truffleFile.newByteChannel(options, attributes);
928936
return getResources().open(truffleFile, fc);
929937
} catch (NoSuchFileException e) {
930938
gotException.enter();
@@ -1076,7 +1084,7 @@ public abstract static class UnlinkNode extends PythonFileNode {
10761084

10771085
@Specialization
10781086
Object unlink(VirtualFrame frame, Object pathArg,
1079-
@Cached CastToPathNode cast) {
1087+
@Cached CastToPathNode cast) {
10801088
String path = cast.execute(frame, pathArg);
10811089
try {
10821090
getContext().getEnv().getPublicTruffleFile(path).delete();
@@ -1106,13 +1114,13 @@ public abstract static class MkdirNode extends PythonFileNode {
11061114

11071115
@Specialization
11081116
Object mkdir(VirtualFrame frame, Object path, @SuppressWarnings("unused") PNone mode, PNone dirFd,
1109-
@Cached CastToPathNode cast) {
1117+
@Cached CastToPathNode cast) {
11101118
return mkdirMode(frame, path, 511, dirFd, cast);
11111119
}
11121120

11131121
@Specialization
11141122
Object mkdirMode(VirtualFrame frame, Object pathArg, @SuppressWarnings("unused") int mode, @SuppressWarnings("unused") PNone dirFd,
1115-
@Cached CastToPathNode cast) {
1123+
@Cached CastToPathNode cast) {
11161124
String path = cast.execute(frame, pathArg);
11171125
try {
11181126
getContext().getEnv().getPublicTruffleFile(path).createDirectory();
@@ -1263,13 +1271,13 @@ abstract static class ChmodNode extends PythonBuiltinNode {
12631271

12641272
@Specialization
12651273
Object chmod(VirtualFrame frame, Object path, long mode, @SuppressWarnings("unused") PNone dir_fd, @SuppressWarnings("unused") PNone follow_symlinks,
1266-
@Cached CastToPathNode cast) {
1274+
@Cached CastToPathNode cast) {
12671275
return chmodFollow(frame, path, mode, dir_fd, true, cast);
12681276
}
12691277

12701278
@Specialization
12711279
Object chmodFollow(VirtualFrame frame, Object pathArg, long mode, @SuppressWarnings("unused") PNone dir_fd, boolean follow_symlinks,
1272-
@Cached CastToPathNode cast) {
1280+
@Cached CastToPathNode cast) {
12731281
String path = cast.execute(frame, pathArg);
12741282
Set<PosixFilePermission> permissions = modeToPermissions(mode);
12751283
try {
@@ -1472,7 +1480,7 @@ PTuple waitpid(VirtualFrame frame, int pid, int options) {
14721480
@SuppressWarnings("unused")
14731481
@Specialization
14741482
PTuple waitpidFallback(VirtualFrame frame, Object pid, Object options,
1475-
@Cached CastToIndexNode castToInt) {
1483+
@Cached CastToIndexNode castToInt) {
14761484
return waitpid(frame, castToInt.execute(pid), castToInt.execute(options));
14771485
}
14781486
}
@@ -1908,8 +1916,8 @@ String ctermid() {
19081916
@GenerateNodeFactory
19091917
@TypeSystemReference(PythonArithmeticTypes.class)
19101918
abstract static class KillNode extends PythonBinaryBuiltinNode {
1911-
private static final String[] KILL_SIGNALS = new String[] { "SIGKILL", "SIGQUIT", "SIGTRAP", "SIGABRT" };
1912-
private static final String[] TERMINATION_SIGNALS = new String[] { "SIGTERM", "SIGINT" };
1919+
private static final String[] KILL_SIGNALS = new String[]{"SIGKILL", "SIGQUIT", "SIGTRAP", "SIGABRT"};
1920+
private static final String[] TERMINATION_SIGNALS = new String[]{"SIGTERM", "SIGINT"};
19131921

19141922
@Specialization
19151923
PNone kill(VirtualFrame frame, int pid, int signal,

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/ModuleBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
8383
return ModuleBuiltinsFactory.getFactories();
8484
}
8585

86-
@Builtin(name = __INIT__ , minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 3, declaresExplicitSelf = true)
86+
@Builtin(name = __INIT__, minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 3, declaresExplicitSelf = true)
8787
@GenerateNodeFactory
8888
@TypeSystemReference(PythonArithmeticTypes.class)
8989
public abstract static class ModuleNode extends PythonBuiltinNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/PythonModule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2019, Oracle and/or its affiliates.
33
* Copyright (c) 2013, Regents of the University of California
44
*
55
* All rights reserved.

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromObjectNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ protected static boolean isBuiltinDict(PHashingCollection globals, IsBuiltinClas
119119
}
120120

121121
/**
122-
* @param module Non-cached parameter to help the DSL produce a guard, not an assertion
122+
* @param module Non-cached parameter to help the DSL produce a guard, not an assertion
123123
*/
124124
protected static HashingStorage getStorage(Object module, Object cachedGlobals) {
125125
return ((PDict) cachedGlobals).getDictStorage();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToPathNode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ String doObject(VirtualFrame frame, Object object,
125125
protected LookupAndCallUnaryNode createFsPathCall() {
126126
return LookupAndCallUnaryNode.create(SpecialMethodNames.__FSPATH__, () -> new NoAttributeHandler() {
127127
@Child PRaiseNode raise = PRaiseNode.create();
128+
128129
@Override
129130
public Object execute(Object receiver) {
130131
throw raise.raise(PythonBuiltinClassType.TypeError, ERROR_MESSAGE, receiver);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ public PosixResources() {
152152
files.add(null);
153153
files.add(null);
154154
files.add(null);
155-
children.add(new ProcessGroup(children)); // PID 0 is special, and refers to all processes in the process group
155+
children.add(new ProcessGroup(children)); // PID 0 is special, and refers to all processes
156+
// in the process group
156157
inodes = new HashMap<>();
157158
}
158159

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.util;
42+
43+
import java.io.File;
44+
import java.io.IOException;
45+
import java.nio.file.StandardOpenOption;
46+
import java.util.Random;
47+
import java.util.Set;
48+
49+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
50+
51+
public final class TempFileUtils {
52+
private static final String CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
53+
private static final Random RANDOM = new Random(System.currentTimeMillis());
54+
55+
@TruffleBoundary
56+
public static String getRandomString(int length) {
57+
StringBuilder sb = new StringBuilder(length);
58+
for (int i = 0; i < length; i++) {
59+
sb.append(CHARS.charAt(RANDOM.nextInt(CHARS.length())));
60+
}
61+
return sb.toString();
62+
}
63+
64+
public static String getRandomFilePath(String path, Set<StandardOpenOption> options) throws IOException {
65+
return getRandomFilePath(path, null, null, options);
66+
}
67+
68+
@TruffleBoundary
69+
public static String getRandomFilePath(String path, String prefix, String suffix, Set<StandardOpenOption> options) throws IOException {
70+
if (path == null) {
71+
path = System.getProperty("java.io.tmpdir");
72+
}
73+
if (prefix == null) {
74+
prefix = "";
75+
}
76+
if (suffix == null) {
77+
suffix = "";
78+
}
79+
80+
while (true) {
81+
String tmpPath = path + File.separator + prefix + getRandomString(8) + suffix;
82+
File tmpFile = new File(tmpPath);
83+
if (!tmpFile.exists()) {
84+
tmpFile.deleteOnExit();
85+
if (tmpFile.createNewFile()) {
86+
options.remove(StandardOpenOption.CREATE_NEW);
87+
options.remove(StandardOpenOption.DELETE_ON_CLOSE);
88+
options.add(StandardOpenOption.CREATE);
89+
return tmpPath;
90+
}
91+
}
92+
}
93+
}
94+
}

graalpython/lib-graalpython/_ast.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0

0 commit comments

Comments
 (0)