I just noticed that Stdio.exist returns 0 for dangling symlinks. I think that's unfortunate.
What do you say, consider it a bug and fix it (with compat goo for #pike 7.6), or document it as intended behavior?
Maybe add an option if you want to know if the symlink exist, or if the target exist? I'd think that it's mainly used to see if you can open a file, and since you can't open a dangling symlink...?
Well, it returns true for directories as well (and also devices etc, although the docstring hints otherwise). So it's not the right thing to use before an open anyway (Stdio.is_file would be more appropriate, although I usually just try to open it right away and look at errno() instead).
The semantic I think makes sense is that it returns true for anything that exists in any way. E.g. if you do get_dir then Stdio.exist would return true for all its entries.
Martin Stjernholm, Roxen IS @ Pike developers forum wrote:
The semantic I think makes sense is that it returns true for anything that exists in any way. E.g. if you do get_dir then Stdio.exist would return true for all its entries.
From a UNIX/POSIX standpoint, the current behaviour is expected and sane.
The semantics you want might be reasonable, but are unexpected by anyone used to UNIX/POSIX semantics.
The Stdio.exist matches the behaviour of: a. access(2). b. test -e ... c. open(2) works (even for directories, on a local filesystem), it return ENOENT on a danglink symlink.
So I'd vote against changing it, but perhaps provide an flag for it to consider a symlink an actual existing object.
Your examples are from non-pike contexts and I think therefore of limited applicability:
The first two aren't accessible at all from pike.
The pike wrapper for the last (Stdio.File.open) does actually work for dirs too, but it's of very limited use (you can't read or write to an Stdio.File which has an opened directory). I dare say that's a bug too since it's neither useful nor expected.
Martin Stjernholm, Roxen IS @ Pike developers forum wrote:
Your examples are from non-pike contexts and I think therefore of limited applicability:
Maybe. Then again, it's all about expectations. If things behave as one would expect, there is no learning curve.
The pike wrapper for the last (Stdio.File.open) does actually work for dirs too, but it's of very limited use (you can't read or write to an Stdio.File which has an opened directory). I dare say that's a bug too since it's neither useful nor expected.
In any case, if you'd change the behaviour, please document that it differs from POSIX (in order to help people like me understand the differences).
Maybe. Then again, it's all about expectations. If things behave as one would expect, there is no learning curve.
That is true, and I didn't expect the current behavior. I thought, if an ls lists it, then it exists. Martin Bährs expectation expresses the same thing another way: If it doesn't exist then using open() on it in "wcx" mode shouldn't fail. This is the most generic form of existence, and thus imho appropriate for a function called "exist".
When it comes to POSIX, does it clearly define such a generic "existence" concept? Just because some functions, e.g. open(2), returns ENOENT in some situations doesn't really account for anything - there are others, e.g. lstat(2), that do it differently.
Martin Stjernholm, Roxen IS @ Pike developers forum wrote:
Maybe. Then again, it's all about expectations. If things behave as one would expect, there is no learning curve.
That is true, and I didn't expect the current behavior. I thought, if an ls lists it, then it exists. Martin B?hrs expectation expresses the same thing another way: If it doesn't exist then using open() on it in "wcx" mode shouldn't fail. This is the most generic form of existence, and thus imho appropriate for a function called "exist".
True. But given a UNIX/POSIX background, the meaning of "exist" is slightly different and matches exactly with current behaviour.
When it comes to POSIX, does it clearly define such a generic "existence" concept? Just because some functions, e.g. open(2), returns ENOENT in some situations doesn't really account for anything
- there are others, e.g. lstat(2), that do it differently.
Don't ask me to quote standards, since I rarely read up on the POSIX standard itself, all I know is from perusing the programmers manuals and the various POSIX hints in there. However, the concept that POSIX breaths is that the standard "exist" and also the acces(2)/open(2) functions operate on real objects (i.e. files, sockets, directories, devices); whereas symlinks are considered mere pointers, not real objects. These pointers are invisible for most file operations, and need special function-calls to actually handle them (like lstat() vs. stat()).
So in light of the POSIX philosophy, the current Stdio.exist behaviour is perfectly fine, and using an extra flag to make it aware of symlinks would be the proper way to go.
Stephen R. van den Berg wrote:
So in light of the POSIX philosophy, the current Stdio.exist behaviour is perfectly fine, and using an extra flag to make it aware of symlinks would be the proper way to go.
Incidentally, the reason why I'd like to stick to POSIX is because Pike looks like C, and therefore you'd expect (a bit) to have a similar file interface as C (which offers POSIX usually).
i think the symlink option can be added now, since it doesn't break compatibilty, and hen we can continue to argue about which way is actually better.
the thing that i don't get about the posic argument is: is there a posix exists() function? if not, then how is posix relevant?
i agree that functions which are equivalent to posix should also have equivalent behaviour. but for any other functions that we make up, we also get to make up how they behave.
i don't think that a posix concept of existance matters as much...
also, i have the impression that pike is a rather posix-less language, a lot of posix stuff like popen(), etc, that exists eg in python has a much better interface in pike instead, moving pike to a higher level. i'd like to support that trend. if you want posix, use c :-)
greetings, martin.
i agree that functions which are equivalent to posix should also have equivalent behaviour. but for any other functions that we make up, we also get to make up how they behave.
Yes, that's why I asked if posix says anything about "existence" on a conceptual level. Imo all the test functions Stdio.{exist,is_dir,is_file,is_link} are higher level wrappers designed to be convenient. Afaik they don't have counterparts in posix at all, which makes it a bit meaningless to talk about "posix compliance" for them.
When it comes to functions mapping to posix calls then it's file_stat we're talking about. It already got a flag for lstat behavior, and I don't propose to change that. I don't think there's any use adding such a flag to Stdio.exist too; one can just use file_stat directly instead then.
Isn't is_dir and is_link mapping directly to S_ISDIR and S_ISLNK? Those are pretty POSIX. (POSIX.1-2001)
If you ignore the fact that you can't call them, perhaps.. The direct mapping to S_ISDIR would be file_stat(..)->isdir, I think.
But yes, posix does define pretty well what directories and symlinks are on a conceptual level too, so there's no ambiguity in how Stdio.{is_dir,is_link} would work.
That's what I mean.
Since exist() would, I assume, map to file_stat -> lstat success or not, and with that explanation it should probably find symlinks.
The pike wrapper for the last (Stdio.File.open) does actually work for dirs too, but it's of very limited use (you can't read or write to an Stdio.File which has an opened directory). I dare say that's a bug too since it's neither useful nor expected.
It is useful, since you can use it as a starting point for directory operations:
object f = Stdio.File("/etc"); f->openat("motd", "r")->read();
(1) Result: "Sun Microsystems Inc.\tSunOS 5.10\tGeneric\tJanuary 2005\n"
good question. my initial reaction was with mirar, but then i thought that exists should tell me if i can use that filename or if it is in use already.
if i want to be able to read or write, the appropriate check should be made. i think exists should only tell if an item with that name exists.
greetings, martin.
pike-devel@lists.lysator.liu.se