[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