OSDN Git Service

6faddf37b77899d1c78a8dae8ea189a3290995ef
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / dir.cc
1 /* dir.cc: Posix directory-related routines
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <sys/stat.h>
15
16 #define _COMPILING_NEWLIB
17 #include <dirent.h>
18
19 #include "pinfo.h"
20 #include "cygerrno.h"
21 #include "security.h"
22 #include "path.h"
23 #include "fhandler.h"
24 #include "dtable.h"
25 #include "cygheap.h"
26 #include "cygtls.h"
27
28 extern "C" int
29 dirfd (DIR *dir)
30 {
31   myfault efault;
32   if (efault.faulted (EFAULT))
33     return -1;
34   if (dir->__d_cookie != __DIRENT_COOKIE)
35     {
36       set_errno (EBADF);
37       syscall_printf ("-1 = dirfd (%p)", dir);
38       return -1;
39     }
40   return dir->__d_dirent->d_fd;
41 }
42
43 /* opendir: POSIX 5.1.2.1 */
44 extern "C" DIR *
45 opendir (const char *name)
46 {
47   fhandler_base *fh;
48   DIR *res;
49
50   fh = build_fh_name (name, NULL, PC_SYM_FOLLOW);
51   if (!fh)
52     res = NULL;
53   else if (fh->exists ())
54       res = fh->opendir ();
55   else
56     {
57       set_errno (ENOENT);
58       res = NULL;
59     }
60
61   if (res)
62     /* nothing */;
63   else if (fh)
64     delete fh;
65   return res;
66 }
67
68 static int
69 readdir_worker (DIR *dir, dirent *de)
70 {
71   myfault efault;
72   if (efault.faulted ())
73     return EFAULT;
74
75   if (dir->__d_cookie != __DIRENT_COOKIE)
76     {
77       syscall_printf ("%p = readdir (%p)", NULL, dir);
78       return EBADF;
79     }
80
81   int res = ((fhandler_base *) dir->__fh)->readdir (dir, de);
82
83   if (res == ENMFILE)
84     {
85       if (!(dir->__flags & dirent_saw_dot))
86         {
87           strcpy (de->d_name, ".");
88           dir->__flags |= dirent_saw_dot;
89           dir->__d_position++;
90           res = 0;
91         }
92       else if (!(dir->__flags & dirent_saw_dot_dot))
93         {
94           strcpy (de->d_name, "..");
95           dir->__flags |= dirent_saw_dot_dot;
96           dir->__d_position++;
97           res = 0;
98         }
99     }
100
101   if (!res)
102     {
103       /* Compute d_ino by combining filename hash with the directory hash
104          (which was stored in dir->__d_dirhash when opendir was called). */
105       if (de->d_name[0] == '.')
106         {
107           if (de->d_name[1] == '\0')
108             {
109               de->d_ino = dir->__d_dirhash;
110               dir->__flags |= dirent_saw_dot;
111             }
112           else if (de->d_name[1] != '.' || de->d_name[2] != '\0')
113             goto hashit;
114           else
115             {
116               dir->__flags |= dirent_saw_dot_dot;
117               char *p, up[strlen (dir->__d_dirname) + 1];
118               strcpy (up, dir->__d_dirname);
119               if (!(p = strrchr (up, '\\')))
120                 goto hashit;
121               *p = '\0';
122               if (!(p = strrchr (up, '\\')))
123                 de->d_ino = hash_path_name (0, ".");
124               else
125                 {
126                   *p = '\0';
127                   de->d_ino = hash_path_name (0, up);
128                 }
129             }
130         }
131       else
132         {
133       hashit:
134           __ino64_t dino = hash_path_name (dir->__d_dirhash, "\\");
135           de->d_ino = hash_path_name (dino, de->d_name);
136         }
137       de->__ino32 = de->d_ino;  // for legacy applications
138     }
139   return res;
140 }
141
142 /* readdir: POSIX 5.1.2.1 */
143 extern "C" struct dirent *
144 readdir (DIR *dir)
145 {
146   int res = readdir_worker (dir, dir->__d_dirent);
147   if (res == 0)
148     return dir->__d_dirent;
149   if (res != ENMFILE)
150     set_errno (res);
151   return NULL;
152 }
153
154 extern "C" int
155 readdir_r (DIR *dir, dirent *de, dirent **ode)
156 {
157   int res = readdir_worker (dir, de);
158   if (!res)
159     *ode = de;
160   else
161     {
162       *ode = NULL;
163       if (res == ENMFILE)
164         res = 0;
165     }
166   return res;
167 }
168
169 extern "C" _off64_t
170 telldir64 (DIR *dir)
171 {
172   myfault efault;
173   if (efault.faulted (EFAULT))
174     return -1;
175
176   if (dir->__d_cookie != __DIRENT_COOKIE)
177     return 0;
178   return ((fhandler_base *) dir->__fh)->telldir (dir);
179 }
180
181 /* telldir */
182 extern "C" _off_t
183 telldir (DIR *dir)
184 {
185   return telldir64 (dir);
186 }
187
188 extern "C" void
189 seekdir64 (DIR *dir, _off64_t loc)
190 {
191   myfault efault;
192   if (efault.faulted (EFAULT))
193     return;
194
195   if (dir->__d_cookie != __DIRENT_COOKIE)
196     return;
197   dir->__flags &= dirent_isroot;
198   return ((fhandler_base *) dir->__fh)->seekdir (dir, loc);
199 }
200
201 /* seekdir */
202 extern "C" void
203 seekdir (DIR *dir, _off_t loc)
204 {
205   seekdir64 (dir, (_off64_t)loc);
206 }
207
208 /* rewinddir: POSIX 5.1.2.1 */
209 extern "C" void
210 rewinddir (DIR *dir)
211 {
212   myfault efault;
213   if (efault.faulted (EFAULT))
214     return;
215
216   if (dir->__d_cookie != __DIRENT_COOKIE)
217     return;
218   dir->__flags &= dirent_isroot;
219   return ((fhandler_base *) dir->__fh)->rewinddir (dir);
220 }
221
222 /* closedir: POSIX 5.1.2.1 */
223 extern "C" int
224 closedir (DIR *dir)
225 {
226   myfault efault;
227   if (efault.faulted (EFAULT))
228     return -1;
229
230   if (dir->__d_cookie != __DIRENT_COOKIE)
231     {
232       set_errno (EBADF);
233       syscall_printf ("-1 = closedir (%p)", dir);
234       return -1;
235     }
236
237   /* Reset the marker in case the caller tries to use `dir' again.  */
238   dir->__d_cookie = 0;
239
240   int res = ((fhandler_base *) dir->__fh)->closedir (dir);
241
242   cygheap->fdtab.release (dir->__d_dirent->d_fd);
243
244   free (dir->__d_dirname);
245   free (dir->__d_dirent);
246   free (dir);
247   syscall_printf ("%d = closedir (%p)", res);
248   return res;
249 }
250
251 /* mkdir: POSIX 5.4.1.1 */
252 extern "C" int
253 mkdir (const char *dir, mode_t mode)
254 {
255   int res = -1;
256   fhandler_base *fh = NULL;
257
258   myfault efault;
259   if (efault.faulted (EFAULT))
260     return -1;
261
262   if (has_dot_last_component (dir))
263     {
264       set_errno (ENOENT);
265       return -1;
266     }
267
268   if (!(fh = build_fh_name (dir, NULL, PC_SYM_NOFOLLOW)))
269     goto done;   /* errno already set */;
270
271   if (fh->error ())
272     {
273       debug_printf ("got %d error from build_fh_name", fh->error ());
274       set_errno (fh->error ());
275     }
276   else if (!fh->mkdir (mode))
277     res = 0;
278   delete fh;
279
280  done:
281   syscall_printf ("%d = mkdir (%s, %d)", res, dir, mode);
282   return res;
283 }
284
285 /* rmdir: POSIX 5.5.2.1 */
286 extern "C" int
287 rmdir (const char *dir)
288 {
289   int res = -1;
290   fhandler_base *fh = NULL;
291
292   myfault efault;
293   if (efault.faulted (EFAULT))
294     return -1;
295
296   if (has_dot_last_component (dir))
297     {
298       set_errno (EINVAL);
299       return -1;
300     }
301
302   if (!(fh = build_fh_name (dir, NULL, PC_SYM_NOFOLLOW)))
303     goto done;   /* errno already set */;
304
305   if (fh->error ())
306     {
307       debug_printf ("got %d error from build_fh_name", fh->error ());
308       set_errno (fh->error ());
309     }
310   else if (!fh->rmdir ())
311     res = 0;
312   delete fh;
313
314  done:
315   syscall_printf ("%d = rmdir (%s)", res, dir);
316   return res;
317 }