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