xapian-core  1.4.25
msvc_dirent.cc
Go to the documentation of this file.
1 
4 /*
5  Implementation of POSIX directory browsing functions and types for Win32.
6 
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).
14  2019-12-16 Make dir->name a one element array member and over-allocate
15  the struct so there's enough room for its actual size.
16 
17  Copyright Kevlin Henney, 1997, 2003. All rights reserved.
18 
19  Permission to use, copy, modify, and distribute this software and its
20  documentation for any purpose is hereby granted without fee, provided
21  that this copyright and permissions notice appear in all copies and
22  derivatives.
23 
24  This software is supplied "as is" without express or implied warranty.
25 
26  But that said, if there are any problems please get in touch.
27 */
28 
29 #include <config.h>
30 #ifdef __WIN32__
31 
32 #include "msvc_dirent.h"
33 #include <cerrno>
34 #include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
35 #include <cstdlib>
36 #include <cstring>
37 
38 #ifdef __cplusplus
39 extern "C"
40 {
41 #endif
42 
43 struct DIR
44 {
45  intptr_t handle; /* -1 for failed rewind */
46  struct _finddata_t info;
47  struct dirent result; /* d_name null iff first time */
48  char name[1];/* null-terminated char string */
49 };
50 
51 DIR *opendir(const char *name)
52 {
53  DIR *dir = 0;
54 
55  if(name && name[0])
56  {
57  size_t base_length = strlen(name);
58  /* 2 allows for appending `/` and `*`. We don't need to allow
59  * 1 for the nul here as there will always be at least one byte
60  * in struct DIR for name (plus padding). */
61  size_t alloc_size = sizeof(DIR) + base_length + 2;
62 
63  if((dir = (DIR *) malloc(alloc_size)) != 0)
64  {
65  memcpy(dir->name, name, base_length);
66  /* Search pattern must end with suitable wildcard */
67  if(name[base_length - 1] != '/' && name[base_length - 1] != '\\')
68  dir->name[base_length++] = '/';
69  memcpy(dir->name + base_length, "*", 2);
70 
71  if((dir->handle = _findfirst(dir->name, &dir->info)) != -1)
72  {
73  dir->result.d_name = 0;
74  }
75  else /* rollback */
76  {
77  /* _findfirst() will have set errno suitably. */
78  free(dir);
79  dir = 0;
80  }
81  }
82  else /* rollback */
83  {
84  free(dir);
85  dir = 0;
86  errno = ENOMEM;
87  }
88  }
89  else
90  {
91  errno = EINVAL;
92  }
93 
94  return dir;
95 }
96 
97 int closedir(DIR *dir)
98 {
99  int result = -1;
100 
101  if(dir)
102  {
103  if(dir->handle != -1)
104  {
105  result = _findclose(dir->handle);
106  }
107 
108  free(dir);
109  }
110 
111  if(result == -1) /* map all errors to EBADF */
112  {
113  errno = EBADF;
114  }
115 
116  return result;
117 }
118 
119 struct dirent *readdir(DIR *dir)
120 {
121  struct dirent *result = 0;
122 
123  if(dir && dir->handle != -1)
124  {
125  if(!dir->result.d_name) {
126  result = &dir->result;
127  result->d_name = dir->info.name;
128  } else {
129  int orig_errno = errno;
130  if (_findnext(dir->handle, &dir->info) != -1) {
131  result = &dir->result;
132  result->d_name = dir->info.name;
133  } else if (errno == ENOENT) {
134  // _findnext sets errno to ENOENT when the end of the directory
135  // is reached. However, according to POSIX, the value of errno
136  // should not be changed by this condition. Therefore, we have
137  // to set it back to the original value.
138  errno = orig_errno;
139  }
140  }
141  }
142  else
143  {
144  errno = EBADF;
145  }
146 
147  return result;
148 }
149 
150 void rewinddir(DIR *dir)
151 {
152  if(dir && dir->handle != -1)
153  {
154  _findclose(dir->handle);
155  dir->handle = _findfirst(dir->name, &dir->info);
156  dir->result.d_name = 0;
157  }
158  else
159  {
160  errno = EBADF;
161  }
162 }
163 
164 #ifdef __cplusplus
165 }
166 #endif
167 
168 #endif
int closedir(DIR *)
struct dirent * readdir(DIR *)
void rewinddir(DIR *)
DIR * opendir(const char *)
char * d_name
Definition: msvc_dirent.h:36
struct DIR DIR
Definition: msvc_dirent.h:32
Implementation of dirent functions using WIN32 API.
Definition: header.h:151