standards/179248: A return value of telldir(3) only seekable for once

Akinori MUSHA knu at FreeBSD.org
Mon Jun 3 07:20:01 UTC 2013


>Number:         179248
>Category:       standards
>Synopsis:       A return value of telldir(3) only seekable for once
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-standards
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 03 07:20:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Akinori MUSHA
>Release:        FreeBSD 9.1-STABLE
>Organization:
>Environment:
FreeBSD 9.1-STABLE #29 r250273: Mon May  6 01:09:00 JST 2013 (amd64)
>Description:
Our implementation of telldir(3)/seekdir(3) is not POSIX compliant in that a value obtained from telldir(3) is invalidated after calling seekdir(3) and then readdir(3).

IEEE Std 1003.1, 2008/2013 says that only a call of rewinddir(3) may invalidate the location values returned by telldir(3):

    If the value of loc was not obtained from an earlier call to
    telldir(), or if a call to rewinddir() occurred between the call
    to telldir() and the call to seekdir(), the results of subsequent
    calls to readdir() are unspecified.


>How-To-Repeat:
% cat ../dirtest.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>

int main(void)
{
	DIR *dirp;
	struct dirent *dp;
	long pos;

	if ((dirp = opendir(".")) == NULL) return 1;
	printf("telldir = %ld\n", telldir(dirp));

	if ((dp = readdir(dirp)) == NULL) return 1;
	printf("readdir = %s\n", dp->d_name);
	printf("telldir = %ld\n", telldir(dirp));

	if ((dp = readdir(dirp)) == NULL) return 1;
	printf("readdir = %s\n", dp->d_name);
	printf("telldir = %ld\n", telldir(dirp));

	if ((dp = readdir(dirp)) == NULL) return 1;
	printf("readdir = %s\n", dp->d_name);
	printf("telldir = %ld\n", pos = telldir(dirp));

	if ((dp = readdir(dirp)) == NULL) return 1;
	printf("readdir = %s\n", dp->d_name);
	printf("telldir = %ld\n", telldir(dirp));

	printf("seekdir to %ld\n", pos);
	seekdir(dirp, pos);

	if ((dp = readdir(dirp)) == NULL) return 1;
	printf("readdir = %s\n", dp->d_name);
	printf("telldir = %ld\n", telldir(dirp));

	printf("seekdir to %ld\n", pos);
	seekdir(dirp, pos);

	if ((dp = readdir(dirp)) == NULL) return 1;
	printf("readdir = %s\n", dp->d_name);
	printf("telldir = %ld\n", telldir(dirp));

	(void)closedir(dirp);
	return 0;
}
% make ../dirtest
cc -O2 -pipe -g -march=core2  ../dirtest.c  -o ../dirtest
% ls -al
total 35
drwxr-xr-x   2 knu  knu   6 Jun  3 15:39 .
drwx------  11 knu  knu  53 Jun  3 15:39 ..
-rw-r--r--   1 knu  knu   0 Jun  3 15:39 aaa
-rw-r--r--   1 knu  knu   0 Jun  3 15:39 bbb
-rw-r--r--   1 knu  knu   0 Jun  3 15:39 ccc
-rw-r--r--   1 knu  knu   0 Jun  3 15:39 ddd
% ../dirtest
telldir = 1
readdir = .
telldir = 2
readdir = ..
telldir = 3
readdir = aaa
telldir = 4
readdir = ccc
telldir = 5
seekdir to 4
readdir = ccc    # <= OK
telldir = 6
seekdir to 4
readdir = bbb    # <= FAIL
telldir = 7

>Fix:
I don't have a quick fix for this, as it may need a revamp of how the location thing is defined.

NetBSD seems to have a different implementation which doesn't have this problem.
However, I'm not sure if theirs is flawless esp. wrt memory management.

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-standards mailing list