1 /* syscalls.cc: syscalls
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
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
12 #define fstat __FOOfstat__
13 #define lstat __FOOlstat__
14 #define stat __FOOstat__
15 #define _close __FOO_close__
16 #define _lseek __FOO_lseek__
17 #define _open __FOO_open__
18 #define _read __FOO_read__
19 #define _write __FOO_write__
20 #define _open64 __FOO_open64__
21 #define _lseek64 __FOO_lseek64__
22 #define _fstat64 __FOO_fstat64__
23 #define pread __FOO_pread
24 #define pwrite __FOO_pwrite
28 #include "miscfuncs.h"
30 #include <sys/vfs.h> /* needed for statfs */
31 #include <sys/statvfs.h> /* needed for statvfs */
50 #include <cygwin/version.h>
52 #include "perprocess.h"
59 #include "shared_info.h"
67 #include "child_info.h"
78 static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t,
81 /* Close all files and process any queued deletions.
82 Lots of unix style applications will open a tmp file, unlink it,
83 but never call close. This function is called by _exit to
84 ensure we don't leave any such files lying around. */
87 close_all_files (bool norelease)
89 cygheap->fdtab.lock ();
91 semaphore::terminate ();
96 for (int i = 0; i < (int) cygheap->fdtab.size; i++)
97 if ((fh = cygheap->fdtab[i]) != NULL)
100 debug_printf ("closing fd %d", i);
103 DuplicateHandle (GetCurrentProcess (), fh->get_output_handle (),
104 GetCurrentProcess (), &h,
105 0, false, DUPLICATE_SAME_ACCESS);
106 fh->close_with_arch ();
108 cygheap->fdtab.release (i);
111 if (!have_execed && cygheap->ctty)
112 cygheap->close_ctty ();
114 fhandler_base_overlapped::flush_all_async_io ();
116 SetStdHandle (STD_ERROR_HANDLE, h);
117 cygheap->fdtab.unlock ();
123 int res = cygheap->fdtab.dup3 (fd, cygheap_fdnew (), 0);
124 syscall_printf ("%R = dup(%d)", res, fd);
129 dup2 (int oldfd, int newfd)
132 if (newfd >= OPEN_MAX_MAX)
137 else if (newfd == oldfd)
139 cygheap_fdget cfd (oldfd);
140 res = (cfd >= 0) ? oldfd : -1;
143 res = cygheap->fdtab.dup3 (oldfd, newfd, 0);
145 syscall_printf ("%R = dup2(%d, %d)", res, oldfd, newfd);
150 dup3 (int oldfd, int newfd, int flags)
153 if (newfd >= OPEN_MAX_MAX)
158 else if (newfd == oldfd)
160 cygheap_fdget cfd (oldfd, false, false);
161 set_errno (cfd < 0 ? EBADF : EINVAL);
165 res = cygheap->fdtab.dup3 (oldfd, newfd, flags);
166 syscall_printf ("%R = dup2(%d, %d, %p)", res, oldfd, newfd, flags);
171 start_transaction (HANDLE &old_trans, HANDLE &trans)
173 NTSTATUS status = NtCreateTransaction (&trans,
174 SYNCHRONIZE | TRANSACTION_ALL_ACCESS,
175 NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
176 if (NT_SUCCESS (status))
178 old_trans = RtlGetCurrentTransaction ();
179 RtlSetCurrentTransaction (trans);
183 debug_printf ("NtCreateTransaction failed, %p", status);
184 old_trans = trans = NULL;
188 static inline NTSTATUS
189 stop_transaction (NTSTATUS status, HANDLE old_trans, HANDLE trans)
191 RtlSetCurrentTransaction (old_trans);
192 if (NT_SUCCESS (status))
193 status = NtCommitTransaction (trans, TRUE);
195 status = NtRollbackTransaction (trans, TRUE);
200 static char desktop_ini[] =
201 "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
202 static BYTE info2[] =
204 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
216 try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access)
218 bin_status bin_stat = move_to_bin;
220 OBJECT_ATTRIBUTES attr;
222 HANDLE rootdir = NULL, recyclerdir = NULL, tmp_fh = NULL;
223 USHORT recycler_base_len = 0, recycler_user_len = 0;
224 UNICODE_STRING root, recycler, fname;
225 WCHAR recyclerbuf[NAME_MAX + 1]; /* Enough for recycler + SID + filename */
226 PFILE_NAME_INFORMATION pfni;
227 PFILE_INTERNAL_INFORMATION pfii;
228 PFILE_RENAME_INFORMATION pfri;
229 FILE_DISPOSITION_INFORMATION disp = { TRUE };
232 PBYTE infobuf = (PBYTE) tp.w_get ();
234 pfni = (PFILE_NAME_INFORMATION) infobuf;
235 status = NtQueryInformationFile (fh, &io, pfni, 65536, FileNameInformation);
236 if (!NT_SUCCESS (status))
238 debug_printf ("NtQueryInformationFile (%S, FileNameInformation) "
239 "failed, status = %p", pc.get_nt_native_path (), status);
242 /* The filename could change, the parent dir not. So we split both paths
243 and take the prefix. However, there are two special cases:
244 - The handle refers to the root dir of the volume.
245 - The handle refers to the recycler or a subdir.
246 Both cases are handled by just returning and not even trying to move
247 them into the recycler. */
248 if (pfni->FileNameLength == 2) /* root dir. */
250 /* Initialize recycler path. */
251 RtlInitEmptyUnicodeString (&recycler, recyclerbuf, sizeof recyclerbuf);
254 if (wincap.has_recycle_dot_bin ()) /* NTFS and FAT since Vista */
255 RtlAppendUnicodeToString (&recycler, L"\\$Recycle.Bin\\");
256 else if (pc.fs_is_ntfs ()) /* NTFS up to 2K3 */
257 RtlAppendUnicodeToString (&recycler, L"\\RECYCLER\\");
258 else if (pc.fs_is_fat ()) /* FAT up to 2K3 */
259 RtlAppendUnicodeToString (&recycler, L"\\Recycled\\");
262 /* Is the file a subdir of the recycler? */
263 RtlInitCountedUnicodeString(&fname, pfni->FileName, pfni->FileNameLength);
264 if (RtlEqualUnicodePathPrefix (&fname, &recycler, TRUE))
266 /* Is fname the recycler? Temporarily hide trailing backslash. */
267 recycler.Length -= sizeof (WCHAR);
268 if (RtlEqualUnicodeString (&fname, &recycler, TRUE))
271 /* Create root dir path from file name information. */
272 RtlSplitUnicodePath (&fname, &fname, NULL);
273 RtlSplitUnicodePath (pc.get_nt_native_path (), &root, NULL);
274 root.Length -= fname.Length - sizeof (WCHAR);
276 /* Open root directory. All recycler bin ops are caseinsensitive. */
277 InitializeObjectAttributes (&attr, &root, OBJ_CASE_INSENSITIVE,
279 status = NtOpenFile (&rootdir, FILE_TRAVERSE, &attr, &io,
280 FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
281 if (!NT_SUCCESS (status))
283 debug_printf ("NtOpenFile (%S) failed, status = %p", &root, status);
287 /* Strip leading backslash */
289 recycler.Length -= sizeof (WCHAR);
290 /* Store length of recycler base dir, if it's necessary to create it. */
291 recycler_base_len = recycler.Length;
292 /* On NTFS the recycler dir contains user specific subdirs, which are the
293 actual recycle bins per user. The name if this dir is the string
294 representation of the user SID. */
295 if (pc.fs_is_ntfs ())
299 /* Unhide trailing backslash. */
300 recycler.Length += sizeof (WCHAR);
301 RtlInitEmptyUnicodeString (&sid, sidbuf, sizeof sidbuf);
302 /* In contrast to what MSDN claims, this function is already available
304 RtlConvertSidToUnicodeString (&sid, cygheap->user.sid (), FALSE);
305 RtlAppendUnicodeStringToString (&recycler, &sid);
306 recycler_user_len = recycler.Length;
308 RtlAppendUnicodeToString (&recycler, L"\\");
310 /* Create hopefully unique filename.
311 Since we have to stick to the current directory on remote shares, make
312 the new filename at least very unlikely to match by accident. It starts
313 with ".cyg", with "cyg" transposed into the Unicode low surrogate area
314 starting at U+dc00. Use plain ASCII chars on filesystems not supporting
315 Unicode. The rest of the filename is the inode number in hex encoding
316 and a hash of the full NT path in hex. The combination allows to remove
317 multiple hardlinks to the same file. */
318 RtlAppendUnicodeToString (&recycler,
319 pc.fs_flags () & FILE_UNICODE_ON_DISK
320 ? L".\xdc63\xdc79\xdc67" : L".cyg");
321 pfii = (PFILE_INTERNAL_INFORMATION) infobuf;
322 status = NtQueryInformationFile (fh, &io, pfii, 65536,
323 FileInternalInformation);
324 if (!NT_SUCCESS (status))
326 debug_printf ("NtQueryInformationFile (%S, FileInternalInformation) "
327 "failed, status = %p", pc.get_nt_native_path (), status);
330 RtlInt64ToHexUnicodeString (pfii->FileId.QuadPart, &recycler, TRUE);
331 RtlInt64ToHexUnicodeString (hash_path_name (0, pc.get_nt_native_path ()),
334 pfri = (PFILE_RENAME_INFORMATION) infobuf;
335 pfri->ReplaceIfExists = TRUE;
336 pfri->RootDirectory = pc.isremote () ? NULL : rootdir;
337 pfri->FileNameLength = recycler.Length;
338 memcpy (pfri->FileName, recycler.Buffer, recycler.Length);
339 status = NtSetInformationFile (fh, &io, pfri, 65536, FileRenameInformation);
340 if (status == STATUS_OBJECT_PATH_NOT_FOUND && !pc.isremote ())
342 /* Ok, so the recycler and/or the recycler/SID directory don't exist.
343 First reopen root dir with permission to create subdirs. */
345 status = NtOpenFile (&rootdir, FILE_ADD_SUBDIRECTORY, &attr, &io,
346 FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
347 if (!NT_SUCCESS (status))
349 debug_printf ("NtOpenFile (%S) failed, status = %p",
353 /* Then check if recycler exists by opening and potentially creating it.
354 Yes, we can really do that. Typically the recycle bin is created
355 by the first user actually using the bin. The permissions are the
356 default permissions propagated from the root directory. */
357 InitializeObjectAttributes (&attr, &recycler, OBJ_CASE_INSENSITIVE,
359 recycler.Length = recycler_base_len;
360 status = NtCreateFile (&recyclerdir,
362 | (pc.fs_is_ntfs () ? 0 : FILE_ADD_FILE),
364 FILE_ATTRIBUTE_DIRECTORY
365 | FILE_ATTRIBUTE_SYSTEM
366 | FILE_ATTRIBUTE_HIDDEN,
367 FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF,
368 FILE_DIRECTORY_FILE, NULL, 0);
369 if (!NT_SUCCESS (status))
371 debug_printf ("NtCreateFile (%S) failed, status = %p",
375 /* Next, if necessary, check if the recycler/SID dir exists and
377 if (pc.fs_is_ntfs ())
379 NtClose (recyclerdir);
380 recycler.Length = recycler_user_len;
381 status = NtCreateFile (&recyclerdir, READ_CONTROL | FILE_ADD_FILE,
382 &attr, &io, NULL, FILE_ATTRIBUTE_DIRECTORY
383 | FILE_ATTRIBUTE_SYSTEM
384 | FILE_ATTRIBUTE_HIDDEN,
385 FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF,
386 FILE_DIRECTORY_FILE, NULL, 0);
387 if (!NT_SUCCESS (status))
389 debug_printf ("NtCreateFile (%S) failed, status = %p",
394 /* The desktop.ini and INFO2 (pre-Vista) files are expected by
395 Windows Explorer. Otherwise, the created bin is treated as
397 if (io.Information == FILE_CREATED)
399 RtlInitUnicodeString (&fname, L"desktop.ini");
400 InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE,
402 status = NtCreateFile (&tmp_fh, FILE_GENERIC_WRITE, &attr, &io, NULL,
403 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
404 FILE_SHARE_VALID_FLAGS, FILE_CREATE,
405 FILE_SYNCHRONOUS_IO_NONALERT
406 | FILE_NON_DIRECTORY_FILE, NULL, 0);
407 if (!NT_SUCCESS (status))
408 debug_printf ("NtCreateFile (%S) failed, status = %p",
412 status = NtWriteFile (tmp_fh, NULL, NULL, NULL, &io, desktop_ini,
413 sizeof desktop_ini - 1, NULL, NULL);
414 if (!NT_SUCCESS (status))
415 debug_printf ("NtWriteFile (%S) failed, status = %p",
419 if (!wincap.has_recycle_dot_bin ()) /* No INFO2 file since Vista */
421 RtlInitUnicodeString (&fname, L"INFO2");
422 status = NtCreateFile (&tmp_fh, FILE_GENERIC_WRITE, &attr, &io,
423 NULL, FILE_ATTRIBUTE_ARCHIVE
424 | FILE_ATTRIBUTE_HIDDEN,
425 FILE_SHARE_VALID_FLAGS, FILE_CREATE,
426 FILE_SYNCHRONOUS_IO_NONALERT
427 | FILE_NON_DIRECTORY_FILE, NULL, 0);
428 if (!NT_SUCCESS (status))
429 debug_printf ("NtCreateFile (%S) failed, status = %p",
433 status = NtWriteFile (tmp_fh, NULL, NULL, NULL, &io, info2,
434 sizeof info2, NULL, NULL);
435 if (!NT_SUCCESS (status))
436 debug_printf ("NtWriteFile (%S) failed, status = %p",
442 NtClose (recyclerdir);
444 status = NtSetInformationFile (fh, &io, pfri, 65536,
445 FileRenameInformation);
447 if (!NT_SUCCESS (status))
449 debug_printf ("Move %S to %S failed, status = %p",
450 pc.get_nt_native_path (), &recycler, status);
453 /* Moving to the bin worked. */
454 bin_stat = has_been_moved;
455 /* Now we try to set the delete disposition. If that worked, we're done.
456 We try this here first, as long as we still have the open handle.
457 Otherwise the below code closes the handle to allow replacing the file. */
458 status = NtSetInformationFile (fh, &io, &disp, sizeof disp,
459 FileDispositionInformation);
460 /* In case of success, restore R/O attribute to accommodate hardlinks.
461 That leaves potentially hardlinks around with the R/O bit suddenly
462 off if setting the delete disposition failed, but please, keep in
463 mind this is really a border case only. */
464 if ((access & FILE_WRITE_ATTRIBUTES) && NT_SUCCESS (status) && !pc.isdir ())
465 NtSetAttributesFile (fh, pc.file_attributes ());
467 fh = NULL; /* So unlink_nt doesn't close the handle twice. */
468 /* On success or when trying to unlink a directory we just return here.
469 The below code only works for files. */
470 if (NT_SUCCESS (status) || pc.isdir ())
472 /* The final trick. We create a temporary file with delete-on-close
473 semantic and rename that file to the file just moved to the bin.
474 This typically overwrites the original file and we get rid of it,
475 even if neither setting the delete dispostion, nor setting
476 delete-on-close on the original file succeeds. There are still
477 cases in which this fails, for instance, when trying to delete a
478 hardlink to a DLL used by the unlinking application itself. */
479 RtlAppendUnicodeToString (&recycler, L"X");
480 InitializeObjectAttributes (&attr, &recycler, 0, rootdir, NULL);
481 status = NtCreateFile (&tmp_fh, DELETE, &attr, &io, NULL,
482 FILE_ATTRIBUTE_NORMAL, 0, FILE_SUPERSEDE,
483 FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE,
485 if (!NT_SUCCESS (status))
487 debug_printf ("Creating file for overwriting failed, status = %p",
491 status = NtSetInformationFile (tmp_fh, &io, pfri, 65536,
492 FileRenameInformation);
494 if (!NT_SUCCESS (status))
495 debug_printf ("Overwriting with another file failed, status = %p", status);
500 debug_printf ("%S, return status %d", pc.get_nt_native_path (), bin_stat);
505 check_dir_not_empty (HANDLE dir, path_conv &pc)
508 const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION)
509 + 3 * NAME_MAX * sizeof (WCHAR);
510 PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION)
512 NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni,
513 bufsiz, FileNamesInformation,
515 if (!NT_SUCCESS (status))
517 debug_printf ("Checking if directory %S is empty failed, status = %p",
518 pc.get_nt_native_path (), status);
524 while (pfni->NextEntryOffset)
528 UNICODE_STRING fname;
529 OBJECT_ATTRIBUTES attr;
530 FILE_BASIC_INFORMATION fbi;
532 pfni = (PFILE_NAMES_INFORMATION)
533 ((caddr_t) pfni + pfni->NextEntryOffset);
534 RtlInitCountedUnicodeString(&fname, pfni->FileName,
535 pfni->FileNameLength);
536 InitializeObjectAttributes (&attr, &fname, 0, dir, NULL);
537 status = NtQueryAttributesFile (&attr, &fbi);
538 /* Intensive testing shows that sometimes directories, for which
539 the delete disposition has already been set, and the deleting
540 handle is already closed, can linger in the parent dir for a
541 couple of ms for no apparent reason (Windows Defender or other
542 real-time scanners are suspect).
544 A fast rm -r is capable to exploit this problem. Setting the
545 delete disposition of the parent dir then fails with
546 STATUS_DIRECTORY_NOT_EMPTY. Examining the content of the
547 affected dir can then show either that the dir is empty, or it
548 can contain a lingering subdir. Calling NtQueryAttributesFile
549 on that subdir returns with STATUS_DELETE_PENDING, or it
550 disappeared before that call.
552 That's what we do here. If NtQueryAttributesFile succeeded,
553 or if the error code does not indicate an already deleted
554 entry, STATUS_DIRECTORY_NOT_EMPTY is returned.
556 Otherwise STATUS_SUCCESS is returned. Read on in unlink_nt. */
557 if (status != STATUS_DELETE_PENDING
558 && status != STATUS_OBJECT_NAME_NOT_FOUND
559 && status != STATUS_OBJECT_PATH_NOT_FOUND)
561 debug_printf ("Directory %S not empty, found file <%S>, "
563 pc.get_nt_native_path (), &fname, status);
564 return STATUS_DIRECTORY_NOT_EMPTY;
567 pfni = (PFILE_NAMES_INFORMATION) ((caddr_t) pfni + pfni->NextEntryOffset);
570 while (NT_SUCCESS (NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni,
571 bufsiz, FileNamesInformation,
572 FALSE, NULL, FALSE)));
573 return STATUS_SUCCESS;
577 unlink_nt (path_conv &pc)
580 HANDLE fh, fh_ro = NULL;
581 OBJECT_ATTRIBUTES attr;
583 HANDLE old_trans = NULL, trans = NULL;
585 FILE_DISPOSITION_INFORMATION disp = { TRUE };
588 bin_status bin_stat = dont_move;
590 syscall_printf ("Trying to delete %S, isdir = %d",
591 pc.get_nt_native_path (), pc.isdir ());
592 ACCESS_MASK access = DELETE;
593 ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
594 /* Add the reparse point flag to native symlinks, otherwise we remove the
595 target, not the symlink. */
596 if (pc.is_rep_symlink ())
597 flags |= FILE_OPEN_REPARSE_POINT;
599 pc.get_object_attr (attr, sec_none_nih);
600 /* If the R/O attribute is set, we have to open the file with
601 FILE_WRITE_ATTRIBUTES to be able to remove this flags before trying
602 to delete it. We do this separately because there are filesystems
603 out there (MVFS), which refuse a request to open a file for DELETE
604 if the DOS R/O attribute is set for the file. After removing the R/O
605 attribute, just re-open the file for DELETE and go ahead. */
606 if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
608 FILE_STANDARD_INFORMATION fsi;
610 /* If possible, hide the non-atomicity of the "remove R/O flag, remove
611 link to file" operation behind a transaction. */
612 if (wincap.has_transactions ()
613 && (pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
614 start_transaction (old_trans, trans);
616 status = NtOpenFile (&fh_ro, FILE_WRITE_ATTRIBUTES, &attr, &io,
617 FILE_SHARE_VALID_FLAGS, flags);
618 if (NT_SUCCESS (status))
620 debug_printf ("Opening %S for removing R/O succeeded",
621 pc.get_nt_native_path ());
622 NTSTATUS status2 = NtSetAttributesFile (fh_ro,
623 pc.file_attributes ()
624 & ~FILE_ATTRIBUTE_READONLY);
625 if (!NT_SUCCESS (status2))
626 debug_printf ("Removing R/O on %S failed, status = %p",
627 pc.get_nt_native_path (), status2);
628 pc.init_reopen_attr (&attr, fh_ro);
631 debug_printf ("Opening %S for removing R/O failed, status = %p",
632 pc.get_nt_native_path (), status);
633 if (pc.is_lnk_symlink ())
635 status = NtQueryInformationFile (fh_ro, &io, &fsi, sizeof fsi,
636 FileStandardInformation);
637 if (NT_SUCCESS (status))
638 num_links = fsi.NumberOfLinks;
640 access |= FILE_WRITE_ATTRIBUTES;
642 /* First try to open the file with only allowing sharing for delete. If
643 the file has an open handle on it, other than just for deletion, this
644 will fail. That indicates that the file has to be moved to the recycle
645 bin so that it actually disappears from its directory even though its
646 in use. Otherwise, if opening doesn't fail, the file is not in use and
647 we can go straight to setting the delete disposition flag.
649 NOTE: The missing sharing modes FILE_SHARE_READ and FILE_SHARE_WRITE do
650 NOT result in a STATUS_SHARING_VIOLATION, if another handle is
651 opened for reading/writing metadata only. In other words, if
652 another handle is open, but does not have the file open with
653 FILE_READ_DATA or FILE_WRITE_DATA, the following NtOpenFile call
654 will succeed. So, apparently there is no reliable way to find out
655 if a file is already open elsewhere for other purposes than
656 reading and writing data. */
657 status = NtOpenFile (&fh, access, &attr, &io, FILE_SHARE_DELETE, flags);
658 if (status == STATUS_SHARING_VIOLATION || status == STATUS_LOCK_NOT_GRANTED)
660 /* STATUS_LOCK_NOT_GRANTED can be generated under not quite clear
661 circumstances when trying to open a file on NFS with FILE_SHARE_DELETE
662 only. This has been observed with SFU 3.5 if the NFS share has been
663 mounted under a drive letter. It's not generated for all files, but
664 only for some. If it's generated once for a file, it will be
665 generated all the time. It looks like wrong file state information
666 is stored within the NFS client, for no apparent reason, which never
667 times out. Opening the file with FILE_SHARE_VALID_FLAGS will work,
668 though, and it is then possible to delete the file quite normally.
670 NFS implements its own mechanism to remove in-use files which
671 looks quite similar to what we do in try_to_bin for remote files.
672 That's why we don't call try_to_bin on NFS.
674 Netapp filesystems don't understand the "move and delete" method
675 at all and have all kinds of weird effects. Just setting the delete
676 dispositon usually works fine, though. */
677 debug_printf ("Sharing violation when opening %S",
678 pc.get_nt_native_path ());
679 if (!pc.fs_is_nfs () && !pc.fs_is_netapp ())
680 bin_stat = move_to_bin;
681 if (!pc.isdir () || pc.isremote ())
682 status = NtOpenFile (&fh, access, &attr, &io,
683 FILE_SHARE_VALID_FLAGS, flags);
686 /* It's getting tricky. The directory is opened in some process,
687 so we're supposed to move it to the recycler and mark it for
688 deletion. But what if the directory is not empty? The move
689 will work, but the subsequent delete will fail. So we would
690 have to move it back. That's bad, because the directory would
691 be moved around which results in a temporary inconsistent state.
692 So, what we do here is to test if the directory is empty. If
693 not, we bail out with STATUS_DIRECTORY_NOT_EMPTY. The below code
694 tests for at least three entries in the directory, ".", "..",
695 and another one. Three entries means, not empty. This doesn't
696 work for the root directory of a drive, but the root dir can
697 neither be deleted, nor moved anyway. */
698 status = NtOpenFile (&fh, access | FILE_LIST_DIRECTORY | SYNCHRONIZE,
699 &attr, &io, FILE_SHARE_VALID_FLAGS,
700 flags | FILE_SYNCHRONOUS_IO_NONALERT);
701 if (NT_SUCCESS (status))
703 status = check_dir_not_empty (fh, pc);
704 if (!NT_SUCCESS (status))
716 if (!NT_SUCCESS (status))
718 if (status == STATUS_DELETE_PENDING)
720 debug_printf ("Delete %S already pending", pc.get_nt_native_path ());
721 status = STATUS_SUCCESS;
724 debug_printf ("Opening %S for delete failed, status = %p",
725 pc.get_nt_native_path (), status);
728 /* Try to move to bin if a sharing violation occured. If that worked,
730 if (bin_stat == move_to_bin
731 && (bin_stat = try_to_bin (pc, fh, access)) == has_been_moved)
733 status = STATUS_SUCCESS;
738 /* Try to set delete disposition. */
739 status = NtSetInformationFile (fh, &io, &disp, sizeof disp,
740 FileDispositionInformation);
741 if (!NT_SUCCESS (status))
743 debug_printf ("Setting delete disposition on %S failed, status = %p",
744 pc.get_nt_native_path (), status);
745 if (status == STATUS_DIRECTORY_NOT_EMPTY)
747 NTSTATUS status2 = STATUS_SUCCESS;
751 /* Have to close and reopen the file from scratch, otherwise
752 we collide with the delete-only sharing mode. */
753 pc.get_object_attr (attr, sec_none_nih);
755 status2 = NtOpenFile (&fh, access | FILE_LIST_DIRECTORY
757 &attr, &io, FILE_SHARE_VALID_FLAGS,
758 flags | FILE_SYNCHRONOUS_IO_NONALERT);
760 if (NT_SUCCESS (status2) && reopened < 20)
762 /* Workaround rm -r problem:
764 Sometimes a deleted directory lingers in its parent dir
765 after the deleting handle has already been closed. This
766 can break deleting the parent dir. See the comment in
767 check_dir_not_empty for more information.
769 What we do here is this: If check_dir_not_empty returns
770 STATUS_SUCCESS, the dir is either empty, or only inhabited
771 by already deleted entries. If so, we try to move the dir
772 into the bin. This usually works.
774 However, if we're on a filesystem which doesn't support
775 the try_to_bin method, or if moving to the bin doesn't work
776 for some reason, just try to delete the directory again,
777 with a very short grace period to free the CPU for a while.
778 This gives the OS time to clean up. 5ms is enough in my
779 testing to make sure that we don't have to try more than
780 once in practically all cases.
781 While this is an extrem bordercase, we don't want to hang
782 infinitely in case a file in the directory is in the "delete
783 pending" state but an application holds an open handle to it
784 for a longer time. So we don't try this more than 20 times,
785 which means a process time of 100-120ms. */
786 if (check_dir_not_empty (fh, pc) == STATUS_SUCCESS)
788 if (bin_stat == dont_move)
790 bin_stat = move_to_bin;
791 if (!pc.fs_is_nfs () && !pc.fs_is_netapp ())
793 debug_printf ("Try-to-bin %S",
794 pc.get_nt_native_path ());
795 bin_stat = try_to_bin (pc, fh, access);
798 if (bin_stat == has_been_moved)
799 status = STATUS_SUCCESS;
802 debug_printf ("Try %S again", pc.get_nt_native_path ());
812 debug_printf ("Opening dir %S for check_dir_not_empty failed, "
813 "status = %p", pc.get_nt_native_path (), status2);
816 /* Trying to delete a hardlink to a file in use by the system in some
817 way (for instance, font files) by setting the delete disposition fails
818 with STATUS_CANNOT_DELETE. Strange enough, deleting these hardlinks
819 using delete-on-close semantic works... most of the time.
821 Don't use delete-on-close on remote shares. If two processes
822 have open handles on a file and one of them calls unlink, the
823 file is removed from the remote share even though the other
824 process still has an open handle. That process than gets Win32
825 error 59, ERROR_UNEXP_NET_ERR when trying to access the file.
826 Microsoft KB 837665 describes this problem as a bug in 2K3, but
827 I have reproduced it on other systems. */
828 else if (status == STATUS_CANNOT_DELETE
829 && (!pc.isremote () || pc.fs_is_ncfsd ()))
833 debug_printf ("Cannot delete %S, try delete-on-close",
834 pc.get_nt_native_path ());
835 /* Re-open from handle so we open the correct file no matter if it
836 has been moved to the bin or not. */
837 pc.init_reopen_attr (&attr, fh);
838 status = NtOpenFile (&fh2, DELETE, &attr, &io,
839 bin_stat == move_to_bin ? FILE_SHARE_VALID_FLAGS
841 flags | FILE_DELETE_ON_CLOSE);
842 if (!NT_SUCCESS (status))
844 debug_printf ("Setting delete-on-close on %S failed, status = %p",
845 pc.get_nt_native_path (), status);
846 /* This is really the last chance. If it hasn't been moved
847 to the bin already, try it now. If moving to the bin
848 succeeds, we got rid of the file in some way, even if
849 unlinking didn't work. */
850 if (bin_stat == dont_move)
851 bin_stat = try_to_bin (pc, fh, access);
852 if (bin_stat == has_been_moved)
853 status = STATUS_SUCCESS;
861 if (access & FILE_WRITE_ATTRIBUTES)
863 /* Restore R/O attribute if setting the delete dispostion failed. */
864 if (!NT_SUCCESS (status))
865 NtSetAttributesFile (fh, pc.file_attributes ());
866 /* If we succeeded, restore R/O attribute to accommodate hardlinks.
867 Only ever try to do this for our own winsymlinks, because there's
868 a problem with setting the delete disposition:
869 http://msdn.microsoft.com/en-us/library/ff545765%28VS.85%29.aspx
870 "Subsequently, the only legal operation by such a caller is
871 to close the open file handle."
873 FIXME? On Vista and later, we could use FILE_HARD_LINK_INFORMATION
874 to find all hardlinks and use one of them to restore the R/O bit,
875 after the NtClose, but before we stop the transaction. This
876 avoids the aforementioned problem entirely . */
877 else if (pc.is_lnk_symlink () && num_links > 1)
878 NtSetAttributesFile (fh, pc.file_attributes ());
885 /* Stop transaction if we started one. */
886 if ((access & FILE_WRITE_ATTRIBUTES)
887 && wincap.has_transactions ()
888 && (pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
889 stop_transaction (status, old_trans, trans);
891 syscall_printf ("%S, return status = %p", pc.get_nt_native_path (), status);
896 unlink (const char *ourname)
902 path_conv win32_name (ourname, PC_SYM_NOFOLLOW, stat_suffixes);
904 if (win32_name.error)
906 set_errno (win32_name.error);
910 devn = win32_name.get_devn ();
911 if (isproc_dev (devn))
917 if (!win32_name.exists ())
919 debug_printf ("unlinking a nonexistent file");
923 else if (win32_name.isdir ())
925 debug_printf ("unlinking a directory");
930 status = unlink_nt (win32_name);
931 if (NT_SUCCESS (status))
934 __seterrno_from_nt_status (status);
937 syscall_printf ("%R = unlink(%s)", res, ourname);
942 _remove_r (struct _reent *, const char *ourname)
944 path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
946 if (win32_name.error)
948 set_errno (win32_name.error);
949 syscall_printf ("%R = remove(%s)",-1, ourname);
953 return win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
957 remove (const char *ourname)
959 path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
961 if (win32_name.error)
963 set_errno (win32_name.error);
964 syscall_printf ("-1 = remove (%s)", ourname);
968 int res = win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
969 syscall_printf ("%R = remove(%s)", res, ourname);
976 syscall_printf ("%d = getpid()", myself->pid);
981 _getpid_r (struct _reent *)
986 /* getppid: POSIX 4.1.1.1 */
990 syscall_printf ("%d = getppid()", myself->ppid);
994 /* setsid: POSIX 4.3.2.1 */
999 vfork_save *vf = vfork_storage.val ();
1000 /* This is a horrible, horrible kludge */
1001 if (vf && vf->pid < 0)
1003 pid_t pid = fork ();
1006 syscall_printf ("longjmping due to vfork");
1007 vf->restore_pid (pid);
1009 /* assuming that fork was successful */
1013 if (myself->pgid == myself->pid)
1014 syscall_printf ("hmm. pgid %d pid %d", myself->pgid, myself->pid);
1018 cygheap->manage_console_count ("setsid", 0);
1019 myself->sid = getpid ();
1020 myself->pgid = getpid ();
1022 cygheap->close_ctty ();
1023 syscall_printf ("sid %d, pgid %d, %s", myself->sid, myself->pgid, myctty ());
1048 syscall_printf ("%R = getsid(%d)", pid);
1053 read (int fd, void *ptr, size_t len)
1055 pthread_testcancel ();
1058 if (efault.faulted (EFAULT))
1061 size_t res = (size_t) -1;
1063 cygheap_fdget cfd (fd);
1067 if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
1073 /* Could block, so let user know we at least got here. */
1074 syscall_printf ("read(%d, %p, %d) %sblocking",
1075 fd, ptr, len, cfd->is_nonblocking () ? "non" : "");
1077 cfd->read (ptr, res = len);
1080 syscall_printf ("%R = read(%d, %p, %d)", res, fd, ptr, len);
1082 return (ssize_t) res;
1085 EXPORT_ALIAS (read, _read)
1088 readv (int fd, const struct iovec *const iov, const int iovcnt)
1090 pthread_testcancel ();
1093 if (efault.faulted (EFAULT))
1097 const ssize_t tot = check_iovec_for_read (iov, iovcnt);
1099 cygheap_fdget cfd (fd);
1109 if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
1115 /* Could block, so let user know we at least got here. */
1116 syscall_printf ("readv(%d, %p, %d) %sblocking",
1117 fd, iov, iovcnt, cfd->is_nonblocking () ? "non" : "");
1119 res = cfd->readv (iov, iovcnt, tot);
1122 syscall_printf ("%R = readv(%d, %p, %d)", res, fd, iov, iovcnt);
1128 pread (int fd, void *ptr, size_t len, _off64_t off)
1130 pthread_testcancel ();
1133 cygheap_fdget cfd (fd);
1137 res = cfd->pread (ptr, len, off);
1139 syscall_printf ("%R = pread(%d, %p, %d, %d)", res, fd, ptr, len, off);
1144 write (int fd, const void *ptr, size_t len)
1146 pthread_testcancel ();
1149 if (efault.faulted (EFAULT))
1154 cygheap_fdget cfd (fd);
1158 if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
1164 /* Could block, so let user know we at least got here. */
1165 if (fd == 1 || fd == 2)
1166 paranoid_printf ("write(%d, %p, %d)", fd, ptr, len);
1168 syscall_printf ("write(%d, %p, %d)", fd, ptr, len);
1170 res = cfd->write (ptr, len);
1173 syscall_printf ("%R = write(%d, %p, %d)", res, fd, ptr, len);
1179 EXPORT_ALIAS (write, _write)
1182 writev (const int fd, const struct iovec *const iov, const int iovcnt)
1184 pthread_testcancel ();
1187 if (efault.faulted (EFAULT))
1191 const ssize_t tot = check_iovec_for_write (iov, iovcnt);
1193 cygheap_fdget cfd (fd);
1203 if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
1209 /* Could block, so let user know we at least got here. */
1210 if (fd == 1 || fd == 2)
1211 paranoid_printf ("writev(%d, %p, %d)", fd, iov, iovcnt);
1213 syscall_printf ("writev(%d, %p, %d)", fd, iov, iovcnt);
1215 res = cfd->writev (iov, iovcnt, tot);
1218 if (fd == 1 || fd == 2)
1219 paranoid_printf ("%R = writev(%d, %p, %d)", res, fd, iov, iovcnt);
1221 syscall_printf ("%R = writev(%d, %p, %d)", res, fd, iov, iovcnt);
1228 pwrite (int fd, void *ptr, size_t len, _off64_t off)
1230 pthread_testcancel ();
1233 cygheap_fdget cfd (fd);
1237 res = cfd->pwrite (ptr, len, off);
1239 syscall_printf ("%R = pwrite(%d, %p, %d, %d)", res, fd, ptr, len, off);
1244 /* newlib's fcntl.h defines _open as taking variable args so we must
1245 correspond. The third arg if it exists is: mode_t mode. */
1247 open (const char *unix_path, int flags, ...)
1253 syscall_printf ("open(%s, %p)", unix_path, flags);
1254 pthread_testcancel ();
1256 if (efault.faulted (EFAULT))
1257 /* errno already set */;
1258 else if (!*unix_path)
1262 /* check for optional mode argument */
1263 va_start (ap, flags);
1264 mode = va_arg (ap, mode_t);
1272 /* This is a temporary kludge until all utilities can catch up with
1273 a change in behavior that implements linux functionality: opening
1274 a tty should not automatically cause it to become the controlling
1275 tty for the process. */
1276 int opt = PC_OPEN | ((flags & (O_NOFOLLOW | O_EXCL))
1277 ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW);
1278 if (!(flags & O_NOCTTY)&& fd > 2)
1281 opt |= PC_CTTY; /* flag that, if opened, this fhandler could
1282 later be capable of being a controlling
1283 terminal if /dev/tty is opened. */
1285 if (!(fh = build_fh_name (unix_path, opt, stat_suffixes)))
1286 res = -1; // errno already set
1287 else if ((flags & O_NOFOLLOW) && fh->issymlink ())
1293 else if ((flags & O_DIRECTORY) && !fh->pc.isdir ())
1297 set_errno (ENOTDIR);
1299 else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) && fh->exists ())
1305 else if ((fh->is_fs_special () && fh->device_access_denied (flags))
1306 || !fh->open_with_arch (flags, (mode & 07777) & ~cygheap->umask))
1315 set_std_handle (fd);
1321 syscall_printf ("%R = open(%s, %p)", res, unix_path, flags);
1325 EXPORT_ALIAS (open, _open )
1326 EXPORT_ALIAS (open, _open64 )
1329 lseek64 (int fd, _off64_t pos, int dir)
1333 if (dir != SEEK_SET && dir != SEEK_CUR && dir != SEEK_END)
1340 cygheap_fdget cfd (fd);
1342 res = cfd->lseek (pos, dir);
1346 syscall_printf ("%R = lseek(%d, %D, %d)", res, fd, pos, dir);
1351 EXPORT_ALIAS (lseek64, _lseek64)
1354 lseek (int fd, _off_t pos, int dir)
1356 return lseek64 (fd, (_off64_t) pos, dir);
1359 EXPORT_ALIAS (lseek, _lseek)
1366 syscall_printf ("close(%d)", fd);
1368 pthread_testcancel ();
1371 cygheap_fdget cfd (fd, true);
1376 res = cfd->close_with_arch ();
1380 syscall_printf ("%R = close(%d)", res, fd);
1385 EXPORT_ALIAS (close, _close)
1392 cygheap_fdget cfd (fd);
1396 res = cfd->is_tty ();
1397 syscall_printf ("%R = isatty(%d)", res, fd);
1400 EXPORT_ALIAS (isatty, _isatty)
1403 link (const char *oldpath, const char *newpath)
1408 if (!(fh = build_fh_name (oldpath, PC_SYM_NOFOLLOW | PC_KEEP_HANDLE,
1414 debug_printf ("got %d error from build_fh_name", fh->error ());
1415 set_errno (fh->error ());
1417 else if (fh->pc.isdir ())
1418 set_errno (EPERM); /* We do not permit linking directories. */
1419 else if (!fh->pc.exists ())
1422 res = fh->link (newpath);
1426 syscall_printf ("%R = link(%s, %s)", res, oldpath, newpath);
1430 /* chown: POSIX 5.6.5.1 */
1432 * chown () is only implemented for Windows NT. Under other operating
1433 * systems, it is only a stub that always returns zero.
1436 chown_worker (const char *name, unsigned fmode, __uid32_t uid, __gid32_t gid)
1441 if (!(fh = build_fh_name (name, fmode, stat_suffixes)))
1446 debug_printf ("got %d error from build_fh_name", fh->error ());
1447 set_errno (fh->error ());
1450 res = fh->fchown (uid, gid);
1454 syscall_printf ("%R = %schown(%s,...)",
1455 res, (fmode & PC_SYM_NOFOLLOW) ? "l" : "", name);
1460 chown32 (const char * name, __uid32_t uid, __gid32_t gid)
1462 return chown_worker (name, PC_SYM_FOLLOW, uid, gid);
1466 chown (const char * name, __uid16_t uid, __gid16_t gid)
1468 return chown_worker (name, PC_SYM_FOLLOW,
1469 uid16touid32 (uid), gid16togid32 (gid));
1473 lchown32 (const char * name, __uid32_t uid, __gid32_t gid)
1475 return chown_worker (name, PC_SYM_NOFOLLOW, uid, gid);
1479 lchown (const char * name, __uid16_t uid, __gid16_t gid)
1481 return chown_worker (name, PC_SYM_NOFOLLOW,
1482 uid16touid32 (uid), gid16togid32 (gid));
1486 fchown32 (int fd, __uid32_t uid, __gid32_t gid)
1488 cygheap_fdget cfd (fd);
1491 syscall_printf ("-1 = fchown (%d,...)", fd);
1495 int res = cfd->fchown (uid, gid);
1497 syscall_printf ("%R = fchown(%s,...)", res, cfd->get_name ());
1502 fchown (int fd, __uid16_t uid, __gid16_t gid)
1504 return fchown32 (fd, uid16touid32 (uid), gid16togid32 (gid));
1507 /* umask: POSIX 5.3.3.1 */
1513 oldmask = cygheap->umask;
1514 cygheap->umask = mask & 0777;
1519 chmod_device (path_conv& pc, mode_t mode)
1521 return mknod_worker (pc.get_win32 (), pc.dev.mode & S_IFMT, mode, pc.dev.get_major (), pc.dev.get_minor ());
1524 #define FILTERED_MODE(m) ((m) & (S_ISUID | S_ISGID | S_ISVTX \
1525 | S_IRWXU | S_IRWXG | S_IRWXO))
1527 /* chmod: POSIX 5.6.4.1 */
1529 chmod (const char *path, mode_t mode)
1533 if (!(fh = build_fh_name (path, PC_SYM_FOLLOW, stat_suffixes)))
1538 debug_printf ("got %d error from build_fh_name", fh->error ());
1539 set_errno (fh->error ());
1542 res = fh->fchmod (FILTERED_MODE (mode));
1546 syscall_printf ("%R = chmod(%s, %p)", res, path, mode);
1550 /* fchmod: P96 5.6.4.1 */
1553 fchmod (int fd, mode_t mode)
1555 cygheap_fdget cfd (fd);
1558 syscall_printf ("-1 = fchmod (%d, 0%o)", fd, mode);
1562 return cfd->fchmod (FILTERED_MODE (mode));
1566 stat64_to_stat32 (struct __stat64 *src, struct __stat32 *dst)
1568 dst->st_dev = ((src->st_dev >> 8) & 0xff00) | (src->st_dev & 0xff);
1569 dst->st_ino = ((unsigned) (src->st_ino >> 32)) | (unsigned) src->st_ino;
1570 dst->st_mode = src->st_mode;
1571 dst->st_nlink = src->st_nlink;
1572 dst->st_uid = src->st_uid;
1573 dst->st_gid = src->st_gid;
1574 dst->st_rdev = ((src->st_rdev >> 8) & 0xff00) | (src->st_rdev & 0xff);
1575 dst->st_size = src->st_size;
1576 dst->st_atim = src->st_atim;
1577 dst->st_mtim = src->st_mtim;
1578 dst->st_ctim = src->st_ctim;
1579 dst->st_blksize = src->st_blksize;
1580 dst->st_blocks = src->st_blocks;
1584 fstat64 (int fd, struct __stat64 *buf)
1588 cygheap_fdget cfd (fd);
1593 memset (buf, 0, sizeof (struct __stat64));
1594 res = cfd->fstat (buf);
1598 buf->st_ino = cfd->get_ino ();
1600 buf->st_dev = cfd->get_device ();
1602 buf->st_rdev = buf->st_dev;
1606 syscall_printf ("%R = fstat(%d, %p)", res, fd, buf);
1611 _fstat64_r (struct _reent *ptr, int fd, struct __stat64 *buf)
1615 if ((ret = fstat64 (fd, buf)) == -1)
1616 ptr->_errno = get_errno ();
1621 fstat (int fd, struct __stat32 *buf)
1623 struct __stat64 buf64;
1624 int ret = fstat64 (fd, &buf64);
1626 stat64_to_stat32 (&buf64, buf);
1631 _fstat_r (struct _reent *ptr, int fd, struct __stat32 *buf)
1635 if ((ret = fstat (fd, buf)) == -1)
1636 ptr->_errno = get_errno ();
1640 /* fsync: P96 6.6.1.1 */
1644 pthread_testcancel ();
1645 cygheap_fdget cfd (fd);
1648 syscall_printf ("-1 = fsync (%d)", fd);
1651 return cfd->fsync ();
1654 EXPORT_ALIAS (fsync, fdatasync)
1657 sync_worker (HANDLE dir, USHORT len, LPCWSTR vol)
1662 OBJECT_ATTRIBUTES attr;
1663 UNICODE_STRING uvol = { len, len, (WCHAR *) vol };
1665 InitializeObjectAttributes (&attr, &uvol, OBJ_CASE_INSENSITIVE, dir, NULL);
1666 status = NtOpenFile (&fh, GENERIC_WRITE, &attr, &io,
1667 FILE_SHARE_VALID_FLAGS, 0);
1668 if (!NT_SUCCESS (status))
1669 debug_printf ("NtOpenFile (%S), status %p", &uvol, status);
1672 status = NtFlushBuffersFile (fh, &io);
1673 if (!NT_SUCCESS (status))
1674 debug_printf ("NtFlushBuffersFile (%S), status %p", &uvol, status);
1683 OBJECT_ATTRIBUTES attr;
1686 UNICODE_STRING device;
1688 /* Open \Device object directory. */
1689 RtlInitUnicodeString (&device, L"\\Device");
1690 InitializeObjectAttributes (&attr, &device, OBJ_CASE_INSENSITIVE, NULL, NULL);
1691 status = NtOpenDirectoryObject (&devhdl, DIRECTORY_QUERY, &attr);
1692 if (!NT_SUCCESS (status))
1694 debug_printf ("NtOpenDirectoryObject, status %p", status);
1697 /* Traverse \Device directory ... */
1698 PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION)
1700 BOOLEAN restart = TRUE;
1702 while (NT_SUCCESS (NtQueryDirectoryObject (devhdl, dbi, 640, TRUE, restart,
1706 /* ... and call sync_worker for each HarddiskVolumeX entry. */
1707 if (dbi->ObjectName.Length >= 15 * sizeof (WCHAR)
1708 && !wcsncasecmp (dbi->ObjectName.Buffer, L"HarddiskVolume", 14)
1709 && iswdigit (dbi->ObjectName.Buffer[14]))
1710 sync_worker (devhdl, dbi->ObjectName.Length, dbi->ObjectName.Buffer);
1715 /* Cygwin internal */
1717 stat_worker (path_conv &pc, struct __stat64 *buf)
1722 if (efault.faulted (EFAULT))
1727 debug_printf ("got %d error from path_conv", pc.error);
1728 set_errno (pc.error);
1730 else if (pc.exists ())
1734 if (!(fh = build_fh_pc (pc)))
1737 debug_printf ("(%S, %p, %p), file_attributes %d",
1738 pc.get_nt_native_path (), buf, fh, (DWORD) *fh);
1739 memset (buf, 0, sizeof (*buf));
1740 res = fh->fstat (buf);
1744 buf->st_ino = fh->get_ino ();
1746 buf->st_dev = fh->get_device ();
1748 buf->st_rdev = buf->st_dev;
1757 syscall_printf ("%d = (%S,%p)", res, pc.get_nt_native_path (), buf);
1762 stat64 (const char *name, struct __stat64 *buf)
1764 syscall_printf ("entering");
1765 path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE,
1767 return stat_worker (pc, buf);
1771 _stat64_r (struct _reent *ptr, const char *name, struct __stat64 *buf)
1775 if ((ret = stat64 (name, buf)) == -1)
1776 ptr->_errno = get_errno ();
1781 stat (const char *name, struct __stat32 *buf)
1783 struct __stat64 buf64;
1784 int ret = stat64 (name, &buf64);
1786 stat64_to_stat32 (&buf64, buf);
1791 _stat_r (struct _reent *ptr, const char *name, struct __stat32 *buf)
1795 if ((ret = stat (name, buf)) == -1)
1796 ptr->_errno = get_errno ();
1800 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1802 lstat64 (const char *name, struct __stat64 *buf)
1804 syscall_printf ("entering");
1805 path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX | PC_KEEP_HANDLE,
1807 return stat_worker (pc, buf);
1810 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1812 lstat (const char *name, struct __stat32 *buf)
1814 struct __stat64 buf64;
1815 int ret = lstat64 (name, &buf64);
1817 stat64_to_stat32 (&buf64, buf);
1822 access (const char *fn, int flags)
1824 // flags were incorrectly specified
1826 if (flags & ~(F_OK|R_OK|W_OK|X_OK))
1830 fhandler_base *fh = build_fh_name (fn, PC_SYM_FOLLOW | PC_KEEP_HANDLE,
1834 res = fh->fhaccess (flags, false);
1838 debug_printf ("returning %d", res);
1842 /* Linux provides this extension; it is basically a wrapper around the
1843 POSIX:2008 faccessat (AT_FDCWD, fn, flags, AT_EACCESS). We also
1844 provide eaccess as an alias for this, in cygwin.din. */
1846 euidaccess (const char *fn, int flags)
1848 // flags were incorrectly specified
1850 if (flags & ~(F_OK|R_OK|W_OK|X_OK))
1854 fhandler_base *fh = build_fh_name (fn, PC_SYM_FOLLOW | PC_KEEP_HANDLE,
1858 res = fh->fhaccess (flags, true);
1862 debug_printf ("returning %d", res);
1867 rename_append_suffix (path_conv &pc, const char *path, size_t len,
1872 if (ascii_strcasematch (path + len - 4, ".lnk")
1873 || ascii_strcasematch (path + len - 4, ".exe"))
1875 stpcpy (stpncpy (buf, path, len), suffix);
1876 pc.check (buf, PC_SYM_NOFOLLOW);
1879 /* This function tests if a filename has one of the "approved" executable
1880 suffix. This list is probably not complete... */
1882 nt_path_has_executable_suffix (PUNICODE_STRING upath)
1884 static const PUNICODE_STRING blessed_executable_suffixes[] =
1887 &ro_u_dll, /* Messy, messy. Per MSDN, the GetBinaryType function is
1888 supposed to return with ERROR_BAD_EXE_FORMAT. if the file
1889 is a DLL. On 64-bit Windows, this works as expected for
1890 32-bit and 64-bit DLLs. On 32-bit Windows this only works
1891 for 32-bit DLLs. For 64-bit DLLs, 32-bit Windows returns
1892 true with the type set to SCS_64BIT_BINARY. */
1899 USHORT pos = upath->Length / sizeof (WCHAR);
1901 UNICODE_STRING usuf;
1902 const PUNICODE_STRING *suf;
1904 /* Too short for a native path? */
1907 /* Assumption: All executable suffixes have a length of three. */
1908 path = upath->Buffer + pos - 4;
1911 RtlInitCountedUnicodeString (&usuf, path, 4 * sizeof (WCHAR));
1912 for (suf = blessed_executable_suffixes; *suf; ++suf)
1913 if (RtlEqualUnicodeString (&usuf, *suf, TRUE))
1919 rename (const char *oldpath, const char *newpath)
1923 path_conv oldpc, newpc, new2pc, *dstpc, *removepc = NULL;
1924 bool old_dir_requested = false, new_dir_requested = false;
1925 bool old_explicit_suffix = false, new_explicit_suffix = false;
1928 NTSTATUS status = STATUS_SUCCESS;
1929 HANDLE fh = NULL, nfh;
1930 HANDLE old_trans = NULL, trans = NULL;
1931 OBJECT_ATTRIBUTES attr;
1934 FILE_STANDARD_INFORMATION ofsi;
1935 PFILE_RENAME_INFORMATION pfri;
1938 if (efault.faulted (EFAULT))
1941 if (!*oldpath || !*newpath)
1943 /* Reject rename("","x"), rename("x",""). */
1947 if (has_dot_last_component (oldpath, true))
1949 /* Reject rename("dir/.","x"). */
1950 oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1951 set_errno (oldpc.isdir () ? EINVAL : ENOTDIR);
1954 if (has_dot_last_component (newpath, true))
1956 /* Reject rename("dir","x/."). */
1957 newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
1958 set_errno (!newpc.exists () ? ENOENT : newpc.isdir () ? EINVAL : ENOTDIR);
1962 /* A trailing slash requires that the pathname points to an existing
1963 directory. If it's not, it's a ENOTDIR condition. The same goes
1964 for newpath a bit further down this function. */
1965 olen = strlen (oldpath);
1966 if (isdirsep (oldpath[olen - 1]))
1969 char *p = stpcpy (buf = tp.c_get (), oldpath) - 1;
1971 while (p >= oldpath && isdirsep (*p))
1973 olen = p + 1 - oldpath;
1976 /* The root directory cannot be renamed. This also rejects
1977 the corner case of rename("/","/"), even though it is the
1982 old_dir_requested = true;
1984 oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1987 set_errno (oldpc.error);
1990 if (!oldpc.exists ())
1995 if (oldpc.isspecial () && !oldpc.issocket () && !oldpc.is_fs_special ())
1997 /* No renames from virtual FS */
2001 if (oldpc.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT) && !oldpc.issymlink ())
2003 /* Volume mount point. If we try to rename a volume mount point, NT
2004 returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==>
2005 errno EXDEV. That's bad since mv(1) will now perform a cross-device
2006 move. So what we do here is to treat the volume mount point just
2007 like Linux treats a mount point. */
2011 if (old_dir_requested && !oldpc.isdir ())
2013 /* Reject rename("file/","x"). */
2014 set_errno (ENOTDIR);
2017 if (oldpc.known_suffix
2018 && (ascii_strcasematch (oldpath + olen - 4, ".lnk")
2019 || ascii_strcasematch (oldpath + olen - 4, ".exe")))
2020 old_explicit_suffix = true;
2022 nlen = strlen (newpath);
2023 if (isdirsep (newpath[nlen - 1]))
2026 char *p = stpcpy (buf = tp.c_get (), newpath) - 1;
2028 while (p >= newpath && isdirsep (*p))
2030 nlen = p + 1 - newpath;
2031 if (!nlen) /* The root directory is never empty. */
2033 set_errno (ENOTEMPTY);
2036 new_dir_requested = true;
2038 newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
2041 set_errno (newpc.error);
2044 if (newpc.isspecial () && !newpc.issocket ()) /* No renames to virtual FSes */
2049 if (new_dir_requested && !(newpc.exists ()
2050 ? newpc.isdir () : oldpc.isdir ()))
2052 /* Reject rename("file1","file2/"), but allow rename("dir","d/"). */
2053 set_errno (newpc.exists () ? ENOTDIR : ENOENT);
2056 if (newpc.exists () && (oldpc.isdir () ? !newpc.isdir () : newpc.isdir ()))
2058 /* Reject rename("file","dir") and rename("dir","file"). */
2059 set_errno (newpc.isdir () ? EISDIR : ENOTDIR);
2062 if (newpc.known_suffix
2063 && (ascii_strcasematch (newpath + nlen - 4, ".lnk")
2064 || ascii_strcasematch (newpath + nlen - 4, ".exe")))
2065 new_explicit_suffix = true;
2067 /* This test is necessary in almost every case, so just do it once here. */
2068 equal_path = RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2069 newpc.get_nt_native_path (),
2070 oldpc.objcaseinsensitive ());
2072 /* First check if oldpath and newpath only differ by case. If so, it's
2073 just a request to change the case of the filename. By simply setting
2074 the file attributes to INVALID_FILE_ATTRIBUTES (which translates to
2075 "file doesn't exist"), all later tests are skipped. */
2076 if (oldpc.objcaseinsensitive () && newpc.exists () && equal_path
2077 && old_explicit_suffix == new_explicit_suffix)
2079 if (RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2080 newpc.get_nt_native_path (),
2086 newpc.file_attributes (INVALID_FILE_ATTRIBUTES);
2088 else if (oldpc.isdir ())
2090 /* Check for newpath being identical or a subdir of oldpath. */
2091 if (RtlPrefixUnicodeString (oldpc.get_nt_native_path (),
2092 newpc.get_nt_native_path (),
2095 if (newpc.get_nt_native_path ()->Length
2096 == oldpc.get_nt_native_path ()->Length)
2101 if (*(PWCHAR) ((PBYTE) newpc.get_nt_native_path ()->Buffer
2102 + oldpc.get_nt_native_path ()->Length) == L'\\')
2109 else if (!newpc.exists ())
2111 if (equal_path && old_explicit_suffix != new_explicit_suffix)
2113 newpc.check (newpath, PC_SYM_NOFOLLOW);
2114 if (RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2115 newpc.get_nt_native_path (),
2116 oldpc.objcaseinsensitive ()))
2122 else if (oldpc.is_lnk_special ()
2123 && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2125 rename_append_suffix (newpc, newpath, nlen, ".lnk");
2126 else if (oldpc.is_binary () && !old_explicit_suffix
2127 && oldpc.known_suffix
2128 && !nt_path_has_executable_suffix (newpc.get_nt_native_path ()))
2129 /* Never append .exe suffix if oldpath had .exe suffix given
2130 explicitely, or if oldpath wasn't already a .exe file, or
2131 if the destination filename has one of the blessed executable
2133 Note: To rename an executable foo.exe to bar-without-suffix,
2134 the .exe suffix must be given explicitly in oldpath. */
2135 rename_append_suffix (newpc, newpath, nlen, ".exe");
2139 if (equal_path && old_explicit_suffix != new_explicit_suffix)
2141 newpc.check (newpath, PC_SYM_NOFOLLOW);
2142 if (RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2143 newpc.get_nt_native_path (),
2144 oldpc.objcaseinsensitive ()))
2150 else if (oldpc.is_lnk_special ())
2152 if (!newpc.is_lnk_special ()
2153 && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2156 rename_append_suffix (new2pc, newpath, nlen, ".lnk");
2160 else if (oldpc.is_binary ())
2162 /* Never append .exe suffix if oldpath had .exe suffix given
2163 explicitely, or if newfile is a binary (in which case the given
2164 name probably makes sesne as it is), or if the destination
2165 filename has one of the blessed executable suffixes. */
2166 if (!old_explicit_suffix && oldpc.known_suffix
2167 && !newpc.is_binary ()
2168 && !nt_path_has_executable_suffix (newpc.get_nt_native_path ()))
2170 rename_append_suffix (new2pc, newpath, nlen, ".exe");
2176 if ((RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2178 || RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2180 && !new_explicit_suffix)
2182 new2pc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
2183 newpc.get_nt_native_path ()->Length -= 4 * sizeof (WCHAR);
2184 if (new2pc.is_binary () || new2pc.is_lnk_special ())
2189 dstpc = (removepc == &newpc) ? &new2pc : &newpc;
2191 /* Opening the file must be part of the transaction. It's not sufficient
2192 to call only NtSetInformationFile under the transaction. Therefore we
2193 have to start the transaction here, if necessary. */
2194 if (wincap.has_transactions ()
2195 && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS)
2197 || (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY))))
2198 start_transaction (old_trans, trans);
2203 /* Talking about inconsistent behaviour...
2204 - DELETE is required to rename a file. So far, so good.
2205 - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the
2206 FileRenameInformation call fails with STATUS_ACCESS_DENIED. However,
2207 on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used
2208 and the file we try to rename is a symlink. Urgh.
2209 - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE mode if
2210 the file has the R/O attribute set and returns STATUS_ACCESS_DENIED in
2213 ULONG access = DELETE | (oldpc.fs_is_cifs () ? FILE_READ_ATTRIBUTES : 0);
2214 ULONG sharing = FILE_SHARE_READ | FILE_SHARE_WRITE
2215 | (oldpc.fs_is_samba () ? 0 : FILE_SHARE_DELETE);
2216 ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT
2217 | (oldpc.is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0);
2218 status = NtOpenFile (&fh, access,
2219 oldpc.get_object_attr (attr, sec_none_nih),
2220 &io, sharing, flags);
2222 if (!NT_SUCCESS (status))
2224 debug_printf ("status %p", status);
2225 if (status == STATUS_SHARING_VIOLATION
2226 && WaitForSingleObject (signal_arrived, 10L) != WAIT_OBJECT_0)
2228 /* Typical BLODA problem. Some virus scanners check newly generated
2229 files and while doing that disallow DELETE access. That's really
2230 bad because it breaks applications which copy files by creating
2231 a temporary filename and then rename the temp filename to the
2232 target filename. This renaming fails due to the jealous virus
2233 scanner and the application fails to create the target file.
2235 This kludge tries to work around that by yielding until the
2236 sharing violation goes away, or a signal arrived, or after
2237 about a second, give or take. */
2238 if (++retry_count < 40)
2244 __seterrno_from_nt_status (status);
2248 /* Renaming a dir to another, existing dir fails always, even if
2249 ReplaceIfExists is set to TRUE and the existing dir is empty. So
2250 we have to remove the destination dir first. This also covers the
2251 case that the destination directory is not empty. In that case,
2252 unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */
2253 if (dstpc->isdir ())
2255 status = unlink_nt (*dstpc);
2256 if (!NT_SUCCESS (status))
2258 __seterrno_from_nt_status (status);
2262 /* You can't copy a file if the destination exists and has the R/O
2263 attribute set. Remove the R/O attribute first. But first check
2264 if a removepc exists. If so, dstpc points to a non-existing file
2265 due to a mangled suffix. */
2266 else if (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY))
2268 status = NtOpenFile (&nfh, FILE_WRITE_ATTRIBUTES,
2269 dstpc->get_object_attr (attr, sec_none_nih),
2270 &io, FILE_SHARE_VALID_FLAGS,
2271 FILE_OPEN_FOR_BACKUP_INTENT
2272 | (dstpc->is_rep_symlink ()
2273 ? FILE_OPEN_REPARSE_POINT : 0));
2274 if (!NT_SUCCESS (status))
2276 __seterrno_from_nt_status (status);
2279 status = NtSetAttributesFile (nfh, dstpc->file_attributes ()
2280 & ~FILE_ATTRIBUTE_READONLY);
2282 if (!NT_SUCCESS (status))
2284 __seterrno_from_nt_status (status);
2289 /* SUSv3: If the old argument and the new argument resolve to the same
2290 existing file, rename() shall return successfully and perform no
2292 The test tries to be as quick as possible. First it tests for identical
2293 volume serial numbers because that information is available anyway.
2294 Then it tests if oldpath has more than 1 hardlink, then it opens newpath
2295 and tests for identical file ids. If so, oldpath and newpath refer to
2297 if ((removepc || dstpc->exists ())
2299 && dstpc->fs_serial_number () == oldpc.fs_serial_number ()
2300 && NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofsi, sizeof ofsi,
2301 FileStandardInformation))
2302 && ofsi.NumberOfLinks > 1
2303 && NT_SUCCESS (NtOpenFile (&nfh, READ_CONTROL,
2304 (removepc ?: dstpc)->get_object_attr (attr, sec_none_nih),
2305 &io, FILE_SHARE_VALID_FLAGS,
2306 FILE_OPEN_FOR_BACKUP_INTENT
2307 | ((removepc ?: dstpc)->is_rep_symlink ()
2308 ? FILE_OPEN_REPARSE_POINT : 0))))
2310 FILE_INTERNAL_INFORMATION ofii, nfii;
2312 if (NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofii, sizeof ofii,
2313 FileInternalInformation))
2314 && NT_SUCCESS (NtQueryInformationFile (nfh, &io, &nfii, sizeof nfii,
2315 FileInternalInformation))
2316 && ofii.FileId.QuadPart == nfii.FileId.QuadPart)
2318 debug_printf ("%s and %s are the same file", oldpath, newpath);
2325 size = sizeof (FILE_RENAME_INFORMATION)
2326 + dstpc->get_nt_native_path ()->Length;
2327 if (size > NT_MAX_PATH * sizeof (WCHAR)) /* Hopefully very seldom. */
2328 pfri = (PFILE_RENAME_INFORMATION) alloca (size);
2330 pfri = (PFILE_RENAME_INFORMATION) tp.w_get ();
2331 pfri->ReplaceIfExists = TRUE;
2332 pfri->RootDirectory = NULL;
2333 pfri->FileNameLength = dstpc->get_nt_native_path ()->Length;
2334 memcpy (&pfri->FileName, dstpc->get_nt_native_path ()->Buffer,
2335 pfri->FileNameLength);
2336 status = NtSetInformationFile (fh, &io, pfri, size, FileRenameInformation);
2337 /* This happens if the access rights don't allow deleting the destination.
2338 Even if the handle to the original file is opened with BACKUP
2339 and/or RECOVERY, these flags don't apply to the destination of the
2340 rename operation. So, a privileged user can't rename a file to an
2341 existing file, if the permissions of the existing file aren't right.
2342 Like directories, we have to handle this separately by removing the
2343 destination before renaming. */
2344 if (status == STATUS_ACCESS_DENIED && dstpc->exists () && !dstpc->isdir ())
2346 if (wincap.has_transactions ()
2347 && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS)
2350 start_transaction (old_trans, trans);
2351 /* As mentioned earlier, opening the file must be part of the
2352 transaction. Therefore we have to reopen the file here if the
2353 transaction hasn't been started already. Unfortunately we can't
2354 use the NT "reopen file from existing handle" feature. In that
2355 case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT. We *have*
2356 to close the handle to the file first, *then* we can re-open it.
2357 Fortunately nothing has happened yet, so the atomicity of the
2358 rename functionality is not spoiled. */
2360 status = NtOpenFile (&fh, DELETE,
2361 oldpc.get_object_attr (attr, sec_none_nih),
2362 &io, FILE_SHARE_VALID_FLAGS,
2363 FILE_OPEN_FOR_BACKUP_INTENT
2364 | (oldpc.is_rep_symlink ()
2365 ? FILE_OPEN_REPARSE_POINT : 0));
2366 if (!NT_SUCCESS (status))
2368 __seterrno_from_nt_status (status);
2372 if (NT_SUCCESS (status = unlink_nt (*dstpc)))
2373 status = NtSetInformationFile (fh, &io, pfri, size,
2374 FileRenameInformation);
2376 if (NT_SUCCESS (status))
2379 unlink_nt (*removepc);
2383 __seterrno_from_nt_status (status);
2388 if (wincap.has_transactions () && trans)
2389 stop_transaction (status, old_trans, trans);
2390 syscall_printf ("%R = rename(%s, %s)", res, oldpath, newpath);
2395 system (const char *cmdstring)
2397 pthread_testcancel ();
2400 if (efault.faulted (EFAULT))
2404 const char* command[4];
2406 if (cmdstring == NULL)
2411 command[2] = cmdstring;
2412 command[3] = (const char *) NULL;
2414 if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1)
2416 // when exec fails, return value should be as if shell
2417 // executed exit (127)
2425 setdtablesize (int size)
2427 if (size <= (int)cygheap->fdtab.size || cygheap->fdtab.extend (size - cygheap->fdtab.size))
2436 return cygheap->fdtab.size > OPEN_MAX ? cygheap->fdtab.size : OPEN_MAX;
2442 return (size_t) wincap.allocation_granularity ();
2446 getsystempagesize ()
2448 return (size_t) wincap.page_size ();
2451 /* FIXME: not all values are correct... */
2453 fpathconf (int fd, int v)
2455 cygheap_fdget cfd (fd);
2458 return cfd->fpathconf (v);
2462 pathconf (const char *file, int v)
2468 if (efault.faulted (EFAULT))
2476 if (!(fh = build_fh_name (file, PC_SYM_FOLLOW, stat_suffixes)))
2481 ret = fh->fpathconf (v);
2487 ttyname_r (int fd, char *buf, size_t buflen)
2491 if (efault.faulted ())
2495 cygheap_fdget cfd (fd, true);
2498 else if (!cfd->is_tty ())
2500 else if (buflen < strlen (cfd->ttyname ()) + 1)
2503 strcpy (buf, cfd->ttyname ());
2505 debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf);
2512 static char name[TTY_NAME_MAX];
2513 int ret = ttyname_r (fd, name, TTY_NAME_MAX);
2526 str = _my_tls.locals.ttybuf;
2527 if (myself->ctty < 0)
2528 strcpy (str, "no tty");
2532 d.parse (myself->ctty);
2533 strcpy (str, d.name);
2538 /* Tells stdio if it should do the cr/lf conversion for this file */
2540 _cygwin_istext_for_stdio (int fd)
2542 if (CYGWIN_VERSION_OLD_STDIO_CRLF_HANDLING)
2544 syscall_printf ("fd %d: old API", fd);
2545 return 0; /* we do it for old apps, due to getc/putc macros */
2548 cygheap_fdget cfd (fd, false, false);
2551 syscall_printf ("fd %d: not open", fd);
2556 if (cfd->get_device () != FH_FS)
2558 syscall_printf ("fd not disk file. Defaulting to binary.");
2563 if (cfd->wbinary () || cfd->rbinary ())
2565 syscall_printf ("fd %d: opened as binary", fd);
2569 syscall_printf ("fd %d: defaulting to text", fd);
2573 /* internal newlib function */
2574 extern "C" int _fwalk (struct _reent *ptr, int (*function) (FILE *));
2577 setmode_helper (FILE *f)
2579 if (fileno (f) != _my_tls.locals.setmode_file)
2581 syscall_printf ("improbable, but %d != %d", fileno (f), _my_tls.locals.setmode_file);
2584 syscall_printf ("file was %s now %s", f->_flags & __SCLE ? "text" : "binary",
2585 _my_tls.locals.setmode_mode & O_TEXT ? "text" : "binary");
2586 if (_my_tls.locals.setmode_mode & O_TEXT)
2587 f->_flags |= __SCLE;
2589 f->_flags &= ~__SCLE;
2596 cygheap_fdget cfd (fd);
2600 return cfd->get_flags () & (O_BINARY | O_TEXT);
2603 /* Set a file descriptor into text or binary mode, returning the
2607 setmode (int fd, int mode)
2609 cygheap_fdget cfd (fd);
2612 if (mode != O_BINARY && mode != O_TEXT && mode != 0)
2618 /* Note that we have no way to indicate the case that writes are
2619 binary but not reads, or vice-versa. These cases can arise when
2620 using the tty or console interface. People using those
2621 interfaces should not use setmode. */
2624 if (cfd->wbinary () && cfd->rbinary ())
2626 else if (cfd->wbinset () && cfd->rbinset ())
2627 res = O_TEXT; /* Specifically set O_TEXT */
2632 cfd->reset_to_open_binmode ();
2634 cfd->set_flags ((cfd->get_flags () & ~(O_TEXT | O_BINARY)) | mode);
2636 syscall_printf ("(%d<%S>, %p) returning %s", fd,
2637 cfd->pc.get_nt_native_path (), mode,
2638 res & O_TEXT ? "text" : "binary");
2643 cygwin_setmode (int fd, int mode)
2645 int res = setmode (fd, mode);
2648 _my_tls.locals.setmode_file = fd;
2649 if (_cygwin_istext_for_stdio (fd))
2650 _my_tls.locals.setmode_mode = O_TEXT;
2652 _my_tls.locals.setmode_mode = O_BINARY;
2653 _fwalk (_GLOBAL_REENT, setmode_helper);
2659 posix_fadvise (int fd, _off64_t offset, _off64_t len, int advice)
2662 cygheap_fdget cfd (fd);
2664 res = cfd->fadvise (offset, len, advice);
2667 syscall_printf ("%R = posix_fadvice(%d, %D, %D, %d)",
2668 res, fd, offset, len, advice);
2673 posix_fallocate (int fd, _off64_t offset, _off64_t len)
2676 if (offset < 0 || len == 0)
2680 cygheap_fdget cfd (fd);
2682 res = cfd->ftruncate (offset + len, false);
2686 syscall_printf ("%R = posix_fallocate(%d, %D, %D)", res, fd, offset, len);
2691 ftruncate64 (int fd, _off64_t length)
2694 cygheap_fdget cfd (fd);
2696 res = cfd->ftruncate (length, true);
2699 syscall_printf ("%R = ftruncate(%d, %D)", res, fd, length);
2703 /* ftruncate: P96 5.6.7.1 */
2705 ftruncate (int fd, _off_t length)
2707 return ftruncate64 (fd, (_off64_t)length);
2710 /* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
2712 truncate64 (const char *pathname, _off64_t length)
2717 fd = open (pathname, O_RDWR);
2721 res = ftruncate64 (fd, length);
2724 syscall_printf ("%R = truncate(%s, %D)", res, pathname, length);
2729 /* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
2731 truncate (const char *pathname, _off_t length)
2733 return truncate64 (pathname, (_off64_t)length);
2737 get_osfhandle (int fd)
2741 cygheap_fdget cfd (fd);
2743 res = (long) cfd->get_handle ();
2747 syscall_printf ("%R = get_osfhandle(%d)", res, fd);
2752 fstatvfs (int fd, struct statvfs *sfs)
2755 if (efault.faulted (EFAULT))
2758 cygheap_fdget cfd (fd);
2761 return cfd->fstatvfs (sfs);
2765 statvfs (const char *name, struct statvfs *sfs)
2768 fhandler_base *fh = NULL;
2771 if (efault.faulted (EFAULT))
2774 if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes)))
2779 debug_printf ("got %d error from build_fh_name", fh->error ());
2780 set_errno (fh->error ());
2782 else if (fh->exists ())
2784 debug_printf ("(%s, %p), file_attributes %d", name, sfs, (DWORD) *fh);
2785 res = fh->fstatvfs (sfs);
2793 syscall_printf ("%R = statvfs(%s,%p)", res, name, sfs);
2798 fstatfs (int fd, struct statfs *sfs)
2801 int ret = fstatvfs (fd, &vfs);
2804 sfs->f_type = vfs.f_flag;
2805 sfs->f_bsize = vfs.f_bsize;
2806 sfs->f_blocks = vfs.f_blocks;
2807 sfs->f_bavail = vfs.f_bavail;
2808 sfs->f_bfree = vfs.f_bfree;
2811 sfs->f_fsid = vfs.f_fsid;
2812 sfs->f_namelen = vfs.f_namemax;
2818 statfs (const char *fname, struct statfs *sfs)
2821 int ret = statvfs (fname, &vfs);
2824 sfs->f_type = vfs.f_flag;
2825 sfs->f_bsize = vfs.f_bsize;
2826 sfs->f_blocks = vfs.f_blocks;
2827 sfs->f_bavail = vfs.f_bavail;
2828 sfs->f_bfree = vfs.f_bfree;
2831 sfs->f_fsid = vfs.f_fsid;
2832 sfs->f_namelen = vfs.f_namemax;
2837 /* setpgid: POSIX 4.3.3.1 */
2839 setpgid (pid_t pid, pid_t pgid)
2851 pinfo p (pid, PID_MAP_RW);
2854 else if (p->pgid == pgid)
2856 /* A process may only change the process group of itself and its children */
2857 else if (p != myself && p->ppid != myself->pid)
2862 if (p->pid != p->pgid)
2863 p->set_has_pgid_children (0);
2868 syscall_printf ("pid %d, pgid %d, res %d", pid, pgid, res);
2890 return setpgid (0, 0);
2902 static char buf[TTY_NAME_MAX];
2903 return ptsname_r (fd, buf, sizeof (buf)) == 0 ? buf : NULL;
2907 ptsname_r (int fd, char *buf, size_t buflen)
2915 cygheap_fdget cfd (fd);
2918 return cfd->ptsname_r (buf, buflen);
2921 static int __stdcall
2922 mknod_worker (const char *path, mode_t type, mode_t mode, _major_t major,
2925 char buf[sizeof (":\\00000000:00000000:00000000") + PATH_MAX];
2926 sprintf (buf, ":\\%x:%x:%x", major, minor,
2927 type | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)));
2928 return symlink_worker (buf, path, true, true);
2932 mknod32 (const char *path, mode_t mode, __dev32_t dev)
2935 if (efault.faulted (EFAULT))
2943 if (strlen (path) >= PATH_MAX)
2946 path_conv w32path (path, PC_SYM_NOFOLLOW);
2947 if (w32path.exists ())
2953 mode_t type = mode & S_IFMT;
2954 _major_t major = _major (dev);
2955 _minor_t minor = _minor (dev);
2963 major = _major (FH_FIFO);
2964 minor = _minor (FH_FIFO);
2970 int fd = open (path, O_CREAT, mode);
2982 return mknod_worker (w32path.get_win32 (), type, mode, major, minor);
2986 mknod (const char *_path, mode_t mode, __dev16_t dev)
2988 return mknod32 (_path, mode, (__dev32_t) dev);
2992 mkfifo (const char *path, mode_t mode)
2994 return mknod32 (path, (mode & ~S_IFMT) | S_IFIFO, 0);
2997 /* seteuid: standards? */
2999 seteuid32 (__uid32_t uid)
3001 debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
3002 uid, myself->uid, myself->gid);
3004 /* Same uid as we're just running under is usually a no-op.
3006 Except we have an external token which is a restricted token. Or,
3007 the external token is NULL, but the current impersonation token is
3008 a restricted token. This allows to restrict user rights temporarily
3011 cygwin_internal(CW_SET_EXTERNAL_TOKEN, restricted_token,
3012 CW_TOKEN_RESTRICTED);
3014 [...do stuff with restricted rights...]
3015 cygwin_internal(CW_SET_EXTERNAL_TOKEN, INVALID_HANDLE_VALUE,
3016 CW_TOKEN_RESTRICTED);
3019 Note that using the current uid is a requirement! Starting with Windows
3020 Vista, we have restricted tokens galore (UAC), so this is really just
3021 a special case to restict your own processes to lesser rights. */
3022 bool request_restricted_uid_switch = (uid == myself->uid
3023 && cygheap->user.ext_token_is_restricted);
3024 if (uid == myself->uid && !cygheap->user.groups.ischanged
3025 && !request_restricted_uid_switch)
3027 debug_printf ("Nothing happens");
3032 user_groups &groups = cygheap->user.groups;
3033 HANDLE new_token = INVALID_HANDLE_VALUE;
3034 struct passwd * pw_new;
3035 bool token_is_internal, issamesid = false;
3037 pw_new = internal_getpwuid (uid);
3038 if (!usersid.getfrompw (pw_new))
3044 cygheap->user.deimpersonate ();
3046 /* Verify if the process token is suitable. */
3047 /* First of all, skip all checks if a switch to a restricted token has been
3048 requested, or if trying to switch back from it. */
3049 if (request_restricted_uid_switch)
3051 if (cygheap->user.external_token != NO_IMPERSONATION)
3053 debug_printf ("Switch to restricted token");
3054 new_token = cygheap->user.external_token;
3058 debug_printf ("Switch back from restricted token");
3059 new_token = hProcToken;
3060 cygheap->user.ext_token_is_restricted = false;
3063 /* TODO, CV 2008-11-25: The check against saved_sid is a kludge and a
3064 shortcut. We must check if it's really feasible in the long run.
3065 The reason to add this shortcut is this: sshd switches back to the
3066 privileged user running sshd at least twice in the process of
3067 authentication. It calls seteuid first, then setegid. Due to this
3068 order, the setgroups group list is still active when calling seteuid
3069 and verify_token treats the original token of the privileged user as
3070 insufficient. This in turn results in creating a new user token for
3071 the privileged user instead of using the orignal token. This can have
3072 unfortunate side effects. The created token has different group
3073 memberships, different user rights, and misses possible network
3075 Therefore we try this shortcut now. When switching back to the
3076 privileged user, we probably always want a correct (aka original)
3077 user token for this privileged user, not only in sshd. */
3078 else if ((uid == cygheap->user.saved_uid
3079 && usersid == cygheap->user.saved_sid ())
3080 || verify_token (hProcToken, usersid, groups))
3081 new_token = hProcToken;
3082 /* Verify if the external token is suitable */
3083 else if (cygheap->user.external_token != NO_IMPERSONATION
3084 && verify_token (cygheap->user.external_token, usersid, groups))
3085 new_token = cygheap->user.external_token;
3086 /* Verify if the current token (internal or former external) is suitable */
3087 else if (cygheap->user.curr_primary_token != NO_IMPERSONATION
3088 && cygheap->user.curr_primary_token != cygheap->user.external_token
3089 && verify_token (cygheap->user.curr_primary_token, usersid, groups,
3090 &token_is_internal))
3091 new_token = cygheap->user.curr_primary_token;
3092 /* Verify if the internal token is suitable */
3093 else if (cygheap->user.internal_token != NO_IMPERSONATION
3094 && cygheap->user.internal_token != cygheap->user.curr_primary_token
3095 && verify_token (cygheap->user.internal_token, usersid, groups,
3096 &token_is_internal))
3097 new_token = cygheap->user.internal_token;
3099 debug_printf ("Found token %d", new_token);
3101 /* If no impersonation token is available, try to authenticate using
3102 LSA private data stored password, LSA authentication using our own
3103 LSA module, or, as last chance, NtCreateToken. */
3104 if (new_token == INVALID_HANDLE_VALUE)
3106 new_token = lsaprivkeyauth (pw_new);
3109 /* We have to verify this token since settings in /etc/group
3110 might render it unusable im terms of group membership. */
3111 if (!verify_token (new_token, usersid, groups))
3113 CloseHandle (new_token);
3119 debug_printf ("lsaprivkeyauth failed, try lsaauth.");
3120 if (!(new_token = lsaauth (usersid, groups, pw_new)))
3122 debug_printf ("lsaauth failed, try create_token.");
3123 new_token = create_token (usersid, groups, pw_new);
3124 if (new_token == INVALID_HANDLE_VALUE)
3126 debug_printf ("create_token failed, bail out of here");
3127 cygheap->user.reimpersonate ();
3133 /* Keep at most one internal token */
3134 if (cygheap->user.internal_token != NO_IMPERSONATION)
3135 CloseHandle (cygheap->user.internal_token);
3136 cygheap->user.internal_token = new_token;
3139 if (new_token != hProcToken)
3143 if (!request_restricted_uid_switch)
3145 /* Avoid having HKCU use default user */
3147 load_registry_hive (usersid.string (name));
3150 /* Try setting owner to same value as user. */
3151 status = NtSetInformationToken (new_token, TokenOwner,
3152 &usersid, sizeof usersid);
3153 if (!NT_SUCCESS (status))
3154 debug_printf ("NtSetInformationToken (user.token, TokenOwner), %p",
3156 /* Try setting primary group in token to current group */
3157 status = NtSetInformationToken (new_token, TokenPrimaryGroup,
3158 &groups.pgsid, sizeof (cygsid));
3159 if (!NT_SUCCESS (status))
3160 debug_printf ("NtSetInformationToken (user.token, TokenPrimaryGroup),"
3162 /* Try setting default DACL */
3163 PACL dacl_buf = (PACL) alloca (MAX_DACL_LEN (5));
3164 if (sec_acl (dacl_buf, true, true, usersid))
3166 TOKEN_DEFAULT_DACL tdacl = { dacl_buf };
3167 status = NtSetInformationToken (new_token, TokenDefaultDacl,
3168 &tdacl, sizeof (tdacl));
3169 if (!NT_SUCCESS (status))
3170 debug_printf ("NtSetInformationToken (TokenDefaultDacl), %p",
3175 issamesid = (usersid == cygheap->user.sid ());
3176 cygheap->user.set_sid (usersid);
3177 cygheap->user.curr_primary_token = new_token == hProcToken ? NO_IMPERSONATION
3179 cygheap->user.curr_token_is_restricted = false;
3180 cygheap->user.setuid_to_restricted = false;
3181 if (cygheap->user.curr_imp_token != NO_IMPERSONATION)
3183 CloseHandle (cygheap->user.curr_imp_token);
3184 cygheap->user.curr_imp_token = NO_IMPERSONATION;
3186 if (cygheap->user.curr_primary_token != NO_IMPERSONATION)
3188 /* HANDLE_FLAG_INHERIT may be missing in external token. */
3189 if (!SetHandleInformation (cygheap->user.curr_primary_token,
3190 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)
3191 || !DuplicateTokenEx (cygheap->user.curr_primary_token,
3192 MAXIMUM_ALLOWED, &sec_none,
3193 SecurityImpersonation, TokenImpersonation,
3194 &cygheap->user.curr_imp_token))
3197 cygheap->user.curr_primary_token = NO_IMPERSONATION;
3200 cygheap->user.curr_token_is_restricted = request_restricted_uid_switch;
3201 set_cygwin_privileges (cygheap->user.curr_primary_token);
3202 set_cygwin_privileges (cygheap->user.curr_imp_token);
3204 if (!cygheap->user.reimpersonate ())
3210 cygheap->user.set_name (pw_new->pw_name);
3212 groups.ischanged = FALSE;
3214 /* Recreate and fill out the user shared region for a new user. */
3215 user_info::create (true);
3220 seteuid (__uid16_t uid)
3222 return seteuid32 (uid16touid32 (uid));
3225 /* setuid: POSIX 4.2.2.1 */
3227 setuid32 (__uid32_t uid)
3229 int ret = seteuid32 (uid);
3232 cygheap->user.real_uid = myself->uid;
3233 /* If restricted token, forget original privileges on exec (). */
3234 cygheap->user.setuid_to_restricted = cygheap->user.curr_token_is_restricted;
3236 debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
3241 setuid (__uid16_t uid)
3243 return setuid32 (uid16touid32 (uid));
3247 setreuid32 (__uid32_t ruid, __uid32_t euid)
3251 __uid32_t old_euid = myself->uid;
3253 if (ruid != ILLEGAL_UID && cygheap->user.real_uid != ruid && euid != ruid)
3254 tried = !(ret = seteuid32 (ruid));
3255 if (!ret && euid != ILLEGAL_UID)
3256 ret = seteuid32 (euid);
3257 if (tried && (ret || euid == ILLEGAL_UID) && seteuid32 (old_euid))
3258 system_printf ("Cannot restore original euid %u", old_euid);
3259 if (!ret && ruid != ILLEGAL_UID)
3260 cygheap->user.real_uid = ruid;
3261 debug_printf ("real: %u, effective: %u", cygheap->user.real_uid, myself->uid);
3266 setreuid (__uid16_t ruid, __uid16_t euid)
3268 return setreuid32 (uid16touid32 (ruid), uid16touid32 (euid));
3271 /* setegid: from System V. */
3273 setegid32 (__gid32_t gid)
3275 debug_printf ("new egid: %u current: %u", gid, myself->gid);
3277 if (gid == myself->gid)
3284 user_groups * groups = &cygheap->user.groups;
3286 struct __group32 * gr = internal_getgrgid (gid);
3288 if (!gsid.getfromgr (gr))
3295 groups->update_pgrp (gsid);
3296 if (cygheap->user.issetuid ())
3298 /* If impersonated, update impersonation token... */
3299 status = NtSetInformationToken (cygheap->user.primary_token (),
3300 TokenPrimaryGroup, &gsid, sizeof gsid);
3301 if (!NT_SUCCESS (status))
3302 debug_printf ("NtSetInformationToken (primary_token, "
3303 "TokenPrimaryGroup), %p", status);
3304 status = NtSetInformationToken (cygheap->user.imp_token (),
3305 TokenPrimaryGroup, &gsid, sizeof gsid);
3306 if (!NT_SUCCESS (status))
3307 debug_printf ("NtSetInformationToken (token, TokenPrimaryGroup), %p",
3310 cygheap->user.deimpersonate ();
3311 status = NtSetInformationToken (hProcToken, TokenPrimaryGroup,
3312 &gsid, sizeof gsid);
3313 if (!NT_SUCCESS (status))
3314 debug_printf ("NtSetInformationToken (hProcToken, TokenPrimaryGroup), %p",
3316 clear_procimptoken ();
3317 cygheap->user.reimpersonate ();
3322 setegid (__gid16_t gid)
3324 return setegid32 (gid16togid32 (gid));
3327 /* setgid: POSIX 4.2.2.1 */
3329 setgid32 (__gid32_t gid)
3331 int ret = setegid32 (gid);
3333 cygheap->user.real_gid = myself->gid;
3338 setgid (__gid16_t gid)
3340 int ret = setegid32 (gid16togid32 (gid));
3342 cygheap->user.real_gid = myself->gid;
3347 setregid32 (__gid32_t rgid, __gid32_t egid)
3351 __gid32_t old_egid = myself->gid;
3353 if (rgid != ILLEGAL_GID && cygheap->user.real_gid != rgid && egid != rgid)
3354 tried = !(ret = setegid32 (rgid));
3355 if (!ret && egid != ILLEGAL_GID)
3356 ret = setegid32 (egid);
3357 if (tried && (ret || egid == ILLEGAL_GID) && setegid32 (old_egid))
3358 system_printf ("Cannot restore original egid %u", old_egid);
3359 if (!ret && rgid != ILLEGAL_GID)
3360 cygheap->user.real_gid = rgid;
3361 debug_printf ("real: %u, effective: %u", cygheap->user.real_gid, myself->gid);
3366 setregid (__gid16_t rgid, __gid16_t egid)
3368 return setregid32 (gid16togid32 (rgid), gid16togid32 (egid));
3371 /* chroot: privileged Unix system call. */
3372 /* FIXME: Not privileged here. How should this be done? */
3374 chroot (const char *newroot)
3376 path_conv path (newroot, PC_SYM_FOLLOW | PC_POSIX);
3380 set_errno (path.error);
3381 else if (!path.exists ())
3383 else if (!path.isdir ())
3384 set_errno (ENOTDIR);
3385 else if (path.isspecial ())
3389 getwinenv("PATH="); /* Save the native PATH */
3390 cygheap->root.set (path.normalized_path, path.get_win32 (),
3391 !!path.objcaseinsensitive ());
3395 syscall_printf ("%R = chroot(%s)", ret, newroot ?: "NULL");
3400 creat (const char *path, mode_t mode)
3402 return open (path, O_WRONLY | O_CREAT | O_TRUNC, mode);
3419 setpriority (int which, id_t who, int value)
3421 DWORD prio = nice_to_winprio (value);
3429 if ((pid_t) who == myself->pid)
3431 if (!SetPriorityClass (GetCurrentProcess (), prio))
3436 myself->nice = value;
3437 debug_printf ("Set nice to %d", myself->nice);
3453 winpids pids ((DWORD) PID_MAP_RW);
3454 for (DWORD i = 0; i < pids.npids; ++i)
3456 _pinfo *p = pids[i];
3462 if ((pid_t) who != p->pid)
3466 if ((pid_t) who != p->pgid)
3470 if ((__uid32_t) who != p->uid)
3474 HANDLE proc_h = OpenProcess (PROCESS_SET_INFORMATION, FALSE,
3480 if (!SetPriorityClass (proc_h, prio))
3484 CloseHandle (proc_h);
3498 getpriority (int which, id_t who)
3500 int nice = NZERO * 2; /* Illegal value */
3507 if ((pid_t) who == myself->pid)
3508 return myself->nice;
3522 winpids pids ((DWORD) 0);
3523 for (DWORD i = 0; i < pids.npids; ++i)
3525 _pinfo *p = pids[i];
3530 if ((pid_t) who == p->pid)
3537 if ((pid_t) who == p->pgid && p->nice < nice)
3541 if ((__uid32_t) who == p->uid && p->nice < nice)
3548 if (nice == NZERO * 2)
3559 return setpriority (PRIO_PROCESS, myself->pid, myself->nice + incr);
3563 * Find the first bit set in I.
3569 static const unsigned char table[] =
3571 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
3572 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
3573 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
3574 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
3575 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
3576 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
3577 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
3578 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
3580 unsigned long int a;
3581 unsigned long int x = i & -i;
3583 a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24);
3585 return table[x >> a] + a;
3589 locked_append (int fd, const void * buf, size_t size)
3591 struct __flock64 lock_buffer = {F_WRLCK, SEEK_SET, 0, 0, 0};
3595 if ((lock_buffer.l_start = lseek64 (fd, 0, SEEK_END)) != (_off64_t) -1
3596 && fcntl64 (fd, F_SETLKW, &lock_buffer) != -1)
3598 if (lseek64 (fd, 0, SEEK_END) != (_off64_t) -1)
3599 write (fd, buf, size);
3600 lock_buffer.l_type = F_UNLCK;
3601 fcntl64 (fd, F_SETLK, &lock_buffer);
3604 while (count++ < 1000
3605 && (errno == EACCES || errno == EAGAIN)
3610 updwtmp (const char *wtmp_file, const struct utmp *ut)
3614 if ((fd = open (wtmp_file, O_WRONLY | O_BINARY, 0)) >= 0)
3616 locked_append (fd, ut, sizeof *ut);
3621 static int utmp_fd = -1;
3622 static bool utmp_readonly = false;
3623 static char *utmp_file = (char *) _PATH_UTMP;
3626 internal_setutent (bool force_readwrite)
3628 if (force_readwrite && utmp_readonly)
3632 utmp_fd = open (utmp_file, O_RDWR | O_BINARY);
3633 /* If open fails, we assume an unprivileged process (who?). In this
3634 case we try again for reading only unless the process calls
3635 pututline() (==force_readwrite) in which case opening just fails. */
3636 if (utmp_fd < 0 && !force_readwrite)
3638 utmp_fd = open (utmp_file, O_RDONLY | O_BINARY);
3640 utmp_readonly = true;
3644 lseek (utmp_fd, 0, SEEK_SET);
3650 internal_setutent (false);
3660 utmp_readonly = false;
3665 utmpname (const char *file)
3668 if (efault.faulted () || !*file)
3670 debug_printf ("Invalid file");
3674 utmp_file = strdup (file);
3675 debug_printf ("New UTMP file: %s", utmp_file);
3678 EXPORT_ALIAS (utmpname, utmpxname)
3680 /* Note: do not make NO_COPY */
3681 static struct utmp utmp_data_buf[16];
3682 static unsigned utix = 0;
3683 #define nutdbuf (sizeof (utmp_data_buf) / sizeof (utmp_data_buf[0]))
3684 #define utmp_data ({ \
3685 if (utix >= nutdbuf) \
3687 utmp_data_buf + utix++; \
3690 static struct utmpx *
3691 copy_ut_to_utx (struct utmp *ut, struct utmpx *utx)
3695 memcpy (utx, ut, sizeof *ut);
3696 utx->ut_tv.tv_sec = ut->ut_time;
3697 utx->ut_tv.tv_usec = 0;
3701 extern "C" struct utmp *
3706 internal_setutent (false);
3711 utmp *ut = utmp_data;
3712 if (read (utmp_fd, ut, sizeof *ut) != sizeof *ut)
3717 extern "C" struct utmp *
3718 getutid (const struct utmp *id)
3721 if (efault.faulted (EFAULT))
3725 internal_setutent (false);
3730 utmp *ut = utmp_data;
3731 while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
3733 switch (id->ut_type)
3739 if (id->ut_type == ut->ut_type)
3746 if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0)
3756 extern "C" struct utmp *
3757 getutline (const struct utmp *line)
3760 if (efault.faulted (EFAULT))
3764 internal_setutent (false);
3769 utmp *ut = utmp_data;
3770 while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
3771 if ((ut->ut_type == LOGIN_PROCESS ||
3772 ut->ut_type == USER_PROCESS) &&
3773 !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line)))
3779 extern "C" struct utmp *
3780 pututline (const struct utmp *ut)
3783 if (efault.faulted (EFAULT))
3785 internal_setutent (true);
3788 debug_printf ("error: utmp_fd %d", utmp_fd);
3791 debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n",
3792 ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id);
3793 debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n",
3794 ut->ut_user, ut->ut_host);
3797 if ((u = getutid (ut)))
3799 lseek (utmp_fd, -sizeof *ut, SEEK_CUR);
3800 write (utmp_fd, ut, sizeof *ut);
3803 locked_append (utmp_fd, ut, sizeof *ut);
3804 /* The documentation says to return a pointer to this which implies that
3805 this has to be cast from a const. That doesn't seem right but the
3806 documentation seems pretty clear on this. */
3807 return (struct utmp *) ut;
3813 internal_setutent (false);
3822 extern "C" struct utmpx *
3825 /* UGH. Not thread safe. */
3826 static struct utmpx utx;
3827 return copy_ut_to_utx (getutent (), &utx);
3830 extern "C" struct utmpx *
3831 getutxid (const struct utmpx *id)
3833 /* UGH. Not thread safe. */
3834 static struct utmpx utx;
3837 if (efault.faulted (EFAULT))
3839 ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec;
3840 return copy_ut_to_utx (getutid ((struct utmp *) id), &utx);
3843 extern "C" struct utmpx *
3844 getutxline (const struct utmpx *line)
3846 /* UGH. Not thread safe. */
3847 static struct utmpx utx;
3850 if (efault.faulted (EFAULT))
3852 ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec;
3853 return copy_ut_to_utx (getutline ((struct utmp *) line), &utx);
3856 extern "C" struct utmpx *
3857 pututxline (const struct utmpx *utmpx)
3859 /* UGH. Not thread safe. */
3860 static struct utmpx utx;
3863 if (efault.faulted (EFAULT))
3865 ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3866 return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx);
3870 updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
3872 ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3873 updwtmp (wtmpx_file, (const struct utmp *) utmpx);
3879 unsigned data[13] = {0x92895012,
3893 bool has_cpuid = false;
3895 DWORD opmask = SetThreadAffinityMask (GetCurrentThread (), 1);
3897 debug_printf ("SetThreadAffinityMask to 1 failed, %E");
3899 if (!can_set_flag (0x00040000))
3900 debug_printf ("386 processor - no cpuid");
3903 debug_printf ("486 processor");
3904 if (can_set_flag (0x00200000))
3906 debug_printf ("processor supports CPUID instruction");
3910 debug_printf ("processor does not support CPUID instruction");
3914 unsigned maxf, unused[3];
3915 cpuid (&maxf, &unused[0], &unused[1], &unused[2], 0);
3920 cpuid (&data[0], &unused[0], &unused[1], &features, 1);
3921 if (features & (1 << 18))
3923 debug_printf ("processor has psn");
3926 cpuid (&unused[0], &unused[1], &data[1], &data[2], 3);
3927 debug_printf ("Processor PSN: %04x-%04x-%04x-%04x-%04x-%04x",
3928 data[0] >> 16, data[0] & 0xffff, data[2] >> 16, data[2] & 0xffff, data[1] >> 16, data[1] & 0xffff);
3932 debug_printf ("processor does not have psn");
3945 NTSTATUS status = NtAllocateUuids (&u1, &u2, &u3, u4.mac);
3946 if (NT_SUCCESS (status))
3950 // Unfortunately Windows will sometimes pick a virtual Ethernet card
3951 // e.g. VMWare Virtual Ethernet Adaptor
3952 debug_printf ("MAC address of first Ethernet card: "
3953 "%02x:%02x:%02x:%02x:%02x:%02x",
3954 u4.mac[0], u4.mac[1], u4.mac[2],
3955 u4.mac[3], u4.mac[4], u4.mac[5]);
3958 debug_printf ("no Ethernet card installed");
3961 reg_key key (HKEY_LOCAL_MACHINE, KEY_READ, L"SOFTWARE", L"Microsoft",
3962 L"Windows NT", L"CurrentVersion", NULL);
3963 key.get_string (L"ProductId", wdata, 24, L"00000-000-0000000-00000");
3964 sys_wcstombs ((char *)&data[6], 24, wdata, 24);
3965 debug_printf ("Windows Product ID: %s", (char *)&data[6]);
3967 GetDiskFreeSpaceEx ("C:\\", NULL, (PULARGE_INTEGER) &data[11], NULL);
3969 debug_printf ("hostid entropy: %08x %08x %08x %08x "
3970 "%08x %08x %08x %08x "
3971 "%08x %08x %08x %08x "
3981 long hostid = 0x40291372;
3982 // a random hashing algorithm
3983 // dependancy on md5 is probably too costly
3984 for (int i=0;i<13;i++)
3985 hostid ^= ((data[i] << (i << 2)) | (data[i] >> (32 - (i << 2))));
3987 if (opmask && !SetThreadAffinityMask (GetCurrentThread (), opmask))
3988 debug_printf ("SetThreadAffinityMask to %p failed, %E", opmask);
3990 debug_printf ("hostid: %08x", hostid);
3995 #define ETC_SHELLS "/etc/shells"
3996 static int shell_index;
3997 static struct __sFILE64 *shell_fp;
4002 /* List of default shells if no /etc/shells exists, defined as on Linux.
4003 FIXME: SunOS has a far longer list, containing all shells which
4004 might be shipped with the OS. Should we do the same for the Cygwin
4005 distro, adding bash, tcsh, ksh, pdksh and zsh? */
4006 static NO_COPY const char *def_shells[] = {
4013 static char buf[PATH_MAX];
4016 if (!shell_fp && !(shell_fp = fopen64 (ETC_SHELLS, "rt")))
4018 if (def_shells[shell_index])
4019 return strcpy (buf, def_shells[shell_index++]);
4022 /* Skip white space characters. */
4023 while ((ch = getc (shell_fp)) != EOF && isspace (ch))
4025 /* Get each non-whitespace character as part of the shell path as long as
4028 ch != EOF && !isspace (ch) && buf_idx < PATH_MAX;
4029 buf_idx++, ch = getc (shell_fp))
4031 /* Skip any trailing non-whitespace character not fitting in buf. If the
4032 path is longer than PATH_MAX, it's invalid anyway. */
4033 while (ch != EOF && !isspace (ch))
4034 ch = getc (shell_fp);
4037 buf[buf_idx] = '\0';
4047 fseek (shell_fp, 0L, SEEK_SET);
4063 flockfile (FILE *file)
4069 ftrylockfile (FILE *file)
4071 return _ftrylockfile (file);
4075 funlockfile (FILE *file)
4077 _funlockfile (file);
4081 popen (const char *command, const char *in_type)
4083 const char *type = in_type;
4086 /* Sanity check in_type */
4087 if (*type == 'b' || *type == 't')
4089 if ((rw != 'r' && rw != 'w') || (*type != '\0'))
4099 int myix = rw == 'r' ? 0 : 1;
4102 FILE *fp = fdopen (fds[myix], in_type);
4105 /* If fds are in the range of stdin/stdout/stderr, move them
4106 out of the way (possibly temporarily). Otherwise, spawn_guts
4107 will be confused. We do this here rather than adding logic to
4108 spawn_guts because spawn_guts is likely to be a more frequently
4109 used routine and having stdin/stdout/stderr closed and reassigned
4110 to pipe handles is an unlikely event. */
4111 int orig_fds[2] = {fds[0], fds[1]};
4112 for (int i = 0; i < 2; i++)
4115 cygheap_fdnew newfd(3);
4116 cygheap->fdtab.move_fd (fds[i], newfd);
4120 int myfd = fds[myix]; /* myfd - convenience variable for manipulation
4121 of the "parent" end of the pipe. */
4122 int stdchild = myix ^ 1; /* stdchild denotes the index into fd for the
4123 handle which will be redirected to
4126 __std[myix] = -1; /* -1 means don't pass this fd to the child
4128 __std[stdchild] = fds[stdchild]; /* Do pass this as the std handle */
4130 const char *argv[4] =
4138 /* Don't pass our end of the pipe to the child process */
4139 int fd_state = fcntl64 (myfd, F_GETFD, 0);
4140 fcntl64 (myfd, F_SETFD, fd_state | FD_CLOEXEC);
4142 /* Also don't pass the file handle currently associated with stdin/stdout
4143 to the child. This function may actually fail if the stdchild fd
4144 is closed. But that's ok. */
4145 int stdchild_state = fcntl64 (stdchild, F_GETFD, 0);
4146 fcntl64 (stdchild, F_SETFD, stdchild_state | FD_CLOEXEC);
4148 /* Start a shell process to run the given command without forking. */
4149 pid_t pid = ch_spawn.worker ("/bin/sh", argv, cur_environ (), _P_NOWAIT,
4150 __std[0], __std[1]);
4152 /* Reinstate the close-on-exec state */
4153 fcntl64 (stdchild, F_SETFD, stdchild_state);
4155 /* If pid >= 0 then spawn_guts succeeded. */
4158 close (fds[stdchild]); /* Close the child end of the pipe. */
4159 /* Move the fd back to its original slot if it has been moved since
4160 we're always supposed to open the lowest numbered available fd
4161 and, if fds[mix] != orig_fds[myix] then orig_fds[myix] is
4162 presumably lower. */
4163 if (fds[myix] != orig_fds[myix])
4164 cygheap->fdtab.move_fd (fds[myix], myfd = orig_fds[myix]);
4165 fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[myfd];
4166 /* Flag that this handle is associated with popen and then reset
4167 the handle's original close-on-exec state. */
4168 fh->set_popen_pid (pid);
4169 fcntl64 (myfd, F_SETFD, fd_state);
4174 /* If we reach here we've seen an error but the pipe handles are open.
4175 Close them and return NULL. */
4176 int save_errno = get_errno ();
4179 set_errno (save_errno);
4186 fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[fileno(fp)];
4188 if (fh->get_device () != FH_PIPEW && fh->get_device () != FH_PIPER)
4194 int pid = fh->get_popen_pid ();
4206 if (waitpid (pid, &status, 0) == pid)
4208 else if (get_errno () == EINTR)
4216 /* Preliminary(?) implementation of the openat family of functions. */
4219 gen_full_path_at (char *path_ret, int dirfd, const char *pathname,
4220 bool null_pathname_allowed = false)
4222 /* Set null_pathname_allowed to true to allow GLIBC compatible behaviour
4223 for NULL pathname. Only used by futimesat. */
4224 if (!pathname && !null_pathname_allowed)
4236 if (strlen (pathname) >= PATH_MAX)
4238 set_errno (ENAMETOOLONG);
4242 if (pathname && isabspath (pathname))
4243 stpcpy (path_ret, pathname);
4248 if (dirfd == AT_FDCWD)
4250 cwdstuff::cwd_lock.acquire ();
4251 p = stpcpy (path_ret, cygheap->cwd.get_posix ());
4252 cwdstuff::cwd_lock.release ();
4256 cygheap_fdget cfd (dirfd);
4259 if (!cfd->pc.isdir ())
4261 set_errno (ENOTDIR);
4264 p = stpcpy (path_ret, cfd->get_name ());
4268 set_errno (ENOTDIR);
4275 stpcpy (p, pathname);
4282 openat (int dirfd, const char *pathname, int flags, ...)
4286 if (efault.faulted (EFAULT))
4288 char *path = tp.c_get ();
4289 if (gen_full_path_at (path, dirfd, pathname))
4295 va_start (ap, flags);
4296 mode = va_arg (ap, mode_t);
4298 return open (path, flags, mode);
4302 faccessat (int dirfd, const char *pathname, int mode, int flags)
4306 if (efault.faulted (EFAULT))
4310 char *path = tp.c_get ();
4311 if (!gen_full_path_at (path, dirfd, pathname))
4313 if ((mode & ~(F_OK|R_OK|W_OK|X_OK))
4314 || (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EACCESS)))
4318 fhandler_base *fh = build_fh_name (path, (flags & AT_SYMLINK_NOFOLLOW
4325 res = fh->fhaccess (mode, !!(flags & AT_EACCESS));
4330 debug_printf ("returning %d", res);
4335 fchmodat (int dirfd, const char *pathname, mode_t mode, int flags)
4339 if (efault.faulted (EFAULT))
4343 /* BSD has lchmod, but Linux does not. POSIX says
4344 AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks; but Linux
4345 blindly fails even for non-symlinks. */
4346 set_errno ((flags & ~AT_SYMLINK_NOFOLLOW) ? EINVAL : EOPNOTSUPP);
4349 char *path = tp.c_get ();
4350 if (gen_full_path_at (path, dirfd, pathname))
4352 return chmod (path, mode);
4356 fchownat (int dirfd, const char *pathname, __uid32_t uid, __gid32_t gid,
4361 if (efault.faulted (EFAULT))
4363 if (flags & ~AT_SYMLINK_NOFOLLOW)
4368 char *path = tp.c_get ();
4369 if (gen_full_path_at (path, dirfd, pathname))
4371 return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW)
4372 ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid);
4376 fstatat (int dirfd, const char *pathname, struct __stat64 *st, int flags)
4380 if (efault.faulted (EFAULT))
4382 if (flags & ~AT_SYMLINK_NOFOLLOW)
4387 char *path = tp.c_get ();
4388 if (gen_full_path_at (path, dirfd, pathname))
4390 path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW)
4391 ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
4392 | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes);
4393 return stat_worker (pc, st);
4396 extern int utimens_worker (path_conv &, const struct timespec *);
4399 utimensat (int dirfd, const char *pathname, const struct timespec *times,
4404 if (efault.faulted (EFAULT))
4406 char *path = tp.c_get ();
4407 if (flags & ~AT_SYMLINK_NOFOLLOW)
4412 if (gen_full_path_at (path, dirfd, pathname))
4414 path_conv win32 (path, PC_POSIX | ((flags & AT_SYMLINK_NOFOLLOW)
4415 ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW),
4417 return utimens_worker (win32, times);
4421 futimesat (int dirfd, const char *pathname, const struct timeval *times)
4425 if (efault.faulted (EFAULT))
4427 char *path = tp.c_get ();
4428 if (gen_full_path_at (path, dirfd, pathname, true))
4430 return utimes (path, times);
4434 linkat (int olddirfd, const char *oldpathname,
4435 int newdirfd, const char *newpathname,
4440 if (efault.faulted (EFAULT))
4442 if (flags & ~AT_SYMLINK_FOLLOW)
4447 char *oldpath = tp.c_get ();
4448 if (gen_full_path_at (oldpath, olddirfd, oldpathname))
4450 char *newpath = tp.c_get ();
4451 if (gen_full_path_at (newpath, newdirfd, newpathname))
4453 if (flags & AT_SYMLINK_FOLLOW)
4455 path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
4458 set_errno (old_name.error);
4461 strcpy (oldpath, old_name.normalized_path);
4463 return link (oldpath, newpath);
4467 mkdirat (int dirfd, const char *pathname, mode_t mode)
4471 if (efault.faulted (EFAULT))
4473 char *path = tp.c_get ();
4474 if (gen_full_path_at (path, dirfd, pathname))
4476 return mkdir (path, mode);
4480 mkfifoat (int dirfd, const char *pathname, mode_t mode)
4484 if (efault.faulted (EFAULT))
4486 char *path = tp.c_get ();
4487 if (gen_full_path_at (path, dirfd, pathname))
4489 return mkfifo (path, mode);
4493 mknodat (int dirfd, const char *pathname, mode_t mode, __dev32_t dev)
4497 if (efault.faulted (EFAULT))
4499 char *path = tp.c_get ();
4500 if (gen_full_path_at (path, dirfd, pathname))
4502 return mknod32 (path, mode, dev);
4506 readlinkat (int dirfd, const char *pathname, char *buf, size_t bufsize)
4510 if (efault.faulted (EFAULT))
4512 char *path = tp.c_get ();
4513 if (gen_full_path_at (path, dirfd, pathname))
4515 return readlink (path, buf, bufsize);
4519 renameat (int olddirfd, const char *oldpathname,
4520 int newdirfd, const char *newpathname)
4524 if (efault.faulted (EFAULT))
4526 char *oldpath = tp.c_get ();
4527 if (gen_full_path_at (oldpath, olddirfd, oldpathname))
4529 char *newpath = tp.c_get ();
4530 if (gen_full_path_at (newpath, newdirfd, newpathname))
4532 return rename (oldpath, newpath);
4536 symlinkat (const char *oldpath, int newdirfd, const char *newpathname)
4540 if (efault.faulted (EFAULT))
4542 char *newpath = tp.c_get ();
4543 if (gen_full_path_at (newpath, newdirfd, newpathname))
4545 return symlink (oldpath, newpath);
4549 unlinkat (int dirfd, const char *pathname, int flags)
4553 if (efault.faulted (EFAULT))
4555 if (flags & ~AT_REMOVEDIR)
4560 char *path = tp.c_get ();
4561 if (gen_full_path_at (path, dirfd, pathname))
4563 return (flags & AT_REMOVEDIR) ? rmdir (path) : unlink (path);