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