Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dir symlink recursive loop #55

Open
enthor opened this issue Apr 3, 2021 · 5 comments
Open

dir symlink recursive loop #55

enthor opened this issue Apr 3, 2021 · 5 comments

Comments

@enthor
Copy link

enthor commented Apr 3, 2021

With Deep symlink copying in use, when a directory containing a symlink
is copied and the symlink points directly to the directory or to
another directory -- which is subsequently copied and contains
a symlink to the original directory, a loop ensues which is terminated in
os.Create with a "file name too long error" ...

I understand that there may be other issues copying symlinks,
but

https://github.com/enthor/copy/tree/enthor-patch-1

fixes this issue. (I believe...)

I included a test case -- search "case03b" in all_test.go.
To see the error output remove the "Not()." in
the following lines (temporarily):

// stop the recursive loop: opt = Options{OnSymlink: func(string) SymlinkAction { return Deep }} err = Copy("test/data/case03b", "test/data.copy/case03b.deep", opt) Expect(t, err).Not().ToBe(nil)

@enthor
Copy link
Author

enthor commented Apr 3, 2021

it may be that the line in onsymlink():

id := info.Name()

should be changed (somehow) to refer to the linked-to object
(rather than the base name in the copied directory).

could use some feedback on this...

@enthor
Copy link
Author

enthor commented Apr 3, 2021

ok, i think this is better -- though only 1 level deep symlink copy:

` case Deep:
orig, err := os.Readlink(src)
if err != nil {
return err
}

	id, err := filepath.Abs(orig)
	if err != nil {
		return err
	}
	err = inProcess.Start(id, "copy.onsymlink()")
	if err != nil {
		return err
	}
	defer inProcess.End(id)

	info, err = os.Lstat(orig)
	if err != nil {
		return err
	}
	return copy(orig, dest, info, opt, inProcess)

`

@enthor
Copy link
Author

enthor commented Apr 3, 2021

ok! a wrap on stopping a recursive copy of a directory caused by a deep symlink copy:

https://github.com/enthor/copy/tree/enthor-patch-1

this does not resolve nested symlinks or the issue with shallow symlinks
and it does not alter the symlink copy itself, but puts an "InProcess"
tracker to halt a recursive copy of a directory:

`
case Deep:
// ensure that if this symlink recursively comes back here, copy stops.
id, err := filepath.Abs(filepath.Dir(src))
if err != nil {
return err
}
err = inProcess.Start(id, "copy.onsymlink()")
if err != nil {
return err
}
defer inProcess.End(id)

	orig, err := os.Readlink(src)
	if err != nil {
		return err
	}
	info, err = os.Lstat(orig)
	if err != nil {
		return err
	}
	return copy(orig, dest, info, opt, inProcess)

`

@enthor
Copy link
Author

enthor commented Apr 4, 2021

Well...I just reviewed Wikipedia's entry for Symbolic Links:

https://en.wikipedia.org/wiki/Symbolic_link

The topic is beyond being a rabbit hole. There's an entire rabbit world down there!

Which is fine at the OS level, but it is "out of scope" for Applications level code. (Or should be.)

I don't use symbolic links, or hidden files, or named pipes or anything except for
directories and files. And I don't want to because those features tend to be OS-specific.
And if I write OS specific code then constant upgrades, revisions, recompiles, etc.
lie ahead, not to mention making it hard to port my applications from one OS to another.

I think I may clone copy.Copy() in order to make a version that is blissfully unaware of
symbolic links, named pipes, times and permissions. Those things are not part of my
application.

To some extent the complications involved here derive from the nature of Go itself,
and its heritage in C and Unix. It is just very low-level programming. An example of
the complications, google "golang how to tell if a file exists". Yielding stackoverflow:

https://stackoverflow.com/questions/12518876/how-to-check-if-a-file-exists-in-go

It requires 12 answers, including admonishments that one should not do that and a dive
into the metaphysical nature of the question itself. And then finally it is explained that
it is best to check that it isn't true that the file doesn't exist. Mmm...ok. Fine. Whatever.

Life is short. Let's not get bogged down in things...not without being paid to do the work.
If someone want to pay me $100 an hour to write code using an Atomic Force Microscope
then great, I'll consider doing that. But otherwise, mmmmm...

@enthor
Copy link
Author

enthor commented Apr 7, 2021

The difficulty of writing an OS-independent directory copy is now more apparent. I found another bit of code at stackoverflow:

https://stackoverflow.com/questions/51779243/copy-a-folder-in-go

and it looks promising, but it is only for Unix. So, I looked into things a bit more
and made the discovery that package "syscall" has been frozen since go 1.4
and golang.org/x/sys is recommended -- the old syscall is not being updated.

So there's that. And the question of whether a distinction of "Deep" vs. "Shallow"
is even required.

Also, the question of what happens when attempt made to copy and src == dest.
None of the test code actually looks at the contents of the copied files, all of which
are "README.md" and empty. Well, empty would be expected, I think, if src == dest
and dest was opened, os.Create().

My view is that the Go authors should be asked to add a directory copy utility to
Go, perhaps in Go 2. It would be nice if Go had more built-in utilities...like, say,
Python. Maybe however, it is too difficult to write os-independent utilities in Go
given how many OS'es and architectures it supports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant