lunarmodules / luafilesystem

LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution.
https://lunarmodules.github.io/luafilesystem/
MIT License
900 stars 291 forks source link

realpath for luafilesystem #64

Open tst2005 opened 8 years ago

tst2005 commented 8 years ago

Hello luafilesystem should have a realpath like luaposix. It is very difficult to implement in lua with the existing lfs API. Some times, I only require luaposix only for this feature...

Regards,

robertlzj commented 3 years ago

Hi, in higher version, I think lfs.symlinkattributes(filepath).target is the real path? - subject path if filepath is symbolic path.

tst2005 commented 3 years ago

@robertlzj no, the target value is the (absolute or relative path) of the symlink.

You can have a foo1 symlink pointing to bar or a foo2 symlink pointing to /home/xyz/bar

in /home/xyz/
foo1 -> bar
foo2 -> /home/xyz/bar

The realpath is use to travel in all "directories" and get out of any symlink to get a real uniq storage path. It is usefull in more complicated case like

d /storage/
d /storage/users/
d /storage/users/xyz
l /home -> /storage/users

If we want to implement the realpath job in lua, we need to

It is a little complex ... the system realpath know how to do this job perfectly !

Regards,

robertlzj commented 3 years ago

Hi, thinks for your introduce about about realpath - the final path without symbolic. I think it's easy? to iterate each directory and expand if it is symlink then recurs iterate, at last make up the realpath. If there is realpath in system would be nice of cause.

And in windows, I had just compare lfs.link/lfs.symlinkattributes.target and ln.exe. target also make sense on hardlink, if it is in virtual volume (which is treated as symlink/junction directory?), it points to actual directory of virtual volume. target of hardlink in file property

Other test on multi levels of symlink, substitute virtual volume, and multi symlink parts in path. ln lfs symlink symbolic link hard link source target destination multiple level I had thought final source above is realptah.

local lfs=require'lfs'
local vb=[[G:\]]--virtual base (on virtual volume)
local ab=[[E:\VirtualVolume\]]--actual base
if not lfs.attributes(vb) then
    assert(lfs.attributes(ab))
    os.execute('subst '..vb..' '..ab)
end
lfs.chdir(vb)
assert(not lfs.attributes'D' and not lfs.attributes'S')
os.execute('mkdir D')--origin
assert(lfs.link('D','S',true))--symlink directory
--
lfs.chdir(vb..[[S\]])
local E={close=function()end}
assert(not (io.open'O.txt' or E):close() and not (io.open'S.txt' or E):close() and not (io.open'S2.txt' or E):close() and not (io.open'S2b.txt' or E):close() and not (io.open'H.txt' or E):close() and not (io.open'Hb.txt' or E):close() and not (io.open'H2.txt' or E):close() and not (io.open'H2b.txt' or E):close())
----O: origin, H: config as hardlink, S: symlink
io.open('O.txt','w'):close()
lfs.link('O.txt','S.txt',true)
--hardlink
lfs.link('S.txt','H.txt')
os.execute('ln >nul 2>nul S.txt Hb.txt')
--symlink level 2
lfs.link('S.txt','S2.txt',true)
os.execute('ln >nul 2>nul --symbolic S.txt S2b.txt')
--hardlink level 2
lfs.link('S2.txt','H2.txt')
os.execute('ln >nul 2>nul S2.txt H2b.txt')
----
assert(lfs.symlinkattributes'H.txt'.mode=='link')
assert(lfs.symlinkattributes'Hb.txt'.mode=='link')
assert(lfs.symlinkattributes'S.txt'.mode=='link')
assert(lfs.symlinkattributes'S2.txt'.mode=='link')
assert(lfs.symlinkattributes'S2b.txt'.mode=='link')
assert(lfs.symlinkattributes'H2.txt'.mode=='link')
assert(lfs.symlinkattributes'H2b.txt'.mode=='link')
----
local function ln_target(fn)--show the target of a symbolic link
    local r=io.popen('ln --symbolic '..fn)
    return string.match(r:read'a','%-> (.+)\n')
end
assert(ln_target'H.txt'=='O.txt')
assert(ln_target'Hb.txt'=='O.txt')
assert(ln_target'S.txt'=='O.txt')
assert(ln_target'S2.txt'=='S.txt')
assert(ln_target'S2b.txt'=='S.txt')
assert(ln_target'H2.txt'=='S.txt')
assert(ln_target'H2b.txt'=='S.txt')
----
local t=(lfs.attributes(ab) and ab or vb)..[[D\O.txt]]
assert(lfs.symlinkattributes'H.txt'.target==t)
assert(lfs.symlinkattributes'Hb.txt'.target==t)
assert(lfs.symlinkattributes'S.txt'.target==t)
assert(lfs.symlinkattributes'S2.txt'.target==t)
assert(lfs.symlinkattributes'S2b.txt'.target==t)
assert(lfs.symlinkattributes'H2.txt'.target==t)
assert(lfs.symlinkattributes'H2b.txt'.target==t)
----
os.execute('del O.txt S.txt S2.txt S2b.txt H.txt Hb.txt H2.txt H2b.txt')
lfs.chdir(vb)
--
os.execute('rmdir D')
os.execute('rmdir S')
print'test done.'