1/*
2 * opendir.c --
3 *
4 *	This file provides dirent-style directory-reading procedures for V7
5 *	Unix systems that don't have such procedures. The origin of this code
6 *	is unclear, but it seems to have come originally from Larry Wall.
7 *
8 * RCS: @(#) $Id: opendir.c,v 1.4 2007/04/16 13:36:34 dkf Exp $
9 */
10
11#include "tclInt.h"
12
13#undef DIRSIZ
14#define DIRSIZ(dp) \
15    ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
16
17/*
18 * open a directory.
19 */
20
21DIR *
22opendir(
23    char *name)
24{
25    register DIR *dirp;
26    register int fd;
27    char *myname;
28
29    myname = ((*name == '\0') ? "." : name);
30    if ((fd = open(myname, 0, 0)) == -1) {
31	return NULL;
32    }
33    dirp = (DIR *) ckalloc(sizeof(DIR));
34    if (dirp == NULL) {
35	/* unreachable? */
36	close(fd);
37	return NULL;
38    }
39    dirp->dd_fd = fd;
40    dirp->dd_loc = 0;
41    return dirp;
42}
43
44/*
45 * read an old style directory entry and present it as a new one
46 */
47#ifndef pyr
48#define	ODIRSIZ	14
49
50struct	olddirect {
51    ino_t od_ino;
52    char od_name[ODIRSIZ];
53};
54#else	/* a Pyramid in the ATT universe */
55#define	ODIRSIZ	248
56
57struct	olddirect {
58    long od_ino;
59    short od_fill1, od_fill2;
60    char od_name[ODIRSIZ];
61};
62#endif
63
64/*
65 * get next entry in a directory.
66 */
67
68struct dirent *
69readdir(
70    register DIR *dirp)
71{
72    register struct olddirect *dp;
73    static struct dirent dir;
74
75    for (;;) {
76	if (dirp->dd_loc == 0) {
77	    dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
78	    if (dirp->dd_size <= 0) {
79		return NULL;
80	    }
81	}
82	if (dirp->dd_loc >= dirp->dd_size) {
83	    dirp->dd_loc = 0;
84	    continue;
85	}
86	dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
87	dirp->dd_loc += sizeof(struct olddirect);
88	if (dp->od_ino == 0) {
89	    continue;
90	}
91	dir.d_ino = dp->od_ino;
92	strncpy(dir.d_name, dp->od_name, ODIRSIZ);
93	dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
94	dir.d_namlen = strlen(dir.d_name);
95	dir.d_reclen = DIRSIZ(&dir);
96	return &dir;
97    }
98}
99
100/*
101 * close a directory.
102 */
103
104void
105closedir(
106    register DIR *dirp)
107{
108    close(dirp->dd_fd);
109    dirp->dd_fd = -1;
110    dirp->dd_loc = 0;
111    ckfree((char *) dirp);
112}
113