How to check if can write to a folder - julia

In julia, how do I check if the current is allowed to write to a folder?
I could do the python way, and just attempt to do it, and then fail fail and recover.
(In my case I can definitely recover, I have a list of locations to attempt to write to, as fallbacks. I expect the first few not to work (The first few are shared locations, so only computer admins are likely to have permission to writer there)

Python has also os.access function. Maybe Julia will have something similar in the future. Now we could borrow idea. :)
It is implemented in posixmodule.c (also functionality for windows!) so if you are on posix you could simply mimic:
julia> const R_OK = 4 # readability
julia> const W_OK = 2 # writability
julia> const X_OK = 1 # executability
julia> const F_OK = 4 # existence
julia> access(path, mode) = ccall(:access, Cint, (Cstring, Cint), path, mode) == 0;
Small test:
julia> access("/root", W_OK)
false
julia> access("/tmp", W_OK)
true
(for windows it could be just a little more complicated... But I could not test it now)
EDIT:
Thanks to Matt B. we could use libuv support in Julia which has to be portable (although slower on posix systems):
julia> function uv_access(path, mode)
local ret
req = Libc.malloc(Base._sizeof_uv_fs)
try
ret = ccall(:uv_fs_access, Int32, (Ptr{Void}, Ptr{Void}, Cstring, Int64, Ptr{Void}), Base.eventloop(), req, path, mode, C_NULL)
ccall(:uv_fs_req_cleanup, Void, (Ptr{Void},), req)
finally
Libc.free(req)
end
return ret, ret==0 ? "OK" : Base.struverror(ret)
end
julia> uv_access("/tmp", W_OK)
(0, "OK")
julia> uv_access("/root", W_OK)
(-13, "permission denied")
julia> uv_access("/nonexist", W_OK)
(-2, "no such file or directory")

Is the following sufficient:
julia> testdir(dirpath) = try (p,i) = mktemp(dirpath) ; rm(p) ; true catch false end
testdir (generic function with 1 method)
julia> testdir("/tmp")
true
julia> testdir("/root")
false
Returns true if dirpath is writable (by creating a temporary file inside a try-catch block). To find the first writable directory in a list, the following can be used:
julia> findfirst(testdir, ["/root","/tmp"])
2

Doing apropos("permissions"):
julia> apropos("permissions")
Base.Filesystem.gperm
Base.Filesystem.mkpath
Base.Filesystem.operm
Base.Filesystem.uperm
Base.Filesystem.mkdir
Base.Filesystem.chmod
shows a function called Base.Filesystem.uperm which seems to do exactly what you want it to:
help?> uperm
search: uperm supertype uppercase UpperTriangular isupper unescape_string unsafe_pointer_to_objref
uperm(file)
Gets the permissions of the owner of the file as a bitfield of
Value Description
––––– ––––––––––––––––––
01 Execute Permission
02 Write Permission
04 Read Permission
For allowed arguments, see stat.
Unfortunately it seems to be a bit buggy on my (old v7 nightly) build:
julia> uperm("/root")
0x07 # Uhhh I hope not?
I will update my build and raise a bug if one is not already present.
PS. In case it wasn't clear, I would expect to use this in combination with isdir to detect directory permissions specifically

I don't think that Dan Getz's answer will work on Windows because the temporary file created cannot be deleted while there is an open handle to it, but this amended version with a call to close does work:
function isfolderwritable(folder)
try
(p,i) = mktemp(folder)
close(i)
rm(p)
return(true)
catch
return(false)
end
end

Related

OCaml - Error: Module `Unix' is unavailable [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
I have been working through Harvard's CS51 class using materials available online. I'm trying to start the final project and downloaded the necessary files, but when I try to compile them I get the following error:
Error: Module `Unix' is unavailable (required by `Thread')
Command exited with code 2.
Compilation unsuccessful after building 18 targets (15 cached) in 00:00:00.
I have not made any changes to the code I downloaded yet and supposedly I should be able to compile it successfully in its current state. Any ideas why I might be getting this error?
EDIT: Below is the code from the file I downloaded and am trying to compile.
module Ev = Evaluation ;;
module MP = Miniml_parse ;;
module ML = Miniml_lex ;;
module Ex = Expr ;;
open Printf ;;
(* str_to_exp str -- Returns the expression specified by `str` using
the MiniML parser. *)
let str_to_exp (str: string) : Ex.expr =
let lexbuf = Lexing.from_string str in
let exp = MP.input ML.token lexbuf in
exp ;;
(* repl () -- Read-eval-print loop for MiniML, which prompts for and
evaluates MiniML expressions, printing the resulting value. Exits
the loop and terminates upon reading an end-of-file
(control-d). *)
let repl () =
(* lexical analyzer buffer from stdin *)
let lexbuf = Lexing.from_channel stdin in
(* set up the initial environment *)
let env = Ev.Env.empty () in
(* the main LOOP *)
while true do
(try
(* prompt *)
printf "<== %!";
(* READ and parse an expression from the input *)
let exp = MP.input ML.token lexbuf in
(* EVALuate it *)
let res = Ev.evaluate exp env in
(* PRINT the result; in this initial version, the trivial
evaluator just returns the expression unchanged as an
element of the `Env.value` type (found in `expr.ml`), so we
just extract the expression back out and print it *)
match res with
| Val resexp ->
printf "==> %s\n" (Ex.exp_to_abstract_string resexp)
| _ -> failwith "not handling other cases yet"
with
| MP.Error -> printf "xx> parse error\n"
| Ev.EvalError msg -> printf "xx> evaluation error: %s\n" msg
| Ev.EvalException -> printf "xx> evaluation exception\n"
| End_of_file -> printf "Goodbye.\n"; exit 0
);
flush stdout
done
;;
(* Run REPL if called from command line *)
try
let _ = Str.search_forward (Str.regexp "miniml\\.\\(byte\\|native\\|bc\\|exe\\)")
(Sys.argv.(0)) 0 in
repl ()
with Not_found -> () ;;
If I add open Unix it does take care of the error above, but I then get a different error:
26 | let lexbuf = Lexing.from_channel stdin in
^^^^^
Error: This expression has type Unix.file_descr
but an expression was expected of type in_channel
Command exited with code 2.
Generally, you have to explicitly ask to be linked to the Unix module.
The following program:
$ cat main.ml
Unix.gethostname () |> print_endline
would need to be built like this:
$ ocamlfind opt -linkpkg -package unix -o main main.ml; echo $?
0
whereas the bare minimum would fail with a similar error as yours:
$ ocamlopt -o main main.ml; echo $?
File "main.ml", line 1:
Error: No implementations provided for the following modules:
Unix referenced from main.cmx
2
That said, it looks like you're using Core, in which case (as well as most
other cases, actually) you're probably better off with dune:
$ cat dune
(executable
(name main)
(libraries unix))
$ dune build main.exe
$ ./_build/default/main.exe
amam-oy
However, if you ask Dune to link you to Core, Unix is already included
automatically, so the following dune file would also work for the above
program:
$ cat dune
(executable
(name main)
(libraries core))
Just add
open Unix;;
at the very start of your .ml file

Function clause error Erlang

I am trying to understand process communication in erlang. Here I have a master process and five friends process. If a friend sends a message to any of the other 5 they have to reply back. But the master should be aware of all this. I am pasting the code below.
-module(prog).
-import(lists,[append/2,concat/1]).
-import(maps,[from_lists/1,find/2,get/2,update/3]).
-import(string,[equal/2]).
-import(file,[consult/1]).
-export([create_process/1,friends/4, master/1, main/0,prnt/1]).
%% CREATE PROCESS
create_process([])->ok;
create_process([H|T])->
{A,B} = H,
Pid = spawn(prog,friends,[B,self(),0,A]),
register(A,Pid),
create_process(T).
%% FRIENDS PROCESS
friends(Msg, M_pid, State, Self_name)->
S = lists:concat([Self_name," state =",State,"\n"]),
io:fwrite(S),
if
State == 0 ->
timer:sleep(500),
io:fwrite("~p~n",[Self_name]),
lists:foreach(fun(X) -> whereis(X)!{Self_name,"intro",self()} end, Msg),
friends(Msg, M_pid, State + 1, Self_name);
State > 0 ->
receive
{Process_name, Process_msg, Process_id} ->
I = equal(Process_msg,"intro"),
R = equal(Process_msg,"reply"),
XxX = lists:concat([Self_name," recieved ",Process_msg," from ",Process_name,"\n"]),
io:fwrite(XxX),
if
I == true ->
io:fwrite("~p~n",[whereis(Process_name)]),
M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",Process_id,"]"]), self()},
io:fwrite(I),
whereis(Process_name)!{Self_name, "reply",self()},
friends(Msg, M_pid, State + 1, Self_name);
R == true ->
M_pid!{lists:concat([Self_name," received reply message from ", Process_name , "[",Process_id,"]"]), self()},
io:fwrite(R),
friends(Msg, M_pid, State + 1, Self_name)
end
after
1000->
io:fwrite(lists:concat([Self_name," has received no calls for 1 second, ending..."]))
end
end.
master(State)->
receive
{Process_message, Process_id} ->
io:fwrite(Process_message),
master(State+1)
after
2000->
ok
end.
main() ->
B = [{john, [jill,joe,bob]},
{jill, [bob,joe,bob]},
{sue, [jill,jill,jill,bob,jill]},
{bob, [john]},
{joe, [sue]}],
create_process(B),
io:fwrite("~p~n",[whereis(sue)]),
master(0).
I think the line in friends() function,
M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",Process_id,"]"]), self()}
is the cause of error but I cannot understand why. M_pid is known and I am concatenating all the info and sending it to master but I am confused why it isnt working.
The error I am getting is as follows:
Error in process <0.55.0> with exit value: {function_clause,[{lists,thing_to_list,
[<0.54.0>],
[{file,"lists.erl"},{line,603}]},
{lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
{lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
{prog,friends,4,[{file,"prog.erl"},{line,45}]}]}
I dont know what is causing the error. Sorry for asking noob questions and thanks for your help.
An example of what Dogbert discovered:
-module(my).
-compile(export_all).
go() ->
Pid = spawn(my, nothing, []),
lists:concat(["hello", Pid]).
nothing() -> nothing.
In the shell:
2> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
3> my:go().
** exception error: no function clause matching
lists:thing_to_list(<0.75.0>) (lists.erl, line 603)
in function lists:flatmap/2 (lists.erl, line 1250)
in call from lists:flatmap/2 (lists.erl, line 1250)
4>
But:
-module(my).
-compile(export_all).
go() ->
Pid = spawn(my, nothing, []),
lists:concat(["hello", pid_to_list(Pid)]).
nothing() -> nothing.
In the shell:
4> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
5> my:go().
"hello<0.83.0>"
From the erl docs:
concat(Things) -> string()
Things = [Thing]
Thing = atom() | integer() | float() | string()
The list that you feed concat() must contain either atoms, integers, floats, or strings. A pid is neither an atom, integer, float, nor string, so a pid cannot be used with concat(). However, pid_to_list() returns a string:
pid_to_list(Pid) -> string()
Pid = pid()
As you can see, a pid has its own type: pid().
I ran your code.
Where you went wrong was to pass Process_id(which is of type pid()) to lists:concat/1.
Let us try to understand this error:
{function_clause,[{lists,thing_to_list,
[<0.84.0>],
[{file,"lists.erl"},{line,603}]},
{lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
{lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
{prog,friends,4,[{file,"prog.erl"},{line,39}]}]}
It states the function lists:thing_to_list/1 has no definition(see the word function_clause in the error log) which accepts an argument of type pid() as denoted here by [<0.84.0>].
Strings are represented as lists in erlang, which is why we use lists:concat/1.
As #7stud pointed out these are the valid types which can be passed to lists:concat/1 as per the documentation:
atom() | integer() | float() | string()
There are 2 occurrences of the following line. Fix them and you are good to go:
Incorrect Code:
M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",Process_id,"]"]), self()},
Corrected Code
M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",pid_to_list(Process_id),"]"]), self()},
Notice the use of the function erlang:pid_to_list/1. As per the documentation the function accepts type pid() and returns it as string().

How to read from socket without blocking

I ran into a problem when dealing with the server, sending me initial "greetings header" (smtp server):
I need to read this header before send any commands and receive any answers from the server, but i dont know, how to do this, because Julia seems to lack any possibility to readi from IO stream without blocking: "read" command and its analogues does not have any NB-options, nb_available always is 0 though i know exactly that server send me header and my read buffer cant be empty (and "read" command issued right after "nb_available" give me data immediately, without blocking).
julia> s=connect("smtp.mail.ru",25)
TCPSocket(RawFD(18) open, 0 bytes waiting)
julia> nb_available(s)
0
julia> nb_available(s)
0
(after 5 seconds or so...)
julia> nb_available(s)
0
julia> t=read(s,10)
10-element Array{UInt8,1}:
0x32
0x32
0x30
0x20
0x73
0x6d
0x74
0x70
0x31
0x34
(HOW, WHY???? nb_available==0, but read returns me 10 bytes?!)
... (read was repeated many times...)
julia> t=read(s,10)
^CERROR: InterruptException:
Stacktrace:
[1] process_events at ./libuv.jl:82 [inlined]
[2] wait() at ./event.jl:216
[3] wait(::Condition) at ./event.jl:27
[4] wait_readnb(::TCPSocket, ::Int64) at ./stream.jl:296
[5] readbytes!(::TCPSocket, ::Array{UInt8,1}, ::Int64) at ./stream.jl:714
[6] read(::TCPSocket, ::Int64) at ./io.jl:529
I dont want to use #async for the simplest case described above.
Who knows, how to read from TCP socket in non-blocking mode, when i can determine some way, whether read buffer contain any data or no and/or whether next read issued by tcp client will block overall client process or no.
Is it possible in Julia without "green threads" usage?
Since no-one's provided an "official" solution yet, here's the workaround I mentioned above.
Functions:
# Causes stagnant 'nb' count to be updated.
# Note asynchronous nature; this means refresh may not yet have occurred
# when function has exited.
function refreshBufsize(s)
#async eof(s);
return nothing;
end;
# Check if socket is blocked (refresh bytecount first)
# Note, since refresh is asynchronous, may misreport 'blockage' until
# 'refresh' operation is actually finished; however, if socket is actually
# unblocked, subsequent calls of this function will eventually properly
# report socket is not blocked, and in general, misreporting blockage once
# or twice when socket is actually free is probably acceptable (rather
# than other way round).
function isblocked(s)
refreshBufsize(s)
return nb_available(s) == 0;
end;
# Peek contents of socket without consuming stream
function peek(s, nb)
refreshBufsize(s)
s.buffer.seekable = true;
Out = read(s.buffer, nb);
seekstart(s.buffer);
s.buffer.seekable = false
return Out
end;
Example: (console outputs denoted as "#>" comments, for copy-pastable code)
server = listen(9001);
sOut = connect(9001);
sIn = accept(server);
nb_available(sIn)
#> 0
isblocked(sIn)
#> true
refreshBufsize(sIn); # we expect no change, as we haven't written anything yet
isblocked(sIn)
#> true
write(sOut, "Greetinks and salutations!\n")
#> 27
write(sOut, "We would be honoured if you would join us.\n")
#> 43
refreshBufsize(sIn);
isblocked(sIn) # note: may say true at first (until refresh properly finished)
#> false
nb_available(sIn)
#> 27
String( peek( sIn, 10)) # peek socket contents without consuming
#> "Greetinks "
String( read( sIn, nb_available( sIn))) # read (consume) as normal
#> "Greetinks and salutations!\n"
nb_available(sIn) # note 0 even though second buffer awaiting. needs refresh!
#> 0
isblocked(sIn) # note: called "refresh" under the hood
# (but keep async in mind, i.e. might say 'true' at first!)
#> false
nb_available(sIn)
#> 43
String( read( sIn, nb_available( sIn)))
#> "We would be honoured if you would join us.\n"
isblocked(sIn)
#> true
EDIT: for comparison, a more typical "asynchronous" socket session (which typically relies on such "blocking" behaviour) would probably look something like this:
server = listen(9002);
sOut = connect(9002);
sIn = accept(server);
TaskRef = #async try
while true
In = String(readavailable(sIn));
if !isempty(In); println("Received from server: $In"); else; break; end
end
println("Connection closed normally");
catch E
println("Connection closed (with status $E)");
end;
write(sOut, "Stop repeating everything I say!\n");
#> Received from server: Stop repeating everything I say!
close(sIn)
#> Connection closed normally

Pkg.installed("anInvalidPackage") , should return nothing or throw an error?

refer to this paragraph:
installed(pkg) → Void | VersionNumber
If pkg is installed, return the installed version number, otherwise return nothing.
from JuliaDoc
Pkg.installed("anInvalidPackage") function should return nothing but it throws an error:
julia> VERSION
v"0.5.0"
julia> Pkg.installed("anInvalidPackage")
ERROR: anInvalidPackage is not a package (not registered or installed)
in installed(::String) at .\pkg\entry.jl:123
in (::Base.Pkg.Dir.##2#3{Array{Any,1},Base.Pkg.Entry.#installed,Tuple{String}})
() at .\pkg\dir.jl:31
in cd(::Base.Pkg.Dir.##2#3{Array{Any,1},Base.Pkg.Entry.#installed,Tuple{String}
}, ::String) at .\file.jl:48
in #cd#1 at .\pkg\dir.jl:31
in installed(::String) at .\pkg\pkg.jl:129
EDIT : issue
If we tale a look at the source code for the Pkg module in base it should give use some clues:
function installed(pkg::AbstractString)
avail = Read.available(pkg)
if Read.isinstalled(pkg)
res = typemin(VersionNumber)
### some libgit2 stuff ###
end
isempty(avail) && throw(PkgError("$pkg is not a package (not registered or installed)"))
return nothing # registered but not installed
end
From the last two lines we can see that Julia is going to throw an error if the package is not registered or installed. However if the package is registered but not installed then no error will be thrown and nothing is returned.
So
var = Pkg.installed("AMD") # returns nothing for me as I don't have AMD installed
# but it is a registered package
But:
altvar = Pkg.installed("this_is_not_the_name_of_any_package")
# will throw an error
I agree the docs should probably make this more clear...

How to differentiate /dev/tty with stdin, stdout, stderr?

I try this with Python3:
import os
fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
print(fd)
It always prints 3 in Linux. Is /dev/tty file descriptor always 3?
I want to differentiate /dev/tty with stdin,stdout,stderr. My initial attempt is to check the file descriptor since stdin,stdout,stderr return 0, 1, or 2.
The reason I am asking this is because to write to /dev/tty in Python, I have to use bytes not string while with stdin,stderr,stdout, I have to use string.
So my second attempt is:
try:
if file.isatty() and file not in [sys.stdout,sys.stdin,sys.stderr]:
use_bytes = True
else:
use_bytes = False
except AttributeError:
use_bytes = False
Is there any better way to do this?

Resources