backport to buster
[hcoop/debian/openafs.git] / src / util / readdir_nt.c
CommitLineData
805e021f
CE
1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10/*
11 * readdir.c - A minimal implementation of readdir to ease porting of AFS to
12 * NT. Include dirent.h to pickup the required structs and prototypes.
13 *
14 * Implemented routines:
15 * opendir
16 * closedir
17 * readdir
18 */
19#include <afsconfig.h>
20#include <afs/param.h>
21
22#include <roken.h>
23
24#include <afs/errmap_nt.h>
25#include <windows.h>
26#include <winbase.h>
27
28/* opendir() - The case insensitive version of opendir */
29DIR *
30opendir(const char *path)
31{
32 DIR *tDir;
33 HANDLE tH;
34 char tPath[MAX_PATH];
35 WIN32_FIND_DATA tData;
36 int ntErr;
37
38 (void)strcpy(tPath, path);
39 (void)strcat(tPath, "\\*");
40 tH = FindFirstFile(tPath, &tData);
41
42 if (tH == INVALID_HANDLE_VALUE) {
43 ntErr = GetLastError();
44 switch (ntErr) {
45 case ERROR_DIRECTORY:
46 errno = ENOTDIR;
47 return (DIR *) 0;
48 case ERROR_BAD_PATHNAME:
49 /* AFS NT client returns ERROR_BAD_PATHNAME where it should return
50 * ERROR_DIRECTORY.
51 */
52 case ERROR_FILE_NOT_FOUND:
53 /* If at the "root" directory, then this can happen if it's empty.
54 */
55 {
56 struct stat status;
57 size_t len = strlen(tPath) - 1;
58 tPath[len] = '\0';
59 if (len >= 2 && tPath[len - 2] != ':') {
60 tPath[len - 1] = '\0';
61 }
62 if (stat(tPath, &status) < 0) {
63 errno = nterr_nt2unix(GetLastError(), ENOENT);
64 return (DIR *) 0;
65 }
66 if (!(status.st_mode & _S_IFDIR)) {
67 errno = ENOTDIR;
68 return (DIR *) 0;
69 }
70 }
71 break;
72 default:
73 errno = nterr_nt2unix(GetLastError(), ENOENT);
74 return (DIR *) 0;
75 }
76 }
77
78 tDir = calloc(1, sizeof(DIR));
79 if (!tDir) {
80 errno = ENOMEM;
81 } else {
82 tDir->h = tH;
83 tDir->data = tData;
84 }
85 return tDir;
86}
87
88int
89closedir(DIR * dir)
90{
91 if (!dir || !dir->h) {
92 errno = EINVAL;
93 return -1;
94 }
95
96 if (dir->h != INVALID_HANDLE_VALUE)
97 FindClose(dir->h);
98 free(dir);
99 return 0;
100}
101
102struct dirent *
103readdir(DIR * dir)
104{
105 int rc;
106
107 if (!dir) {
108 errno = EBADF;
109 return (struct dirent *)0;
110 }
111
112 errno = 0;
113 if (dir->h == INVALID_HANDLE_VALUE)
114 return (struct dirent *)0;
115
116 if (dir->first) {
117 dir->first = 0;
118 } else {
119 while (rc = FindNextFile(dir->h, &dir->data)) {
120 if ((strcmp(dir->data.cFileName, ".") == 0)
121 || (strcmp(dir->data.cFileName, "..") == 0)) {
122
123 continue; /* skip "." and ".." */
124 }
125 break; /* found a non '.' or '..' entry. */
126 }
127 if (rc == 0) { /* FindNextFile() failed */
128 if (GetLastError() == ERROR_NO_MORE_FILES)
129 return (struct dirent *)0;
130 else {
131 errno = nterr_nt2unix(GetLastError(), EBADF);
132 return (struct dirent *)0;
133 }
134 }
135 }
136
137 dir->cdirent.d_name = dir->data.cFileName;
138 return &dir->cdirent;
139}