a9677825a7932be0841eaf1c3dd2d4587168d4f4
[debian/tar] / gnu / opendir.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* Start reading the entries of a directory.
4    Copyright (C) 2006-2013 Free Software Foundation, Inc.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 #include <config.h>
20
21 /* Specification.  */
22 #include <dirent.h>
23
24 #include <errno.h>
25 #include <stddef.h>
26
27 #if HAVE_OPENDIR
28
29 /* Override opendir(), to keep track of the open file descriptors.
30    Needed because there is a function dirfd().  */
31
32 #else
33
34 # include <stdlib.h>
35
36 # include "dirent-private.h"
37 # include "filename.h"
38
39 #endif
40
41 #if REPLACE_FCHDIR
42 # include <unistd.h>
43 #endif
44
45 DIR *
46 opendir (const char *dir_name)
47 {
48 #if HAVE_OPENDIR
49 # undef opendir
50   DIR *dirp;
51
52   dirp = opendir (dir_name);
53   if (dirp == NULL)
54     return NULL;
55
56 #else
57
58   char dir_name_mask[MAX_PATH + 1 + 1 + 1];
59   int status;
60   HANDLE current;
61   WIN32_FIND_DATA entry;
62   struct gl_directory *dirp;
63
64   if (dir_name[0] == '\0')
65     {
66       errno = ENOENT;
67       return NULL;
68     }
69
70   /* Make the dir_name absolute, so that we continue reading the same
71      directory if the current directory changed between this opendir()
72      call and a subsequent rewinddir() call.  */
73   if (!GetFullPathName (dir_name, MAX_PATH, dir_name_mask, NULL))
74     {
75       errno = EINVAL;
76       return NULL;
77     }
78
79   /* Append the mask.
80      "*" and "*.*" appear to be equivalent.  */
81   {
82     char *p;
83
84     p = dir_name_mask + strlen (dir_name_mask);
85     if (p > dir_name_mask && !ISSLASH (p[-1]))
86       *p++ = '\\';
87     *p++ = '*';
88     *p = '\0';
89   }
90
91   /* Start searching the directory.  */
92   status = -1;
93   current = FindFirstFile (dir_name_mask, &entry);
94   if (current == INVALID_HANDLE_VALUE)
95     {
96       switch (GetLastError ())
97         {
98         case ERROR_FILE_NOT_FOUND:
99           status = -2;
100           break;
101         case ERROR_PATH_NOT_FOUND:
102           errno = ENOENT;
103           return NULL;
104         case ERROR_DIRECTORY:
105           errno = ENOTDIR;
106           return NULL;
107         case ERROR_ACCESS_DENIED:
108           errno = EACCES;
109           return NULL;
110         default:
111           errno = EIO;
112           return NULL;
113         }
114     }
115
116   /* Allocate the result.  */
117   dirp =
118     (struct gl_directory *)
119     malloc (offsetof (struct gl_directory, dir_name_mask[0])
120             + strlen (dir_name_mask) + 1);
121   if (dirp == NULL)
122     {
123       if (current != INVALID_HANDLE_VALUE)
124         FindClose (current);
125       errno = ENOMEM;
126       return NULL;
127     }
128   dirp->status = status;
129   dirp->current = current;
130   if (status == -1)
131     memcpy (&dirp->entry, &entry, sizeof (WIN32_FIND_DATA));
132   strcpy (dirp->dir_name_mask, dir_name_mask);
133
134 #endif
135
136 #if REPLACE_FCHDIR
137   {
138     int fd = dirfd (dirp);
139     if (0 <= fd && _gl_register_fd (fd, dir_name) != fd)
140       {
141         int saved_errno = errno;
142         closedir (dirp);
143         errno = saved_errno;
144         return NULL;
145       }
146   }
147 #endif
148
149   return dirp;
150 }