Can telldir() == 0 value be made special?
Conrad Meyer
cem at freebsd.org
Tue Aug 22 14:42:45 UTC 2017
Hi Nikolaus,
As you have surmised, DIR* seekpoints are created dynamically whenever
requested by user's telldir() call:
https://github.com/freebsd/freebsd/blob/master/lib/libc/gen/telldir.c#L53
I believe we could special case zero without breaking ABI
compatibility of correct programs. Something like this:
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -70,6 +70,20 @@ telldir(DIR *dirp)
}
}
if (lp == NULL) {
+ /* Create special zero telldir entry, similar to Linux */
+ if (dirp->dd_td->td_loccnt == 0 && dirp->dd_loc != 0) {
+ lp = malloc(sizeof(struct ddloc));
+ if (lp == NULL) {
+ if (__isthreaded)
+ _pthread_mutex_unlock(&dirp->dd_lock);
+ return (-1);
+ }
+ lp->loc_index = dirp->dd_td->td_loccnt++;
+ lp->loc_seek = 0;
+ lp->loc_loc = 0;
+ LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
+ }
+
lp = malloc(sizeof(struct ddloc));
if (lp == NULL) {
if (__isthreaded)
I don't know if there are any downsides to special-casing zero like
this, other than additional code complexity.
Best,
Conrad
On Tue, Aug 22, 2017 at 4:38 AM, Nikolaus Rath <Nikolaus at rath.org> wrote:
> Hello,
>
> I am trying to debug a test failure of libfuse under FreeBSD. I believe
> I have reduced it to the following root cause:
>
> Consider the following program:
>
> #include <stdio.h>
> #include <dirent.h>
> #include <sys/types.h>
>
> int main(void) {
> struct dirent *e = NULL;
> DIR *dirp;
>
> printf("opendir...\n");
> dirp = opendir("/");
> if(dirp == NULL) {
> perror("opendir");
> return 1;
> }
> printf("telldir: %ld\n", telldir(dirp));
> e = readdir(dirp);
> printf("readdir: %s\n", e->d_name);
> printf("telldir: %ld\n", telldir(dirp));
> e = readdir(dirp);
> printf("readdir: %s\n", e->d_name);
> printf("closedir..\n");
> closedir(dirp);
>
> printf("opendir...\n");
> dirp = opendir("/");
> if(dirp == NULL) {
> perror("opendir");
> return 1;
> }
> e = readdir(dirp);
> printf("readdir: %s\n", e->d_name);
> printf("telldir: %ld\n", telldir(dirp));
> e = readdir(dirp);
> printf("readdir: %s\n", e->d_name);
> printf("closedir..\n");
> closedir(dirp);
>
> return 0;
> }
>
>
> Under FreeBSD, running it gives:
>
> # ./simple
> opendir...
> telldir: 0
> readdir: .
> telldir: 1
> readdir: ..
> closedir..
> opendir...
> readdir: .
> telldir: 0
> readdir: ..
> closedir..
>
> In other words, if telldir() is called right after opendir(), it gives
> an offset of zero. But if telldir() is called only after the first
> readdir() call, it also gives an offset of zero. My hypothesis is that
> FreeBSD actually just enumerates the different telldir() calls - is that
> correct?
>
> Now, the offsets returned by telldir() are documented to be valid only
> within a given *dirp, so FreeBSD isn't doing anything wrong.
>
> However, having different meanings even for an offset of zero causes
> problems for libfuse, because under Linux an offset of zero is
> guaranteed to mean "first entry". This is reflected in the definition of
> the fuse readdir() function which always receives an *offset* parameter
> that needs to have a definite value even when telldir() was never
> called. If zero is suddenly also a valid telldir() return value that may
> indicate some other position in the stream, things get complicated.
>
> Now, I think I managed to work around that by shifting all offsets by
> one, but that is awkward (and I may have overlooked some problems that
> the unit tests don't cover). So I am wondering:
>
> Is there a reason why the FreeBSD kernel could not start enumerating
> telldir() offsets with 1, so that 0 can always have the same meaning?
>
>
> Best,
> -Nikolaus
>
> --
> GPG Fingerprint: ED31 791B 2C5C 1613 AF38 8B8A D113 FCAC 3C4E 599F
>
> »Time flies like an arrow, fruit flies like a Banana.«
> _______________________________________________
> freebsd-fs at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-fs
> To unsubscribe, send any mail to "freebsd-fs-unsubscribe at freebsd.org"
More information about the freebsd-fs
mailing list