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