vos-listaddrs-avoid-holes-in-index-20020805
[openafs.git] / src / util / readdir_nt.c
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 RCSID("$Header$");
23
24 #include <errno.h>
25 #include <afs/errmap_nt.h>
26 #include <windows.h>
27 #include <winbase.h>
28 #include <dirent.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31
32 /* opendir() - The case insensitive version of opendir */
33 DIR *opendir(const char *path)
34 {
35     struct DIR *tDir;
36     HANDLE tH;
37     char tPath[MAX_PATH];
38     WIN32_FIND_DATA tData;
39     int ntErr;
40
41     (void) strcpy(tPath, path);
42     (void) strcat(tPath, "\\*");
43     tH = FindFirstFile(tPath, &tData);
44
45     if (tH == INVALID_HANDLE_VALUE) {
46         ntErr = GetLastError();
47         switch (ntErr) {
48         case ERROR_DIRECTORY:
49             errno = ENOTDIR;
50             return (DIR*)0;
51         case ERROR_BAD_PATHNAME:
52             /* AFS NT client returns ERROR_BAD_PATHNAME where it should return
53              * ERROR_DIRECTORY.
54              */
55         case ERROR_FILE_NOT_FOUND:
56             /* If at the "root" directory, then this can happen if it's empty.
57              */
58             {
59                 struct stat status;
60                 int len = strlen(tPath) - 1;
61                 tPath[len] = '\0';
62                 if (len >= 2 && tPath[len-2] != ':') {
63                     tPath[len-1] = '\0';
64                 }
65                 if (stat(tPath, &status)<0) {
66                     errno = nterr_nt2unix(GetLastError(), ENOENT);
67                     return (DIR*)0;
68                 }
69                 if (!(status.st_mode & _S_IFDIR)) {
70                     errno = ENOTDIR;
71                     return (DIR*)0;
72                 }
73             }
74             break;
75         default:
76             errno = nterr_nt2unix(GetLastError(), ENOENT);
77             return (DIR*)0;
78         }
79     }
80
81     tDir = (DIR*)malloc(sizeof(DIR));
82     if (!tDir) {
83         errno = ENOMEM;
84     }
85     else {
86         memset((void*)tDir, 0, sizeof(*tDir));
87         tDir->h = tH;
88         tDir->data = tData;
89     }
90     return tDir;
91 }
92
93 int closedir(DIR *dir)
94 {
95     if (!dir || !dir->h) {
96         errno = EINVAL;
97         return -1;
98     }
99
100     if (dir->h != INVALID_HANDLE_VALUE)
101         FindClose(dir->h);
102     free((void*)dir);
103     return 0;
104 }
105
106 struct dirent *readdir(DIR *dir)
107 {
108     int rc;
109
110     if (!dir) {
111         errno = EBADF;
112         return (struct dirent*)0;
113     }
114
115     errno = 0;
116     if (dir->h == INVALID_HANDLE_VALUE)
117         return (struct dirent*)0;
118
119     if (dir->first) {
120         dir->first = 0;
121     }
122     else {
123       while(rc = FindNextFile(dir->h, &dir->data)) {
124         if ((strcmp(dir->data.cFileName, ".") == 0) ||
125             (strcmp(dir->data.cFileName, "..") == 0)) {
126           
127           continue;     /* skip "." and ".." */
128         }
129         break;  /* found a non '.' or '..' entry. */
130       }
131       if (rc == 0) { /* FindNextFile() failed */
132         if (GetLastError() == ERROR_NO_MORE_FILES)
133           return (struct dirent*)0;
134         else {
135           errno = nterr_nt2unix(GetLastError(), EBADF);
136                 return (struct dirent*)0;
137         }
138       }
139     }
140
141     dir->cdirent.d_name = dir->data.cFileName;
142     return &dir->cdirent;
143 }
144