1 /* @(#)dirent.c	1.4 17/02/02 Copyright 2011-2017 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)dirent.c	1.4 17/02/02 Copyright 2011-2017 J. Schilling";
6 #endif
7 /*
8  *	Copyright (c) 2011-2017 J. Schilling
9  */
10 /*
11  * The contents of this file are subject to the terms of the
12  * Common Development and Distribution License, Version 1.0 only
13  * (the "License").  You may not use this file except in compliance
14  * with the License.
15  *
16  * See the file CDDL.Schily.txt in this distribution for details.
17  * A copy of the CDDL is also available via the Internet at
18  * http://www.opensource.org/licenses/cddl1.txt
19  *
20  * When distributing Covered Code, include this CDDL HEADER in each
21  * file and include the License file CDDL.Schily.txt from this distribution.
22  */
23 
24 #include <schily/dirent.h>
25 #include <schily/maxpath.h>
26 #include <schily/string.h>
27 #include <schily/errno.h>
28 
29 #ifdef	NEED_READDIR
30 
31 #if	defined(__MINGW32__) || defined(_MSC_VER)
32 
33 #include <schily/windows.h>
34 #include <schily/utypes.h>
35 #include <schily/schily.h>
36 
37 EXPORT	DIR		*opendir __PR((const char *));
38 EXPORT	int		closedir __PR((DIR *));
39 EXPORT	struct dirent	*readdir __PR((DIR *));
40 
41 EXPORT DIR *
42 opendir(dname)
43 	const char	*dname;
44 {
45 	char	path[PATH_MAX];
46 	size_t	len;
47 	uint32_t attr;
48 	DIR	*dp;
49 
50 	if (dname == NULL) {
51 		seterrno(EFAULT);
52 		return ((DIR *)0);
53 	}
54 	len = strlen(dname);
55 	if (len > PATH_MAX) {
56 		seterrno(ENAMETOOLONG);
57 		return ((DIR *)0);
58 	}
59 	if (len == 0) {
60 		seterrno(ENOENT);
61 		return ((DIR *)0);
62 	}
63 
64 	attr = GetFileAttributes(dname);
65 	if (attr == INVALID_FILE_ATTRIBUTES ||
66 	    (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
67 		seterrno(ENOTDIR);
68 		return ((DIR *)0);
69 	}
70 	path[0] = '\0';
71 	_fullpath(path, dname, PATH_MAX);
72 	len = strlen(path);
73 	if (len == 0) {
74 		seterrno(ENOENT);
75 		return ((DIR *)0);
76 	}
77 
78 	dp = malloc(sizeof (*dp) + len + 2);	/* Add 2 for "/ *" */
79 	if (dp == NULL) {
80 		seterrno(ENOMEM);
81 		return ((DIR *)0);
82 	}
83 	strcpy(dp->dd_dirname, path);
84 	if (dp->dd_dirname[len-1] != '/' &&
85 	    dp->dd_dirname[len-1] != '\\') {
86 		dp->dd_dirname[len] = '\\';
87 		len++;
88 	}
89 	dp->dd_dirname[len++] = '*';
90 	dp->dd_dirname[len]   = '\0';
91 	dp->dd_handle = -1;
92 	dp->dd_state  = 0;
93 
94 	dp->dd_dir.d_ino    = 0;
95 	dp->dd_dir.d_reclen = 0;
96 	dp->dd_dir.d_namlen = 0;
97 	zerobytes(dp->dd_dir.d_name, sizeof (dp->dd_dir.d_name));
98 
99 	return (dp);
100 }
101 
102 EXPORT	int
103 closedir(dp)
104 	DIR	*dp;
105 {
106 	int	ret = 0;
107 
108 	if (dp == NULL) {
109 		seterrno(EFAULT);
110 		return (-1);
111 	}
112 	if (dp->dd_handle != -1) {
113 		ret = _findclose(dp->dd_handle);
114 	}
115 	free(dp);
116 
117 	return (ret);
118 }
119 
120 EXPORT struct dirent *
121 readdir(dp)
122 	DIR	*dp;
123 {
124 	if (dp == NULL) {
125 		seterrno(EFAULT);
126 		return ((struct dirent *)0);
127 	}
128 	if (dp->dd_state == (char)-1) {
129 		return ((struct dirent *)0);
130 	} else if (dp->dd_state == (char)0) {
131 		dp->dd_handle = _findfirst(dp->dd_dirname, &(dp->dd_data));
132 		if (dp->dd_handle != -1)
133 			dp->dd_state = 1;
134 		else
135 			dp->dd_state = -1;
136 	} else {
137 		if (_findnext(dp->dd_handle, &(dp->dd_data))) {
138 			uint32_t	werrno = GetLastError();
139 
140 			if (werrno == ERROR_NO_MORE_FILES)
141 				seterrno(0);
142 			_findclose(dp->dd_handle);
143 			dp->dd_handle = -1;
144 			dp->dd_state = -1;
145 		} else {
146 			dp->dd_state = 1;	/* state++ to support seekdir */
147 		}
148 	}
149 	if (dp->dd_state > 0) {
150 		strlcpy(dp->dd_dir.d_name, dp->dd_data.name,
151 				sizeof (dp->dd_dir.d_name));
152 
153 		return (&dp->dd_dir);
154 	}
155 	return ((struct dirent *)0);
156 }
157 
158 #endif	/* defined(__MINGW32__) || defined(_MSC_VER) */
159 
160 #endif	/* NEED_READDIR */
161