use-consistent-data-typing-for-hosts-20010404
[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 <afs/param.h>
20 #include <errno.h>
21 #include <afs/errmap_nt.h>
22 #include <windows.h>
23 #include <winbase.h>
24 #include <dirent.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27
28 /* opendir() - The case insensitive version of opendir */
29 DIR *opendir(const char *path)
30 {
31     struct DIR *tDir;
32     HANDLE tH;
33     char tPath[MAX_PATH];
34     WIN32_FIND_DATA tData;
35     int ntErr;
36
37     (void) strcpy(tPath, path);
38     (void) strcat(tPath, "\\*");
39     tH = FindFirstFile(tPath, &tData);
40
41     if (tH == INVALID_HANDLE_VALUE) {
42         ntErr = GetLastError();
43         switch (ntErr) {
44         case ERROR_DIRECTORY:
45             errno = ENOTDIR;
46             return (DIR*)0;
47         case ERROR_BAD_PATHNAME:
48             /* AFS NT client returns ERROR_BAD_PATHNAME where it should return
49              * ERROR_DIRECTORY.
50              */
51         case ERROR_FILE_NOT_FOUND:
52             /* If at the "root" directory, then this can happen if it's empty.
53              */
54             {
55                 struct stat status;
56                 int len = strlen(tPath) - 1;
57                 tPath[len] = '\0';
58                 if (len >= 2 && tPath[len-2] != ':') {
59                     tPath[len-1] = '\0';
60                 }
61                 if (stat(tPath, &status)<0) {
62                     errno = nterr_nt2unix(GetLastError(), ENOENT);
63                     return (DIR*)0;
64                 }
65                 if (!(status.st_mode & _S_IFDIR)) {
66                     errno = ENOTDIR;
67                     return (DIR*)0;
68                 }
69             }
70             break;
71         default:
72             errno = nterr_nt2unix(GetLastError(), ENOENT);
73             return (DIR*)0;
74         }
75     }
76
77     tDir = (DIR*)malloc(sizeof(DIR));
78     if (!tDir) {
79         errno = ENOMEM;
80     }
81     else {
82         memset((void*)tDir, 0, sizeof(*tDir));
83         tDir->h = tH;
84         tDir->data = tData;
85     }
86     return tDir;
87 }
88
89 int closedir(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((void*)dir);
99     return 0;
100 }
101
102 struct dirent *readdir(DIR *dir)
103 {
104     int rc;
105
106     if (!dir) {
107         errno = EBADF;
108         return (struct dirent*)0;
109     }
110
111     errno = 0;
112     if (dir->h == INVALID_HANDLE_VALUE)
113         return (struct dirent*)0;
114
115     if (dir->first) {
116         dir->first = 0;
117     }
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 }
140