[ci] Enable IRC notifications from travis
[xapian.git] / xapian-core / common / msvc_dirent.cc
blob640ff91ba6e35c3f8e8f78f9a4e14aebf2c2040d
1 /** @file msvc_dirent.cc
2 * @brief Implementation of dirent functions using WIN32 API.
3 */
4 /*
5 Implementation of POSIX directory browsing functions and types for Win32.
7 Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
8 History: Created March 1997. Updated June 2003.
9 Fixes since importing into Xapian:
10 2008-03-04 Fixed readdir() not to set errno to ENOENT when the
11 end of the directory is reached.
12 2018-04-01 Fix handle to be intptr_t not long to avoid truncation
13 with WIN64 (where long is still 32 bits).
15 Copyright Kevlin Henney, 1997, 2003. All rights reserved.
17 Permission to use, copy, modify, and distribute this software and its
18 documentation for any purpose is hereby granted without fee, provided
19 that this copyright and permissions notice appear in all copies and
20 derivatives.
22 This software is supplied "as is" without express or implied warranty.
24 But that said, if there are any problems please get in touch.
27 #include <config.h>
28 #ifdef __WIN32__
30 #include "msvc_dirent.h"
31 #include <cerrno>
32 #include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
33 #include <cstdlib>
34 #include <cstring>
36 #ifdef __cplusplus
37 extern "C"
39 #endif
41 struct DIR
43 intptr_t handle; /* -1 for failed rewind */
44 struct _finddata_t info;
45 struct dirent result; /* d_name null iff first time */
46 char *name; /* null-terminated char string */
49 DIR *opendir(const char *name)
51 DIR *dir = 0;
53 if(name && name[0])
55 size_t base_length = strlen(name);
56 const char *all = /* search pattern must end with suitable wildcard */
57 strchr("/\\", name[base_length - 1]) ? "*" : "/*";
59 if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
60 (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
62 strcat(strcpy(dir->name, name), all);
64 if((dir->handle = _findfirst(dir->name, &dir->info)) != -1)
66 dir->result.d_name = 0;
68 else /* rollback */
70 free(dir->name);
71 free(dir);
72 dir = 0;
75 else /* rollback */
77 free(dir);
78 dir = 0;
79 errno = ENOMEM;
82 else
84 errno = EINVAL;
87 return dir;
90 int closedir(DIR *dir)
92 int result = -1;
94 if(dir)
96 if(dir->handle != -1)
98 result = _findclose(dir->handle);
101 free(dir->name);
102 free(dir);
105 if(result == -1) /* map all errors to EBADF */
107 errno = EBADF;
110 return result;
113 struct dirent *readdir(DIR *dir)
115 struct dirent *result = 0;
117 if(dir && dir->handle != -1)
119 if(!dir->result.d_name) {
120 result = &dir->result;
121 result->d_name = dir->info.name;
122 } else {
123 int orig_errno = errno;
124 if (_findnext(dir->handle, &dir->info) != -1) {
125 result = &dir->result;
126 result->d_name = dir->info.name;
127 } else if (errno == ENOENT) {
128 // _findnext sets errno to ENOENT when the end of the directory
129 // is reached. However, according to POSIX, the value of errno
130 // should not be changed by this condition. Therefore, we have
131 // to set it back to the original value.
132 errno = orig_errno;
136 else
138 errno = EBADF;
141 return result;
144 void rewinddir(DIR *dir)
146 if(dir && dir->handle != -1)
148 _findclose(dir->handle);
149 dir->handle = _findfirst(dir->name, &dir->info);
150 dir->result.d_name = 0;
152 else
154 errno = EBADF;
158 #ifdef __cplusplus
160 #endif
162 #endif