1 /* fhandler_disk_file.cc
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
15 #include <sys/cygwin.h>
19 #include "perprocess.h"
21 #include "cygwin/version.h"
26 #include "shared_info.h"
34 #define _COMPILING_NEWLIB
38 path_conv::ndisk_links (DWORD nNumberOfLinks)
40 if (!isdir () || isremote ())
41 return nNumberOfLinks;
43 int len = strlen (*this);
49 if (nNumberOfLinks <= 1)
57 count = nNumberOfLinks;
60 if (len == 0 || isdirsep (fn[len - 1]))
61 strcpy (fn + len, s + 1);
66 HANDLE h = FindFirstFile (fn, &buf);
69 if (h != INVALID_HANDLE_VALUE)
71 if (nNumberOfLinks > 1)
76 if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
78 if (buf.cFileName[0] == '.'
79 && (buf.cFileName[1] == '\0'
80 || (buf.cFileName[1] == '.' && buf.cFileName[2] == '\0')))
83 while (FindNextFileA (h, &buf));
87 if (nNumberOfLinks > 1)
90 h = FindFirstFile (fn, &buf);
96 return count + saw_dot;
100 fhandler_base::fstat_by_handle (struct __stat64 *buf)
102 BY_HANDLE_FILE_INFORMATION local;
104 if (wincap.is_winnt ())
108 /* The entries potentially contain a name of MAX_PATH wide characters. */
109 DWORD fvi_size = 2 * CYG_MAX_PATH + sizeof (FILE_FS_VOLUME_INFORMATION);
110 DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION);
112 PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
114 PFILE_ALL_INFORMATION pfai = (PFILE_ALL_INFORMATION) alloca (fai_size);
116 status = NtQueryVolumeInformationFile (get_handle (), &io, pfvi, fvi_size,
117 FileFsVolumeInformation);
118 if (!NT_SUCCESS (status))
120 debug_printf ("%u = NtQueryVolumeInformationFile)",
121 RtlNtStatusToDosError (status));
122 pfvi->VolumeSerialNumber = 0; /* Set to pc.volser () in helper. */
124 status = NtQueryInformationFile (get_handle (), &io, pfai, fai_size,
126 if (NT_SUCCESS (status))
127 /* If the change time is 0, it's a file system which doesn't
128 support a change timestamp. In that case use the LastWriteTime
129 entry, as in other calls to fstat_helper. */
130 return fstat_helper (buf,
131 pfai->BasicInformation.ChangeTime.QuadPart ?
132 *(FILETIME *) &pfai->BasicInformation.ChangeTime :
133 *(FILETIME *) &pfai->BasicInformation.LastWriteTime,
134 *(FILETIME *) &pfai->BasicInformation.LastAccessTime,
135 *(FILETIME *) &pfai->BasicInformation.LastWriteTime,
136 pfvi->VolumeSerialNumber,
137 pfai->StandardInformation.EndOfFile.HighPart,
138 pfai->StandardInformation.EndOfFile.LowPart,
139 pfai->StandardInformation.AllocationSize.QuadPart,
140 pfai->InternalInformation.IndexNumber.HighPart,
141 pfai->InternalInformation.IndexNumber.LowPart,
142 pfai->StandardInformation.NumberOfLinks);
144 debug_printf ("%u = NtQueryInformationFile)",
145 RtlNtStatusToDosError (status));
148 BOOL res = GetFileInformationByHandle (get_handle (), &local);
149 debug_printf ("%d = GetFileInformationByHandle (%s, %d)",
150 res, get_win32_name (), get_handle ());
151 /* GetFileInformationByHandle will fail if it's given stdio handle or pipe.
152 It also fails on 9x when trying to access directories on shares. */
155 memset (&local, 0, sizeof (local));
156 local.nFileSizeLow = GetFileSize (get_handle (), &local.nFileSizeHigh);
157 /* Even GetFileSize fails on 9x when trying to access directories
158 on shares. In this case reset filesize to 0. */
159 if (local.nFileSizeLow == 0xffffffff && GetLastError ())
160 local.nFileSizeLow = 0;
163 return fstat_helper (buf,
164 local.ftLastWriteTime, /* see fstat_helper comment */
165 local.ftLastAccessTime,
166 local.ftLastWriteTime,
167 local.dwVolumeSerialNumber,
171 local.nFileIndexHigh,
173 local.nNumberOfLinks);
177 fhandler_base::fstat_by_name (struct __stat64 *buf)
181 WIN32_FIND_DATA local;
185 debug_printf ("already determined that pc does not exist");
189 else if ((handle = FindFirstFile (pc, &local)) != INVALID_HANDLE_VALUE)
192 res = fstat_helper (buf,
193 local.ftLastWriteTime, /* see fstat_helper comment */
194 local.ftLastAccessTime,
195 local.ftLastWriteTime,
204 else if (pc.isdir ())
207 res = fstat_helper (buf, ft, ft, ft, pc.volser (), 0, 0, -1LL, 0, 0, 1);
211 debug_printf ("FindFirstFile failed for '%s', %E", (char *) pc);
219 fhandler_base::fstat_fs (struct __stat64 *buf)
223 int open_flags = O_RDONLY | O_BINARY;
225 if (get_io_handle ())
227 if (nohandle () || is_fs_special ())
228 return fstat_by_name (buf);
230 return fstat_by_handle (buf);
232 /* If we don't care if the file is executable or we already know if it is,
233 then just do a "query open" as it is apparently much faster. */
234 if (pc.exec_state () != dont_know_if_executable)
236 if (pc.fs_is_fat () && !strpbrk (get_win32_name (), "?*|<>"))
237 return fstat_by_name (buf);
238 query_open (query_stat_control);
240 if (!(oret = open_fs (open_flags, 0)) && get_errno () == EACCES)
242 /* If we couldn't open the file, try a query open with no permissions.
243 This allows us to determine *some* things about the file, at least. */
245 query_open (query_read_control);
246 oret = open_fs (open_flags, 0);
251 /* We now have a valid handle, regardless of the "nohandle" state.
252 Since fhandler_base::open only calls CloseHandle if !nohandle,
253 we have to set it to false before calling close_fs and restore
254 the state afterwards. */
255 res = fstat_by_handle (buf);
256 bool no_handle = nohandle ();
259 nohandle (no_handle);
260 set_io_handle (NULL);
263 res = fstat_by_name (buf);
268 /* The ftChangeTime is taken from the NTFS ChangeTime entry, if reading
269 the file information using NtQueryInformationFile succeeded. If not,
270 it's faked using the LastWriteTime entry from GetFileInformationByHandle
271 or FindFirstFile. We're deliberatly not using the creation time anymore
272 to simplify interaction with native Windows applications which choke on
273 creation times >= access or write times. */
275 fhandler_base::fstat_helper (struct __stat64 *buf,
276 FILETIME ftChangeTime,
277 FILETIME ftLastAccessTime,
278 FILETIME ftLastWriteTime,
279 DWORD dwVolumeSerialNumber,
283 DWORD nFileIndexHigh,
285 DWORD nNumberOfLinks)
288 FILE_COMPRESSION_INFORMATION fci;
290 to_timestruc_t (&ftLastAccessTime, &buf->st_atim);
291 to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
292 to_timestruc_t (&ftChangeTime, &buf->st_ctim);
293 buf->st_dev = dwVolumeSerialNumber ?: pc.volser ();
294 buf->st_size = ((_off64_t) nFileSizeHigh << 32) + nFileSizeLow;
295 /* The number of links to a directory includes the
296 number of subdirectories in the directory, since all
297 those subdirectories point to it.
298 This is too slow on remote drives, so we do without it.
299 Setting the count to 2 confuses `find (1)' command. So
300 let's try it with `1' as link count. */
301 buf->st_nlink = pc.ndisk_links (nNumberOfLinks);
303 /* Assume that if a drive has ACL support it MAY have valid "inodes".
304 It definitely does not have valid inodes if it does not have ACL
306 switch (pc.has_acls () && (nFileIndexHigh || nFileIndexLow)
307 ? pc.drive_type () : DRIVE_UNKNOWN)
310 case DRIVE_REMOVABLE:
313 /* Although the documentation indicates otherwise, it seems like
314 "inodes" on these devices are persistent, at least across reboots. */
315 buf->st_ino = (((__ino64_t) nFileIndexHigh) << 32)
316 | (__ino64_t) nFileIndexLow;
319 /* Either the nFileIndex* fields are unreliable or unavailable. Use the
320 next best alternative. */
321 buf->st_ino = get_namehash ();
325 buf->st_blksize = S_BLKSIZE;
327 if (nAllocSize >= 0LL)
328 /* A successful NtQueryInformationFile returns the allocation size
329 correctly for compressed and sparse files as well. */
330 buf->st_blocks = (nAllocSize + S_BLKSIZE - 1) / S_BLKSIZE;
331 else if (pc.has_attribute (FILE_ATTRIBUTE_COMPRESSED
332 | FILE_ATTRIBUTE_SPARSE_FILE)
333 && get_io_handle () && !is_fs_special ()
334 && !NtQueryInformationFile (get_io_handle (), &st, (PVOID) &fci,
335 sizeof fci, FileCompressionInformation))
336 /* Otherwise we request the actual amount of bytes allocated for
337 compressed and sparsed files. */
338 buf->st_blocks = (fci.CompressedSize.QuadPart + S_BLKSIZE - 1) / S_BLKSIZE;
340 /* Otherwise compute no. of blocks from file size. */
341 buf->st_blocks = (buf->st_size + S_BLKSIZE - 1) / S_BLKSIZE;
344 /* Using a side effect: get_file_attibutes checks for
345 directory. This is used, to set S_ISVTX, if needed. */
347 buf->st_mode = S_IFDIR;
348 else if (pc.issymlink ())
350 buf->st_size = pc.get_symlink_length ();
351 /* symlinks are everything for everyone! */
352 buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
353 get_file_attribute (pc.has_acls (), get_io_handle (), get_win32_name (),
354 NULL, &buf->st_uid, &buf->st_gid);
357 else if (pc.issocket ())
358 buf->st_mode = S_IFSOCK;
360 if (!get_file_attribute (pc.has_acls (), is_fs_special () ? NULL: get_io_handle (),
361 get_win32_name (), &buf->st_mode, &buf->st_uid, &buf->st_gid))
363 /* If read-only attribute is set, modify ntsec return value */
364 if (pc.has_attribute (FILE_ATTRIBUTE_READONLY) && !pc.issymlink ())
365 buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
367 if (buf->st_mode & S_IFMT)
369 else if (!is_fs_special ())
370 buf->st_mode |= S_IFREG;
373 buf->st_dev = dev ();
374 buf->st_mode = dev ().mode;
379 buf->st_mode |= STD_RBITS;
381 if (!pc.has_attribute (FILE_ATTRIBUTE_READONLY) && !pc.issymlink ())
382 buf->st_mode |= STD_WBITS;
383 /* | S_IWGRP | S_IWOTH; we don't give write to group etc */
385 if (S_ISDIR (buf->st_mode))
386 buf->st_mode |= S_IFDIR | STD_XBITS;
387 else if (buf->st_mode & S_IFMT)
389 else if (is_fs_special ())
391 buf->st_dev = dev ();
392 buf->st_mode = dev ().mode;
396 buf->st_mode |= S_IFREG;
397 if (pc.exec_state () == dont_know_if_executable)
402 /* First retrieve current position, set to beginning
403 of file if not already there. */
404 cur = SetFilePointer (get_handle (), 0, NULL, FILE_CURRENT);
405 if (cur != INVALID_SET_FILE_POINTER
406 && (!cur || SetFilePointer (get_handle (), 0, NULL, FILE_BEGIN)
407 != INVALID_SET_FILE_POINTER))
409 /* FIXME should we use /etc/magic ? */
410 magic[0] = magic[1] = magic[2] = '\0';
411 if (ReadFile (get_handle (), magic, 3, &done, NULL)
412 && has_exec_chars (magic, done))
415 buf->st_mode |= STD_XBITS;
417 SetFilePointer (get_handle (), cur, NULL, FILE_BEGIN);
422 if (pc.exec_state () == is_executable)
423 buf->st_mode |= STD_XBITS;
425 /* This fakes the permissions of all files to match the current umask. */
426 buf->st_mode &= ~(cygheap->umask);
430 syscall_printf ("0 = fstat (, %p) st_atime=%x st_size=%D, st_mode=%p, st_ino=%d, sizeof=%d",
431 buf, buf->st_atime, buf->st_size, buf->st_mode,
432 (int) buf->st_ino, sizeof (*buf));
437 fhandler_disk_file::fstat (struct __stat64 *buf)
439 /* Changing inode data requires setting ctime (only 9x). */
442 return fstat_fs (buf);
446 fhandler_disk_file::touch_ctime ()
450 GetSystemTimeAsFileTime (&ft);
451 /* Modification time is touched if the file data has changed as well.
452 This happens for instance on write() or ftruncate(). */
453 if (!SetFileTime (get_io_handle (), NULL, NULL, &ft))
454 debug_printf ("SetFileTime (%s) failed, %E", get_win32_name ());
460 fhandler_disk_file::fchmod (mode_t mode)
462 extern int chmod_device (path_conv& pc, mode_t mode);
466 if (pc.is_fs_special ())
467 return chmod_device (pc, mode);
469 /* Also open on 9x, otherwise we can't touch ctime. */
470 if (!get_io_handle ())
472 query_open (query_write_control);
473 if (!(oret = open (O_BINARY, 0)))
475 /* If the file couldn't be opened, that's really only a problem if
476 ACLs or EAs should get written. */
477 if ((allow_ntsec && pc.has_acls ()) || allow_ntea)
482 if ((allow_ntsec && pc.has_acls ()) || allow_ntea)
484 if (!allow_ntsec && allow_ntea) /* Not necessary when manipulating SD. */
485 SetFileAttributes (pc, (DWORD) pc & ~FILE_ATTRIBUTE_READONLY);
488 if (!set_file_attribute (pc.has_acls (), get_io_handle (), pc,
489 ILLEGAL_UID, ILLEGAL_GID, mode)
494 /* if the mode we want has any write bits set, we can't be read only. */
495 if (mode & (S_IWUSR | S_IWGRP | S_IWOTH))
496 pc &= (DWORD) ~FILE_ATTRIBUTE_READONLY;
498 pc |= (DWORD) FILE_ATTRIBUTE_READONLY;
500 if (!SetFileAttributes (pc, pc))
502 else if (!allow_ntsec || !pc.has_acls ())
503 /* Correct NTFS security attributes have higher priority */
506 /* Set ctime on success. */
507 if (!res && !wincap.is_winnt ())
517 fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid)
521 if (!pc.has_acls () || !allow_ntsec)
523 /* fake - if not supported, pretend we're like win95
524 where it just works */
528 if (!get_io_handle ())
530 query_open (query_write_control);
531 if (!(oret = fhandler_disk_file::open (O_BINARY, 0)))
538 int res = get_file_attribute (pc.has_acls (), get_io_handle (), pc, &attrib);
540 res = set_file_attribute (pc.has_acls (), get_io_handle (), pc,
550 fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp)
555 if (!pc.has_acls () || !allow_ntsec)
562 /* Open for writing required to be able to set ctime
563 (even though setting the ACL is just pretended). */
564 if (!get_io_handle ())
565 oret = open (O_WRONLY | O_BINARY, 0);
571 else if (nentries < MIN_ACL_ENTRIES)
575 if (!get_io_handle ())
577 query_open (query_read_control);
578 if (!(oret = open (O_BINARY, 0)))
581 if (!fstat_by_handle (&st))
583 aclbufp[0].a_type = USER_OBJ;
584 aclbufp[0].a_id = st.st_uid;
585 aclbufp[0].a_perm = (st.st_mode & S_IRWXU) >> 6;
586 aclbufp[1].a_type = GROUP_OBJ;
587 aclbufp[1].a_id = st.st_gid;
588 aclbufp[1].a_perm = (st.st_mode & S_IRWXG) >> 3;
589 aclbufp[2].a_type = OTHER_OBJ;
590 aclbufp[2].a_id = ILLEGAL_GID;
591 aclbufp[2].a_perm = st.st_mode & S_IRWXO;
592 aclbufp[3].a_type = CLASS_OBJ;
593 aclbufp[3].a_id = ILLEGAL_GID;
594 aclbufp[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
595 res = MIN_ACL_ENTRIES;
600 res = MIN_ACL_ENTRIES;
609 if (!get_io_handle ())
611 query_open (cmd == SETACL ? query_write_control : query_read_control);
612 if (!(oret = open (O_BINARY, 0)))
618 if (!aclsort32 (nentries, 0, aclbufp))
619 res = setacl (get_io_handle (), pc, nentries, aclbufp);
625 res = getacl (get_io_handle (), pc, pc, nentries, aclbufp);
628 res = getacl (get_io_handle (), pc, pc, 0, NULL);
643 fhandler_disk_file::ftruncate (_off64_t length)
645 int res = -1, res_bug = 0;
647 if (length < 0 || !get_output_handle ())
649 else if (pc.isdir ())
651 else if (!(get_access () & GENERIC_WRITE))
655 _off64_t prev_loc = lseek (0, SEEK_CUR);
656 if (lseek (length, SEEK_SET) >= 0)
658 if (get_fs_flags (FILE_SUPPORTS_SPARSE_FILES))
660 _off64_t actual_length;
662 actual_length = GetFileSize (get_output_handle (), &size_high);
663 actual_length += ((_off64_t) size_high) << 32;
664 if (length >= actual_length + (128 * 1024))
667 BOOL r = DeviceIoControl (get_output_handle (),
668 FSCTL_SET_SPARSE, NULL, 0, NULL,
670 syscall_printf ("%d = DeviceIoControl(%p, FSCTL_SET_SPARSE)",
671 r, get_output_handle ());
674 else if (wincap.has_lseek_bug ())
675 res_bug = write (&res, 0);
676 if (!SetEndOfFile (get_output_handle ()))
680 /* restore original file pointer location */
681 lseek (prev_loc, SEEK_SET);
688 fhandler_disk_file::link (const char *newpath)
690 path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX);
691 extern bool allow_winsymlinks;
695 set_errno (newpc.case_clash ? ECASECLASH : newpc.error);
701 syscall_printf ("file '%s' exists?", (char *) newpc);
706 if (newpc[strlen (newpc) - 1] == '.')
708 syscall_printf ("trailing dot, bailing out");
714 char new_lnk_buf[CYG_MAX_PATH + 5];
715 if (allow_winsymlinks && pc.is_lnk_special () && !newpc.case_clash)
717 strcpy (new_lnk_buf, newpath);
718 strcat (new_lnk_buf, ".lnk");
719 newpath = new_lnk_buf;
720 newpc.check (newpath, PC_SYM_NOFOLLOW);
723 query_open (query_write_attributes);
724 if (!open (O_BINARY, 0))
726 syscall_printf ("Opening file failed");
731 /* Try to make hard link first on Windows NT */
732 if (wincap.has_hard_links ())
734 if (CreateHardLinkA (newpc, pc, NULL))
737 /* There are two cases to consider:
738 - The FS doesn't support hard links ==> ERROR_INVALID_FUNCTION
740 - CreateHardLinkA is not supported ==> ERROR_PROC_NOT_FOUND
741 In that case (<= NT4) we try the old-style method.
742 Any other error should be taken seriously. */
743 if (GetLastError () == ERROR_INVALID_FUNCTION)
745 syscall_printf ("FS doesn't support hard links: Copy file");
748 if (GetLastError () != ERROR_PROC_NOT_FOUND)
750 syscall_printf ("CreateHardLinkA failed");
756 WIN32_STREAM_ID stream_id;
758 WCHAR wbuf[CYG_MAX_PATH];
760 DWORD written, write_err, path_len, size;
762 path_len = sys_mbstowcs (wbuf, newpc, CYG_MAX_PATH) * sizeof (WCHAR);
764 stream_id.dwStreamId = BACKUP_LINK;
765 stream_id.dwStreamAttributes = 0;
766 stream_id.dwStreamNameSize = 0;
767 stream_id.Size.HighPart = 0;
768 stream_id.Size.LowPart = path_len;
769 size = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**)
770 + stream_id.dwStreamNameSize;
773 /* Write WIN32_STREAM_ID */
774 ret = BackupWrite (get_handle (), (LPBYTE) &stream_id, size,
775 &written, FALSE, FALSE, &context);
778 /* write the buffer containing the path */
779 /* FIXME: BackupWrite sometimes traps if linkname is invalid.
781 ret = BackupWrite (get_handle (), (LPBYTE) wbuf, path_len,
782 &written, FALSE, FALSE, &context);
785 write_err = GetLastError ();
786 syscall_printf ("cannot write linkname, %E");
789 BackupWrite (get_handle (), NULL, 0, &written,
790 TRUE, FALSE, &context);
794 write_err = GetLastError ();
795 syscall_printf ("cannot write stream_id, %E");
800 /* Only copy file if FS doesn't support hard links */
801 if (write_err == ERROR_INVALID_FUNCTION)
803 syscall_printf ("FS doesn't support hard links: Copy file");
808 __seterrno_from_win_error (write_err);
814 if (!allow_winsymlinks && pc.is_lnk_special ())
815 SetFileAttributes (newpc, (DWORD) pc
816 | FILE_ATTRIBUTE_SYSTEM
817 | FILE_ATTRIBUTE_READONLY);
821 /* do this with a copy */
822 if (!CopyFileA (pc, newpc, 1))
827 /* Set ctime on success (copy gets it automatically). */
828 if (!wincap.is_winnt ())
831 fhandler_disk_file fh (newpc);
832 fh.query_open (query_write_attributes);
833 if (fh.open (O_BINARY, 0))
839 fhandler_disk_file::utimes (const struct timeval *tvp)
841 return utimes_fs (tvp);
845 fhandler_base::utimes_fs (const struct timeval *tvp)
847 FILETIME lastaccess, lastwrite;
848 struct timeval tmp[2];
850 query_open (query_write_attributes);
851 if (!open_fs (O_BINARY, 0))
853 /* It's documented in MSDN that FILE_WRITE_ATTRIBUTES is sufficient
854 to change the timestamps. Unfortunately it's not sufficient for a
855 remote HPFS which requires GENERIC_WRITE, so we just retry to open
856 for writing, though this fails for R/O files of course. */
857 query_open (no_query);
858 if (!open_fs (O_WRONLY | O_BINARY, 0))
860 syscall_printf ("Opening file failed");
865 if (nohandle ()) /* Directory query_open on 9x. */
868 gettimeofday (&tmp[0], 0);
874 timeval_to_filetime (&tvp[0], &lastaccess);
875 timeval_to_filetime (&tvp[1], &lastwrite);
876 debug_printf ("incoming lastaccess %08x %08x", tvp[0].tv_sec, tvp[0].tv_usec);
878 if (is_fs_special ())
879 SetFileAttributes (pc, (DWORD) pc & ~FILE_ATTRIBUTE_READONLY);
880 BOOL res = SetFileTime (get_handle (), NULL, &lastaccess, &lastwrite);
881 DWORD errcode = GetLastError ();
882 if (is_fs_special ())
883 SetFileAttributes (pc, pc);
884 /* Opening a directory on a 9x share from a NT machine works(!), but
885 then the SetFileTimes fails with ERROR_NOT_SUPPORTED. Oh well... */
886 if (!res && errcode != ERROR_NOT_SUPPORTED)
889 __seterrno_from_win_error (errcode);
897 fhandler_disk_file::fhandler_disk_file () :
902 fhandler_disk_file::fhandler_disk_file (path_conv &pc) :
909 fhandler_disk_file::open (int flags, mode_t mode)
911 return open_fs (flags, mode);
915 fhandler_base::open_fs (int flags, mode_t mode)
917 if (pc.case_clash && flags & O_CREAT)
919 debug_printf ("case clash detected");
920 set_errno (ECASECLASH);
924 /* Unfortunately NT allows to open directories for writing, but that's
925 disallowed according to SUSv3. */
926 if (pc.isdir () && (flags & (O_WRONLY | O_RDWR)))
932 int res = fhandler_base::open (flags | O_DIROPEN, mode);
936 /* This is for file systems known for having a buggy CreateFile call
937 which might return a valid HANDLE without having actually opened
939 The only known file system to date is the SUN NFS Solstice Client 3.1
940 which returns a valid handle when trying to open a file in a nonexistent
942 if (pc.has_buggy_open () && !pc.exists ())
944 debug_printf ("Buggy open detected.");
950 /* Attributes may be set only if a file is _really_ created.
951 This code is now only used for ntea here since the files
952 security attributes are set in CreateFile () now. */
954 && GetLastError () != ERROR_ALREADY_EXISTS
955 && !allow_ntsec && allow_ntea)
956 set_file_attribute (false, NULL, get_win32_name (), mode);
958 set_fs_flags (pc.fs_flags ());
961 syscall_printf ("%d = fhandler_disk_file::open (%s, %p)", res,
962 get_win32_name (), flags);
967 fhandler_disk_file::close ()
971 /* Changing inode data requires setting ctime (only 9x). */
979 fhandler_base::close_fs ()
981 int res = fhandler_base::close ();
983 user_shared->delqueue.process_queue ();
988 fhandler_disk_file::pread (void *buf, size_t count, _off64_t offset)
991 _off64_t curpos = lseek (0, SEEK_CUR);
992 if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
996 size_t tmp_count = count;
997 read (buf, tmp_count);
998 if (lseek (curpos, SEEK_SET) == 0)
999 res = (ssize_t) tmp_count;
1003 debug_printf ("%d = pread (%p, %d, %d)\n", res, buf, count, offset);
1008 fhandler_disk_file::pwrite (void *buf, size_t count, _off64_t offset)
1011 _off64_t curpos = lseek (0, SEEK_CUR);
1012 if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
1016 res = (ssize_t) write (buf, count);
1017 if (lseek (curpos, SEEK_SET) < 0)
1020 debug_printf ("%d = pwrite (%p, %d, %d)\n", res, buf, count, offset);
1024 /* FIXME: The correct way to do this to get POSIX locking semantics is to
1025 keep a linked list of posix lock requests and map them into Win32 locks.
1026 he problem is that Win32 does not deal correctly with overlapping lock
1027 requests. Also another pain is that Win95 doesn't do non-blocking or
1028 non-exclusive locks at all. For '95 just convert all lock requests into
1029 blocking,exclusive locks. This shouldn't break many apps but denying all
1030 locking would. For now just convert to Win32 locks and hope for
1034 fhandler_disk_file::lock (int cmd, struct __flock64 *fl)
1036 _off64_t win32_start;
1041 * We don't do getlck calls yet.
1051 * Calculate where in the file to start from,
1052 * then adjust this by fl->l_start.
1055 switch (fl->l_whence)
1061 if ((startpos = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK)
1066 BY_HANDLE_FILE_INFORMATION finfo;
1067 if (GetFileInformationByHandle (get_handle (), &finfo) == 0)
1072 startpos = ((_off64_t)finfo.nFileSizeHigh << 32)
1073 + finfo.nFileSizeLow;
1082 * Now the fun starts. Adjust the start and length
1083 * fields until they make sense.
1086 win32_start = startpos + fl->l_start;
1089 win32_start -= fl->l_len;
1090 win32_len = -fl->l_len;
1093 win32_len = fl->l_len;
1095 if (win32_start < 0)
1097 /* watch the signs! */
1098 win32_len -= -win32_start;
1108 DWORD off_high, off_low, len_high, len_low;
1110 off_low = (DWORD)(win32_start & UINT32_MAX);
1111 off_high = (DWORD)(win32_start >> 32);
1114 /* Special case if len == 0 for POSIX means lock to the end of
1115 the entire file (and all future extensions). */
1116 /* CV, 2003-12-03: And yet another Win 9x bugginess. For some reason
1117 offset + length must be <= 0x100000000. I'm using 0xffffffff as
1118 upper border here, this should be sufficient. */
1119 len_low = UINT32_MAX - (wincap.lock_file_highword () ? 0 : off_low);
1120 len_high = wincap.lock_file_highword ();
1124 len_low = (DWORD)(win32_len & UINT32_MAX);
1125 len_high = (DWORD)(win32_len >> 32);
1130 if (wincap.has_lock_file_ex ())
1132 DWORD lock_flags = (cmd == F_SETLK) ? LOCKFILE_FAIL_IMMEDIATELY : 0;
1133 lock_flags |= (fl->l_type == F_WRLCK) ? LOCKFILE_EXCLUSIVE_LOCK : 0;
1138 ov.InternalHigh = 0;
1139 ov.Offset = off_low;
1140 ov.OffsetHigh = off_high;
1141 ov.hEvent = (HANDLE) 0;
1143 if (fl->l_type == F_UNLCK)
1145 res = UnlockFileEx (get_handle (), 0, len_low, len_high, &ov);
1149 res = LockFileEx (get_handle (), lock_flags, 0,
1150 len_low, len_high, &ov);
1151 /* Deal with the fail immediately case. */
1153 * FIXME !! I think this is the right error to check for
1154 * but I must admit I haven't checked....
1156 if ((res == 0) && (lock_flags & LOCKFILE_FAIL_IMMEDIATELY) &&
1157 (GetLastError () == ERROR_LOCK_FAILED))
1166 /* Windows 95 -- use primitive lock call */
1167 if (fl->l_type == F_UNLCK)
1168 res = UnlockFile (get_handle (), off_low, off_high, len_low, len_high);
1170 res = LockFile (get_handle (), off_low, off_high, len_low, len_high);
1183 fhandler_disk_file::mkdir (mode_t mode)
1186 SECURITY_ATTRIBUTES sa = sec_none_nih;
1187 security_descriptor sd;
1189 if (allow_ntsec && has_acls ())
1190 set_security_attribute (S_IFDIR | ((mode & 07777) & ~cygheap->umask),
1193 if (CreateDirectoryA (get_win32_name (), &sa))
1195 if (!allow_ntsec && allow_ntea)
1196 set_file_attribute (false, NULL, get_win32_name (),
1197 S_IFDIR | ((mode & 07777) & ~cygheap->umask));
1198 #ifdef HIDDEN_DOT_FILES
1199 char *c = strrchr (real_dir.get_win32 (), '\\');
1200 if ((c && c[1] == '.') || *get_win32_name () == '.')
1201 SetFileAttributes (get_win32_name (), FILE_ATTRIBUTE_HIDDEN);
1212 fhandler_disk_file::rmdir ()
1216 /* Even own directories can't be removed if R/O attribute is set. */
1217 if (pc.has_attribute (FILE_ATTRIBUTE_READONLY))
1218 SetFileAttributes (get_win32_name (),
1219 (DWORD) pc & ~FILE_ATTRIBUTE_READONLY);
1221 for (bool is_cwd = false; ; is_cwd = true)
1224 int rc = RemoveDirectory (get_win32_name ());
1226 if (isremote () && exists ())
1227 att = GetFileAttributes (get_win32_name ());
1229 /* Sometimes smb indicates failure when it really succeeds, so check for
1230 this case specifically. */
1231 if (rc || att == INVALID_FILE_ATTRIBUTES)
1233 /* RemoveDirectory on a samba drive doesn't return an error if the
1234 directory can't be removed because it's not empty. Checking for
1235 existence afterwards keeps us informed about success. */
1236 if (!isremote () || att == INVALID_FILE_ATTRIBUTES)
1241 err = ERROR_DIR_NOT_EMPTY;
1244 err = GetLastError ();
1246 /* This kludge detects if we are attempting to remove the current working
1247 directory. If so, we will move elsewhere to potentially allow the
1248 rmdir to succeed. This means that cygwin's concept of the current working
1249 directory != Windows concept but, hey, whaddaregonnado?
1250 Note that this will not cause something like the following to work:
1253 since the shell will have foo "open" in the above case and so Windows will
1254 not allow the deletion. (Actually it does on 9X.)
1255 FIXME: A potential workaround for this is for cygwin apps to *never* call
1256 SetCurrentDirectory. */
1258 extern char windows_system_directory[];
1259 if (strcasematch (get_win32_name (), cygheap->cwd.win32)
1260 && !strcasematch (windows_system_directory, cygheap->cwd.win32)
1262 && SetCurrentDirectory (windows_system_directory))
1265 /* On 9X ERROR_ACCESS_DENIED is returned
1266 if you try to remove a non-empty directory. */
1267 if (err == ERROR_ACCESS_DENIED
1268 && wincap.access_denied_on_delete ())
1269 err = ERROR_DIR_NOT_EMPTY;
1271 __seterrno_from_win_error (err);
1273 /* Directory still exists, restore its characteristics. */
1274 if (pc.has_attribute (FILE_ATTRIBUTE_READONLY))
1275 SetFileAttributes (get_win32_name (), (DWORD) pc);
1277 SetCurrentDirectory (get_win32_name ());
1285 fhandler_disk_file::opendir ()
1290 path_conv rootdir ("/");
1293 set_errno (ENOTDIR);
1294 else if ((len = strlen (pc)) > CYG_MAX_PATH - 3)
1295 set_errno (ENAMETOOLONG);
1296 else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
1298 else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
1303 else if ((dir->__d_dirent =
1304 (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
1309 else if (fhaccess (R_OK) != 0)
1313 strcpy (dir->__d_dirname, get_win32_name ());
1314 dir->__d_dirent->d_version = __DIRENT_VERSION;
1321 fd->nohandle (true);
1322 dir->__d_dirent->d_fd = fd;
1324 /* FindFirstFile doesn't seem to like duplicate /'s. */
1325 len = strlen (dir->__d_dirname);
1326 if (len == 0 || isdirsep (dir->__d_dirname[len - 1]))
1327 strcat (dir->__d_dirname, "*");
1329 strcat (dir->__d_dirname, "\\*"); /**/
1330 dir->__d_cookie = __DIRENT_COOKIE;
1331 dir->__handle = INVALID_HANDLE_VALUE;
1332 dir->__d_position = 0;
1333 dir->__d_dirhash = get_namehash ();
1336 dir->__flags = strcasematch (pc, rootdir) ? dirent_isroot : 0;
1339 syscall_printf ("%p = opendir (%s)", res, get_name ());
1343 free (dir->__d_dirent);
1345 free (dir->__d_dirname);
1352 fhandler_disk_file::readdir (DIR *dir, dirent *de)
1354 WIN32_FIND_DATA buf;
1363 if (dir->__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0)
1365 handle = FindFirstFileA (dir->__d_dirname, &buf);
1366 DWORD lasterr = GetLastError ();
1367 dir->__handle = handle;
1368 if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES))
1370 res = geterrno_from_win_error ();
1374 else if (dir->__handle == INVALID_HANDLE_VALUE)
1379 else if (!FindNextFileA (dir->__handle, &buf))
1382 if (!(dir->__flags & dirent_isroot))
1384 else if (0 && !(dir->__flags & dirent_saw_dev))
1386 strcpy (buf.cFileName, "dev");
1389 else if (!(dir->__flags & dirent_saw_proc))
1391 strcpy (buf.cFileName, "proc");
1394 else if (!(dir->__flags & dirent_saw_cygdrive)
1395 && mount_table->cygdrive_len > 1)
1397 strcpy (buf.cFileName, mount_table->cygdrive + 1);
1398 buf.cFileName[mount_table->cygdrive_len - 2] = '\0';
1403 buf.dwFileAttributes = 0;
1406 res = geterrno_from_win_error ();
1407 FindClose (dir->__handle);
1408 dir->__handle = NULL;
1413 /* Check for Windows shortcut. If it's a Cygwin or U/WIN
1414 symlink, drop the .lnk suffix. */
1415 if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1417 char *c = buf.cFileName;
1418 int len = strlen (c);
1419 if (strcasematch (c + len - 4, ".lnk"))
1421 char fbuf[CYG_MAX_PATH];
1422 strcpy (fbuf, dir->__d_dirname);
1423 strcpy (fbuf + strlen (fbuf) - 1, c);
1424 path_conv fpath (fbuf, PC_SYM_NOFOLLOW);
1425 if (fpath.issymlink () || fpath.isspecial ())
1430 /* We get here if `buf' contains valid data. */
1431 if (pc.isencoded ())
1432 fnunmunge (de->d_name, buf.cFileName);
1434 strcpy (de->d_name, buf.cFileName);
1435 if (dir->__flags && dirent_isroot)
1437 if (strcasematch (de->d_name, "dev"))
1438 dir->__flags |= dirent_saw_dev;
1439 else if (strcasematch (de->d_name, "proc"))
1440 dir->__flags |= dirent_saw_proc;
1441 if (strlen (de->d_name) == mount_table->cygdrive_len - 2
1442 && strncasematch (de->d_name, mount_table->cygdrive + 1,
1443 mount_table->cygdrive_len - 2))
1444 dir->__flags |= dirent_saw_cygdrive;
1447 dir->__d_position++;
1450 syscall_printf ("%d = readdir (%p) (%s)", dir, &de, de->d_name);
1455 fhandler_disk_file::telldir (DIR *dir)
1457 return dir->__d_position;
1461 fhandler_disk_file::seekdir (DIR *dir, _off64_t loc)
1464 while (loc > dir->__d_position)
1465 if (!::readdir (dir))
1470 fhandler_disk_file::rewinddir (DIR *dir)
1472 if (dir->__handle != INVALID_HANDLE_VALUE)
1475 FindClose (dir->__handle);
1476 dir->__handle = INVALID_HANDLE_VALUE;
1478 dir->__d_position = 0;
1482 fhandler_disk_file::closedir (DIR *dir)
1485 if (dir->__handle && dir->__handle != INVALID_HANDLE_VALUE
1486 && FindClose (dir->__handle) == 0)
1491 syscall_printf ("%d = closedir (%p)", res, dir);
1495 fhandler_cygdrive::fhandler_cygdrive () :
1496 fhandler_disk_file (), ndrives (0), pdrive (NULL)
1500 #define DRVSZ sizeof ("x:\\")
1502 fhandler_cygdrive::set_drives ()
1504 const int len = 2 + 26 * DRVSZ;
1505 char *p = const_cast<char *> (get_win32_name ());
1507 ndrives = GetLogicalDriveStrings (len, p) / DRVSZ;
1511 fhandler_cygdrive::fstat (struct __stat64 *buf)
1513 buf->st_mode = S_IFDIR | 0555;
1516 buf->st_nlink = ndrives + 2;
1521 fhandler_cygdrive::opendir ()
1525 dir = fhandler_disk_file::opendir ();
1526 if (dir && !ndrives)
1533 fhandler_cygdrive::readdir (DIR *dir, dirent *de)
1535 if (!pdrive || !*pdrive)
1537 if (GetFileAttributes (pdrive) == INVALID_FILE_ATTRIBUTES)
1539 pdrive = strchr (pdrive, '\0') + 1;
1540 return readdir (dir, de);
1543 *de->d_name = cyg_tolower (*pdrive);
1544 de->d_name[1] = '\0';
1545 dir->__d_position++;
1546 pdrive = strchr (pdrive, '\0') + 1;
1547 syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name);
1552 fhandler_cygdrive::rewinddir (DIR *dir)
1554 pdrive = get_win32_name ();
1555 dir->__d_position = 0;
1559 fhandler_cygdrive::closedir (DIR *dir)
1561 pdrive = get_win32_name ();