1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495(*
* Copyright (c) 2011-2015 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2013-2015 Thomas Gazagnaire <thomas@gazagnaire.org>
* Copyright (c) 2013 Citrix Systems Inc
*
* 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.
*)moduleKey=structtypet=stringlist(* Store the path as a reverse list to optimise basename and (/)
operations *)leterr_invalid_segmentx=Fmt.kstrinvalid_arg"%S is not a valid segment"xletcheck_segmentx=String.iter(function'/'->err_invalid_segmentx|_->())x;xletempty=[]letvs=List.filter((<>)"")@@List.rev(String.split_on_char'/'s)letaddtv=(check_segmentv)::tlet(/)=addletappendxy=y@xlet(//)=appendletsegments=List.revletbasename=function|[]->""|hd::_->hdletparent=function|_::tl->tl|[]->[]letcompare=compareletequal=(=)letto_stringk="/"^String.concat"/"(List.revk)letppppfk=Fmt.stringppf(String.escaped(to_stringk))endtypekey=Key.ttypeerror=[|`Not_foundofkey|`Dictionary_expectedofkey|`Value_expectedofkey]letpp_errorppf=function|`Not_foundk->Fmt.pfppf"Cannot find the key %a"Key.ppk|`Dictionary_expectedk->Fmt.pfppf"Expecting a dictionary for the key %a"Key.ppk|`Value_expectedk->Fmt.pfppf"Expecting a value for the key %a"Key.ppkmoduletypeRO=sigtypenonrecerror=private[>error]valpp_error:errorFmt.ttypetvaldisconnect:t->unitLwt.ttypekey=Key.tvalexists:t->key->([`Value|`Dictionary]option,error)resultLwt.tvalget:t->key->(string,error)resultLwt.tvalget_partial:t->key->offset:Optint.Int63.t->length:int->(string,error)resultLwt.tvallist:t->key->((key*[`Value|`Dictionary])list,error)resultLwt.tvallast_modified:t->key->(Ptime.t,error)resultLwt.tvaldigest:t->key->(string,error)resultLwt.tvalsize:t->key->(Optint.Int63.t,error)resultLwt.tendtypewrite_error=[error|`No_space|`Rename_source_prefixofkey*key|`Already_presentofkey]letpp_write_errorppf=function|#errorase->pp_errorppfe|`No_space->Fmt.stringppf"No space left on device"|`Rename_source_prefix(src,dest)->Fmt.pfppf"Rename: source %a is prefix of destination %a"Key.ppsrcKey.ppdest|`Already_presentk->Fmt.pfppf"Key %a is already present"Key.ppkmoduletypeRW=sigincludeROtypenonrecwrite_error=private[>write_error]valpp_write_error:write_errorFmt.tvalallocate:t->key->?last_modified:Ptime.t->Optint.Int63.t->(unit,write_error)resultLwt.tvalset:t->key->string->(unit,write_error)resultLwt.tvalset_partial:t->key->offset:Optint.Int63.t->string->(unit,write_error)resultLwt.tvalremove:t->key->(unit,write_error)resultLwt.tvalrename:t->source:key->dest:key->(unit,write_error)resultLwt.tend