1 /* dir.cc: Posix directory-related routines
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
16 #define _COMPILING_NEWLIB
30 if (check_null_invalid_struct_errno (dir))
32 if (dir->__d_cookie != __DIRENT_COOKIE)
35 syscall_printf ("-1 = dirfd (%p)", dir);
38 return dir->__d_dirent->d_fd;
41 /* opendir: POSIX 5.1.2.1 */
43 opendir (const char *name)
48 fh = build_fh_name (name, NULL, PC_SYM_FOLLOW | PC_FULL);
51 else if (fh->exists ())
66 /* readdir: POSIX 5.1.2.1 */
67 extern "C" struct dirent *
70 if (check_null_invalid_struct_errno (dir))
73 if (dir->__d_cookie != __DIRENT_COOKIE)
76 syscall_printf ("%p = readdir (%p)", NULL, dir);
80 dirent *res = ((fhandler_base *) dir->__fh)->readdir (dir);
84 if (!(dir->__flags & dirent_saw_dot))
86 res = dir->__d_dirent;
87 strcpy (res->d_name, ".");
88 dir->__flags |= dirent_saw_dot;
91 else if (!(dir->__flags & dirent_saw_dot_dot))
93 res = dir->__d_dirent;
94 strcpy (res->d_name, "..");
95 dir->__flags |= dirent_saw_dot_dot;
102 /* Compute d_ino by combining filename hash with the directory hash
103 (which was stored in dir->__d_dirhash when opendir was called). */
104 if (res->d_name[0] == '.')
106 if (res->d_name[1] == '\0')
108 dir->__d_dirent->d_ino = dir->__d_dirhash;
109 dir->__flags |= dirent_saw_dot;
111 else if (res->d_name[1] != '.' || res->d_name[2] != '\0')
115 dir->__flags |= dirent_saw_dot_dot;
116 char *p, up[strlen (dir->__d_dirname) + 1];
117 strcpy (up, dir->__d_dirname);
118 if (!(p = strrchr (up, '\\')))
121 if (!(p = strrchr (up, '\\')))
122 dir->__d_dirent->d_ino = hash_path_name (0, ".");
126 dir->__d_dirent->d_ino = hash_path_name (0, up);
133 __ino64_t dino = hash_path_name (dir->__d_dirhash, "\\");
134 dir->__d_dirent->d_ino = hash_path_name (dino, res->d_name);
136 res->__ino32 = dir->__d_dirent->d_ino; // for legacy applications
144 if (check_null_invalid_struct_errno (dir))
147 if (dir->__d_cookie != __DIRENT_COOKIE)
149 return ((fhandler_base *) dir->__fh)->telldir (dir);
156 return telldir64 (dir);
160 seekdir64 (DIR *dir, _off64_t loc)
162 if (check_null_invalid_struct_errno (dir))
165 if (dir->__d_cookie != __DIRENT_COOKIE)
168 return ((fhandler_base *) dir->__fh)->seekdir (dir, loc);
173 seekdir (DIR *dir, _off_t loc)
175 seekdir64 (dir, (_off64_t)loc);
178 /* rewinddir: POSIX 5.1.2.1 */
182 if (check_null_invalid_struct_errno (dir))
185 if (dir->__d_cookie != __DIRENT_COOKIE)
188 return ((fhandler_base *) dir->__fh)->rewinddir (dir);
191 /* closedir: POSIX 5.1.2.1 */
195 if (check_null_invalid_struct_errno (dir))
198 if (dir->__d_cookie != __DIRENT_COOKIE)
201 syscall_printf ("-1 = closedir (%p)", dir);
205 /* Reset the marker in case the caller tries to use `dir' again. */
208 int res = ((fhandler_base *) dir->__fh)->closedir (dir);
210 cygheap->fdtab.release (dir->__d_dirent->d_fd);
212 free (dir->__d_dirname);
213 free (dir->__d_dirent);
215 syscall_printf ("%d = closedir (%p)", res);
219 /* mkdir: POSIX 5.4.1.1 */
221 mkdir (const char *dir, mode_t mode)
224 SECURITY_ATTRIBUTES sa = sec_none_nih;
225 security_descriptor sd;
227 path_conv real_dir (dir, PC_SYM_NOFOLLOW | PC_WRITABLE);
231 set_errno (real_dir.case_clash ? ECASECLASH : real_dir.error);
235 nofinalslash (real_dir.get_win32 (), real_dir.get_win32 ());
237 if (allow_ntsec && real_dir.has_acls ())
238 set_security_attribute (S_IFDIR | ((mode & 07777) & ~cygheap->umask),
241 if (CreateDirectoryA (real_dir.get_win32 (), &sa))
243 if (!allow_ntsec && allow_ntea)
244 set_file_attribute (false, NULL, real_dir.get_win32 (),
245 S_IFDIR | ((mode & 07777) & ~cygheap->umask));
246 #ifdef HIDDEN_DOT_FILES
247 char *c = strrchr (real_dir.get_win32 (), '\\');
248 if ((c && c[1] == '.') || *real_dir.get_win32 () == '.')
249 SetFileAttributes (real_dir.get_win32 (), FILE_ATTRIBUTE_HIDDEN);
257 syscall_printf ("%d = mkdir (%s, %d)", res, dir, mode);
261 /* rmdir: POSIX 5.5.2.1 */
263 rmdir (const char *dir)
267 path_conv real_dir (dir, PC_SYM_NOFOLLOW | PC_FULL | PC_WRITABLE);
270 set_errno (real_dir.error);
271 else if (!real_dir.exists ())
273 else if (!real_dir.isdir ())
277 /* Even own directories can't be removed if R/O attribute is set. */
278 if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
279 SetFileAttributes (real_dir,
280 (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY);
282 for (bool is_cwd = false; ; is_cwd = true)
285 int rc = RemoveDirectory (real_dir);
286 DWORD att = GetFileAttributes (real_dir);
288 /* Sometimes smb indicates failure when it really succeeds, so check for
289 this case specifically. */
290 if (rc || att == INVALID_FILE_ATTRIBUTES)
292 /* RemoveDirectory on a samba drive doesn't return an error if the
293 directory can't be removed because it's not empty. Checking for
294 existence afterwards keeps us informed about success. */
295 if (att == INVALID_FILE_ATTRIBUTES)
300 err = ERROR_DIR_NOT_EMPTY;
303 err = GetLastError ();
305 /* This kludge detects if we are attempting to remove the current working
306 directory. If so, we will move elsewhere to potentially allow the
307 rmdir to succeed. This means that cygwin's concept of the current working
308 directory != Windows concept but, hey, whaddaregonnado?
309 Note that this will not cause something like the following to work:
312 since the shell will have foo "open" in the above case and so Windows will
313 not allow the deletion. (Actually it does on 9X.)
314 FIXME: A potential workaround for this is for cygwin apps to *never* call
315 SetCurrentDirectory. */
317 if (strcasematch (real_dir, cygheap->cwd.win32)
318 && !strcasematch ("c:\\", cygheap->cwd.win32)
320 && SetCurrentDirectory ("c:\\"))
323 /* On 9X ERROR_ACCESS_DENIED is returned
324 if you try to remove a non-empty directory. */
325 if (err == ERROR_ACCESS_DENIED
326 && wincap.access_denied_on_delete ())
327 err = ERROR_DIR_NOT_EMPTY;
329 __seterrno_from_win_error (err);
331 /* Directory still exists, restore its characteristics. */
332 if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
333 SetFileAttributes (real_dir, real_dir);
335 SetCurrentDirectory (real_dir);
340 syscall_printf ("%d = rmdir (%s)", res, dir);