From: Michal Suchanek Date: 2007-05-13T21:53:53+09:00 Subject: Re: [ ruby-Bugs-8676 ] File.basename fails on Windows root paths On 13/05/07, Nobuyoshi Nakada wrote: > Hi, > > At Sun, 13 May 2007 02:07:13 +0900, > Austin Ziegler wrote in [ruby-core:11161]: > > On 5/12/07, Nobuyoshi Nakada wrote: > > > At Fri, 16 Feb 2007 02:09:08 +0900, > > > Daniel Berger wrote in [ruby-core:10321]: > > > > The File.basename method does not work properly on Windows > > > > root paths. IMO, calling File.basename on a root path should > > > > return itself. However, on MS Windows it appears to be > > > > dropping the volume name and it doesn't handle UNC root paths > > > > correctly: > > > Drive letter is part of base name? It feels very strange to me. > > > > It's right, though. > > > > File.basename("C:/") should return "C:/" > > File.dirname("C:/") should return "C:/" > > File.basename("//server/share/") must return "//server/share/" > > File.dirname("//server/share/") must return "//server/share/" > > What's the reason? Do you consider a drive letter to be a part > of basename? > > And if they were work so, then File.join(*File.split("C:/")) > should return "C:/C:/", but it is incorrect on Windows. Is it > what you want? > > > This would be true for any filesystem environment that allows multiple roots. > > Really? Do you know other such environments? > When you include some sort of networking into file path you usually get multiple roots. In some cases this can be abstracted as single root that includes the hostname but you would usually also get some sort of shortcut for local files. Sure, systems that include such things are either obscure or Windows. I would the basename and dirname to preserve two invariants: given class String def basename File.basename self end def dirname FIle.dirname self end end I) (s.dirname + File::SEPARATOR + s.basename) should refer to the same file as (s) as long as neither s.dirname nor s.basename is empty. This breaks with the concept of "current directory" in Windows. II) (s + File::SEPARATOR).dirname == s.dirname (s + File::SEPARATOR).basename == s.basename However, this cannot be preserved in cases when adding the separator changes path designation as understood by the OS ( "C:" is not the same as "C:/" but "C:/a" and "C:/a/" hopefully is). III) s.dirname should be "" only if s does not contain directory specification. On unix directory specification is only File::SEPARATOR but on Windows "C:" alone is also a directory specification but does not contain any separator. s.basename should not be empty nor the separator. But "C:" is a directory specification which cannot be split. "C:".dirname must be "C:" to specify the directory, and "C:".basename must be "", "." would not work ( "C:" + "/" + ".") is something else. The same goes for "C:/" and unix "/" except "." or "/" would be probably an acceptable basename as well. We might specify that basename for roots is "" which would solve all cases in POSIX and Windows. Still the windows programmer must be careful and check for empty basename while the unix programmer does not have to. Also there is the case "C:file" which refers to file in the current directory on C. This cannot be reasonably split so that adding the separator would yield the same result. It might work if "C:." and "C:./file" are valid and do the expected thing. Thanks Michal