Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file lwt_utils_unix.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* Copyright (c) 2021 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openError_monadlet()=register_error_kind`Temporary~id:"unix_error"~title:"Unix error"~description:"An unhandled unix exception"~pp:Format.pp_print_stringData_encoding.(obj1(req"msg"string))(function|Exn(Unix.Unix_error(err,fn,_))->Some("Unix error in "^fn^": "^Unix.error_messageerr)|_->None)(funmsg->Exn(Failuremsg))letdefault_net_timeout=ref(Ptime.Span.of_int_s8)letread_bytes_with_timeout?(timeout=!default_net_timeout)?file_offset?(pos=0)?lenfdbuf=letbuflen=Bytes.lengthbufinletlen=matchlenwithNone->buflen-pos|Somel->linifpos<0||pos+len>buflentheninvalid_arg"read_bytes";letrecinnernb_readposlen=iflen=0thenLwt.return_unitelseletreader=matchfile_offsetwith|None->Lwt_unix.read|Somefo->Lwt_unix.pread~file_offset:(fo+nb_read)inLwt_unix.with_timeout(Ptime.Span.to_float_stimeout)(fun()->readerfdbufposlen)>>=function|0->Lwt.failEnd_of_file(* other endpoint cleanly closed its connection *)|nb_read'->inner(nb_read+nb_read')(pos+nb_read')(len-nb_read')ininner0poslenletread_bytes?file_offset?(pos=0)?lenfdbuf=letbuflen=Bytes.lengthbufinletlen=matchlenwithNone->buflen-pos|Somel->linifpos<0||pos+len>buflentheninvalid_arg"read_bytes";letrecinnernb_readposlen=iflen=0thenLwt.return_unitelseletreader=matchfile_offsetwith|None->Lwt_unix.read|Somefo->Lwt_unix.pread~file_offset:(fo+nb_read)inreaderfdbufposlen>>=function|0->Lwt.failEnd_of_file|nb_read'->inner(nb_read+nb_read')(pos+nb_read')(len-nb_read')ininner0poslenletwrite_bytes?file_offset?(pos=0)?lendescrbuf=letbuflen=Bytes.lengthbufinletlen=matchlenwithNone->buflen-pos|Somel->linifpos<0||pos+len>buflentheninvalid_arg"write_bytes";letrecinnernb_writtenposlen=iflen=0thenLwt.return_unitelseletwriter=matchfile_offsetwith|None->Lwt_unix.write|Somefo->Lwt_unix.pwrite~file_offset:(fo+nb_written)inwriterdescrbufposlen>>=function|0->Lwt.failEnd_of_file(* other endpoint cleanly closed its connection *)|nb_written'->inner(nb_written+nb_written')(pos+nb_written')(len-nb_written')ininner0poslenletwrite_string?(pos=0)?lendescrbuf=letlen=matchlenwithNone->String.lengthbuf-pos|Somel->linletrecinnerposlen=iflen=0thenLwt.return_unitelseLwt_unix.write_stringdescrbufposlen>>=function|0->Lwt.failEnd_of_file(* other endpoint cleanly closed its connection *)|nb_written->inner(pos+nb_written)(len-nb_written)ininnerposlenletis_directoryfile_name=Lwt_unix.lstatfile_name>|=funs->s.st_kind=S_DIRletremove_dirdir=letrecremovedir=letfiles=Lwt_unix.files_of_directorydirinLwt_stream.iter_s(funfile->iffile="."||file=".."thenLwt.return_unitelseletfile=Filename.concatdirfileinifSys.is_directoryfilethenremovefileelseLwt_unix.unlinkfile)files>>=fun()->Lwt_unix.rmdirdirinifSys.file_existsdir&&Sys.is_directorydirthenremovedirelseLwt.return_unitletreccreate_dir?(perm=0o755)dir=Lwt_unix.file_existsdir>>=function|false->create_dir(Filename.dirnamedir)>>=fun()->Lwt.catch(fun()->Lwt_unix.mkdirdirperm)(function|Unix.Unix_error(Unix.EEXIST,_,_)->(* This is the case where the directory has been created
by another Lwt.t, after the call to Lwt_unix.file_exists. *)Lwt.return_unit|e->Lwt.faile)|true->(Lwt_unix.statdir>>=function|{st_kind=S_DIR;_}->Lwt.return_unit|_->Stdlib.failwith"Not a directory")letsafe_closefd=Lwt.catch(fun()->Lwt_unix.closefd>>=fun()->return_unit)(funexc->fail(Exnexc))letcreate_file?(close_on_exec=true)?(perm=0o644)namecontent=letflags=letopenUnixinletflags=[O_TRUNC;O_CREAT;O_WRONLY]inifclose_on_execthenO_CLOEXEC::flagselseflagsinLwt_unix.openfilenameflagsperm>>=funfd->Lwt.try_bind(fun()->write_stringfd~pos:0~len:(String.lengthcontent)content)(funv->safe_closefd>>=function|Errortrace->Format.eprintf"Uncaught error: %a\n%!"pp_print_errortrace;Lwt.returnv|Ok()->Lwt.returnv)(funexc->safe_closefd>>=function|Errortrace->Format.eprintf"Uncaught error: %a\n%!"pp_print_errortrace;raiseexc|Ok()->raiseexc)letread_filefn=Lwt_io.with_filefn~mode:Input(funch->Lwt_io.readch)letcopy_file~src~dst=Lwt_io.with_file~mode:Outputdst(fundst_ch->Lwt_io.with_filesrc~mode:Input(funsrc_ch->letbuff=Bytes.create4096inletrecloop()=Lwt_io.read_intosrc_chbuff04096>>=function|0->Lwt.return_unit|n->Lwt_io.write_from_exactlydst_chbuff0n>>=fun()->loop()inloop()))letcopy_dir?(perm=0o755)srcdst=letreccopy_dirdirdst_dir=create_dir~permdst>>=fun()->letfiles=Lwt_unix.files_of_directorydirinLwt_stream.iter_p(funfile->iffile=Filename.current_dir_name||file=Filename.parent_dir_namethenLwt.return_unitelseletbasename=fileinletfile=Filename.concatdirfileinifSys.is_directoryfilethenletnew_dir=Filename.concatdst_dirbasenameincreate_dir~permnew_dir>>=fun()->copy_dirfilenew_direlsecopy_file~src:file~dst:(Filename.concatdst_dirbasename))filesinifSys.file_existssrc&&Sys.is_directorysrcthencopy_dirsrcdstelseLwt.fail(Unix.Unix_error(Unix.ENOTDIR,"","copy_dir"))letof_sockaddr=function|Unix.ADDR_UNIX_->None|Unix.ADDR_INET(addr,port)->(matchIpaddr_unix.of_inet_addraddrwith|V4addr->Some(Ipaddr.v6_of_v4addr,port)|V6addr->Some(addr,port))letgetaddrinfo~passive~node~service=letopenLwt_unixingetaddrinfonodeservice(AI_SOCKTYPESOCK_STREAM::(ifpassivethen[AI_PASSIVE]else[]))>>=funaddr->letpoints=List.filter_map(fun{ai_addr;_}->of_sockaddrai_addr)addrinLwt.returnpointsletgetpass()=letopenUnixin(* Turn echoing off and fail if we can't. *)lettio=tcgetattrstdininletold_echo=tio.c_echoinletold_echonl=tio.c_echonlintio.c_echo<-false;tio.c_echonl<-true;tcsetattrstdinTCSAFLUSHtio;(* Read the passwd. *)letpasswd=read_line()in(* Restore terminal. *)tio.c_echo<-old_echo;tio.c_echonl<-old_echonl;tcsetattrstdinTCSAFLUSHtio;passwdmoduleJson=structletto_root=function|`Octns->`Octns|`Actns->`Actns|`Null->`O[]|oth->`A[oth]letwrite_filefilejson=letjson=to_rootjsoninprotect(fun()->Lwt_io.with_file~mode:Outputfile(funchan->letstr=Data_encoding.Json.to_string~minify:falsejsoninLwt_io.writechanstr>|=ok))letread_filefile=protect(fun()->Lwt_io.with_file~mode:Inputfile(funchan->Lwt_io.readchan>>=funstr->return(Ezjsonm.from_stringstr:>Data_encoding.json)))endletwith_tempdirnamef=letbase_dir=Filename.temp_filename""inLwt_unix.unlinkbase_dir>>=fun()->Lwt_unix.mkdirbase_dir0o700>>=fun()->Lwt.finalize(fun()->fbase_dir)(fun()->remove_dirbase_dir)letrecretry?(log=fun_->Lwt.return_unit)?(n=5)?(sleep=1.)f=f()>>=function|Okr->Lwt.return_okr|Errorerrorasx->ifn>0thenlogerror>>=fun()->Lwt_unix.sleepsleep>>=fun()->retry~log~n:(n-1)~sleepfelseLwt.returnxtype'actionio_error={action:'action;unix_code:Unix.error;caller:string;arg:string;}letwith_open_file~flags?(perm=0o640)filenametask=Lwt.catch(fun()->Lwt_unix.openfilefilenameflagsperm>>=funx->Lwt.return(Okx))(function|Unix.Unix_error(unix_code,caller,arg)->Lwt.return(Error{action=`Open;unix_code;caller;arg})|exn->raiseexn)>>=function|Error_asx->Lwt.returnx|Okfd->taskfd>>=funres->Lwt.catch(fun()->Lwt_unix.closefd>>=fun()->returnres)(function|Unix.Unix_error(unix_code,caller,arg)->Lwt.return(Error{action=`Close;unix_code;caller;arg})|exn->raiseexn)letwith_open_out?(overwrite=true)filetask=letflags=letopenUnixinifoverwritethen[O_WRONLY;O_CREAT;O_TRUNC;O_CLOEXEC]else[O_WRONLY;O_CREAT;O_CLOEXEC]inwith_open_file~flagsfiletaskletwith_open_infiletask=with_open_file~flags:[O_RDONLY;O_CLOEXEC]filetask(* This is to avoid file corruption *)letwith_atomic_open_out?(overwrite=true)?temp_dirfilenamef=lettemp_file=Filename.temp_file?temp_dir(Filename.basenamefilename)".tmp"inwith_open_out~overwritetemp_filef>>=?funres->Lwt.catch(fun()->Lwt_unix.renametemp_filefilename>>=fun()->Lwt.return(Okres))(function|Unix.Unix_error(unix_code,caller,arg)->Lwt.return(Error{action=`Rename;unix_code;caller;arg})|exn->raiseexn)