[MLton-user] OS.FileSys.realPath bug

Stephen Weeks sweeks@sweeks.com
Tue, 9 Sep 2003 17:21:08 -0700


> The following program:
> 
> val _ = print (OS.FileSys.fullPath "/usr/src/linux/drivers" ^ "\n")
> 
> prints "/usr/src/kernel-source-2.4.19" on my system, when it should  
> print "/usr/src/kernel-source-2.4.19/drivers".
> 
> (As /usr/src/linux is a soft link to kernel-source-2.4.19.)

Thanks for the bug report.  I have checked in a fix to the MLton
sources that will go out with the next release.  In the meantime, you
can get the corrected version of fullPath by prefixing the following
to your program.

--------------------------------------------------------------------------------

structure OS: OS =
   struct
      open OS
	 
      structure FileSys =
	 struct
	    open FileSys

	    val maxLinks = 64
	       
	    structure P = Path

	    fun fullPath p =
	       let
		  val oldCWD = getDir()
		  fun mkPath pathFromRoot =
		     P.toString {arcs = List.rev pathFromRoot,
				 isAbs = true,
				 vol = ""}
		  fun walkPath (n, pathFromRoot, arcs) =
		     if n = 0
			then raise SysErr ("too many links", NONE)
		     else
			case arcs of
			   [] => mkPath pathFromRoot
			 | arc :: al =>
			      if arc = "" orelse arc = "."
				 then walkPath (n, pathFromRoot, al)
			      else if arc = ".."
				      then
					 case pathFromRoot of
					    [] => walkPath (n, [], al)
					  | _ :: r =>
					       (chDir ".."; walkPath (n, r, al))
				   else
				      if isLink arc
					 then expandLink (n, pathFromRoot, arc,
							  al)
				      else
					 case al of
					    [] => mkPath (arc :: pathFromRoot)
					  | _ =>
					       (chDir arc
						; walkPath (n, arc :: pathFromRoot, al))
		  and expandLink (n, pathFromRoot, link, rest) =
		     let
			val {isAbs, arcs, ...} = P.fromString (readLink link)
			val arcs = List.@ (arcs, rest)
		     in 
			if isAbs
			   then gotoRoot (n-1, arcs)
			else walkPath (n-1, pathFromRoot, arcs)
		     end
		  and gotoRoot (n, arcs) =
		     (chDir "/"; walkPath (n, [], arcs))
		  fun computeFullPath arcs =
		     (gotoRoot (maxLinks, arcs) before chDir oldCWD)
		     handle ex => (chDir oldCWD; raise ex)
		  val {arcs, isAbs, ...} = P.fromString p
	       in
		  if isAbs
		     then computeFullPath arcs
		  else
		     let
			val {arcs = arcs', ...} = P.fromString oldCWD
		     in
			computeFullPath (List.@ (arcs', arcs))
		     end
	       end
	 end
   end