[m-rev.] diff: Make the make_temp foreign code compatible with Java 1.5
Paul Bone
paul at bone.id.au
Mon Apr 18 17:27:08 AEST 2016
Make the make_temp foreign code compatible with Java 1.5
library/io.m:
As above.
extras/java_extras/make_temp.m:
Move the more secure but Java 1.7 version here.
---
extras/java_extras/make_temp.m | 199 +++++++++++++++++++++++++++++++++++++++++
library/io.m | 106 ++++++++++++++--------
2 files changed, 270 insertions(+), 35 deletions(-)
create mode 100644 extras/java_extras/make_temp.m
diff --git a/extras/java_extras/make_temp.m b/extras/java_extras/make_temp.m
new file mode 100644
index 0000000..9443e83
--- /dev/null
+++ b/extras/java_extras/make_temp.m
@@ -0,0 +1,199 @@
+%-----------------------------------------------------------------------%
+% vim: ft=mercury sts=4 sw=4 et tw=78
+%-----------------------------------------------------------------------%
+% Copyright (C) 2016 The Mercury Team
+% This file may only be copied under the terms of the GNU Library General
+% Public License - see the file COPYING.LIB in the Mercury distribution.
+%-----------------------------------------------------------------------%
+%
+% This module contains alternatives to io.make_temp and
+% io.make_temp_directory that properly set the permission bits during
+% creation. However this cannot be included in io.m as it requires Java
+% 1.7.
+%
+%-----------------------------------------------------------------------%
+:- module make_temp.
+
+:- interface.
+
+:- import_module io.
+:- import_module string.
+
+%-----------------------------------------------------------------------%
+
+:- type make_temp_error
+ ---> make_temp_error(string).
+
+%-----------------------------------------------------------------------%
+
+ % make_temp(Name, !IO) creates an empty file whose name is different
+ % to the name of any existing file. Name is bound to the name of the file.
+ % It is the responsibility of the caller to delete the file when it
+ % is no longer required.
+ %
+ % The file is placed in the directory returned by get_temp_directory/3.
+ %
+ % On the Erlang backend, this does not attempt to create the file with
+ % restrictive permissions (600 on Unix-like systems) and therefore should
+ % not be used when security is required.
+ %
+:- pred make_temp(string::out, io::di, io::uo) is det.
+
+ % make_temp(Dir, Prefix, Name, !IO) creates an empty file whose
+ % name is different to the name of any existing file. The file will reside
+ % in the directory specified by Dir and will have a prefix using up to
+ % the first 5 characters of Prefix. Name is bound to the name of the
+ % file. It is the responsibility of the caller to delete the file when it
+ % is no longer required.
+ %
+ % The C# backend has the following limitations:
+ % - Dir is ignored.
+ % - Prefix is ignored.
+ %
+ % On the Erlang backend, this does not attempt to create the file with
+ % restrictive permissions (600 on Unix-like systems) and therefore should
+ % not be used when security is required.
+ %
+:- pred make_temp(string::in, string::in, string::out, io::di, io::uo)
+ is det.
+
+ % make_temp_directory(DirName, !IO) creates an empty directory whose name
+ % is different from the name of any existing directory.
+ %
+ % On the C# backend this is insecure as the file permissions are not set
+ % and this call does not test for an existing directory.
+ %
+ % This is unimplemented on the Erlang backend.
+ %
+:- pred make_temp_directory(string::out, io::di, io::uo) is det.
+
+ % make_temp_directory(Dir, Prefix, DirName, !IO) creates an empty directory
+ % whose name is different from the name of any existing directory. The new
+ % directory will reside in the existing directory specified by `Dir' and
+ % will have a prefix using up to the first 5 characters of `Prefix'.
+ % DirName is bound to the name of the new directory. It is the
+ % responsibility of the program to delete the directory when it is no
+ % longer needed.
+ %
+ % The C# backend has the following limitations:
+ % - It does not attempt to create the file with restrictive permissions
+ % (600 on Unix-like systems) and therefore should not be used when
+ % security is required.
+ % - Prefix is ignored.
+ %
+ % This is unimplemented on the Erlang backend.
+ %
+:- pred make_temp_directory(string::in, string::in, string::out,
+ io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------%
+%-----------------------------------------------------------------------%
+:- implementation.
+
+:- import_module bool.
+:- import_module exception.
+:- import_module dir.
+
+%-----------------------------------------------------------------------%
+
+:- pragma foreign_decl("Java", local,
+"
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermissions;
+").
+
+%-----------------------------------------------------------------------%
+
+make_temp(Name, !IO) :-
+ io.get_temp_directory(Dir, !IO),
+ make_temp.make_temp(Dir, "mtmp", Name, !IO).
+
+make_temp(Dir, Prefix, Name, !IO) :-
+ do_make_temp(Dir, Prefix, char_to_string(dir.directory_separator),
+ Name, Okay, Message, !IO),
+ (
+ Okay = yes
+ ;
+ Okay = no,
+ throw(make_temp_error(Message))
+ ).
+
+make_temp_directory(DirName, !IO) :-
+ get_temp_directory(Dir, !IO),
+ make_temp.make_temp_directory(Dir, "mtmp", DirName, !IO).
+
+make_temp_directory(Dir, Prefix, DirName, !IO) :-
+ do_make_temp_directory(Dir, Prefix,
+ char_to_string(dir.directory_separator), DirName, Okay, Message, !IO),
+ (
+ Okay = yes
+ ;
+ Okay = no,
+ throw(make_temp_error(Message))
+ ).
+
+%-----------------------------------------------------------------------%
+
+:- pred do_make_temp(string::in, string::in, string::in,
+ string::out, bool::out, string::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("Java",
+ do_make_temp(Dir::in, Prefix::in, _Sep::in, FileName::out,
+ Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+ [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
+ may_not_duplicate],
+"
+ try {
+ Path dir_path, new_file;
+
+ if (Prefix.length() > 5) {
+ // The documentation for io.make_temp says that we should only use
+ // the first five characters of Prefix.
+ Prefix = Prefix.substring(0, 5);
+ }
+ dir_path = Paths.get(Dir);
+ new_file = Files.createTempFile(dir_path, Prefix, null);
+ FileName = new_file.toAbsolutePath().toString();
+ Okay = bool.YES;
+ ErrorMessage = """";
+ } catch (java.lang.Exception e) {
+ FileName = """";
+ Okay = bool.NO;
+ ErrorMessage = e.toString();
+ }
+").
+
+:- pred do_make_temp_directory(string::in, string::in, string::in,
+ string::out, bool::out, string::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("Java",
+ do_make_temp_directory(Dir::in, Prefix::in, _Sep::in, DirName::out,
+ Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+ [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
+ may_not_duplicate],
+"
+ try {
+ Path dir_path, new_file;
+
+ if (Prefix.length() > 5) {
+ // The documentation for io.make_temp says that we should only use
+ // the first five characters of Prefix.
+ Prefix = Prefix.substring(0, 5);
+ }
+ dir_path = Paths.get(Dir);
+ new_file = Files.createTempDirectory(dir_path, Prefix);
+ DirName = new_file.toAbsolutePath().toString();
+ Okay = bool.YES;
+ ErrorMessage = """";
+ } catch (java.lang.Exception e) {
+ DirName = """";
+ Okay = bool.NO;
+ ErrorMessage = e.toString();
+ }
+").
+
+%-----------------------------------------------------------------------%
+%-----------------------------------------------------------------------%
diff --git a/library/io.m b/library/io.m
index 379e888..aa2d96b 100644
--- a/library/io.m
+++ b/library/io.m
@@ -1316,9 +1316,9 @@
%
% Throws an io.error exception if the temporary file could not be created.
%
- % On the Erlang backend, this does not attempt to create the file with
- % restrictive permissions (600 on Unix-like systems) and therefore should
- % not be used when security is required.
+ % On the Erlang and Java backends, this does not attempt to create the file
+ % with restrictive permissions (600 on Unix-like systems) and therefore
+ % should not be used when security is required.
%
:- pred make_temp(string::out, io::di, io::uo) is det.
@@ -1335,9 +1335,9 @@
% - Dir is ignored.
% - Prefix is ignored.
%
- % On the Erlang backend, this does not attempt to create the file with
- % restrictive permissions (600 on Unix-like systems) and therefore should
- % not be used when security is required.
+ % On the Erlang and Java backends, this does not attempt to create the file
+ % with restrictive permissions (600 on Unix-like systems) and therefore
+ % should not be used when security is required.
%
:- pred make_temp(string::in, string::in, string::out, io::di, io::uo)
is det.
@@ -1351,6 +1351,8 @@
% On the C# backend this is insecure as the file permissions are not set
% and this call does not test for an existing directory.
%
+ % On the Java backend this is insecure as the file permissions are not set.
+ %
% This is unimplemented on the Erlang backend.
%
:- pred make_temp_directory(string::out, io::di, io::uo) is det.
@@ -1372,6 +1374,8 @@
% security is required.
% - Prefix is ignored.
%
+ % On the Java backend this is insecure as the file permissions are not set.
+ %
% This is unimplemented on the Erlang backend.
%
:- pred make_temp_directory(string::in, string::in, string::out,
@@ -10368,6 +10372,42 @@ make_temp_directory(Dir, Prefix, DirName, !IO) :-
%-----------------------------------------------------------------------%
+:- pragma foreign_decl("Java", local,
+"
+import java.io.File;
+import java.io.IOException;
+import java.util.Random;
+").
+
+:- pragma foreign_code("Java",
+"
+ public static Random ML_rand = new Random();
+
+ public static String makeTempName(String prefix)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(prefix);
+
+ // Make an 8-digit mixed case alpha-numeric code.
+ for (int i = 0; i < 8; i++) {
+ char c;
+ int c_num = ML_rand.nextInt(10+26+26);
+ if (c_num < 10) {
+ c_num = c_num + '0';
+ } else if (c_num < 10+26) {
+ c_num = c_num + 'A' - 10;
+ } else{
+ c_num = c_num + 'a' - 10 - 26;
+ }
+ c = (char)c_num;
+ sb.append(c);
+ }
+
+ return sb.toString();
+ }
+").
+
:- pred do_make_temp(string::in, string::in, string::in,
string::out, bool::out, string::out, io::di, io::uo) is det.
@@ -10497,16 +10537,6 @@ make_temp_directory(Dir, Prefix, DirName, !IO) :-
}
}").
-:- pragma foreign_decl("Java", local,
-"
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.PosixFilePermissions;
-").
-
-
% For the Java implementation, io.make_temp/3 is overwritten directly,
% since Java is capable of locating the default temp directory itself.
@@ -10517,19 +10547,25 @@ import java.nio.file.attribute.PosixFilePermissions;
may_not_duplicate],
"
try {
- Path dir_path, new_file;
+ File new_file;
if (Prefix.length() > 5) {
// The documentation for io.make_temp says that we should only use
// the first five characters of Prefix.
Prefix = Prefix.substring(0, 5);
}
- dir_path = Paths.get(Dir);
- new_file = Files.createTempFile(dir_path, Prefix, null);
- FileName = new_file.toAbsolutePath().toString();
- Okay = bool.YES;
- ErrorMessage = """";
- } catch (java.lang.Exception e) {
+
+ new_file = new File(new File(Dir), makeTempName(Prefix));
+ if (new_file.createNewFile()) {
+ FileName = new_file.getAbsolutePath();
+ Okay = bool.YES;
+ ErrorMessage = """";
+ } else {
+ FileName = """";
+ Okay = bool.NO;
+ ErrorMessage = ""Could not create file"";
+ }
+ } catch (IOException e) {
FileName = """";
Okay = bool.NO;
ErrorMessage = e.toString();
@@ -10673,23 +10709,23 @@ import java.nio.file.attribute.PosixFilePermissions;
[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
may_not_duplicate],
"
- try {
- Path dir_path, new_file;
+ File new_dir;
- if (Prefix.length() > 5) {
- // The documentation for io.make_temp says that we should only use
- // the first five characters of Prefix.
- Prefix = Prefix.substring(0, 5);
- }
- dir_path = Paths.get(Dir);
- new_file = Files.createTempDirectory(dir_path, Prefix);
- DirName = new_file.toAbsolutePath().toString();
+ if (Prefix.length() > 5) {
+ // The documentation for io.make_temp says that we should only use
+ // the first five characters of Prefix.
+ Prefix = Prefix.substring(0, 5);
+ }
+
+ new_dir = new File(new File(Dir), makeTempName(Prefix));
+ if (new_dir.mkdir()) {
+ DirName = new_dir.getAbsolutePath();
Okay = bool.YES;
ErrorMessage = """";
- } catch (java.lang.Exception e) {
+ } else {
DirName = """";
Okay = bool.NO;
- ErrorMessage = e.toString();
+ ErrorMessage = ""Coudln't create directory"";
}
").
--
2.8.0.rc3
More information about the reviews
mailing list