12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394(*
* Copyright (c) 2018-2021 Tarides <contact@tarides.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)open!Importletsrc=Logs.Src.create"irmin.layers.io"~doc:"IO for irmin-layers"moduleLog=(valLogs.src_logsrc:Logs.LOG)moduletypeS=sigtypetvalv:string->tLwt.tvalclose:t->unitLwt.tvalread_flip:t->boolLwt.tvalwrite_flip:bool->t->unitLwt.tendmoduleIO=structtypet={file:string;fd:Lwt_unix.file_descr}letlseek~offsett=let*off=Lwt_unix.lseekt.fdoffsetLwt_unix.SEEK_SETinifoff<>offsetthenLwt.fail_with"invalid lseek"elseLwt.return_unitletwrite~offsettbuf=lseek~offsett>>=fun()->letlen=Bytes.lengthbufinlet*n=Lwt_unix.writet.fdbuf0leninifn<>lenthenLwt.fail_with"invalid write"elseLwt.return_unitletread~offsettbuf=lseek~offsett>>=fun()->letlen=Bytes.lengthbufinlet*n=Lwt_unix.readt.fdbuf0leninifn<>lenthenLwt.fail_with"invalid read"elseLwt.return_unitletcloset=Lwt_unix.closet.fdletread_flipt=letbuf=Bytes.create1inread~offset:0tbuf>>=fun()->letch=Bytes.getbuf0inmatchint_of_charchwith|0->Lwt.return_false|1->Lwt.return_true|d->Lwt.fail_with("corrupted flip file "^string_of_intd)letwrite_flipflipt=letbuf=Bytes.make1(char_of_int(ifflipthen1else0))inwrite~offset:0tbufletvfile=matchSys.file_existsfilewith|false->let*fd=Lwt_unix.openfilefileLwt_unix.[O_CREAT;O_RDWR;O_CLOEXEC]0o644inlett={file;fd}inwrite_fliptruet>|=fun()->t|true->Lwt_unix.openfilefileLwt_unix.[O_EXCL;O_RDWR;O_CLOEXEC]0o644>|=funfd->{file;fd}endmoduleLock=structtypet={file:string;fd:Lwt_unix.file_descr}letvfile=letpid=string_of_int(Unix.getpid())inlet*fd=Lwt_unix.openfilefileUnix.[O_CREAT;O_WRONLY;O_TRUNC]0o644inlet*n=Lwt_unix.write_stringfdpid0(String.lengthpid)inifn<>String.lengthpidthenLwt.fail_with"invalid write for lock file"elseLwt.return{file;fd}lettest=Sys.file_existsletunlink=Lwt_unix.unlinkletclose{fd;file}=Lwt_unix.closefd>>=fun()->unlinkfileend