1 /* dir.cc: Posix directory-related routines
3 Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
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
17 #define _COMPILING_NEWLIB
28 /* Return whether the directory of a file is writable. Return 1 if it
29 is. Otherwise, return 0, and set errno appropriately. */
31 writable_directory (const char *file)
34 char dir[strlen (file) + 1];
39 char *slash = strrchr (dir, '\\');
42 else if (slash == dir)
52 int acc = access (usedir, W_OK);
60 /* opendir: POSIX 5.1.2.1 */
62 opendir (const char *dirname)
69 path_conv real_dirname (dirname, PC_SYM_FOLLOW | PC_FULL);
71 if (real_dirname.error)
73 set_errno (real_dirname.error);
77 if (stat (myself->rootlen ? dirname : real_dirname.get_win32 (),
81 if (!(statbuf.st_mode & S_IFDIR))
87 len = strlen (real_dirname.get_win32 ());
88 if (len > MAX_PATH - 3)
90 set_errno (ENAMETOOLONG);
94 if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
99 if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
105 if ((dir->__d_dirent =
106 (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
108 free (dir->__d_dirname);
113 strcpy (dir->__d_dirname, real_dirname.get_win32 ());
114 /* FindFirstFile doesn't seem to like duplicate /'s. */
115 len = strlen (dir->__d_dirname);
116 if (len == 0 || SLASH_P (dir->__d_dirname[len - 1]))
117 strcat (dir->__d_dirname, "*");
119 strcat (dir->__d_dirname, "\\*"); /**/
120 dir->__d_cookie = __DIRENT_COOKIE;
121 dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
122 dir->__d_position = 0;
123 dir->__d_dirhash = statbuf.st_ino;
128 syscall_printf ("%p = opendir (%s)", res, dirname);
132 /* readdir: POSIX 5.1.2.1 */
133 extern "C" struct dirent *
138 struct dirent *res = NULL;
140 if (dir->__d_cookie != __DIRENT_COOKIE)
143 syscall_printf ("%p = readdir (%p)", res, dir);
147 if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE)
149 handle = FindFirstFileA (dir->__d_dirname, &buf);
150 DWORD lasterr = GetLastError ();
151 dir->__d_u.__d_data.__handle = handle;
152 if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES))
154 seterrno_from_win_error (__FILE__, __LINE__, lasterr);
158 else if (!FindNextFileA (dir->__d_u.__d_data.__handle, &buf))
160 DWORD lasterr = GetLastError ();
161 (void) FindClose (dir->__d_u.__d_data.__handle);
162 dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
163 /* POSIX says you shouldn't set errno when readdir can't
164 find any more files; so, if another error we leave it set. */
165 if (lasterr != ERROR_NO_MORE_FILES)
166 seterrno_from_win_error (__FILE__, __LINE__, lasterr);
167 syscall_printf ("%p = readdir (%p)", res, dir);
171 /* We get here if `buf' contains valid data. */
172 strcpy (dir->__d_dirent->d_name, buf.cFileName);
174 /* Compute d_ino by combining filename hash with the directory hash
175 (which was stored in dir->__d_dirhash when opendir was called). */
176 if (buf.cFileName[0] == '.')
178 if (buf.cFileName[1] == '\0')
179 dir->__d_dirent->d_ino = dir->__d_dirhash;
180 else if (buf.cFileName[1] != '.' || buf.cFileName[2] != '\0')
184 char *p, up[strlen (dir->__d_dirname) + 1];
185 strcpy (up, dir->__d_dirname);
186 if (!(p = strrchr (up, '\\')))
189 if (!(p = strrchr (up, '\\')))
190 dir->__d_dirent->d_ino = hash_path_name (0, ".");
194 dir->__d_dirent->d_ino = hash_path_name (0, up);
201 ino_t dino = hash_path_name (dir->__d_dirhash, "\\");
202 dir->__d_dirent->d_ino = hash_path_name (dino, buf.cFileName);
206 res = dir->__d_dirent;
207 syscall_printf ("%p = readdir (%p) (%s)",
208 &dir->__d_dirent, dir, buf.cFileName);
216 if (dir->__d_cookie != __DIRENT_COOKIE)
218 return dir->__d_position;
223 seekdir (DIR * dir, off_t loc)
225 if (dir->__d_cookie != __DIRENT_COOKIE)
228 while (loc > dir->__d_position)
233 /* rewinddir: POSIX 5.1.2.1 */
235 rewinddir (DIR * dir)
237 syscall_printf ("rewinddir (%p)", dir);
239 if (dir->__d_cookie != __DIRENT_COOKIE)
241 if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE)
243 (void) FindClose (dir->__d_u.__d_data.__handle);
244 dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
245 dir->__d_position = 0;
249 /* closedir: POSIX 5.1.2.1 */
253 if (dir->__d_cookie != __DIRENT_COOKIE)
256 syscall_printf ("-1 = closedir (%p)", dir);
260 if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE &&
261 FindClose (dir->__d_u.__d_data.__handle) == 0)
264 syscall_printf ("-1 = closedir (%p)", dir);
268 /* Reset the marker in case the caller tries to use `dir' again. */
271 free (dir->__d_dirname);
272 free (dir->__d_dirent);
274 syscall_printf ("0 = closedir (%p)", dir);
278 /* mkdir: POSIX 5.4.1.1 */
280 mkdir (const char *dir, mode_t mode)
284 path_conv real_dir (dir, PC_SYM_NOFOLLOW);
288 set_errno (real_dir.error);
292 nofinalslash(real_dir.get_win32 (), real_dir.get_win32 ());
293 if (! writable_directory (real_dir.get_win32 ()))
296 if (CreateDirectoryA (real_dir.get_win32 (), 0))
298 set_file_attribute (real_dir.has_acls (), real_dir.get_win32 (),
299 S_IFDIR | ((mode & 0777) & ~myself->umask));
306 syscall_printf ("%d = mkdir (%s, %d)", res, dir, mode);
310 /* rmdir: POSIX 5.5.2.1 */
312 rmdir (const char *dir)
316 path_conv real_dir (dir, PC_SYM_NOFOLLOW);
320 set_errno (real_dir.error);
324 if (RemoveDirectoryA (real_dir.get_win32 ()))
326 /* RemoveDirectory on a samba drive doesn't return an error if the
327 directory can't be removed because it's not empty. Checking for
328 existence afterwards keeps us informed about success. */
329 if (GetFileAttributesA (real_dir.get_win32 ()) != (DWORD) -1)
330 set_errno (ENOTEMPTY);
334 else if (GetLastError() == ERROR_ACCESS_DENIED)
336 /* Under Windows 9X or on a samba share, ERROR_ACCESS_DENIED is
337 returned if you try to remove a file. On 9X the same error is
338 returned if you try to remove a non-empty directory. */
339 if (real_dir.file_attributes () != (DWORD) -1 &&
340 !(real_dir.file_attributes () & FILE_ATTRIBUTE_DIRECTORY))
342 else if (os_being_run != winNT)
343 set_errno (ENOTEMPTY);
351 syscall_printf ("%d = rmdir (%s)", res, dir);