{-# LANGUAGE CPP, ForeignFunctionInterface #-}moduleDarcs.Compat(stdout_is_a_pipe,mk_stdout_temp,canonFilename,maybeRelink,atomic_create,sloppy_atomic_create)whereimportPreludehiding(catch)importDarcs.Utils(withCurrentDirectory)#ifdef WIN32importDarcs.Utils(showHexLen)importData.Bits((.&.))importSystem.Random(randomIO)#elseimportForeign.C.String(peekCString)#endifimportControl.Monad(unless)importForeign.C.Types(CInt)importForeign.C.String(CString,withCString)importForeign.C.Error(throwErrno,eEXIST,getErrno)importSystem.Directory(getCurrentDirectory)importSystem.IO(hFlush,stdout,stderr,hSetBuffering,BufferMode(NoBuffering))importSystem.IO.Error(mkIOError,alreadyExistsErrorType)importSystem.Posix.Files(stdFileMode)importSystem.Posix.IO(openFd,closeFd,stdOutput,stdError,dupTo,defaultFileFlags,exclusive,OpenMode(WriteOnly))importSystem.Posix.Types(Fd(..))importDarcs.SignalHandler(stdout_is_a_pipe)canonFilename::FilePath->IOFilePathcanonFilenamef@(_:':':_)=returnf-- absolute windows pathscanonFilenamef@('/':_)=returnfcanonFilename('.':'/':f)=docd<-getCurrentDirectoryreturn$cd++"/"++fcanonFilenamef=casereverse$dropWhile(/='/')$reversefof""->fmap(++('/':f))getCurrentDirectoryrd->withCurrentDirectoryrd$dofd<-getCurrentDirectoryreturn$fd++"/"++simplefilenamewheresimplefilename=reverse$takeWhile(/='/')$reversef#ifdef WIN32mkstemp_core::FilePath->IO(Fd,String)mkstemp_corefp=dor<-randomIOletfp'=fp++(showHexLen6(r.&.0xFFFFFF::Int))fd<-openFdfp'WriteOnly(JuststdFileMode)flagsreturn(fd,fp')whereflags=defaultFileFlags{exclusive=True}#elsemkstemp_core::String->IO(Fd,String)mkstemp_corestr=withCString(str++"XXXXXX")$\cstr->dofd<-c_mkstempcstriffd<0thenthrowErrno$"Failed to create temporary file "++strelsedostr'<-peekCStringcstrfname<-canonFilenamestr'return(Fdfd,fname)foreignimportccallunsafe"static stdlib.h mkstemp"c_mkstemp::CString->IOCInt#endifmk_stdout_temp::String->IOStringmk_stdout_tempstr=do(fd,fn)<-mkstemp_corestrhFlushstdouthFlushstderrdupTofdstdOutputdupTofdstdErrorhFlushstdouthFlushstderrhSetBufferingstdoutNoBufferinghSetBufferingstderrNoBufferingreturnfnforeignimportccallunsafe"maybe_relink.h maybe_relink"maybe_relink::CString->CString->CInt->IOCInt-- Checks whether src and dst are identical. If so, makes dst into a-- link to src. Returns True if dst is a link to src (either because-- we linked it or it already was). Safe against changes to src if-- they are not in place, but not to dst.maybeRelink::String->String->IOBoolmaybeRelinksrcdst=withCStringsrc$\csrc->withCStringdst$\cdst->dorc<-maybe_relinkcsrccdst1(casercof0->returnTrue1->returnTrue-1->throwErrno("Relinking "++dst)-2->returnFalse-3->doputStrLn("Relinking: race condition avoided on file "++dst)returnFalse_->fail("Unexpected situation when relinking "++dst))sloppy_atomic_create::FilePath->IO()sloppy_atomic_createfp=dofd<-openFdfpWriteOnly(JuststdFileMode)flagscloseFdfdwhereflags=defaultFileFlags{exclusive=True}atomic_create::FilePath->IO()atomic_createfp=withCStringfp$\cstr->dorc<-c_atomic_createcstrunless(rc>=0)$doerrno<-getErrnopwd<-getCurrentDirectoryiferrno==eEXISTthenioError$mkIOErroralreadyExistsErrorType("atomic_create in "++pwd)Nothing(Justfp)elsethrowErrno$"atomic_create "++fp++" in "++pwdforeignimportccallunsafe"atomic_create.h atomic_create"c_atomic_create::CString->IOCInt