1 /* syscalls.cc: syscalls
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #include "miscfuncs.h"
12 #include <sys/vfs.h> /* needed for statfs */
13 #include <sys/statvfs.h> /* needed for statvfs */
29 #include <cygwin/version.h>
31 #include "perprocess.h"
38 #include "shared_info.h"
44 #include "child_info.h"
45 #include <cygwin/fs.h> /* needed for RENAME_NOREPLACE */
46 #include <sys/reent.h> /* needed for _fwalk_sglue() declaration */
48 static int mknod_worker (path_conv
&, mode_t
, _major_t
, _minor_t
);
50 /* Close all files and process any queued deletions.
51 Lots of unix style applications will open a tmp file, unlink it,
52 but never call close. This function is called by _exit to
53 ensure we don't leave any such files lying around. */
56 close_all_files (bool norelease
)
58 cygheap
->fdtab
.lock ();
60 semaphore::terminate ();
64 for (int i
= 0; i
< (int) cygheap
->fdtab
.size
; i
++)
66 cygheap_fdget
cfd (i
, false, false);
69 debug_only_printf ("closing fd %d", i
);
70 if (i
== 2 && cfd
->get_dev () != FH_PIPEW
)
71 DuplicateHandle (GetCurrentProcess (), cfd
->get_output_handle (),
72 GetCurrentProcess (), &h
,
73 0, false, DUPLICATE_SAME_ACCESS
);
74 cfd
->close_with_arch ();
80 if (!have_execed
&& cygheap
->ctty
)
81 cygheap
->close_ctty ();
84 SetStdHandle (STD_ERROR_HANDLE
, h
);
85 cygheap
->fdtab
.unlock ();
88 /* Close or set the close-on-exec flag for all open file descriptors
89 from firstfd to lastfd. CLOSE_RANGE_UNSHARE is not supported.
90 Available on FreeBSD since 13 and Linux since 5.9 */
92 close_range (unsigned int firstfd
, unsigned int lastfd
, int flags
)
94 pthread_testcancel ();
96 if (!(firstfd
<= lastfd
&& !(flags
& ~CLOSE_RANGE_CLOEXEC
)))
102 cygheap
->fdtab
.lock ();
104 unsigned int size
= (lastfd
< cygheap
->fdtab
.size
? lastfd
+ 1 :
105 cygheap
->fdtab
.size
);
107 for (unsigned int i
= firstfd
; i
< size
; i
++)
109 cygheap_fdget
cfd ((int) i
, false, false);
113 if (flags
& CLOSE_RANGE_CLOEXEC
)
115 syscall_printf ("set FD_CLOEXEC on fd %u", i
);
116 cfd
->fcntl (F_SETFD
, FD_CLOEXEC
);
120 syscall_printf ("closing fd %u", i
);
121 cfd
->close_with_arch ();
126 cygheap
->fdtab
.unlock ();
138 res
= cygheap
->fdtab
.dup3 (fd
, newfd
, 0);
139 syscall_printf ("%R = dup(%d)", res
, fd
);
144 dup_finish (int oldfd
, int newfd
, int flags
)
147 if ((res
= cygheap
->fdtab
.dup3 (oldfd
, newfd
, flags
| O_EXCL
)) == newfd
)
149 cygheap_fdget (newfd
)->inc_refcnt ();
150 cygheap
->fdtab
.unlock (); /* dup3 exits with lock set on success */
156 dup2 (int oldfd
, int newfd
)
159 if (newfd
>= OPEN_MAX
|| newfd
< 0)
164 else if (newfd
== oldfd
)
166 cygheap_fdget
cfd (oldfd
);
167 res
= (cfd
>= 0) ? oldfd
: -1;
170 res
= dup_finish (oldfd
, newfd
, 0);
172 syscall_printf ("%R = dup2(%d, %d)", res
, oldfd
, newfd
);
177 dup3 (int oldfd
, int newfd
, int flags
)
180 if (newfd
>= OPEN_MAX
)
185 else if (newfd
== oldfd
)
187 cygheap_fdget
cfd (oldfd
, false, false);
188 set_errno (cfd
< 0 ? EBADF
: EINVAL
);
192 res
= dup_finish (oldfd
, newfd
, flags
);
194 syscall_printf ("%R = dup3(%d, %d, %y)", res
, oldfd
, newfd
, flags
);
198 static const char desktop_ini
[] =
199 "[.ShellClassInfo]\r\n"
200 "CLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n"
201 "LocalizedResourceName=@%SystemRoot%\\system32\\shell32.dll,-8964\r\n";
211 /* Typically the recycler on drive C has been created at installation
212 time. The name is then written in camel back. On any other drive,
213 the recycler is created on first usage. shell32.dll then creates
214 the recycler in all upper case. That's only important if the entire
215 operation is running case sensitive. */
216 static WCHAR recycler_basename_drive_c
[] = L
"\\$Recycle.Bin\\";
217 static WCHAR recycler_basename_other
[] = L
"\\$RECYCLE.BIN\\";
220 try_to_bin (path_conv
&pc
, HANDLE
&fh
, ACCESS_MASK access
, ULONG flags
)
222 bin_status bin_stat
= move_to_bin
;
224 OBJECT_ATTRIBUTES attr
;
226 HANDLE rootdir
= NULL
, recyclerdir
= NULL
, tmp_fh
= NULL
;
227 USHORT recycler_base_len
= 0, recycler_user_len
= 0;
228 UNICODE_STRING root
, recycler
, fname
;
229 PWCHAR recycler_basename
= NULL
;
230 WCHAR recyclerbuf
[NAME_MAX
+ 1]; /* Enough for recycler + SID + filename */
231 PFILE_NAME_INFORMATION pfni
;
232 PFILE_INTERNAL_INFORMATION pfii
;
233 PFILE_RENAME_INFORMATION pfri
;
235 FILE_DISPOSITION_INFORMATION disp
= { TRUE
};
236 bool fs_has_per_user_recycler
= pc
.fs_is_ntfs () || pc
.fs_is_refs ();
239 PBYTE infobuf
= (PBYTE
) tp
.w_get ();
241 pfni
= (PFILE_NAME_INFORMATION
) infobuf
;
242 status
= NtQueryInformationFile (fh
, &io
, pfni
, NT_MAX_PATH
* sizeof (WCHAR
),
243 FileNameInformation
);
244 if (!NT_SUCCESS (status
))
246 debug_printf ("NtQueryInformationFile (%S, FileNameInformation) "
247 "failed, status = %y", pc
.get_nt_native_path (), status
);
250 /* The filename could change, the parent dir not. So we split both paths
251 and take the prefix. However, there are two special cases:
252 - The handle refers to the root dir of the volume.
253 - The handle refers to the recycler or a subdir.
254 Both cases are handled by just returning and not even trying to move
255 them into the recycler. */
256 if (pfni
->FileNameLength
== 2) /* root dir. */
258 /* Initialize recycler path. */
259 RtlInitEmptyUnicodeString (&recycler
, recyclerbuf
, sizeof recyclerbuf
);
262 recycler_basename
= wcsncmp (pc
.get_nt_native_path ()->Buffer
,
264 ? recycler_basename_other
265 : recycler_basename_drive_c
;
266 RtlAppendUnicodeToString (&recycler
, recycler_basename
);
267 RtlInitCountedUnicodeString(&fname
, pfni
->FileName
, pfni
->FileNameLength
);
268 /* Is the file a subdir of the recycler? */
269 if (RtlEqualUnicodePathPrefix (&fname
, &recycler
, TRUE
))
271 /* Is fname the recycler? Temporarily hide trailing backslash. */
272 recycler
.Length
-= sizeof (WCHAR
);
273 if (RtlEqualUnicodeString (&fname
, &recycler
, TRUE
))
275 /* Is fname really a subcomponent of the full path? If not, there's
276 a high probability we're accessing the file via a virtual drive
277 created with "subst". Check and accommodate it. Note that we
278 only get here if the virtual drive is really pointing to a local
279 drive. Otherwise pc.isremote () returns "true". */
280 if (!RtlEqualUnicodePathSuffix (pc
.get_nt_native_path (), &fname
, TRUE
))
282 WCHAR drive
[3] = { pc
.get_nt_native_path ()->Buffer
[4], ':', '\0' };
283 PWCHAR tgt
= tp
.w_get ();
285 if (QueryDosDeviceW (drive
, tgt
, NT_MAX_PATH
)
286 && !wcsncmp (tgt
, L
"\\??\\", 4))
288 UNICODE_STRING new_path
;
290 wcsncpy (tgt
+ 6, fname
.Buffer
, fname
.Length
/ sizeof (WCHAR
));
291 RtlInitCountedUnicodeString(&new_path
, tgt
,
292 6 * sizeof (WCHAR
) + fname
.Length
);
293 pc
.set_nt_native_path (&new_path
);
296 /* Create root dir path from file name information. */
297 RtlSplitUnicodePath (&fname
, &fname
, NULL
);
298 RtlSplitUnicodePath (pc
.get_nt_native_path (), &root
, NULL
);
299 root
.Length
-= fname
.Length
- sizeof (WCHAR
);
301 /* Open root directory. All recycler bin ops are caseinsensitive. */
302 InitializeObjectAttributes (&attr
, &root
, OBJ_CASE_INSENSITIVE
,
304 status
= NtOpenFile (&rootdir
, FILE_TRAVERSE
, &attr
, &io
,
305 FILE_SHARE_VALID_FLAGS
, FILE_OPEN_FOR_BACKUP_INTENT
);
306 if (!NT_SUCCESS (status
))
308 debug_printf ("NtOpenFile (%S) failed, status = %y", &root
, status
);
312 /* Strip leading backslash */
314 recycler
.Length
-= sizeof (WCHAR
);
315 /* Store length of recycler base dir, if it's necessary to create it. */
316 recycler_base_len
= recycler
.Length
;
317 /* On NTFS or ReFS the recycler dir contains user specific subdirs, which
318 are the actual recycle bins per user. The name of this dir is the
319 string representation of the user SID. */
320 if (fs_has_per_user_recycler
)
324 /* Unhide trailing backslash. */
325 recycler
.Length
+= sizeof (WCHAR
);
326 RtlInitEmptyUnicodeString (&sid
, sidbuf
, sizeof sidbuf
);
327 RtlConvertSidToUnicodeString (&sid
, cygheap
->user
.sid (), FALSE
);
328 RtlAppendUnicodeStringToString (&recycler
, &sid
);
329 recycler_user_len
= recycler
.Length
;
331 RtlAppendUnicodeToString (&recycler
, L
"\\");
333 if (pc
.file_attributes () & FILE_ATTRIBUTE_TEMPORARY
)
335 UNICODE_STRING basename
;
337 RtlSplitUnicodePath (pc
.get_nt_native_path (), NULL
, &basename
);
338 RtlAppendUnicodeToString (&recycler
, basename
.Buffer
);
342 /* Create unique filename. Start with a dot, followed by "cyg"
343 transposed into the Unicode low surrogate area (U+dc00) on file
344 systems supporting Unicode (except Samba), followed by the inode
345 number in hex, followed by a path hash in hex. The combination
346 allows to remove multiple hardlinks to the same file. */
347 RtlAppendUnicodeToString (&recycler
,
348 (pc
.fs_flags () & FILE_UNICODE_ON_DISK
349 && !pc
.fs_is_samba ())
350 ? L
".\xdc63\xdc79\xdc67" : L
".cyg");
351 pfii
= (PFILE_INTERNAL_INFORMATION
) infobuf
;
352 status
= NtQueryInformationFile (fh
, &io
, pfii
, sizeof *pfii
,
353 FileInternalInformation
);
354 if (!NT_SUCCESS (status
))
356 debug_printf ("NtQueryInformationFile (%S, FileInternalInformation) "
357 "failed, status = %y",
358 pc
.get_nt_native_path (), status
);
361 RtlInt64ToHexUnicodeString (pfii
->IndexNumber
.QuadPart
, &recycler
, TRUE
);
362 RtlInt64ToHexUnicodeString (hash_path_name (0, pc
.get_nt_native_path ()),
366 pfri
= (PFILE_RENAME_INFORMATION
) infobuf
;
367 pfri
->ReplaceIfExists
= TRUE
;
368 pfri
->RootDirectory
= rootdir
;
369 pfri
->FileNameLength
= recycler
.Length
;
370 memcpy (pfri
->FileName
, recycler
.Buffer
, recycler
.Length
);
371 frisiz
= sizeof *pfri
+ pfri
->FileNameLength
- sizeof (WCHAR
);
373 status
= NtSetInformationFile (fh
, &io
, pfri
, frisiz
, FileRenameInformation
);
374 if (status
== STATUS_OBJECT_PATH_NOT_FOUND
&& !pc
.isremote ())
376 /* The recycler and/or the recycler/SID directory don't exist, or the
377 case of recycler dir has changed and the rename op is case sensitive.
378 First reopen root dir with permission to create subdirs. */
380 InitializeObjectAttributes (&attr
, &root
, OBJ_CASE_INSENSITIVE
,
382 status
= NtOpenFile (&rootdir
, FILE_ADD_SUBDIRECTORY
, &attr
, &io
,
383 FILE_SHARE_VALID_FLAGS
, FILE_OPEN_FOR_BACKUP_INTENT
);
384 if (!NT_SUCCESS (status
))
386 debug_printf ("NtOpenFile (%S) failed, status = %y",
390 /* Correct the rootdir HANDLE in pfri after reopening the dir. */
391 pfri
->RootDirectory
= rootdir
;
392 /* Then check if recycler exists by opening and potentially creating it.
393 Yes, we can really do that. Typically the recycle bin is created
394 by the first user actually using the bin. */
395 InitializeObjectAttributes (&attr
, &recycler
, OBJ_CASE_INSENSITIVE
,
396 rootdir
, recycler_sd (true, true));
397 recycler
.Length
= recycler_base_len
;
398 status
= NtCreateFile (&recyclerdir
,
400 | (fs_has_per_user_recycler
? 0 : FILE_ADD_FILE
),
402 FILE_ATTRIBUTE_DIRECTORY
403 | FILE_ATTRIBUTE_SYSTEM
404 | FILE_ATTRIBUTE_HIDDEN
,
405 FILE_SHARE_VALID_FLAGS
, FILE_OPEN_IF
,
406 FILE_DIRECTORY_FILE
, NULL
, 0);
407 if (!NT_SUCCESS (status
))
409 debug_printf ("NtCreateFile (%S) failed, status = %y",
413 /* If we opened the recycler (in contrast to creating it) and our
414 rename op is case sensitive, fetch the actual case of the recycler
415 and store the name in recycler_basename, as well as in pfri->FileName
416 for the below 2nd try to rename the file. */
417 if (io
.Information
== FILE_OPENED
&& !pc
.objcaseinsensitive ())
419 pfni
= (PFILE_NAME_INFORMATION
) tp
.w_get ();
420 status
= NtQueryInformationFile (recyclerdir
, &io
, pfni
,
421 NT_MAX_PATH
* sizeof (WCHAR
),
422 FileNameInformation
);
423 if (NT_SUCCESS (status
))
425 size_t len
= pfni
->FileNameLength
/ sizeof (WCHAR
) - 1;
426 PWCHAR p
= pfni
->FileName
+ 1;
428 wcpncpy (pfri
->FileName
, p
, len
);
429 wcpncpy (recycler_basename
+ 1, p
, len
);
433 /* Next, if necessary, check if the recycler/SID dir exists and
435 if (fs_has_per_user_recycler
)
437 NtClose (recyclerdir
);
438 recycler
.Length
= recycler_user_len
;
439 InitializeObjectAttributes (&attr
, &recycler
, OBJ_CASE_INSENSITIVE
,
440 rootdir
, recycler_sd (false, true));
441 status
= NtCreateFile (&recyclerdir
, READ_CONTROL
| FILE_ADD_FILE
,
442 &attr
, &io
, NULL
, FILE_ATTRIBUTE_DIRECTORY
443 | FILE_ATTRIBUTE_SYSTEM
444 | FILE_ATTRIBUTE_HIDDEN
,
445 FILE_SHARE_VALID_FLAGS
, FILE_OPEN_IF
,
446 FILE_DIRECTORY_FILE
, NULL
, 0);
447 if (!NT_SUCCESS (status
))
449 debug_printf ("NtCreateFile (%S) failed, status = %y",
454 /* The desktop.ini file is expected by Windows Explorer. Otherwise,
455 the created bin is treated as corrupted */
456 if (io
.Information
== FILE_CREATED
)
458 RtlInitUnicodeString (&fname
, L
"desktop.ini");
459 InitializeObjectAttributes (&attr
, &fname
, OBJ_CASE_INSENSITIVE
,
460 recyclerdir
, recycler_sd (false, false));
461 status
= NtCreateFile (&tmp_fh
, FILE_GENERIC_WRITE
, &attr
, &io
, NULL
,
462 FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
463 FILE_SHARE_VALID_FLAGS
, FILE_CREATE
,
464 FILE_SYNCHRONOUS_IO_NONALERT
465 | FILE_NON_DIRECTORY_FILE
, NULL
, 0);
466 if (!NT_SUCCESS (status
))
467 debug_printf ("NtCreateFile (%S) failed, status = %y",
471 status
= NtWriteFile (tmp_fh
, NULL
, NULL
, NULL
, &io
,
472 (PVOID
) desktop_ini
, sizeof desktop_ini
- 1,
474 if (!NT_SUCCESS (status
))
475 debug_printf ("NtWriteFile (%S) failed, status = %y",
480 NtClose (recyclerdir
);
482 status
= NtSetInformationFile (fh
, &io
, pfri
, frisiz
,
483 FileRenameInformation
);
485 if (!NT_SUCCESS (status
))
487 debug_printf ("Move %S to %S failed, status = %y",
488 pc
.get_nt_native_path (), &recycler
, status
);
491 /* Moving to the bin worked. */
492 bin_stat
= has_been_moved
;
493 /* If we're only moving a just created O_TMPFILE, we're done here. */
494 if (pc
.file_attributes () & FILE_ATTRIBUTE_TEMPORARY
)
496 /* Now we try to set the delete disposition. If that worked, we're done.
497 We try this here first, as long as we still have the open handle.
498 Otherwise the below code closes the handle to allow replacing the file. */
499 status
= NtSetInformationFile (fh
, &io
, &disp
, sizeof disp
,
500 FileDispositionInformation
);
505 case STATUS_DIRECTORY_NOT_EMPTY
:
506 /* Uh oh! This was supposed to be avoided by the check_dir_not_empty
507 test in unlink_nt, but given that the test isn't atomic, this *can*
508 happen. Try to move the dir back ASAP. */
509 pfri
->RootDirectory
= NULL
;
510 pfri
->FileNameLength
= pc
.get_nt_native_path ()->Length
;
511 memcpy (pfri
->FileName
, pc
.get_nt_native_path ()->Buffer
,
512 pc
.get_nt_native_path ()->Length
);
513 frisiz
= sizeof *pfri
+ pfri
->FileNameLength
- sizeof (WCHAR
);
514 if (NT_SUCCESS (NtSetInformationFile (fh
, &io
, pfri
, frisiz
,
515 FileRenameInformation
)))
517 /* Give notice to unlink_nt and leave immediately. This avoids
518 closing the handle, which might still be used if called from
519 the rm -r workaround code. */
520 bin_stat
= dir_not_empty
;
523 debug_printf ("Renaming dir %S back to %S failed, status = %y",
524 &recycler
, pc
.get_nt_native_path (), status
);
526 case STATUS_FILE_RENAMED
:
527 /* On NFS, the subsequent request to set the delete disposition fails
528 with STATUS_FILE_RENAMED. We have to reopen the file, close the
529 original handle, and set the delete disposition on the reopened
530 handle to make sure setting delete disposition works. */
531 InitializeObjectAttributes (&attr
, &ro_u_empty
, 0, fh
, NULL
);
532 status
= NtOpenFile (&tmp_fh
, access
, &attr
, &io
,
533 FILE_SHARE_VALID_FLAGS
, flags
);
534 if (!NT_SUCCESS (status
))
535 debug_printf ("NtOpenFile (%S) for reopening in renamed case failed, "
536 "status = %y", pc
.get_nt_native_path (), status
);
541 status
= NtSetInformationFile (fh
, &io
, &disp
, sizeof disp
,
542 FileDispositionInformation
);
543 if (!NT_SUCCESS (status
))
544 debug_printf ("Setting delete disposition %S (%S) in renamed "
545 "case failed, status = %y",
546 &recycler
, pc
.get_nt_native_path (), status
);
550 debug_printf ("Setting delete disposition on %S (%S) failed, status = %y",
551 &recycler
, pc
.get_nt_native_path (), status
);
554 /* In case of success, restore R/O attribute to accommodate hardlinks.
555 That leaves potentially hardlinks around with the R/O bit suddenly
556 off if setting the delete disposition failed, but please, keep in
557 mind this is really a border case only. */
558 if ((access
& FILE_WRITE_ATTRIBUTES
) && NT_SUCCESS (status
) && !pc
.isdir ())
559 NtSetAttributesFile (fh
, pc
.file_attributes ());
561 fh
= NULL
; /* So unlink_nt doesn't close the handle twice. */
562 /* On success or when trying to unlink a directory we just return here.
563 The below code only works for files. It also fails on NFS. */
564 if (NT_SUCCESS (status
) || pc
.isdir () || pc
.fs_is_nfs ())
566 /* The final trick. We create a temporary file with delete-on-close
567 semantic and rename that file to the file just moved to the bin.
568 This typically overwrites the original file and we get rid of it,
569 even if neither setting the delete dispostion, nor setting
570 delete-on-close on the original file succeeds. There are still
571 cases in which this fails, for instance, when trying to delete a
572 hardlink to a DLL used by the unlinking application itself. */
575 /* In the remote case we need the full path, but recycler is only
576 a relative path. Convert to absolute path. */
577 RtlInitEmptyUnicodeString (&fname
, tp
.w_get (),
578 (NT_MAX_PATH
- 1) * sizeof (WCHAR
));
579 RtlCopyUnicodeString (&fname
, pc
.get_nt_native_path ());
580 RtlSplitUnicodePath (&fname
, &fname
, NULL
);
581 /* Reset max length, overwritten by RtlSplitUnicodePath. */
582 fname
.MaximumLength
= (NT_MAX_PATH
- 1) * sizeof (WCHAR
); /* reset */
583 RtlAppendUnicodeStringToString (&fname
, &recycler
);
587 RtlAppendUnicodeToString (&fname
, L
"X");
588 InitializeObjectAttributes (&attr
, &fname
, 0, rootdir
, NULL
);
589 status
= NtCreateFile (&tmp_fh
, DELETE
, &attr
, &io
, NULL
,
590 FILE_ATTRIBUTE_NORMAL
, 0, FILE_SUPERSEDE
,
591 FILE_NON_DIRECTORY_FILE
| FILE_DELETE_ON_CLOSE
,
593 if (!NT_SUCCESS (status
))
595 debug_printf ("Creating file %S for overwriting %S (%S) failed, "
596 "status = %y", &fname
, &recycler
, pc
.get_nt_native_path (),
600 status
= NtSetInformationFile (tmp_fh
, &io
, pfri
, frisiz
,
601 FileRenameInformation
);
603 if (!NT_SUCCESS (status
))
604 debug_printf ("Overwriting %S (%S) with %S failed, status = %y",
605 &recycler
, pc
.get_nt_native_path (), &fname
, status
);
610 debug_printf ("%S, return bin_status %d", pc
.get_nt_native_path (), bin_stat
);
615 check_dir_not_empty (HANDLE dir
, path_conv
&pc
)
618 const ULONG bufsiz
= 3 * sizeof (FILE_NAMES_INFORMATION
)
619 + 3 * NAME_MAX
* sizeof (WCHAR
);
620 PFILE_NAMES_INFORMATION pfni
= (PFILE_NAMES_INFORMATION
)
622 NTSTATUS status
= NtQueryDirectoryFile (dir
, NULL
, NULL
, 0, &io
, pfni
,
623 bufsiz
, FileNamesInformation
,
625 if (!NT_SUCCESS (status
))
627 debug_printf ("Checking if directory %S is empty failed, status = %y",
628 pc
.get_nt_native_path (), status
);
634 while (pfni
->NextEntryOffset
)
638 UNICODE_STRING fname
;
639 OBJECT_ATTRIBUTES attr
;
640 FILE_BASIC_INFORMATION fbi
;
642 pfni
= (PFILE_NAMES_INFORMATION
)
643 ((caddr_t
) pfni
+ pfni
->NextEntryOffset
);
644 RtlInitCountedUnicodeString(&fname
, pfni
->FileName
,
645 pfni
->FileNameLength
);
646 InitializeObjectAttributes (&attr
, &fname
, 0, dir
, NULL
);
647 status
= NtQueryAttributesFile (&attr
, &fbi
);
648 /* Intensive testing shows that sometimes directories, for which
649 the delete disposition has already been set, and the deleting
650 handle is already closed, can linger in the parent dir for a
651 couple of ms for no apparent reason (Windows Defender or other
652 real-time scanners are suspect).
654 A fast rm -r is capable to exploit this problem. Setting the
655 delete disposition of the parent dir then fails with
656 STATUS_DIRECTORY_NOT_EMPTY. Examining the content of the
657 affected dir can then show either that the dir is empty, or it
658 can contain a lingering subdir. Calling NtQueryAttributesFile
659 on that subdir returns with STATUS_DELETE_PENDING, or it
660 disappeared before that call.
662 That's what we do here. If NtQueryAttributesFile succeeded,
663 or if the error code does not indicate an already deleted
664 entry, STATUS_DIRECTORY_NOT_EMPTY is returned.
666 Otherwise STATUS_SUCCESS is returned. Read on in unlink_nt. */
667 if (status
!= STATUS_DELETE_PENDING
668 && status
!= STATUS_OBJECT_NAME_NOT_FOUND
669 && status
!= STATUS_OBJECT_PATH_NOT_FOUND
)
671 debug_printf ("Directory %S not empty, found file <%S>, "
673 pc
.get_nt_native_path (), &fname
, status
);
674 return STATUS_DIRECTORY_NOT_EMPTY
;
677 pfni
= (PFILE_NAMES_INFORMATION
) ((caddr_t
) pfni
+ pfni
->NextEntryOffset
);
680 while (NT_SUCCESS (NtQueryDirectoryFile (dir
, NULL
, NULL
, 0, &io
, pfni
,
681 bufsiz
, FileNamesInformation
,
682 FALSE
, NULL
, FALSE
)));
683 return STATUS_SUCCESS
;
686 static inline NTSTATUS
687 _unlink_nt_post_dir_check (NTSTATUS status
, POBJECT_ATTRIBUTES attr
, const path_conv
&pc
)
689 /* Check for existence of remote dirs after trying to delete them.
691 - Sometimes SMB indicates failure when it really succeeds.
692 - Removing a directory on a Samba drive using an old Samba version
693 sometimes doesn't return an error, if the directory can't be removed
694 because it's not empty. */
697 FILE_BASIC_INFORMATION fbi
;
700 q_status
= NtQueryAttributesFile (attr
, &fbi
);
701 if (!NT_SUCCESS (status
) && q_status
== STATUS_OBJECT_NAME_NOT_FOUND
)
702 status
= STATUS_SUCCESS
;
703 else if (pc
.fs_is_samba ()
704 && NT_SUCCESS (status
) && NT_SUCCESS (q_status
))
705 status
= STATUS_DIRECTORY_NOT_EMPTY
;
711 unlink_nt (path_conv
&pc
, bool shareable
)
714 HANDLE fh
, fh_ro
= NULL
;
715 OBJECT_ATTRIBUTES attr
;
717 ACCESS_MASK access
= DELETE
;
718 ULONG flags
= FILE_OPEN_FOR_BACKUP_INTENT
;
719 HANDLE old_trans
= NULL
, trans
= NULL
;
721 FILE_DISPOSITION_INFORMATION disp
= { TRUE
};
723 bin_status bin_stat
= dont_move
;
725 syscall_printf ("Trying to delete %S, isdir = %d",
726 pc
.get_nt_native_path (), pc
.isdir ());
728 /* Add the reparse point flag to known reparse points, otherwise we remove
729 the target, not the reparse point. */
730 if (pc
.is_known_reparse_point ())
731 flags
|= FILE_OPEN_REPARSE_POINT
;
733 pc
.get_object_attr (attr
, sec_none_nih
);
735 /* First check if we can use POSIX unlink semantics: W10 1709+, local NTFS.
736 For the OPEN_BY_FILE_ID flag, see MINIMAL_WIN_NTFS_FLAGS comment in
737 fs_info::update. With POSIX unlink semantics the entire job gets MUCH
738 easier and faster. Just try to do it and if it fails, it fails. */
739 if (wincap
.has_posix_unlink_semantics ()
740 && !pc
.isremote () && pc
.fs_is_ntfs ()
741 && pc
.has_attribute (FILE_SUPPORTS_OPEN_BY_FILE_ID
))
743 FILE_DISPOSITION_INFORMATION_EX fdie
;
745 /* POSIX unlink semantics are nice, but they still fail if the file has
746 the R/O attribute set. If so, ignoring might be an option: W10 1809+
747 Removing the file is very much a safe bet afterwards, so, no
749 if ((pc
.file_attributes () & FILE_ATTRIBUTE_READONLY
)
750 && !wincap
.has_posix_unlink_semantics_with_ignore_readonly ())
751 access
|= FILE_WRITE_ATTRIBUTES
;
752 status
= NtOpenFile (&fh
, access
, &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
754 if (!NT_SUCCESS (status
))
756 if (access
& FILE_WRITE_ATTRIBUTES
)
758 status
= NtSetAttributesFile (fh
, pc
.file_attributes ()
759 & ~FILE_ATTRIBUTE_READONLY
);
760 if (!NT_SUCCESS (status
))
766 fdie
.Flags
= FILE_DISPOSITION_DELETE
| FILE_DISPOSITION_POSIX_SEMANTICS
;
767 if (wincap
.has_posix_unlink_semantics_with_ignore_readonly ())
768 fdie
.Flags
|= FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE
;
769 status
= NtSetInformationFile (fh
, &io
, &fdie
, sizeof fdie
,
770 FileDispositionInformationEx
);
771 /* Restore R/O attribute in case we have multiple hardlinks. */
772 if (access
& FILE_WRITE_ATTRIBUTES
)
773 NtSetAttributesFile (fh
, pc
.file_attributes ());
775 /* Trying to delete in-use executables and DLLs using
776 FILE_DISPOSITION_POSIX_SEMANTICS returns STATUS_CANNOT_DELETE.
777 Fall back to the default method. */
778 /* Additionaly that returns STATUS_INVALID_PARAMETER
779 on a bind mounted fs in hyper-v container. Falling back too. */
780 if (status
!= STATUS_CANNOT_DELETE
781 && status
!= STATUS_INVALID_PARAMETER
)
783 debug_printf ("NtSetInformationFile returns %y "
784 "with posix semantics. Disable it and retry.", status
);
789 /* If the R/O attribute is set, we have to open the file with
790 FILE_WRITE_ATTRIBUTES to be able to remove this flags before trying
791 to delete it. We do this separately because there are filesystems
792 out there (MVFS), which refuse a request to open a file for DELETE
793 if the DOS R/O attribute is set for the file. After removing the R/O
794 attribute, just re-open the file for DELETE and go ahead. */
795 if (pc
.file_attributes () & FILE_ATTRIBUTE_READONLY
)
797 FILE_STANDARD_INFORMATION fsi
;
799 /* If possible, hide the non-atomicity of the "remove R/O flag, remove
800 link to file" operation behind a transaction. */
801 if ((pc
.fs_flags () & FILE_SUPPORTS_TRANSACTIONS
))
802 start_transaction (old_trans
, trans
);
804 status
= NtOpenFile (&fh_ro
,
805 FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
,
806 &attr
, &io
, FILE_SHARE_VALID_FLAGS
, flags
);
807 if (NT_SUCCESS (status
))
809 debug_printf ("Opening %S for removing R/O succeeded",
810 pc
.get_nt_native_path ());
811 NTSTATUS status2
= NtSetAttributesFile (fh_ro
,
812 pc
.file_attributes ()
813 & ~FILE_ATTRIBUTE_READONLY
);
814 if (!NT_SUCCESS (status2
))
815 debug_printf ("Removing R/O on %S failed, status = %y",
816 pc
.get_nt_native_path (), status2
);
817 pc
.init_reopen_attr (attr
, fh_ro
);
821 debug_printf ("Opening %S for removing R/O failed, status = %y",
822 pc
.get_nt_native_path (), status
);
823 if (NT_TRANSACTIONAL_ERROR (status
) && trans
)
825 /* If NtOpenFile fails due to transactional problems, stop
826 transaction and go ahead without. */
827 stop_transaction (status
, old_trans
, trans
);
828 debug_printf ("Transaction failure. Retry open.");
832 if (pc
.is_lnk_symlink ())
834 status
= NtQueryInformationFile (fh_ro
, &io
, &fsi
, sizeof fsi
,
835 FileStandardInformation
);
836 if (NT_SUCCESS (status
))
837 num_links
= fsi
.NumberOfLinks
;
839 access
|= FILE_WRITE_ATTRIBUTES
;
841 /* First try to open the file with only allowing sharing for delete. If
842 the file has an open handle on it, other than just for deletion, this
843 will fail. That indicates that the file has to be moved to the recycle
844 bin so that it actually disappears from its directory even though its
845 in use. Otherwise, if opening doesn't fail, the file is not in use and
846 we can go straight to setting the delete disposition flag.
847 However, while we have the file open with FILE_SHARE_DELETE, using
848 this file via another hardlink for anything other than DELETE by
849 concurrent processes fails. The 'shareable' argument is to prevent this.
851 NOTE: The missing sharing modes FILE_SHARE_READ and FILE_SHARE_WRITE do
852 NOT result in a STATUS_SHARING_VIOLATION, if another handle is
853 opened for reading/writing metadata only. In other words, if
854 another handle is open, but does not have the file open with
855 FILE_READ_DATA or FILE_WRITE_DATA, the following NtOpenFile call
856 will succeed. So, apparently there is no reliable way to find out
857 if a file is already open elsewhere for other purposes than
858 reading and writing data. */
860 status
= STATUS_SHARING_VIOLATION
;
862 status
= NtOpenFile (&fh
, access
, &attr
, &io
, FILE_SHARE_DELETE
, flags
);
863 /* STATUS_SHARING_VIOLATION is what we expect. STATUS_LOCK_NOT_GRANTED can
864 be generated under not quite clear circumstances when trying to open a
865 file on NFS with FILE_SHARE_DELETE only. This has been observed with
866 SFU 3.5 if the NFS share has been mounted under a drive letter. It's
867 not generated for all files, but only for some. If it's generated once
868 for a file, it will be generated all the time. It looks as if wrong file
869 state information is stored within the NFS client which never times out.
870 Opening the file with FILE_SHARE_VALID_FLAGS will work, though, and it
871 is then possible to delete the file quite normally. */
872 if (status
== STATUS_SHARING_VIOLATION
|| status
== STATUS_LOCK_NOT_GRANTED
)
874 debug_printf ("Sharing violation when opening %S",
875 pc
.get_nt_native_path ());
876 /* We never call try_to_bin on NetApp. Netapp filesystems don't
877 understand the "move and delete" method at all and have all kinds
878 of weird effects. Just setting the delete dispositon usually
881 NFS implements its own mechanism to remove in-use files, which looks
882 quite similar to what we do in try_to_bin for remote files. However,
883 apparently it doesn't work as desired in all cases. This has been
884 observed when running the gawk 4.1.62++ testcase "testext.awk" under
885 Windows 10. So for NFS we still call try_to_bin to rename the file,
886 at least to make room for subsequent creation of a file with the
888 if (!pc
.fs_is_netapp ())
889 bin_stat
= move_to_bin
;
890 /* If the file is not a directory, of if we didn't set the move_to_bin
891 flag, just proceed with the FILE_SHARE_VALID_FLAGS set. */
892 if (!pc
.isdir () || bin_stat
== dont_move
)
893 status
= NtOpenFile (&fh
, access
, &attr
, &io
,
894 FILE_SHARE_VALID_FLAGS
, flags
);
897 /* Otherwise it's getting tricky. The directory is opened in some
898 process, so we're supposed to move it to the recycler and mark it
899 for deletion. But what if the directory is not empty? The move
900 will work, but the subsequent delete will fail. So we would
901 have to move it back. While we do that in try_to_bin, it's bad,
902 because the move results in a temporary inconsistent state.
903 So, we test first if the directory is empty. If not, we bail
904 out with STATUS_DIRECTORY_NOT_EMPTY. This avoids most of the
906 status
= NtOpenFile (&fh
, access
| FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
907 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
908 flags
| FILE_SYNCHRONOUS_IO_NONALERT
);
909 if (NT_SUCCESS (status
))
911 status
= check_dir_not_empty (fh
, pc
);
912 if (!NT_SUCCESS (status
))
924 if (!NT_SUCCESS (status
))
926 if (status
== STATUS_DELETE_PENDING
)
928 debug_printf ("Delete %S already pending", pc
.get_nt_native_path ());
929 status
= STATUS_SUCCESS
;
932 debug_printf ("Opening %S for delete failed, status = %y",
933 pc
.get_nt_native_path (), status
);
936 /* Try to move to bin if a sharing violation occured. If that worked,
938 if (bin_stat
== move_to_bin
939 && (bin_stat
= try_to_bin (pc
, fh
, access
, flags
)) >= has_been_moved
)
941 if (bin_stat
== has_been_moved
)
942 status
= STATUS_SUCCESS
;
945 status
= STATUS_DIRECTORY_NOT_EMPTY
;
952 /* Try to set delete disposition. */
953 status
= NtSetInformationFile (fh
, &io
, &disp
, sizeof disp
,
954 FileDispositionInformation
);
955 if (!NT_SUCCESS (status
))
957 debug_printf ("Setting delete disposition on %S failed, status = %y",
958 pc
.get_nt_native_path (), status
);
959 if (status
== STATUS_DIRECTORY_NOT_EMPTY
)
961 NTSTATUS status2
= STATUS_SUCCESS
;
965 /* Have to close and reopen the file from scratch, otherwise
966 we collide with the delete-only sharing mode. */
967 pc
.get_object_attr (attr
, sec_none_nih
);
969 status2
= NtOpenFile (&fh
, access
| FILE_LIST_DIRECTORY
971 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
972 flags
| FILE_SYNCHRONOUS_IO_NONALERT
);
974 if (NT_SUCCESS (status2
) && reopened
< 20)
976 /* Workaround rm -r problem:
978 Sometimes a deleted directory lingers in its parent dir
979 after the deleting handle has already been closed. This
980 can break deleting the parent dir. See the comment in
981 check_dir_not_empty for more information.
983 What we do here is this: If check_dir_not_empty returns
984 STATUS_SUCCESS, the dir is either empty, or only inhabited
985 by already deleted entries. If so, we try to move the dir
986 into the bin. This usually works.
988 However, if we're on a filesystem which doesn't support
989 the try_to_bin method, or if moving to the bin doesn't work
990 for some reason, just try to delete the directory again,
991 with a very short grace period to free the CPU for a while.
992 This gives the OS time to clean up. 5ms is enough in my
993 testing to make sure that we don't have to try more than
994 once in practically all cases.
995 While this is an extrem bordercase, we don't want to hang
996 infinitely in case a file in the directory is in the "delete
997 pending" state but an application holds an open handle to it
998 for a longer time. So we don't try this more than 20 times,
999 which means a process time of 100-120ms. */
1000 if (check_dir_not_empty (fh
, pc
) == STATUS_SUCCESS
)
1002 if (bin_stat
== dont_move
)
1004 bin_stat
= move_to_bin
;
1005 if (!pc
.fs_is_nfs () && !pc
.fs_is_netapp ())
1007 debug_printf ("Try-to-bin %S",
1008 pc
.get_nt_native_path ());
1009 bin_stat
= try_to_bin (pc
, fh
, access
, flags
);
1012 /* Do NOT handle bin_stat == dir_not_empty here! */
1013 if (bin_stat
== has_been_moved
)
1014 status
= STATUS_SUCCESS
;
1017 debug_printf ("Try %S again", pc
.get_nt_native_path ());
1024 else if (status2
!= STATUS_OBJECT_PATH_NOT_FOUND
1025 && status2
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1028 debug_printf ("Opening dir %S for check_dir_not_empty failed, "
1029 "status = %y", pc
.get_nt_native_path (), status2
);
1031 else /* Directory disappeared between NtClose and NtOpenFile. */
1032 status
= STATUS_SUCCESS
;
1034 /* Trying to delete a hardlink to a file in use by the system in some
1035 way (for instance, font files) by setting the delete disposition fails
1036 with STATUS_CANNOT_DELETE. Strange enough, deleting these hardlinks
1037 using delete-on-close semantic works... most of the time.
1039 Don't use delete-on-close on remote shares. If two processes
1040 have open handles on a file and one of them calls unlink, the
1041 file is removed from the remote share even though the other
1042 process still has an open handle. That process than gets Win32
1043 error 59, ERROR_UNEXP_NET_ERR when trying to access the file.
1044 Microsoft KB 837665 describes this problem as a bug in 2K3, but
1045 I have reproduced it on other systems. */
1046 else if (status
== STATUS_CANNOT_DELETE
1047 && (!pc
.isremote () || pc
.fs_is_ncfsd ()))
1051 debug_printf ("Cannot delete %S, try delete-on-close",
1052 pc
.get_nt_native_path ());
1053 /* Re-open from handle so we open the correct file no matter if it
1054 has been moved to the bin or not. */
1055 status
= NtOpenFile (&fh2
, DELETE
,
1056 pc
.init_reopen_attr (attr
, fh
), &io
,
1057 bin_stat
== move_to_bin
? FILE_SHARE_VALID_FLAGS
1058 : FILE_SHARE_DELETE
,
1059 flags
| FILE_DELETE_ON_CLOSE
);
1060 if (!NT_SUCCESS (status
))
1062 debug_printf ("Setting delete-on-close on %S failed, status = %y",
1063 pc
.get_nt_native_path (), status
);
1064 /* This is really the last chance. If it hasn't been moved
1065 to the bin already, try it now. If moving to the bin
1066 succeeds, we got rid of the file in some way, even if
1067 unlinking didn't work. */
1068 if (bin_stat
== dont_move
)
1069 bin_stat
= try_to_bin (pc
, fh
, access
, flags
);
1070 if (bin_stat
>= has_been_moved
)
1071 status
= bin_stat
== has_been_moved
1073 : STATUS_DIRECTORY_NOT_EMPTY
;
1081 if (access
& FILE_WRITE_ATTRIBUTES
)
1083 /* Restore R/O attribute if setting the delete disposition failed. */
1084 if (!NT_SUCCESS (status
))
1085 NtSetAttributesFile (fh
, pc
.file_attributes ());
1086 /* If we succeeded, restore R/O attribute to accommodate hardlinks.
1087 Only ever try to do this for our own winsymlinks, because there's
1088 a problem with setting the delete disposition:
1089 http://msdn.microsoft.com/en-us/library/ff545765%28VS.85%29.aspx
1090 "Subsequently, the only legal operation by such a caller is
1091 to close the open file handle."
1093 FIXME? We could use FILE_HARD_LINK_INFORMATION to find all
1094 hardlinks and use one of them to restore the R/O bit, after the
1095 NtClose, but before we stop the transaction. This avoids the
1096 aforementioned problem entirely . */
1097 else if (pc
.is_lnk_symlink () && num_links
> 1)
1098 NtSetAttributesFile (fh
, pc
.file_attributes ());
1105 /* Stop transaction if we started one. */
1107 stop_transaction (status
, old_trans
, trans
);
1110 status
= _unlink_nt_post_dir_check (status
, &attr
, pc
);
1112 syscall_printf ("%S, return status = %y", pc
.get_nt_native_path (), status
);
1117 unlink (const char *ourname
)
1123 path_conv
win32_name (ourname
, PC_SYM_NOFOLLOW
, stat_suffixes
);
1125 if (win32_name
.error
)
1127 set_errno (win32_name
.error
);
1131 devn
= win32_name
.get_device ();
1132 if (isproc_dev (devn
))
1137 if (isdevfd_dev (devn
) || (win32_name
.isdevice () && !win32_name
.issocket ()))
1142 if (!win32_name
.exists ())
1144 debug_printf ("unlinking a nonexistent file");
1148 else if (win32_name
.isdir ())
1150 debug_printf ("unlinking a directory");
1155 status
= unlink_nt (win32_name
, false);
1156 if (NT_SUCCESS (status
))
1159 __seterrno_from_nt_status (status
);
1162 syscall_printf ("%R = unlink(%s)", res
, ourname
);
1167 _remove_r (struct _reent
*, const char *ourname
)
1169 path_conv
win32_name (ourname
, PC_SYM_NOFOLLOW
);
1171 if (win32_name
.error
)
1173 set_errno (win32_name
.error
);
1174 syscall_printf ("%R = remove(%s)",-1, ourname
);
1178 int res
= win32_name
.isdir () ? rmdir (ourname
) : unlink (ourname
);
1179 syscall_printf ("%R = remove(%s)", res
, ourname
);
1184 remove (const char *ourname
)
1186 return _remove_r (_REENT
, ourname
);
1192 syscall_printf ("%d = getpid()", myself
->pid
);
1197 _getpid_r (struct _reent
*)
1202 /* getppid: POSIX 4.1.1.1 */
1206 syscall_printf ("%d = getppid()", myself
->ppid
);
1207 return myself
->ppid
;
1210 /* setsid: POSIX 4.3.2.1 */
1214 if (myself
->pgid
== myself
->pid
)
1215 syscall_printf ("hmm. pgid %d pid %d", myself
->pgid
, myself
->pid
);
1218 myself
->ctty
= CTTY_RELEASED
;
1219 myself
->sid
= myself
->pid
;
1220 myself
->pgid
= myself
->pid
;
1222 cygheap
->close_ctty ();
1223 syscall_printf ("sid %d, pgid %d, %s", myself
->sid
, myself
->pgid
, myctty ());
1248 syscall_printf ("%R = getsid(%d)", pid
);
1253 read (int fd
, void *ptr
, size_t len
)
1255 size_t res
= (size_t) -1;
1257 pthread_testcancel ();
1261 cygheap_fdget
cfd (fd
);
1265 if ((cfd
->get_flags () & O_PATH
)
1266 || (cfd
->get_flags () & O_ACCMODE
) == O_WRONLY
)
1272 /* Could block, so let user know we at least got here. */
1273 syscall_printf ("read(%d, %p, %d) %sblocking",
1274 fd
, ptr
, len
, cfd
->is_nonblocking () ? "non" : "");
1276 cfd
->read (ptr
, len
);
1279 __except (EFAULT
) {}
1281 syscall_printf ("%lR = read(%d, %p, %d)", res
, fd
, ptr
, len
);
1282 return (ssize_t
) res
;
1285 EXPORT_ALIAS (read
, _read
)
1288 readv (int fd
, const struct iovec
*const iov
, const int iovcnt
)
1292 pthread_testcancel ();
1296 const ssize_t tot
= check_iovec_for_read (iov
, iovcnt
);
1298 cygheap_fdget
cfd (fd
);
1308 if ((cfd
->get_flags () & O_PATH
)
1309 || (cfd
->get_flags () & O_ACCMODE
) == O_WRONLY
)
1315 /* Could block, so let user know we at least got here. */
1316 syscall_printf ("readv(%d, %p, %d) %sblocking",
1317 fd
, iov
, iovcnt
, cfd
->is_nonblocking () ? "non" : "");
1319 res
= cfd
->readv (iov
, iovcnt
, tot
);
1321 __except (EFAULT
) {}
1323 syscall_printf ("%lR = readv(%d, %p, %d)", res
, fd
, iov
, iovcnt
);
1328 pread (int fd
, void *ptr
, size_t len
, off_t off
)
1332 pthread_testcancel ();
1334 cygheap_fdget
cfd (fd
);
1337 else if (cfd
->get_flags () & O_PATH
)
1343 res
= cfd
->pread (ptr
, len
, off
);
1345 syscall_printf ("%lR = pread(%d, %p, %d, %d)", res
, fd
, ptr
, len
, off
);
1350 write (int fd
, const void *ptr
, size_t len
)
1354 pthread_testcancel ();
1358 cygheap_fdget
cfd (fd
);
1362 if ((cfd
->get_flags () & O_PATH
)
1363 || (cfd
->get_flags () & O_ACCMODE
) == O_RDONLY
)
1369 /* Could block, so let user know we at least got here. */
1370 if (fd
== 1 || fd
== 2)
1371 paranoid_printf ("write(%d, %p, %d)", fd
, ptr
, len
);
1373 syscall_printf ("write(%d, %p, %d)", fd
, ptr
, len
);
1375 res
= cfd
->write (ptr
, len
);
1377 __except (EFAULT
) {}
1379 syscall_printf ("%lR = write(%d, %p, %d)", res
, fd
, ptr
, len
);
1383 EXPORT_ALIAS (write
, _write
)
1386 writev (const int fd
, const struct iovec
*const iov
, const int iovcnt
)
1390 pthread_testcancel ();
1394 const ssize_t tot
= check_iovec_for_write (iov
, iovcnt
);
1396 cygheap_fdget
cfd (fd
);
1406 if ((cfd
->get_flags () & O_PATH
)
1407 || (cfd
->get_flags () & O_ACCMODE
) == O_RDONLY
)
1413 /* Could block, so let user know we at least got here. */
1414 if (fd
== 1 || fd
== 2)
1415 paranoid_printf ("writev(%d, %p, %d)", fd
, iov
, iovcnt
);
1417 syscall_printf ("writev(%d, %p, %d)", fd
, iov
, iovcnt
);
1419 res
= cfd
->writev (iov
, iovcnt
, tot
);
1421 __except (EFAULT
) {}
1423 if (fd
== 1 || fd
== 2)
1424 paranoid_printf ("%lR = writev(%d, %p, %d)", res
, fd
, iov
, iovcnt
);
1426 syscall_printf ("%lR = writev(%d, %p, %d)", res
, fd
, iov
, iovcnt
);
1431 pwrite (int fd
, const void *ptr
, size_t len
, off_t off
)
1433 pthread_testcancel ();
1436 cygheap_fdget
cfd (fd
);
1439 else if (cfd
->get_flags () & O_PATH
)
1445 res
= cfd
->pwrite (const_cast<void *> (ptr
), len
, off
);
1447 syscall_printf ("%lR = pwrite(%d, %p, %d, %d)", res
, fd
, ptr
, len
, off
);
1452 /* newlib's fcntl.h defines _open as taking variable args so we must
1453 correspond. The third arg if it exists is: mode_t mode. */
1455 open (const char *unix_path
, int flags
, ...)
1460 fhandler_base
*fh
= NULL
;
1461 fhandler_base
*fh_file
= NULL
;
1463 pthread_testcancel ();
1467 syscall_printf ("open(%s, %y)", unix_path
, flags
);
1474 /* check for optional mode argument */
1475 va_start (ap
, flags
);
1476 mode
= va_arg (ap
, mode_t
);
1482 __leave
; /* errno already set */
1484 /* When O_PATH is specified in flags, flag bits other than O_CLOEXEC,
1485 O_DIRECTORY, and O_NOFOLLOW are ignored. */
1487 flags
&= (O_PATH
| O_CLOEXEC
| O_DIRECTORY
| O_NOFOLLOW
);
1489 int opt
= PC_OPEN
| PC_SYM_NOFOLLOW_PROCFD
;
1490 opt
|= (flags
& (O_NOFOLLOW
| O_EXCL
)) ? PC_SYM_NOFOLLOW
1493 /* If we're opening a FIFO, we will call device_access_denied
1494 below. This leads to a call to fstat, which can use the
1495 path_conv handle. */
1496 opt
|= PC_KEEP_HANDLE
;
1497 if (!(fh
= build_fh_name (unix_path
, opt
, stat_suffixes
)))
1498 __leave
; /* errno already set */
1499 opt
&= ~PC_KEEP_HANDLE
;
1501 fh
->pc
.close_conv_handle ();
1502 if ((flags
& O_NOFOLLOW
) && fh
->issymlink () && !(flags
& O_PATH
))
1507 if ((flags
& O_DIRECTORY
) && fh
->exists () && !fh
->pc
.isdir ())
1509 set_errno (ENOTDIR
);
1512 if (((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
)) && fh
->exists ())
1517 if (flags
& O_TMPFILE
)
1519 if ((flags
& O_ACCMODE
) != O_WRONLY
&& (flags
& O_ACCMODE
) != O_RDWR
)
1524 if (!fh
->pc
.isdir ())
1526 set_errno (fh
->exists () ? ENOTDIR
: ENOENT
);
1529 /* Unfortunately Windows does not allow to create a nameless file.
1530 So create unique filename instead. It starts with ".cyg_tmp_",
1531 followed by an 8 byte unique hex number, followed by an 8 byte
1532 random hex number. */
1536 new_path
= (char *) malloc (strlen (fh
->get_name ())
1539 + 16 /* 64 bit unique id as hex*/
1540 + 16 /* 64 bit random number as hex */
1541 + 1 /* trailing NUL */);
1544 fh
->set_unique_id ();
1545 RtlGenRandom (&rnd
, sizeof rnd
);
1546 __small_sprintf (new_path
, "%s/%s%016X%016X",
1547 fh
->get_name (), ".cyg_tmp_",
1548 fh
->get_unique_id (), rnd
);
1550 if (!(fh_file
= build_fh_name (new_path
, opt
, NULL
)))
1553 __leave
; /* errno already set */
1559 if (fh
->dev () == FH_PROCESSFD
&& fh
->pc
.follow_fd_symlink ())
1561 /* Reopen file by descriptor */
1562 fh_file
= fh
->fd_reopen (flags
, mode
& 07777);
1570 if (fh
->is_fs_special ())
1572 if (fh
->device_access_denied (flags
))
1573 __leave
; /* errno already set */
1574 else if (fh
->isfifo ())
1575 fh
->pc
.close_conv_handle ();
1577 if (!fh
->open_with_arch (flags
, mode
& 07777))
1578 __leave
; /* errno already set */
1580 /* Move O_TMPFILEs to the bin to avoid blocking the parent dir. */
1581 if ((flags
& O_TMPFILE
) && !fh
->pc
.isremote ())
1582 try_to_bin (fh
->pc
, fh
->get_handle (), DELETE
,
1583 FILE_OPEN_FOR_BACKUP_INTENT
);
1586 set_std_handle (fd
);
1589 __except (EFAULT
) {}
1593 syscall_printf ("%R = open(%s, %y)", res
, unix_path
, flags
);
1597 EXPORT_ALIAS (open
, _open
)
1600 lseek (int fd
, off_t pos
, int dir
)
1604 if (dir
< SEEK_SET
|| dir
> SEEK_HOLE
)
1611 cygheap_fdget
cfd (fd
);
1614 else if (cfd
->getdents_dir ())
1616 if (dir
!= SEEK_SET
&& dir
!= SEEK_CUR
) /* No SEEK_END */
1625 cur
= cfd
->telldir (cfd
->getdents_dir ());
1626 if (dir
== SEEK_CUR
&& cur
== 0)
1630 if (dir
== SEEK_CUR
)
1632 cfd
->seekdir (cfd
->getdents_dir (), pos
);
1638 res
= cfd
->lseek (pos
, dir
);
1640 /* Can't use %R/%lR here since res is always 8 bytes */
1641 syscall_printf (res
== -1 ? "%D = lseek(%d, %D, %d), errno %d"
1642 : "%D = lseek(%d, %D, %d)",
1643 res
, fd
, pos
, dir
, get_errno ());
1648 EXPORT_ALIAS (lseek
, _lseek
)
1655 syscall_printf ("close(%d)", fd
);
1657 pthread_testcancel ();
1659 cygheap_fdget
cfd (fd
, true);
1664 cfd
->isclosed (true);
1665 res
= cfd
->close_with_arch ();
1669 syscall_printf ("%R = close(%d)", res
, fd
);
1673 EXPORT_ALIAS (close
, _close
)
1680 cygheap_fdget
cfd (fd
);
1684 res
= cfd
->is_tty ();
1685 syscall_printf ("%R = isatty(%d)", res
, fd
);
1688 EXPORT_ALIAS (isatty
, _isatty
)
1691 link (const char *oldpath
, const char *newpath
)
1696 if (!(fh
= build_fh_name (oldpath
, PC_SYM_NOFOLLOW
| PC_KEEP_HANDLE
,
1702 debug_printf ("got %d error from build_fh_name", fh
->error ());
1703 set_errno (fh
->error ());
1705 else if (fh
->pc
.isdir ())
1706 set_errno (EPERM
); /* We do not permit linking directories. */
1707 else if (!fh
->pc
.exists ())
1710 res
= fh
->link (newpath
);
1714 syscall_printf ("%R = link(%s, %s)", res
, oldpath
, newpath
);
1718 /* chown: POSIX 5.6.5.1 */
1720 * chown () is only implemented for Windows NT. Under other operating
1721 * systems, it is only a stub that always returns zero.
1724 chown_worker (const char *name
, unsigned fmode
, uid_t uid
, gid_t gid
)
1729 if (!(fh
= build_fh_name (name
, fmode
, stat_suffixes
)))
1734 debug_printf ("got %d error from build_fh_name", fh
->error ());
1735 set_errno (fh
->error ());
1738 res
= fh
->fchown (uid
, gid
);
1742 syscall_printf ("%R = %schown(%s,...)",
1743 res
, (fmode
& PC_SYM_NOFOLLOW
) ? "l" : "", name
);
1748 chown (const char * name
, uid_t uid
, gid_t gid
)
1750 return chown_worker (name
, PC_SYM_FOLLOW
, uid
, gid
);
1754 lchown (const char * name
, uid_t uid
, gid_t gid
)
1756 return chown_worker (name
, PC_SYM_NOFOLLOW
, uid
, gid
);
1760 fchown (int fd
, uid_t uid
, gid_t gid
)
1762 cygheap_fdget
cfd (fd
);
1765 syscall_printf ("-1 = fchown (%d,...)", fd
);
1768 else if (cfd
->get_flags () & O_PATH
)
1774 int res
= cfd
->fchown (uid
, gid
);
1776 syscall_printf ("%R = fchown(%s,...)", res
, cfd
->get_name ());
1780 /* umask: POSIX 5.3.3.1 */
1786 oldmask
= cygheap
->umask
;
1787 cygheap
->umask
= mask
& 0777;
1791 #define FILTERED_MODE(m) ((m) & (S_ISUID | S_ISGID | S_ISVTX \
1792 | S_IRWXU | S_IRWXG | S_IRWXO))
1795 chmod_device (path_conv
& pc
, mode_t mode
)
1797 return mknod_worker (pc
, (pc
.dev
.mode () & S_IFMT
) | FILTERED_MODE (mode
),
1798 pc
.dev
.get_major (), pc
.dev
.get_minor ());
1801 /* chmod: POSIX 5.6.4.1 */
1803 chmod (const char *path
, mode_t mode
)
1807 if (!(fh
= build_fh_name (path
, PC_SYM_FOLLOW
, stat_suffixes
)))
1812 debug_printf ("got %d error from build_fh_name", fh
->error ());
1813 set_errno (fh
->error ());
1816 res
= fh
->fchmod (FILTERED_MODE (mode
));
1820 syscall_printf ("%R = chmod(%s, 0%o)", res
, path
, mode
);
1824 /* fchmod: P96 5.6.4.1 */
1827 fchmod (int fd
, mode_t mode
)
1829 cygheap_fdget
cfd (fd
);
1832 syscall_printf ("-1 = fchmod (%d, 0%o)", fd
, mode
);
1835 else if (cfd
->get_flags () & O_PATH
)
1841 return cfd
->fchmod (FILTERED_MODE (mode
));
1844 static struct stat dev_st
;
1845 static bool dev_st_inited
;
1848 fhandler_base::stat_fixup (struct stat
*buf
)
1850 /* For devices, set inode number to device number. This gives us a valid,
1851 unique inode number without having to call hash_path_name. /dev/tty needs
1852 a bit of persuasion to get the same st_ino value in stat and fstat. */
1855 if (get_major () == DEV_VIRTFS_MAJOR
)
1856 buf
->st_ino
= get_ino ();
1857 else if (dev () == FH_TTY
||
1858 ((get_major () == DEV_PTYS_MAJOR
1859 || get_major () == DEV_CONS_MAJOR
)
1860 && !strcmp (get_name (), "/dev/tty")))
1861 buf
->st_ino
= FH_TTY
;
1863 buf
->st_ino
= get_device ();
1865 /* For /dev-based devices, st_dev must be set to the device number of /dev,
1866 not it's own device major/minor numbers. What we do here to speed up
1867 the process is to fetch the device number of /dev only once, liberally
1868 assuming that /dev doesn't change over the lifetime of a process. */
1871 if (dev ().is_dev_resident ())
1875 stat ("/dev", &dev_st
);
1876 dev_st_inited
= true;
1878 buf
->st_dev
= dev_st
.st_dev
;
1881 buf
->st_dev
= get_device ();
1883 /* Only set st_rdev if it's a device. */
1884 if (!buf
->st_rdev
&& get_major () != DEV_VIRTFS_MAJOR
)
1886 buf
->st_rdev
= get_device ();
1887 /* consX, console, conin, and conout point to the same device.
1888 Make sure the link count is correct. */
1889 if (buf
->st_rdev
== (dev_t
) myself
->ctty
&& iscons_dev (myself
->ctty
))
1891 /* CD-ROM drives have two links, /dev/srX and /dev/scdX. */
1892 else if (gnu_dev_major (buf
->st_rdev
) == DEV_CDROM_MAJOR
)
1898 fstat (int fd
, struct stat
*buf
)
1902 cygheap_fdget
cfd (fd
);
1907 memset (buf
, 0, sizeof (struct stat
));
1908 res
= cfd
->fstat (buf
);
1910 cfd
->stat_fixup (buf
);
1913 syscall_printf ("%R = fstat(%d, %p)", res
, fd
, buf
);
1918 _fstat_r (struct _reent
*ptr
, int fd
, struct stat
*buf
)
1922 if ((ret
= fstat (fd
, buf
)) == -1)
1923 _REENT_ERRNO(ptr
) = get_errno ();
1927 /* fsync: P96 6.6.1.1 */
1931 pthread_testcancel ();
1932 cygheap_fdget
cfd (fd
);
1935 syscall_printf ("-1 = fsync (%d)", fd
);
1938 return cfd
->fsync ();
1941 EXPORT_ALIAS (fsync
, fdatasync
)
1944 sync_worker (HANDLE dir
, USHORT len
, LPCWSTR vol
)
1949 OBJECT_ATTRIBUTES attr
;
1950 UNICODE_STRING uvol
= { len
, len
, (WCHAR
*) vol
};
1952 InitializeObjectAttributes (&attr
, &uvol
, OBJ_CASE_INSENSITIVE
, dir
, NULL
);
1953 status
= NtOpenFile (&fh
, GENERIC_WRITE
, &attr
, &io
,
1954 FILE_SHARE_VALID_FLAGS
, 0);
1955 if (!NT_SUCCESS (status
))
1956 debug_printf ("NtOpenFile (%S), status %y", &uvol
, status
);
1959 status
= NtFlushBuffersFile (fh
, &io
);
1960 if (!NT_SUCCESS (status
))
1961 debug_printf ("NtFlushBuffersFile (%S), status %y", &uvol
, status
);
1970 OBJECT_ATTRIBUTES attr
;
1973 UNICODE_STRING device
;
1975 /* Open \Device object directory. */
1976 RtlInitUnicodeString (&device
, L
"\\Device");
1977 InitializeObjectAttributes (&attr
, &device
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1978 status
= NtOpenDirectoryObject (&devhdl
, DIRECTORY_QUERY
, &attr
);
1979 if (!NT_SUCCESS (status
))
1981 debug_printf ("NtOpenDirectoryObject, status %y", status
);
1984 /* Traverse \Device directory ... */
1986 PDIRECTORY_BASIC_INFORMATION dbi_buf
= (PDIRECTORY_BASIC_INFORMATION
)
1988 BOOLEAN restart
= TRUE
;
1989 bool last_run
= false;
1993 status
= NtQueryDirectoryObject (devhdl
, dbi_buf
, 65536, FALSE
, restart
,
1995 if (!NT_SUCCESS (status
))
1997 debug_printf ("NtQueryDirectoryObject, status %y", status
);
2000 if (status
!= STATUS_MORE_ENTRIES
)
2003 for (PDIRECTORY_BASIC_INFORMATION dbi
= dbi_buf
;
2004 dbi
->ObjectName
.Length
> 0;
2007 /* ... and call sync_worker for each HarddiskVolumeX entry. */
2008 if (dbi
->ObjectName
.Length
>= 15 * sizeof (WCHAR
)
2009 && !wcsncasecmp (dbi
->ObjectName
.Buffer
, L
"HarddiskVolume", 14)
2010 && iswdigit (dbi
->ObjectName
.Buffer
[14]))
2011 sync_worker (devhdl
, dbi
->ObjectName
.Length
,
2012 dbi
->ObjectName
.Buffer
);
2018 /* Cygwin internal */
2020 stat_worker (path_conv
&pc
, struct stat
*buf
)
2028 debug_printf ("got %d error from path_conv", pc
.error
);
2029 set_errno (pc
.error
);
2031 else if (pc
.exists ())
2035 memset (buf
, 0, sizeof (*buf
));
2037 if (!(fh
= build_fh_pc (pc
)))
2040 debug_printf ("(%S, %p, %p), file_attributes %d",
2041 pc
.get_nt_native_path (), buf
, fh
, (DWORD
) *fh
);
2043 res
= fh
->fstat (buf
);
2045 fh
->stat_fixup (buf
);
2051 __except (EFAULT
) {}
2053 syscall_printf ("%d = (%S,%p)", res
, pc
.get_nt_native_path (), buf
);
2058 stat (const char *__restrict name
, struct stat
*__restrict buf
)
2060 syscall_printf ("entering");
2061 path_conv
pc (name
, PC_SYM_FOLLOW
| PC_POSIX
| PC_KEEP_HANDLE
2062 | PC_SYM_NOFOLLOW_PROCFD
,
2064 return stat_worker (pc
, buf
);
2068 _stat_r (struct _reent
*__restrict ptr
, const char *__restrict name
,
2073 if ((ret
= stat (name
, buf
)) == -1)
2074 _REENT_ERRNO(ptr
) = get_errno ();
2078 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
2080 lstat (const char *__restrict name
, struct stat
*__restrict buf
)
2082 syscall_printf ("entering");
2083 path_conv
pc (name
, PC_SYM_NOFOLLOW
| PC_POSIX
| PC_KEEP_HANDLE
,
2085 return stat_worker (pc
, buf
);
2089 access (const char *fn
, int flags
)
2091 // flags were incorrectly specified
2093 if (flags
& ~(F_OK
|R_OK
|W_OK
|X_OK
))
2097 fhandler_base
*fh
= build_fh_name (fn
, PC_SYM_FOLLOW
| PC_KEEP_HANDLE
,
2101 res
= fh
->fhaccess (flags
, false);
2105 debug_printf ("returning %d", res
);
2109 /* Linux provides this extension; it is basically a wrapper around the
2110 POSIX:2008 faccessat (AT_FDCWD, fn, flags, AT_EACCESS). We also
2111 provide eaccess as an alias for this, in cygwin.din. */
2113 euidaccess (const char *fn
, int flags
)
2115 // flags were incorrectly specified
2117 if (flags
& ~(F_OK
|R_OK
|W_OK
|X_OK
))
2121 fhandler_base
*fh
= build_fh_name (fn
, PC_SYM_FOLLOW
| PC_KEEP_HANDLE
,
2125 res
= fh
->fhaccess (flags
, true);
2129 debug_printf ("returning %d", res
);
2134 rename_append_suffix (path_conv
&pc
, const char *path
, size_t len
,
2139 if (ascii_strcasematch (path
+ len
- 4, ".lnk")
2140 || ascii_strcasematch (path
+ len
- 4, ".exe"))
2142 stpcpy (stpncpy (buf
, path
, len
), suffix
);
2143 pc
.check (buf
, PC_SYM_NOFOLLOW
);
2146 /* This function tests if a filename has one of the "approved" executable
2147 suffix. This list is probably not complete... */
2149 nt_path_has_executable_suffix (PUNICODE_STRING upath
)
2151 static const PUNICODE_STRING blessed_executable_suffixes
[] =
2159 USHORT pos
= upath
->Length
/ sizeof (WCHAR
);
2161 UNICODE_STRING usuf
;
2162 const PUNICODE_STRING
*suf
;
2164 /* Too short for a native path? */
2167 /* Assumption: All executable suffixes have a length of three. */
2168 path
= upath
->Buffer
+ pos
- 4;
2171 RtlInitCountedUnicodeString (&usuf
, path
, 4 * sizeof (WCHAR
));
2172 for (suf
= blessed_executable_suffixes
; *suf
; ++suf
)
2173 if (RtlEqualUnicodeString (&usuf
, *suf
, TRUE
))
2179 set_same_file_return (bool noreplace
)
2186 /* If newpath names an existing file and the RENAME_NOREPLACE flag is
2187 specified, fail with EEXIST. Exception: Don't fail if the purpose
2188 of the rename is just to change the case of oldpath on a
2189 case-insensitive file system. */
2191 rename2 (const char *oldpath
, const char *newpath
, unsigned int at2flags
)
2195 path_conv oldpc
, newpc
, new2pc
, *dstpc
, *removepc
= NULL
;
2196 bool old_dir_requested
= false, new_dir_requested
= false;
2197 bool old_explicit_suffix
= false, new_explicit_suffix
= false;
2198 bool use_posix_semantics
;
2199 bool noreplace
= at2flags
& RENAME_NOREPLACE
;
2202 NTSTATUS status
= STATUS_SUCCESS
;
2203 HANDLE fh
= NULL
, nfh
;
2204 HANDLE old_trans
= NULL
, trans
= NULL
;
2205 OBJECT_ATTRIBUTES attr
;
2207 FILE_STANDARD_INFORMATION ofsi
;
2208 PFILE_RENAME_INFORMATION pfri
;
2212 if (at2flags
& ~RENAME_NOREPLACE
)
2213 /* RENAME_NOREPLACE is the only flag currently supported. */
2218 if (!*oldpath
|| !*newpath
)
2220 /* Reject rename("","x"), rename("x",""). */
2224 if (has_dot_last_component (oldpath
, true))
2226 /* Reject rename("dir/.","x"). */
2227 oldpc
.check (oldpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2228 set_errno (oldpc
.isdir () ? EINVAL
: ENOTDIR
);
2231 if (has_dot_last_component (newpath
, true))
2233 /* Reject rename("dir","x/."). */
2234 newpc
.check (newpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2235 set_errno (!newpc
.exists () ? ENOENT
2236 : newpc
.isdir () ? EINVAL
: ENOTDIR
);
2240 /* A trailing slash requires that the pathname points to an existing
2241 directory. If it's not, it's a ENOTDIR condition. The same goes
2242 for newpath a bit further down this function. */
2243 olen
= strlen (oldpath
);
2244 if (isdirsep (oldpath
[olen
- 1]))
2247 char *p
= stpcpy (buf
= tp
.c_get (), oldpath
) - 1;
2249 while (p
>= oldpath
&& isdirsep (*p
))
2251 olen
= p
+ 1 - oldpath
;
2254 /* The root directory cannot be renamed. This also rejects
2255 the corner case of rename("/","/"), even though it is the
2260 old_dir_requested
= true;
2262 oldpc
.check (oldpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2265 set_errno (oldpc
.error
);
2268 if (!oldpc
.exists ())
2273 if (oldpc
.isspecial () && !oldpc
.issocket () && !oldpc
.is_fs_special ())
2275 /* No renames from virtual FS */
2279 if (oldpc
.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT
)
2280 && !oldpc
.issymlink ())
2282 /* Volume mount point. If we try to rename a volume mount point, NT
2283 returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==>
2284 errno EXDEV. That's bad since mv(1) will now perform a
2285 cross-device move. So what we do here is to treat the volume
2286 mount point just like Linux treats a mount point. */
2290 if (old_dir_requested
&& !oldpc
.isdir ())
2292 /* Reject rename("file/","x"). */
2293 set_errno (ENOTDIR
);
2296 if (oldpc
.known_suffix ()
2297 && (ascii_strcasematch (oldpath
+ olen
- 4, ".lnk")
2298 || ascii_strcasematch (oldpath
+ olen
- 4, ".exe")))
2299 old_explicit_suffix
= true;
2301 nlen
= strlen (newpath
);
2302 if (isdirsep (newpath
[nlen
- 1]))
2305 char *p
= stpcpy (buf
= tp
.c_get (), newpath
) - 1;
2307 while (p
>= newpath
&& isdirsep (*p
))
2309 nlen
= p
+ 1 - newpath
;
2310 if (!nlen
) /* The root directory is never empty. */
2312 set_errno (ENOTEMPTY
);
2315 new_dir_requested
= true;
2317 newpc
.check (newpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2320 set_errno (newpc
.error
);
2323 if (newpc
.isspecial () && !newpc
.issocket ())
2325 /* No renames to virtual FSes */
2329 if (new_dir_requested
&& !(newpc
.exists ()
2330 ? newpc
.isdir () : oldpc
.isdir ()))
2332 /* Reject rename("file1","file2/"), but allow rename("dir","d/"). */
2333 set_errno (newpc
.exists () ? ENOTDIR
: ENOENT
);
2337 && (oldpc
.isdir () ? !newpc
.isdir () : newpc
.isdir ()))
2339 /* Reject rename("file","dir") and rename("dir","file"). */
2340 set_errno (newpc
.isdir () ? EISDIR
: ENOTDIR
);
2343 if (newpc
.known_suffix ()
2344 && (ascii_strcasematch (newpath
+ nlen
- 4, ".lnk")
2345 || ascii_strcasematch (newpath
+ nlen
- 4, ".exe")))
2346 new_explicit_suffix
= true;
2348 /* This test is necessary in almost every case, so do it once here. */
2349 equal_path
= RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2350 newpc
.get_nt_native_path (),
2351 oldpc
.objcaseinsensitive ());
2353 /* First check if oldpath and newpath only differ by case. If so, it's
2354 just a request to change the case of the filename. By simply setting
2355 the file attributes to INVALID_FILE_ATTRIBUTES (which translates to
2356 "file doesn't exist"), all later tests are skipped. */
2357 if (oldpc
.objcaseinsensitive () && newpc
.exists () && equal_path
2358 && old_explicit_suffix
== new_explicit_suffix
)
2360 if (RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2361 newpc
.get_nt_native_path (),
2364 res
= set_same_file_return (noreplace
);
2367 newpc
.file_attributes (INVALID_FILE_ATTRIBUTES
);
2369 else if (oldpc
.isdir ())
2371 /* Check for newpath being identical or a subdir of oldpath. */
2372 if (RtlPrefixUnicodeString (oldpc
.get_nt_native_path (),
2373 newpc
.get_nt_native_path (),
2374 oldpc
.objcaseinsensitive ()))
2376 if (newpc
.get_nt_native_path ()->Length
2377 == oldpc
.get_nt_native_path ()->Length
)
2379 res
= set_same_file_return (noreplace
);
2382 if (*(PWCHAR
) ((PBYTE
) newpc
.get_nt_native_path ()->Buffer
2383 + oldpc
.get_nt_native_path ()->Length
) == L
'\\')
2390 else if (!newpc
.exists ())
2392 if (equal_path
&& old_explicit_suffix
!= new_explicit_suffix
)
2394 newpc
.check (newpath
, PC_SYM_NOFOLLOW
);
2395 if (RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2396 newpc
.get_nt_native_path (),
2397 oldpc
.objcaseinsensitive ()))
2399 res
= set_same_file_return (noreplace
);
2403 else if (oldpc
.is_lnk_special ()
2404 && !RtlEqualUnicodePathSuffix (newpc
.get_nt_native_path (),
2406 rename_append_suffix (newpc
, newpath
, nlen
, ".lnk");
2407 else if (oldpc
.is_binary () && !old_explicit_suffix
2408 && oldpc
.known_suffix ()
2409 && !nt_path_has_executable_suffix
2410 (newpc
.get_nt_native_path ()))
2411 /* Never append .exe suffix if oldpath had .exe suffix given
2412 explicitely, or if oldpath wasn't already a .exe file, or
2413 if the destination filename has one of the blessed executable
2415 Note: To rename an executable foo.exe to bar-without-suffix,
2416 the .exe suffix must be given explicitly in oldpath. */
2417 rename_append_suffix (newpc
, newpath
, nlen
, ".exe");
2421 if (equal_path
&& old_explicit_suffix
!= new_explicit_suffix
)
2423 newpc
.check (newpath
, PC_SYM_NOFOLLOW
);
2424 if (RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2425 newpc
.get_nt_native_path (),
2426 oldpc
.objcaseinsensitive ()))
2428 res
= set_same_file_return (noreplace
);
2432 else if (oldpc
.is_lnk_special ())
2434 if (!newpc
.is_lnk_special ()
2435 && !RtlEqualUnicodePathSuffix (newpc
.get_nt_native_path (),
2438 rename_append_suffix (new2pc
, newpath
, nlen
, ".lnk");
2442 else if (oldpc
.is_binary ())
2444 /* Never append .exe suffix if oldpath had .exe suffix given
2445 explicitely, or if newfile is a binary (in which case the given
2446 name probably makes sense as it is), or if the destination
2447 filename has one of the blessed executable suffixes. */
2448 if (!old_explicit_suffix
&& oldpc
.known_suffix ()
2449 && !newpc
.is_binary ()
2450 && !nt_path_has_executable_suffix
2451 (newpc
.get_nt_native_path ()))
2453 rename_append_suffix (new2pc
, newpath
, nlen
, ".exe");
2459 /* If the new path is an existing .lnk symlink or a .exe file,
2460 but the new path has not been specified with explicit suffix,
2461 rename to the new name without suffix, as expected, but also
2462 remove the clashing symlink or executable. Did I ever mention
2463 how I hate the file suffix idea? */
2464 if ((newpc
.is_lnk_special ()
2465 || RtlEqualUnicodePathSuffix (newpc
.get_nt_native_path (),
2467 && !new_explicit_suffix
)
2469 new2pc
.check (newpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2470 newpc
.get_nt_native_path ()->Length
-= 4 * sizeof (WCHAR
);
2471 if (new2pc
.is_binary () || new2pc
.is_lnk_special ())
2476 dstpc
= (removepc
== &newpc
) ? &new2pc
: &newpc
;
2478 /* Check cross-device before touching anything. Otherwise we might end
2479 up with an unlinked target dir even if the actual rename didn't work.*/
2480 if (oldpc
.fs_type () != dstpc
->fs_type ()
2481 || oldpc
.fs_serial_number () != dstpc
->fs_serial_number ())
2487 /* Should we replace an existing file? */
2488 if ((removepc
|| dstpc
->exists ()) && noreplace
)
2494 /* POSIX semantics only on local NTFS drives. For the OPEN_BY_FILE_ID
2495 flag, see MINIMAL_WIN_NTFS_FLAGS comment in fs_info::update. */
2496 use_posix_semantics
= wincap
.has_posix_rename_semantics ()
2497 && !oldpc
.isremote ()
2498 && oldpc
.fs_is_ntfs ()
2499 && oldpc
.has_attribute (FILE_SUPPORTS_OPEN_BY_FILE_ID
);
2501 ignore_posix_semantics_retry
:
2502 /* Opening the file must be part of the transaction. It's not sufficient
2503 to call only NtSetInformationFile under the transaction. Therefore we
2504 have to start the transaction here, if necessary. Don't start
2505 transaction on W10 1709 or later on local NTFS. Use POSIX semantics
2507 if (!use_posix_semantics
2508 && (dstpc
->fs_flags () & FILE_SUPPORTS_TRANSACTIONS
)
2510 || (!removepc
&& dstpc
->has_attribute (FILE_ATTRIBUTE_READONLY
))))
2511 start_transaction (old_trans
, trans
);
2516 /* Talking about inconsistent behaviour...
2517 - DELETE is required to rename a file. So far, so good.
2518 - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the
2519 FileRenameInformation call fails with STATUS_ACCESS_DENIED. However,
2520 on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used
2521 and the file we try to rename is a symlink. Urgh.
2522 - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE
2523 mode if the file has the R/O attribute set and returns
2524 STATUS_ACCESS_DENIED in that case. */
2526 ULONG access
= DELETE
2527 | (oldpc
.fs_is_cifs () ? FILE_READ_ATTRIBUTES
: 0);
2528 ULONG sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
2529 | (oldpc
.fs_is_samba () ? 0 : FILE_SHARE_DELETE
);
2530 ULONG flags
= FILE_OPEN_FOR_BACKUP_INTENT
2531 | (oldpc
.is_known_reparse_point ()
2532 ? FILE_OPEN_REPARSE_POINT
: 0);
2533 status
= NtOpenFile (&fh
, access
,
2534 oldpc
.get_object_attr (attr
, sec_none_nih
),
2535 &io
, sharing
, flags
);
2537 if (!NT_SUCCESS (status
))
2539 debug_printf ("status %y", status
);
2540 if (status
== STATUS_SHARING_VIOLATION
2541 && cygwait (10L) != WAIT_SIGNALED
)
2543 /* Typical BLODA problem. Some virus scanners check newly
2544 generated files and while doing that disallow DELETE access.
2545 That's really bad because it breaks applications which copy
2546 files by creating a temporary filename and then rename the
2547 temp filename to the target filename. This renaming fails due
2548 to the jealous virus scanner and the application fails to
2549 create the target file.
2551 This kludge tries to work around that by yielding until the
2552 sharing violation goes away, or a signal arrived, or after
2553 about a second, give or take. */
2554 if (++retry_count
< 40)
2560 else if (NT_TRANSACTIONAL_ERROR (status
) && trans
)
2562 /* If NtOpenFile fails due to transactional problems, stop
2563 transaction and go ahead without. */
2564 stop_transaction (status
, old_trans
, trans
);
2565 debug_printf ("Transaction failure. Retry open.");
2568 __seterrno_from_nt_status (status
);
2572 if (use_posix_semantics
)
2573 goto skip_pre_W10_checks
;
2575 /* Renaming a dir to another, existing dir fails always, even if
2576 ReplaceIfExists is set to TRUE and the existing dir is empty. So
2577 we have to remove the destination dir first. This also covers the
2578 case that the destination directory is not empty. In that case,
2579 unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */
2580 if (dstpc
->isdir ())
2582 status
= unlink_nt (*dstpc
, false);
2583 if (!NT_SUCCESS (status
))
2585 __seterrno_from_nt_status (status
);
2589 /* You can't copy a file if the destination exists and has the R/O
2590 attribute set. Remove the R/O attribute first. But first check
2591 if a removepc exists. If so, dstpc points to a non-existing file
2592 due to a mangled suffix. */
2593 else if (!removepc
&& dstpc
->has_attribute (FILE_ATTRIBUTE_READONLY
))
2595 status
= NtOpenFile (&nfh
, FILE_WRITE_ATTRIBUTES
,
2596 dstpc
->get_object_attr (attr
, sec_none_nih
),
2597 &io
, FILE_SHARE_VALID_FLAGS
,
2598 FILE_OPEN_FOR_BACKUP_INTENT
2599 | (dstpc
->is_known_reparse_point ()
2600 ? FILE_OPEN_REPARSE_POINT
: 0));
2601 if (!NT_SUCCESS (status
))
2603 __seterrno_from_nt_status (status
);
2606 status
= NtSetAttributesFile (nfh
, dstpc
->file_attributes ()
2607 & ~FILE_ATTRIBUTE_READONLY
);
2609 if (!NT_SUCCESS (status
))
2611 __seterrno_from_nt_status (status
);
2616 skip_pre_W10_checks
:
2618 /* SUSv3: If the old argument and the new argument resolve to the same
2619 existing file, rename() shall return successfully and perform no
2621 The test tries to be as quick as possible. Due to the above cross
2622 device check we already know both files are on the same device. So
2623 it just tests if oldpath has more than 1 hardlink, then it opens
2624 newpath and tests for identical file ids. If so, oldpath and newpath
2625 refer to the same file. */
2626 if ((removepc
|| dstpc
->exists ())
2628 && NT_SUCCESS (NtQueryInformationFile (fh
, &io
, &ofsi
, sizeof ofsi
,
2629 FileStandardInformation
))
2630 && ofsi
.NumberOfLinks
> 1
2631 && NT_SUCCESS (NtOpenFile (&nfh
, READ_CONTROL
,
2632 (removepc
?: dstpc
)->get_object_attr (attr
, sec_none_nih
),
2633 &io
, FILE_SHARE_VALID_FLAGS
,
2634 FILE_OPEN_FOR_BACKUP_INTENT
2635 | ((removepc
?: dstpc
)->is_known_reparse_point ()
2636 ? FILE_OPEN_REPARSE_POINT
: 0))))
2638 FILE_INTERNAL_INFORMATION ofii
, nfii
;
2640 if (NT_SUCCESS (NtQueryInformationFile (fh
, &io
, &ofii
, sizeof ofii
,
2641 FileInternalInformation
))
2642 && NT_SUCCESS (NtQueryInformationFile (nfh
, &io
, &nfii
,
2644 FileInternalInformation
))
2645 && ofii
.IndexNumber
.QuadPart
== nfii
.IndexNumber
.QuadPart
)
2647 debug_printf ("%s and %s are the same file", oldpath
, newpath
);
2649 res
= set_same_file_return (noreplace
);
2654 /* Create FILE_RENAME_INFORMATION struct. Using a tmp_pathbuf area
2655 allows for paths of up to 32757 chars. This test is just for
2657 if (dstpc
->get_nt_native_path ()->Length
2658 > NT_MAX_PATH
* sizeof (WCHAR
) - sizeof (FILE_RENAME_INFORMATION
))
2660 debug_printf ("target filename too long");
2664 pfri
= (PFILE_RENAME_INFORMATION
) tp
.w_get ();
2665 if (use_posix_semantics
)
2666 pfri
->Flags
= noreplace
? 0
2667 : (FILE_RENAME_REPLACE_IF_EXISTS
2668 | FILE_RENAME_POSIX_SEMANTICS
2669 | FILE_RENAME_IGNORE_READONLY_ATTRIBUTE
);
2671 pfri
->ReplaceIfExists
= !noreplace
;
2672 pfri
->RootDirectory
= NULL
;
2673 pfri
->FileNameLength
= dstpc
->get_nt_native_path ()->Length
;
2674 memcpy (&pfri
->FileName
, dstpc
->get_nt_native_path ()->Buffer
,
2675 pfri
->FileNameLength
);
2676 /* If dstpc points to an existing file and RENAME_NOREPLACE has
2677 been specified, then we should get NT error
2678 STATUS_OBJECT_NAME_COLLISION ==> Win32 error
2679 ERROR_ALREADY_EXISTS ==> Cygwin error EEXIST. */
2680 status
= NtSetInformationFile (fh
, &io
, pfri
,
2681 sizeof *pfri
+ pfri
->FileNameLength
,
2683 ? FileRenameInformationEx
2684 : FileRenameInformation
);
2685 /* This happens if the access rights don't allow deleting the destination.
2686 Even if the handle to the original file is opened with BACKUP
2687 and/or RECOVERY, these flags don't apply to the destination of the
2688 rename operation. So, a privileged user can't rename a file to an
2689 existing file, if the permissions of the existing file aren't right.
2690 Like directories, we have to handle this separately by removing the
2691 destination before renaming. */
2692 if (status
== STATUS_ACCESS_DENIED
&& dstpc
->exists ()
2693 && !dstpc
->isdir ())
2695 bool need_open
= false;
2697 if ((dstpc
->fs_flags () & FILE_SUPPORTS_TRANSACTIONS
) && !trans
)
2699 /* As mentioned earlier, opening the file must be part of the
2700 transaction. Therefore we have to reopen the file here if the
2701 transaction hasn't been started already. Unfortunately we
2702 can't use the NT "reopen file from existing handle" feature.
2703 In that case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT.
2704 We *have* to close the handle to the file first, *then* we can
2705 re-open it. Fortunately nothing has happened yet, so the
2706 atomicity of the rename functionality is not spoiled. */
2708 start_transaction (old_trans
, trans
);
2713 status
= STATUS_SUCCESS
;
2715 status
= NtOpenFile (&fh
, DELETE
,
2716 oldpc
.get_object_attr (attr
, sec_none_nih
),
2717 &io
, FILE_SHARE_VALID_FLAGS
,
2718 FILE_OPEN_FOR_BACKUP_INTENT
2719 | (oldpc
.is_known_reparse_point ()
2720 ? FILE_OPEN_REPARSE_POINT
: 0));
2721 if (NT_SUCCESS (status
))
2723 status
= unlink_nt (*dstpc
, false);
2724 if (NT_SUCCESS (status
))
2727 if (!NT_TRANSACTIONAL_ERROR (status
) || !trans
)
2729 /* If NtOpenFile or unlink_nt fail due to transactional problems,
2730 stop transaction and retry without. */
2732 stop_transaction (status
, old_trans
, trans
);
2733 debug_printf ("Transaction failure %y. Retry open.", status
);
2735 if (NT_SUCCESS (status
))
2736 status
= NtSetInformationFile (fh
, &io
, pfri
,
2737 sizeof *pfri
+ pfri
->FileNameLength
,
2738 FileRenameInformation
);
2740 if (NT_SUCCESS (status
))
2743 unlink_nt (*removepc
, false);
2746 else if (use_posix_semantics
&& status
== STATUS_INVALID_PARAMETER
)
2748 /* NtSetInformationFile returns STATUS_INVALID_PARAMETER
2749 on a bind mounted file system in hyper-v container
2750 with FILE_RENAME_POSIX_SEMANTICS.
2751 Disable the use_posix semntics flag and retry. */
2752 debug_printf ("NtSetInformationFile failed with posix semantics. "
2753 "Disable it and retry.");
2754 use_posix_semantics
= 0;
2755 goto ignore_posix_semantics_retry
;
2758 __seterrno_from_nt_status (status
);
2767 /* Stop transaction if we started one. */
2769 stop_transaction (status
, old_trans
, trans
);
2770 if (get_errno () != EFAULT
)
2771 syscall_printf ("%R = rename(%s, %s)", res
, oldpath
, newpath
);
2776 rename (const char *oldpath
, const char *newpath
)
2778 return rename2 (oldpath
, newpath
, 0);
2782 system (const char *cmdstring
)
2784 pthread_testcancel ();
2786 if (cmdstring
== NULL
)
2790 const char* command
[4];
2796 command
[2] = cmdstring
;
2797 command
[3] = (const char *) NULL
;
2799 if ((res
= spawnvp (_P_SYSTEM
, "/bin/sh", command
)) == -1)
2801 // when exec fails, return value should be as if shell
2802 // executed exit (127)
2806 __except (EFAULT
) {}
2812 setdtablesize (int size
)
2820 if (size
<= (int) cygheap
->fdtab
.size
2821 || cygheap
->fdtab
.extend (size
- cygheap
->fdtab
.size
, OPEN_MAX
))
2836 return (size_t) wincap
.allocation_granularity ();
2839 /* FIXME: not all values are correct... */
2841 fpathconf (int fd
, int v
)
2843 cygheap_fdget
cfd (fd
);
2846 return cfd
->fpathconf (v
);
2850 pathconf (const char *file
, int v
)
2852 fhandler_base
*fh
= NULL
;
2862 if (!(fh
= build_fh_name (file
, PC_SYM_FOLLOW
, stat_suffixes
)))
2867 ret
= fh
->fpathconf (v
);
2869 __except (EFAULT
) {}
2876 ttyname_r (int fd
, char *buf
, size_t buflen
)
2882 cygheap_fdget
cfd (fd
, true);
2885 else if (!cfd
->is_tty ())
2887 else if (buflen
< strlen (cfd
->ttyname ()) + 1)
2890 strcpy (buf
, cfd
->ttyname ());
2891 debug_printf ("returning %d tty: %s", ret
, ret
? "NULL" : buf
);
2904 static char name
[TTY_NAME_MAX
];
2905 int ret
= ttyname_r (fd
, name
, TTY_NAME_MAX
);
2918 str
= _my_tls
.locals
.ttybuf
;
2919 if (!CTTY_IS_VALID (myself
->ctty
))
2920 strcpy (str
, "no tty");
2924 d
.parse (myself
->ctty
);
2925 strcpy (str
, d
.name ());
2930 /* Tells stdio if it should do the cr/lf conversion for this file */
2932 _cygwin_istext_for_stdio (int fd
)
2934 cygheap_fdget
cfd (fd
, false, false);
2937 syscall_printf ("fd %d: not open", fd
);
2942 if (cfd
->get_device () != FH_FS
)
2944 syscall_printf ("fd not disk file. Defaulting to binary.");
2949 if (cfd
->wbinary () || cfd
->rbinary ())
2951 syscall_printf ("fd %d: opened as binary", fd
);
2955 syscall_printf ("fd %d: defaulting to text", fd
);
2960 setmode_helper (struct _reent
*ptr __unused
, FILE *f
)
2962 if (fileno (f
) != _my_tls
.locals
.setmode_file
)
2964 syscall_printf ("improbable, but %d != %d", fileno (f
), _my_tls
.locals
.setmode_file
);
2967 syscall_printf ("file was %s now %s", f
->_flags
& __SCLE
? "text" : "binary",
2968 _my_tls
.locals
.setmode_mode
& O_TEXT
? "text" : "binary");
2969 if (_my_tls
.locals
.setmode_mode
& O_TEXT
)
2970 f
->_flags
|= __SCLE
;
2972 f
->_flags
&= ~__SCLE
;
2979 cygheap_fdget
cfd (fd
);
2983 return cfd
->get_flags () & (O_BINARY
| O_TEXT
);
2986 /* Set a file descriptor into text or binary mode, returning the
2990 _setmode (int fd
, int mode
)
2992 cygheap_fdget
cfd (fd
);
2995 if (mode
!= O_BINARY
&& mode
!= O_TEXT
&& mode
!= 0)
3001 /* Note that we have no way to indicate the case that writes are
3002 binary but not reads, or vice-versa. These cases can arise when
3003 using the tty or console interface. People using those
3004 interfaces should not use setmode. */
3007 if (cfd
->wbinary () && cfd
->rbinary ())
3009 else if (cfd
->wbinset () && cfd
->rbinset ())
3010 res
= O_TEXT
; /* Specifically set O_TEXT */
3015 cfd
->reset_to_open_binmode ();
3017 cfd
->set_flags ((cfd
->get_flags () & ~(O_TEXT
| O_BINARY
)) | mode
);
3019 syscall_printf ("(%d<%S>, %p) returning %s", fd
,
3020 cfd
->pc
.get_nt_native_path (), mode
,
3021 res
& O_TEXT
? "text" : "binary");
3026 cygwin_setmode (int fd
, int mode
)
3028 int res
= _setmode (fd
, mode
);
3031 _my_tls
.locals
.setmode_file
= fd
;
3032 if (_cygwin_istext_for_stdio (fd
))
3033 _my_tls
.locals
.setmode_mode
= O_TEXT
;
3035 _my_tls
.locals
.setmode_mode
= O_BINARY
;
3036 _fwalk_sglue (_GLOBAL_REENT
, setmode_helper
, &__sglue
);
3042 posix_fadvise (int fd
, off_t offset
, off_t len
, int advice
)
3045 cygheap_fdget
cfd (fd
);
3047 res
= cfd
->fadvise (offset
, len
, advice
);
3050 syscall_printf ("%R = posix_fadvice(%d, %D, %D, %d)",
3051 res
, fd
, offset
, len
, advice
);
3056 fallocate (int fd
, int mode
, off_t offset
, off_t len
)
3060 /* First check mask of allowed flags */
3061 if (mode
& ~(FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_ZERO_RANGE
3062 | FALLOC_FL_UNSHARE_RANGE
| FALLOC_FL_COLLAPSE_RANGE
3063 | FALLOC_FL_INSERT_RANGE
| FALLOC_FL_KEEP_SIZE
))
3065 /* Either FALLOC_FL_PUNCH_HOLE or FALLOC_FL_ZERO_RANGE, never both */
3066 else if ((mode
& (FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_ZERO_RANGE
))
3067 == (FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_ZERO_RANGE
))
3069 /* FALLOC_FL_PUNCH_HOLE must be ORed with FALLOC_FL_KEEP_SIZE */
3070 else if ((mode
& (FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_KEEP_SIZE
))
3071 == FALLOC_FL_PUNCH_HOLE
)
3073 else if (offset
< 0 || len
<= 0)
3075 else if (INT64_MAX
- len
< offset
)
3079 cygheap_fdget
cfd (fd
);
3081 res
= cfd
->fallocate (mode
, offset
, len
);
3092 syscall_printf ("%R = fallocate(%d, %y, %D, %D)", res
, fd
, mode
, offset
, len
);
3097 posix_fallocate (int fd
, off_t offset
, off_t len
)
3100 if (offset
< 0 || len
<= 0)
3102 else if (INT64_MAX
- len
< offset
)
3106 cygheap_fdget
cfd (fd
);
3108 res
= cfd
->fallocate (0, offset
, len
);
3114 syscall_printf ("%R = posix_fallocate(%d, %D, %D)", res
, fd
, offset
, len
);
3119 ftruncate (int fd
, off_t length
)
3122 cygheap_fdget
cfd (fd
);
3125 res
= cfd
->fallocate (__FALLOC_FL_TRUNCATE
, 0, length
);
3136 syscall_printf ("%R = ftruncate(%d, %D)", res
, fd
, length
);
3140 /* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
3142 truncate (const char *pathname
, off_t length
)
3147 fd
= open (pathname
, O_RDWR
);
3151 res
= ftruncate (fd
, length
);
3154 syscall_printf ("%R = truncate(%s, %D)", res
, pathname
, length
);
3160 _get_osfhandle (int fd
)
3164 cygheap_fdget
cfd (fd
);
3166 res
= (long) cfd
->get_handle ();
3170 syscall_printf ("%R = get_osfhandle(%d)", res
, fd
);
3175 fstatvfs (int fd
, struct statvfs
*sfs
)
3179 cygheap_fdget
cfd (fd
);
3182 return cfd
->fstatvfs (sfs
);
3184 __except (EFAULT
) {}
3190 statvfs (const char *name
, struct statvfs
*sfs
)
3193 fhandler_base
*fh
= NULL
;
3197 if (!(fh
= build_fh_name (name
, PC_SYM_FOLLOW
, stat_suffixes
)))
3202 debug_printf ("got %d error from build_fh_name", fh
->error ());
3203 set_errno (fh
->error ());
3205 else if (fh
->exists ())
3207 debug_printf ("(%s, %p), file_attributes %d", name
, sfs
, (DWORD
) *fh
);
3208 res
= fh
->fstatvfs (sfs
);
3214 __except (EFAULT
) {}
3217 if (get_errno () != EFAULT
)
3218 syscall_printf ("%R = statvfs(%s,%p)", res
, name
, sfs
);
3223 fstatfs (int fd
, struct statfs
*sfs
)
3226 int ret
= fstatvfs (fd
, &vfs
);
3229 sfs
->f_type
= vfs
.f_flag
;
3230 sfs
->f_bsize
= vfs
.f_bsize
;
3231 sfs
->f_blocks
= vfs
.f_blocks
;
3232 sfs
->f_bavail
= vfs
.f_bavail
;
3233 sfs
->f_bfree
= vfs
.f_bfree
;
3236 sfs
->f_fsid
= vfs
.f_fsid
;
3237 sfs
->f_namelen
= vfs
.f_namemax
;
3243 statfs (const char *fname
, struct statfs
*sfs
)
3246 int ret
= statvfs (fname
, &vfs
);
3249 sfs
->f_type
= vfs
.f_flag
;
3250 sfs
->f_bsize
= vfs
.f_bsize
;
3251 sfs
->f_blocks
= vfs
.f_blocks
;
3252 sfs
->f_bavail
= vfs
.f_bavail
;
3253 sfs
->f_bfree
= vfs
.f_bfree
;
3256 sfs
->f_fsid
= vfs
.f_fsid
;
3257 sfs
->f_namelen
= vfs
.f_namemax
;
3262 /* setpgid: POSIX 4.3.3.1 */
3264 setpgid (pid_t pid
, pid_t pgid
)
3276 pinfo
p (pid
, PID_MAP_RW
);
3279 else if (p
->pgid
== pgid
)
3281 /* A process may only change the process group of itself and its children */
3282 else if (p
!= myself
&& p
->ppid
!= myself
->pid
)
3287 if (p
->pid
!= p
->pgid
)
3288 p
->set_has_pgid_children (0);
3293 syscall_printf ("pid %d, pgid %d, res %d", pid
, pgid
, res
);
3315 return setpgid (0, 0);
3327 static char buf
[TTY_NAME_MAX
];
3328 return ptsname_r (fd
, buf
, sizeof (buf
)) == 0 ? buf
: NULL
;
3332 ptsname_r (int fd
, char *buf
, size_t buflen
)
3340 cygheap_fdget
cfd (fd
);
3343 return cfd
->ptsname_r (buf
, buflen
);
3347 mknod_worker (path_conv
&pc
, mode_t mode
, _major_t major
, _minor_t minor
)
3349 char buf
[sizeof (":\\00000000:00000000:00000000") + PATH_MAX
];
3350 sprintf (buf
, ":\\%x:%x:%x", major
, minor
, mode
);
3351 return symlink_worker (buf
, pc
, true);
3355 mknod (const char *path
, mode_t mode
, dev_t dev
)
3365 if (strlen (path
) >= PATH_MAX
)
3368 /* Trailing dirsep is a no-no, only errno differs. */
3369 bool has_trailing_dirsep
= isdirsep (path
[strlen (path
) - 1]);
3371 path_conv
w32path (path
, PC_SYM_NOFOLLOW
| PC_SYM_NOFOLLOW_DIR
3372 | PC_POSIX
, stat_suffixes
);
3374 if (w32path
.exists () || has_trailing_dirsep
)
3376 set_errno (w32path
.exists () ? EEXIST
: ENOENT
);
3380 mode_t type
= mode
& S_IFMT
;
3381 _major_t major
= _major (dev
);
3382 _minor_t minor
= _minor (dev
);
3390 major
= _major (FH_FIFO
);
3391 minor
= _minor (FH_FIFO
);
3397 int fd
= open (path
, O_CREAT
, mode
);
3409 return mknod_worker (w32path
, mode
, major
, minor
);
3417 mkfifo (const char *path
, mode_t mode
)
3419 return mknod (path
, (mode
& ~S_IFMT
) | S_IFIFO
, 0);
3422 /* seteuid: standards? */
3426 debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
3427 uid
, myself
->uid
, myself
->gid
);
3429 /* Same uid as we're just running under is usually a no-op.
3431 Except we have an external token which is a restricted token. Or,
3432 the external token is NULL, but the current impersonation token is
3433 a restricted token. This allows to restrict user rights temporarily
3436 cygwin_internal(CW_SET_EXTERNAL_TOKEN, restricted_token,
3437 CW_TOKEN_RESTRICTED);
3439 [...do stuff with restricted rights...]
3440 cygwin_internal(CW_SET_EXTERNAL_TOKEN, INVALID_HANDLE_VALUE,
3441 CW_TOKEN_RESTRICTED);
3444 Note that using the current uid is a requirement! We have restricted
3445 tokens galore (UAC), so this is really just a special case to restrict
3446 your own processes to lesser rights. */
3447 bool request_restricted_uid_switch
= (uid
== myself
->uid
3448 && cygheap
->user
.ext_token_is_restricted
);
3449 if (uid
== myself
->uid
&& !cygheap
->user
.groups
.ischanged
3450 && !request_restricted_uid_switch
)
3452 debug_printf ("Nothing happens");
3457 user_groups
&groups
= cygheap
->user
.groups
;
3458 HANDLE new_token
= NULL
;
3459 struct passwd
* pw_new
;
3460 bool token_is_internal
, issamesid
= false;
3462 pw_new
= internal_getpwuid (uid
);
3463 if (!usersid
.getfrompw (pw_new
))
3469 cygheap
->user
.deimpersonate ();
3471 /* Verify if the process token is suitable. */
3472 /* First of all, skip all checks if a switch to a restricted token has been
3473 requested, or if trying to switch back from it. */
3474 if (request_restricted_uid_switch
)
3476 if (cygheap
->user
.external_token
!= NO_IMPERSONATION
)
3478 debug_printf ("Switch to restricted token");
3479 new_token
= cygheap
->user
.external_token
;
3483 debug_printf ("Switch back from restricted token");
3484 new_token
= hProcToken
;
3485 cygheap
->user
.ext_token_is_restricted
= false;
3488 /* TODO, CV 2008-11-25: The check against saved_sid is a kludge and a
3489 shortcut. We must check if it's really feasible in the long run.
3490 The reason to add this shortcut is this: sshd switches back to the
3491 privileged user running sshd at least twice in the process of
3492 authentication. It calls seteuid first, then setegid. Due to this
3493 order, the setgroups group list is still active when calling seteuid
3494 and verify_token treats the original token of the privileged user as
3495 insufficient. This in turn results in creating a new user token for
3496 the privileged user instead of using the original token. This can have
3497 unfortunate side effects. The created token has different group
3498 memberships, different user rights, and misses possible network
3500 Therefore we try this shortcut now. When switching back to the
3501 privileged user, we probably always want a correct (aka original)
3502 user token for this privileged user, not only in sshd. */
3503 else if ((uid
== cygheap
->user
.saved_uid
3504 && usersid
== cygheap
->user
.saved_sid ())
3505 || verify_token (hProcToken
, usersid
, groups
))
3506 new_token
= hProcToken
;
3507 /* Verify if the external token is suitable */
3508 else if (cygheap
->user
.external_token
!= NO_IMPERSONATION
3509 && verify_token (cygheap
->user
.external_token
, usersid
, groups
))
3510 new_token
= cygheap
->user
.external_token
;
3511 /* Verify if the current token (internal or former external) is suitable */
3512 else if (cygheap
->user
.curr_primary_token
!= NO_IMPERSONATION
3513 && cygheap
->user
.curr_primary_token
!= cygheap
->user
.external_token
3514 && verify_token (cygheap
->user
.curr_primary_token
, usersid
, groups
,
3515 &token_is_internal
))
3516 new_token
= cygheap
->user
.curr_primary_token
;
3517 /* Verify if the internal token is suitable */
3518 else if (cygheap
->user
.internal_token
!= NO_IMPERSONATION
3519 && cygheap
->user
.internal_token
!= cygheap
->user
.curr_primary_token
3520 && verify_token (cygheap
->user
.internal_token
, usersid
, groups
,
3521 &token_is_internal
))
3522 new_token
= cygheap
->user
.internal_token
;
3524 debug_printf ("Found token %p", new_token
);
3526 /* If no impersonation token is available, try to authenticate using
3527 LSA private data stored password, or, if that fails, S4U logon. */
3528 if (new_token
== NULL
)
3530 if (!(new_token
= lsaprivkeyauth (pw_new
)))
3533 WCHAR domain
[MAX_DOMAIN_NAME_LEN
+ 1];
3534 WCHAR user
[UNLEN
+ 1];
3536 debug_printf ("lsaprivkeyauth failed, try s4uauth.");
3537 extract_nt_dom_user (pw_new
, domain
, user
);
3538 if (!(new_token
= s4uauth (true, domain
, user
, status
)))
3540 debug_printf ("s4uauth failed, bail out");
3541 cygheap
->user
.reimpersonate ();
3546 /* Keep at most one internal token */
3547 if (cygheap
->user
.internal_token
!= NO_IMPERSONATION
)
3548 CloseHandle (cygheap
->user
.internal_token
);
3549 cygheap
->user
.internal_token
= new_token
;
3552 if (new_token
!= hProcToken
)
3556 if (!request_restricted_uid_switch
)
3557 load_user_profile (new_token
, pw_new
, usersid
);
3559 /* Try setting owner to same value as user. */
3560 status
= NtSetInformationToken (new_token
, TokenOwner
,
3561 &usersid
, sizeof usersid
);
3562 if (!NT_SUCCESS (status
))
3563 debug_printf ("NtSetInformationToken (user.token, TokenOwner), %y",
3565 /* Try setting primary group in token to current group */
3566 status
= NtSetInformationToken (new_token
, TokenPrimaryGroup
,
3567 &groups
.pgsid
, sizeof (cygsid
));
3568 if (!NT_SUCCESS (status
))
3569 debug_printf ("NtSetInformationToken (user.token, TokenPrimaryGroup),"
3571 /* Try setting default DACL */
3572 PACL dacl_buf
= (PACL
) alloca (MAX_DACL_LEN (5));
3573 if (sec_acl (dacl_buf
, true, true, usersid
))
3575 TOKEN_DEFAULT_DACL tdacl
= { dacl_buf
};
3576 status
= NtSetInformationToken (new_token
, TokenDefaultDacl
,
3577 &tdacl
, sizeof (tdacl
));
3578 if (!NT_SUCCESS (status
))
3579 debug_printf ("NtSetInformationToken (TokenDefaultDacl), %y",
3584 issamesid
= (usersid
== cygheap
->user
.sid ());
3585 cygheap
->user
.set_sid (usersid
);
3586 cygheap
->user
.curr_primary_token
= new_token
== hProcToken
? NO_IMPERSONATION
3588 cygheap
->user
.curr_token_is_restricted
= false;
3589 cygheap
->user
.setuid_to_restricted
= false;
3590 if (cygheap
->user
.curr_imp_token
!= NO_IMPERSONATION
)
3592 CloseHandle (cygheap
->user
.curr_imp_token
);
3593 cygheap
->user
.curr_imp_token
= NO_IMPERSONATION
;
3595 if (cygheap
->user
.curr_primary_token
!= NO_IMPERSONATION
)
3597 /* HANDLE_FLAG_INHERIT may be missing in external token. */
3598 if (!SetHandleInformation (cygheap
->user
.curr_primary_token
,
3599 HANDLE_FLAG_INHERIT
, HANDLE_FLAG_INHERIT
)
3600 || !DuplicateTokenEx (cygheap
->user
.curr_primary_token
,
3601 MAXIMUM_ALLOWED
, &sec_none
,
3602 SecurityImpersonation
, TokenImpersonation
,
3603 &cygheap
->user
.curr_imp_token
))
3606 cygheap
->user
.curr_primary_token
= NO_IMPERSONATION
;
3609 cygheap
->user
.curr_token_is_restricted
= request_restricted_uid_switch
;
3610 set_cygwin_privileges (cygheap
->user
.curr_primary_token
);
3611 set_cygwin_privileges (cygheap
->user
.curr_imp_token
);
3613 if (!cygheap
->user
.reimpersonate ())
3619 cygheap
->user
.set_name (pw_new
->pw_name
);
3621 groups
.ischanged
= FALSE
;
3623 /* Recreate and fill out the user shared region for a new user. */
3624 user_info::create (true);
3628 /* setuid: POSIX 4.2.2.1 */
3632 int ret
= seteuid (uid
);
3635 cygheap
->user
.real_uid
= myself
->uid
;
3636 /* If restricted token, forget original privileges on exec (). */
3637 cygheap
->user
.setuid_to_restricted
= cygheap
->user
.curr_token_is_restricted
;
3639 debug_printf ("real: %d, effective: %d", cygheap
->user
.real_uid
, myself
->uid
);
3644 setreuid (uid_t ruid
, uid_t euid
)
3648 uid_t old_euid
= myself
->uid
;
3650 if (ruid
!= ILLEGAL_UID
&& cygheap
->user
.real_uid
!= ruid
&& euid
!= ruid
)
3651 tried
= !(ret
= seteuid (ruid
));
3652 if (!ret
&& euid
!= ILLEGAL_UID
)
3653 ret
= seteuid (euid
);
3654 if (tried
&& (ret
|| euid
== ILLEGAL_UID
) && seteuid (old_euid
))
3655 system_printf ("Cannot restore original euid %u", old_euid
);
3656 if (!ret
&& ruid
!= ILLEGAL_UID
)
3657 cygheap
->user
.real_uid
= ruid
;
3658 debug_printf ("real: %u, effective: %u", cygheap
->user
.real_uid
, myself
->uid
);
3662 /* setegid: from System V. */
3666 debug_printf ("new egid: %u current: %u", gid
, myself
->gid
);
3668 if (gid
== myself
->gid
)
3675 user_groups
* groups
= &cygheap
->user
.groups
;
3677 struct group
* gr
= internal_getgrgid (gid
);
3679 if (!gsid
.getfromgr (gr
))
3686 groups
->update_pgrp (gsid
);
3687 if (cygheap
->user
.issetuid ())
3689 /* If impersonated, update impersonation token... */
3690 status
= NtSetInformationToken (cygheap
->user
.primary_token (),
3691 TokenPrimaryGroup
, &gsid
, sizeof gsid
);
3692 if (!NT_SUCCESS (status
))
3693 debug_printf ("NtSetInformationToken (primary_token, "
3694 "TokenPrimaryGroup), %y", status
);
3695 status
= NtSetInformationToken (cygheap
->user
.imp_token (),
3696 TokenPrimaryGroup
, &gsid
, sizeof gsid
);
3697 if (!NT_SUCCESS (status
))
3698 debug_printf ("NtSetInformationToken (token, TokenPrimaryGroup), %y",
3701 cygheap
->user
.deimpersonate ();
3702 status
= NtSetInformationToken (hProcToken
, TokenPrimaryGroup
,
3703 &gsid
, sizeof gsid
);
3704 if (!NT_SUCCESS (status
))
3705 debug_printf ("NtSetInformationToken (hProcToken, TokenPrimaryGroup), %y",
3707 clear_procimptoken ();
3708 cygheap
->user
.reimpersonate ();
3712 /* setgid: POSIX 4.2.2.1 */
3716 int ret
= setegid (gid
);
3718 cygheap
->user
.real_gid
= myself
->gid
;
3723 setregid (gid_t rgid
, gid_t egid
)
3727 gid_t old_egid
= myself
->gid
;
3729 if (rgid
!= ILLEGAL_GID
&& cygheap
->user
.real_gid
!= rgid
&& egid
!= rgid
)
3730 tried
= !(ret
= setegid (rgid
));
3731 if (!ret
&& egid
!= ILLEGAL_GID
)
3732 ret
= setegid (egid
);
3733 if (tried
&& (ret
|| egid
== ILLEGAL_GID
) && setegid (old_egid
))
3734 system_printf ("Cannot restore original egid %u", old_egid
);
3735 if (!ret
&& rgid
!= ILLEGAL_GID
)
3736 cygheap
->user
.real_gid
= rgid
;
3737 debug_printf ("real: %u, effective: %u", cygheap
->user
.real_gid
, myself
->gid
);
3741 /* chroot: privileged Unix system call. */
3742 /* FIXME: Not privileged here. How should this be done? */
3744 chroot (const char *newroot
)
3746 path_conv
path (newroot
, PC_SYM_FOLLOW
| PC_POSIX
);
3750 set_errno (path
.error
);
3751 else if (!path
.exists ())
3753 else if (!path
.isdir ())
3754 set_errno (ENOTDIR
);
3755 else if (path
.isspecial ())
3759 getwinenv("PATH="); /* Save the native PATH */
3760 cygheap
->root
.set (path
.get_posix (), path
.get_win32 (),
3761 !!path
.objcaseinsensitive ());
3765 syscall_printf ("%R = chroot(%s)", ret
, newroot
?: "NULL");
3770 creat (const char *path
, mode_t mode
)
3772 return open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
3789 setpriority (int which
, id_t who
, int value
)
3791 DWORD prio
= nice_to_winprio (value
);
3799 if ((pid_t
) who
== myself
->pid
)
3801 if (!SetPriorityClass (GetCurrentProcess (), prio
))
3806 myself
->nice
= value
;
3807 debug_printf ("Set nice to %d", myself
->nice
);
3823 winpids
pids ((DWORD
) PID_MAP_RW
);
3824 for (DWORD i
= 0; i
< pids
.npids
; ++i
)
3826 _pinfo
*p
= pids
[i
];
3832 if ((pid_t
) who
!= p
->pid
)
3836 if ((pid_t
) who
!= p
->pgid
)
3840 if ((uid_t
) who
!= p
->uid
)
3844 HANDLE proc_h
= OpenProcess (PROCESS_SET_INFORMATION
, FALSE
,
3850 if (!SetPriorityClass (proc_h
, prio
))
3854 CloseHandle (proc_h
);
3868 getpriority (int which
, id_t who
)
3870 int nice
= NZERO
* 2; /* Illegal value */
3877 if ((pid_t
) who
== myself
->pid
)
3879 DWORD winprio
= GetPriorityClass(GetCurrentProcess());
3880 if (winprio
!= nice_to_winprio(myself
->nice
))
3881 myself
->nice
= winprio_to_nice(winprio
);
3882 return myself
->nice
;
3897 winpids
pids ((DWORD
) 0);
3898 for (DWORD i
= 0; i
< pids
.npids
; ++i
)
3900 _pinfo
*p
= pids
[i
];
3905 if ((pid_t
) who
== p
->pid
)
3912 if ((pid_t
) who
== p
->pgid
&& p
->nice
< nice
)
3916 if ((uid_t
) who
== p
->uid
&& p
->nice
< nice
)
3923 if (nice
== NZERO
* 2)
3934 return setpriority (PRIO_PROCESS
, myself
->pid
, myself
->nice
+ incr
);
3938 locked_append (int fd
, const void * buf
, size_t size
)
3940 struct flock lock_buffer
= {F_WRLCK
, SEEK_SET
, 0, 0, 0};
3944 if ((lock_buffer
.l_start
= lseek (fd
, 0, SEEK_END
)) != (off_t
) -1
3945 && fcntl (fd
, F_SETLKW
, &lock_buffer
) != -1)
3947 if (lseek (fd
, 0, SEEK_END
) != (off_t
) -1)
3948 write (fd
, buf
, size
);
3949 lock_buffer
.l_type
= F_UNLCK
;
3950 fcntl (fd
, F_SETLK
, &lock_buffer
);
3953 while (count
++ < 1000
3954 && (errno
== EACCES
|| errno
== EAGAIN
)
3959 updwtmp (const char *wtmp_file
, const struct utmp
*ut
)
3963 if ((fd
= open (wtmp_file
, O_WRONLY
| O_BINARY
, 0)) >= 0)
3965 locked_append (fd
, ut
, sizeof *ut
);
3970 static int utmp_fd
= -1;
3971 static bool utmp_readonly
= false;
3972 static char *utmp_file
= (char *) _PATH_UTMP
;
3975 internal_setutent (bool force_readwrite
)
3977 if (force_readwrite
&& utmp_readonly
)
3981 utmp_fd
= open (utmp_file
, O_RDWR
| O_BINARY
);
3982 /* If open fails, we assume an unprivileged process (who?). In this
3983 case we try again for reading only unless the process calls
3984 pututline() (==force_readwrite) in which case opening just fails. */
3985 if (utmp_fd
< 0 && !force_readwrite
)
3987 utmp_fd
= open (utmp_file
, O_RDONLY
| O_BINARY
);
3989 utmp_readonly
= true;
3993 lseek (utmp_fd
, 0, SEEK_SET
);
3999 internal_setutent (false);
4009 utmp_readonly
= false;
4014 utmpname (const char *file
)
4021 utmp_file
= strdup (file
);
4024 debug_printf ("New UTMP file: %s", utmp_file
);
4029 __except (EFAULT
) {}
4031 debug_printf ("Setting UTMP file failed");
4035 EXPORT_ALIAS (utmpname
, utmpxname
)
4037 /* Note: do not make NO_COPY */
4038 static struct utmp utmp_data_buf
[16];
4039 static unsigned utix
= 0;
4040 #define nutdbuf (sizeof (utmp_data_buf) / sizeof (utmp_data_buf[0]))
4041 #define utmp_data ({ \
4042 if (utix >= nutdbuf) \
4044 utmp_data_buf + utix++; \
4047 static struct utmpx
*
4048 copy_ut_to_utx (struct utmp
*ut
, struct utmpx
*utx
)
4052 memcpy (utx
, ut
, sizeof *ut
);
4053 utx
->ut_tv
.tv_sec
= ut
->ut_time
;
4054 utx
->ut_tv
.tv_usec
= 0;
4058 extern "C" struct utmp
*
4063 internal_setutent (false);
4068 utmp
*ut
= utmp_data
;
4069 if (read (utmp_fd
, ut
, sizeof *ut
) != sizeof *ut
)
4074 extern "C" struct utmp
*
4075 getutid (const struct utmp
*id
)
4081 internal_setutent (false);
4085 utmp
*ut
= utmp_data
;
4086 while (read (utmp_fd
, ut
, sizeof *ut
) == sizeof *ut
)
4088 switch (id
->ut_type
)
4094 if (id
->ut_type
== ut
->ut_type
)
4101 if (strncmp (id
->ut_id
, ut
->ut_id
, UT_IDLEN
) == 0)
4109 __except (EFAULT
) {}
4114 extern "C" struct utmp
*
4115 getutline (const struct utmp
*line
)
4121 internal_setutent (false);
4126 utmp
*ut
= utmp_data
;
4127 while (read (utmp_fd
, ut
, sizeof *ut
) == sizeof *ut
)
4128 if ((ut
->ut_type
== LOGIN_PROCESS
||
4129 ut
->ut_type
== USER_PROCESS
) &&
4130 !strncmp (ut
->ut_line
, line
->ut_line
, sizeof (ut
->ut_line
)))
4133 __except (EFAULT
) {}
4138 extern "C" struct utmp
*
4139 pututline (const struct utmp
*ut
)
4143 internal_setutent (true);
4146 debug_printf ("error: utmp_fd %d", utmp_fd
);
4149 debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n",
4150 ut
->ut_type
, ut
->ut_pid
, ut
->ut_line
, ut
->ut_id
);
4151 debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n",
4152 ut
->ut_user
, ut
->ut_host
);
4155 if ((u
= getutid (ut
)))
4157 lseek (utmp_fd
, -sizeof *ut
, SEEK_CUR
);
4158 write (utmp_fd
, ut
, sizeof *ut
);
4161 locked_append (utmp_fd
, ut
, sizeof *ut
);
4162 /* The documentation says to return a pointer to this which implies that
4163 this has to be cast from a const. That doesn't seem right but the
4164 documentation seems pretty clear on this. */
4165 return (struct utmp
*) ut
;
4167 __except (EFAULT
) {}
4175 internal_setutent (false);
4184 extern "C" struct utmpx
*
4187 /* POSIX: Not required to be thread safe. */
4188 static struct utmpx utx
;
4189 return copy_ut_to_utx (getutent (), &utx
);
4192 extern "C" struct utmpx
*
4193 getutxid (const struct utmpx
*id
)
4195 /* POSIX: Not required to be thread safe. */
4196 static struct utmpx utx
;
4200 ((struct utmpx
*)id
)->ut_time
= id
->ut_tv
.tv_sec
;
4201 return copy_ut_to_utx (getutid ((struct utmp
*) id
), &utx
);
4203 __except (EFAULT
) {}
4208 extern "C" struct utmpx
*
4209 getutxline (const struct utmpx
*line
)
4211 /* POSIX: Not required to be thread safe. */
4212 static struct utmpx utx
;
4216 ((struct utmpx
*)line
)->ut_time
= line
->ut_tv
.tv_sec
;
4217 return copy_ut_to_utx (getutline ((struct utmp
*) line
), &utx
);
4219 __except (EFAULT
) {}
4224 extern "C" struct utmpx
*
4225 pututxline (const struct utmpx
*utmpx
)
4227 /* POSIX: Not required to be thread safe. */
4228 static struct utmpx utx
;
4232 ((struct utmpx
*)utmpx
)->ut_time
= utmpx
->ut_tv
.tv_sec
;
4233 return copy_ut_to_utx (pututline ((struct utmp
*) utmpx
), &utx
);
4235 __except (EFAULT
) {}
4241 updwtmpx (const char *wtmpx_file
, const struct utmpx
*utmpx
)
4243 ((struct utmpx
*)utmpx
)->ut_time
= utmpx
->ut_tv
.tv_sec
;
4244 updwtmp (wtmpx_file
, (const struct utmp
*) utmpx
);
4250 /* Fetch the globally unique MachineGuid value from
4251 HKLM/Software/Microsoft/Cryptography and hash it. */
4252 int32_t hostid
= 0x40291372; /* Choose a nice start value */
4255 reg_key
key (HKEY_LOCAL_MACHINE
, KEY_READ
,
4256 L
"SOFTWARE", L
"Microsoft", L
"Cryptography", NULL
);
4257 key
.get_string (L
"MachineGuid", wguid
, 38,
4258 L
"00000000-0000-0000-0000-000000000000");
4260 for (PWCHAR wp
= wguid
; *wp
; ++wp
)
4261 hostid
= *wp
+ (hostid
<< 6) + (hostid
<< 16) - hostid
;
4262 debug_printf ("hostid %08y from MachineGuid %W", hostid
, wguid
);
4263 return (int32_t) hostid
; /* Avoid sign extension. */
4266 #define ETC_SHELLS "/etc/shells"
4267 static int shell_index
;
4268 static FILE *shell_fp
;
4273 /* List of default shells if no /etc/shells exists, defined as on Linux.
4274 FIXME: SunOS has a far longer list, containing all shells which
4275 might be shipped with the OS. Should we do the same for the Cygwin
4276 distro, adding bash, tcsh, ksh, pdksh and zsh? */
4277 static const char *def_shells
[] = {
4284 static char buf
[PATH_MAX
];
4287 if (!shell_fp
&& !(shell_fp
= fopen (ETC_SHELLS
, "rt")))
4289 if (def_shells
[shell_index
])
4290 return strcpy (buf
, def_shells
[shell_index
++]);
4293 /* Skip white space characters. */
4294 while ((ch
= getc (shell_fp
)) != EOF
&& isspace (ch
))
4296 /* Get each non-whitespace character as part of the shell path as long as
4299 ch
!= EOF
&& !isspace (ch
) && buf_idx
< (PATH_MAX
- 1);
4300 buf_idx
++, ch
= getc (shell_fp
))
4302 /* Skip any trailing non-whitespace character not fitting in buf. If the
4303 path is longer than PATH_MAX, it's invalid anyway. */
4304 while (ch
!= EOF
&& !isspace (ch
))
4305 ch
= getc (shell_fp
);
4308 buf
[buf_idx
] = '\0';
4318 fseek (shell_fp
, 0L, SEEK_SET
);
4334 flockfile (FILE *file
)
4340 ftrylockfile (FILE *file
)
4342 return _ftrylockfile (file
);
4346 funlockfile (FILE *file
)
4348 _funlockfile (file
);
4352 popen (const char *command
, const char *in_type
)
4354 const char *type
= in_type
;
4355 char fdopen_flags
[3] = "\0\0";
4358 #define rw fdopen_flags[0]
4359 #define bintext fdopen_flags[1]
4361 /* Sanity check. GLibc allows any order and any number of repetition,
4362 as long as the string doesn't contradict itself. We do the same here. */
4365 if (*type
== 'r' || *type
== 'w')
4367 if (rw
&& rw
!= *type
)
4371 else if (*type
== 'b' || *type
== 't')
4373 if (bintext
&& bintext
!= *type
)
4377 else if (*type
== 'e')
4379 pipe_flags
= O_CLOEXEC
;
4385 if ((rw
!= 'r' && rw
!= 'w') || (*type
!= '\0'))
4392 if (pipe2 (fds
, pipe_flags
) < 0)
4395 int myix
= rw
== 'r' ? 0 : 1;
4398 FILE *fp
= fdopen (fds
[myix
], fdopen_flags
);
4401 /* If fds are in the range of stdin/stdout/stderr, move them
4402 out of the way (possibly temporarily). Otherwise, spawn_guts
4403 will be confused. We do this here rather than adding logic to
4404 spawn_guts because spawn_guts is likely to be a more frequently
4405 used routine and having stdin/stdout/stderr closed and reassigned
4406 to pipe handles is an unlikely event. */
4407 int orig_fds
[2] = {fds
[0], fds
[1]};
4408 for (int i
= 0; i
< 2; i
++)
4411 cygheap_fdnew
newfd(3);
4412 cygheap
->fdtab
.move_fd (fds
[i
], newfd
);
4416 int myfd
= fds
[myix
]; /* myfd - convenience variable for manipulation
4417 of the "parent" end of the pipe. */
4418 int stdchild
= myix
^ 1; /* stdchild denotes the index into fd for the
4419 handle which will be redirected to
4422 __std
[myix
] = -1; /* -1 means don't pass this fd to the child
4424 __std
[stdchild
] = fds
[stdchild
]; /* Do pass this as the std handle */
4426 const char *argv
[4] =
4434 /* With 'e' flag given, we have to revert the close-on-exec on the child
4435 end of the pipe. Otherwise don't pass our end of the pipe to the
4437 if (pipe_flags
& O_CLOEXEC
)
4438 fcntl (__std
[stdchild
], F_SETFD
, 0);
4440 fcntl (myfd
, F_SETFD
, FD_CLOEXEC
);
4442 /* Also don't pass the file handle currently associated with stdin/stdout
4443 to the child. This function may actually fail if the stdchild fd
4444 is closed. But that's ok. */
4445 int stdchild_state
= fcntl (stdchild
, F_GETFD
, 0);
4446 fcntl (stdchild
, F_SETFD
, stdchild_state
| FD_CLOEXEC
);
4448 /* Start a shell process to run the given command without forking. */
4449 pid_t pid
= ch_spawn
.worker ("/bin/sh", argv
, environ
, _P_NOWAIT
,
4450 __std
[0], __std
[1]);
4452 /* Reinstate the close-on-exec state */
4453 fcntl (stdchild
, F_SETFD
, stdchild_state
);
4455 /* If pid >= 0 then spawn_guts succeeded. */
4458 close (fds
[stdchild
]); /* Close the child end of the pipe. */
4459 /* Move the fd back to its original slot if it has been moved since
4460 we're always supposed to open the lowest numbered available fd
4461 and, if fds[mix] != orig_fds[myix] then orig_fds[myix] is
4462 presumably lower. */
4463 if (fds
[myix
] != orig_fds
[myix
])
4464 cygheap
->fdtab
.move_fd (fds
[myix
], myfd
= orig_fds
[myix
]);
4465 fhandler_pipe
*fh
= (fhandler_pipe
*) cygheap
->fdtab
[myfd
];
4466 /* Flag that this handle is associated with popen. */
4467 fh
->set_popen_pid (pid
);
4472 /* If we reach here we've seen an error but the pipe handles are open.
4473 Close them and return NULL. */
4474 int save_errno
= get_errno ();
4477 /* Must fclose fp to avoid memory leak. */
4479 close (fds
[myix
^ 1]);
4486 set_errno (save_errno
);
4497 fhandler_pipe
*fh
= (fhandler_pipe
*) cygheap
->fdtab
[fileno(fp
)];
4499 if (fh
->get_device () != FH_PIPEW
&& fh
->get_device () != FH_PIPER
)
4505 int pid
= fh
->get_popen_pid ();
4517 if (waitpid (pid
, &status
, 0) == pid
)
4519 else if (get_errno () == EINTR
)
4527 /* Preliminary(?) implementation of the openat family of functions. */
4530 gen_full_path_at (char *path_ret
, int dirfd
, const char *pathname
,
4533 /* futimesat allows a NULL pathname. */
4534 if (!pathname
&& !(flags
& _AT_NULL_PATHNAME_ALLOWED
))
4539 if (pathname
&& isabspath_strict (pathname
))
4540 stpcpy (path_ret
, pathname
);
4545 if (dirfd
== AT_FDCWD
)
4547 cwdstuff::acquire_read ();
4548 p
= stpcpy (path_ret
, cygheap
->cwd
.get_posix ());
4549 cwdstuff::release_read ();
4553 cygheap_fdget
cfd (dirfd
);
4556 if (!cfd
->pc
.isdir () && !(flags
& AT_EMPTY_PATH
))
4558 set_errno (ENOTDIR
);
4561 p
= stpcpy (path_ret
, cfd
->get_name ());
4567 if (flags
& AT_EMPTY_PATH
)
4572 if (strlen (pathname
) >= PATH_MAX
)
4574 set_errno (ENAMETOOLONG
);
4579 stpcpy (p
, pathname
);
4586 openat (int dirfd
, const char *pathname
, int flags
, ...)
4591 char *path
= tp
.c_get ();
4592 if (gen_full_path_at (path
, dirfd
, pathname
))
4598 va_start (ap
, flags
);
4599 mode
= va_arg (ap
, mode_t
);
4601 return open (path
, flags
, mode
);
4603 __except (EFAULT
) {}
4609 faccessat (int dirfd
, const char *pathname
, int mode
, int flags
)
4616 char *path
= tp
.c_get ();
4617 if (!gen_full_path_at (path
, dirfd
, pathname
))
4619 if ((mode
& ~(F_OK
|R_OK
|W_OK
|X_OK
))
4620 || (flags
& ~(AT_SYMLINK_NOFOLLOW
|AT_EACCESS
)))
4624 fhandler_base
*fh
= build_fh_name (path
,
4625 (flags
& AT_SYMLINK_NOFOLLOW
4632 res
= fh
->fhaccess (mode
, !!(flags
& AT_EACCESS
));
4638 __except (EFAULT
) {}
4640 debug_printf ("returning %d", res
);
4645 fchmodat (int dirfd
, const char *pathname
, mode_t mode
, int flags
)
4650 if (flags
& ~AT_SYMLINK_NOFOLLOW
)
4655 char *path
= tp
.c_get ();
4656 if (gen_full_path_at (path
, dirfd
, pathname
))
4658 if (flags
& AT_SYMLINK_NOFOLLOW
)
4660 /* BSD has lchmod, but Linux does not. POSIX says
4661 AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks.
4662 Linux blindly fails even for non-symlinks, but we allow
4664 path_conv
pc (path
, PC_SYM_NOFOLLOW
, stat_suffixes
);
4665 if (pc
.issymlink ())
4667 set_errno (EOPNOTSUPP
);
4671 return chmod (path
, mode
);
4673 __except (EFAULT
) {}
4679 fchownat (int dirfd
, const char *pathname
, uid_t uid
, gid_t gid
, int flags
)
4684 if (flags
& ~(AT_SYMLINK_NOFOLLOW
| AT_EMPTY_PATH
))
4689 char *path
= tp
.c_get ();
4690 int res
= gen_full_path_at (path
, dirfd
, pathname
, flags
);
4693 if (!*pathname
) /* Implies AT_EMPTY_PATH */
4695 /* If dirfd refers to a symlink (which was necessarily opened with
4696 O_PATH | O_NOFOLLOW), we must operate directly on that symlink. */
4697 flags
= AT_SYMLINK_NOFOLLOW
;
4699 return chown_worker (path
, (flags
& AT_SYMLINK_NOFOLLOW
)
4700 ? PC_SYM_NOFOLLOW
: PC_SYM_FOLLOW
, uid
, gid
);
4702 __except (EFAULT
) {}
4708 fstatat (int dirfd
, const char *__restrict pathname
, struct stat
*__restrict st
,
4714 if (flags
& ~(AT_SYMLINK_NOFOLLOW
| AT_EMPTY_PATH
))
4719 char *path
= tp
.c_get ();
4720 int res
= gen_full_path_at (path
, dirfd
, pathname
, flags
);
4723 path_conv
pc (path
, ((flags
& AT_SYMLINK_NOFOLLOW
)
4724 ? PC_SYM_NOFOLLOW
: PC_SYM_FOLLOW
)
4725 | PC_POSIX
| PC_KEEP_HANDLE
, stat_suffixes
);
4726 return stat_worker (pc
, st
);
4728 __except (EFAULT
) {}
4733 extern int utimens_worker (path_conv
&, const struct timespec
*);
4736 utimensat (int dirfd
, const char *pathname
, const struct timespec
*times
,
4742 char *path
= tp
.c_get ();
4743 if (flags
& ~AT_SYMLINK_NOFOLLOW
)
4748 if (gen_full_path_at (path
, dirfd
, pathname
))
4750 path_conv
win32 (path
, PC_POSIX
| ((flags
& AT_SYMLINK_NOFOLLOW
)
4751 ? PC_SYM_NOFOLLOW
: PC_SYM_FOLLOW
),
4753 return utimens_worker (win32
, times
);
4755 __except (EFAULT
) {}
4761 futimesat (int dirfd
, const char *pathname
, const struct timeval times
[2])
4766 char *path
= tp
.c_get ();
4767 if (gen_full_path_at (path
, dirfd
, pathname
, _AT_NULL_PATHNAME_ALLOWED
))
4769 return utimes (path
, times
);
4771 __except (EFAULT
) {}
4777 linkat (int olddirfd
, const char *oldpathname
,
4778 int newdirfd
, const char *newpathname
,
4782 fhandler_base
*fh
= NULL
;
4786 if (flags
& ~(AT_SYMLINK_FOLLOW
| AT_EMPTY_PATH
))
4791 char *oldpath
= tp
.c_get ();
4792 if ((flags
& AT_EMPTY_PATH
) && oldpathname
&& oldpathname
[0] == '\0')
4794 /* Operate directly on olddirfd, which can be anything
4795 except a directory. */
4796 if (olddirfd
== AT_FDCWD
)
4801 cygheap_fdget
cfd (olddirfd
);
4804 if (cfd
->pc
.isdir ())
4810 flags
= 0; /* In case AT_SYMLINK_FOLLOW was set. */
4812 else if (gen_full_path_at (oldpath
, olddirfd
, oldpathname
))
4814 char *newpath
= tp
.c_get ();
4815 if (gen_full_path_at (newpath
, newdirfd
, newpathname
))
4817 if (flags
& AT_SYMLINK_FOLLOW
)
4819 path_conv
old_name (oldpath
,
4820 PC_SYM_FOLLOW
| PC_SYM_NOFOLLOW_PROCFD
| PC_POSIX
,
4824 set_errno (old_name
.error
);
4827 strcpy (oldpath
, old_name
.get_posix ());
4830 return fh
->link (newpath
);
4831 return link (oldpath
, newpath
);
4833 __except (EFAULT
) {}
4839 mkdirat (int dirfd
, const char *pathname
, mode_t mode
)
4844 char *path
= tp
.c_get ();
4845 if (gen_full_path_at (path
, dirfd
, pathname
))
4847 return mkdir (path
, mode
);
4849 __except (EFAULT
) {}
4855 mkfifoat (int dirfd
, const char *pathname
, mode_t mode
)
4860 char *path
= tp
.c_get ();
4861 if (gen_full_path_at (path
, dirfd
, pathname
))
4863 return mkfifo (path
, mode
);
4865 __except (EFAULT
) {}
4871 mknodat (int dirfd
, const char *pathname
, mode_t mode
, dev_t dev
)
4876 char *path
= tp
.c_get ();
4877 if (gen_full_path_at (path
, dirfd
, pathname
))
4879 return mknod (path
, mode
, dev
);
4881 __except (EFAULT
) {}
4887 readlinkat (int dirfd
, const char *__restrict pathname
, char *__restrict buf
,
4893 char *path
= tp
.c_get ();
4894 int save_errno
= errno
;
4895 int res
= gen_full_path_at (path
, dirfd
, pathname
);
4898 if (errno
!= ENOENT
&& errno
!= ENOTDIR
)
4900 /* pathname is an empty string. This is OK if dirfd refers
4901 to a symlink that was opened with O_PATH | O_NOFOLLOW.
4902 In this case, readlinkat operates on the symlink.
4903 Don't propagate errors from gen_full_path_at after this point. */
4905 cygheap_fdget
cfd (dirfd
);
4907 || (!(cfd
->issymlink ()
4908 && cfd
->get_flags () & O_PATH
4909 && cfd
->get_flags () & O_NOFOLLOW
)))
4914 strcpy (path
, cfd
->get_name ());
4916 return readlink (path
, buf
, bufsize
);
4918 __except (EFAULT
) {}
4924 renameat2 (int olddirfd
, const char *oldpathname
,
4925 int newdirfd
, const char *newpathname
, unsigned int flags
)
4930 char *oldpath
= tp
.c_get ();
4931 if (gen_full_path_at (oldpath
, olddirfd
, oldpathname
))
4933 char *newpath
= tp
.c_get ();
4934 if (gen_full_path_at (newpath
, newdirfd
, newpathname
))
4936 return rename2 (oldpath
, newpath
, flags
);
4938 __except (EFAULT
) {}
4944 renameat (int olddirfd
, const char *oldpathname
,
4945 int newdirfd
, const char *newpathname
)
4947 return renameat2 (olddirfd
, oldpathname
, newdirfd
, newpathname
, 0);
4951 scandirat (int dirfd
, const char *pathname
, struct dirent
***namelist
,
4952 int (*select
) (const struct dirent
*),
4953 int (*compar
) (const struct dirent
**, const struct dirent
**))
4958 char *path
= tp
.c_get ();
4959 if (gen_full_path_at (path
, dirfd
, pathname
))
4961 return scandir (path
, namelist
, select
, compar
);
4963 __except (EFAULT
) {}
4969 symlinkat (const char *oldpath
, int newdirfd
, const char *newpathname
)
4974 char *newpath
= tp
.c_get ();
4975 if (gen_full_path_at (newpath
, newdirfd
, newpathname
))
4977 return symlink (oldpath
, newpath
);
4979 __except (EFAULT
) {}
4985 unlinkat (int dirfd
, const char *pathname
, int flags
)
4990 if (flags
& ~AT_REMOVEDIR
)
4995 char *path
= tp
.c_get ();
4996 if (gen_full_path_at (path
, dirfd
, pathname
))
4998 return (flags
& AT_REMOVEDIR
) ? rmdir (path
) : unlink (path
);
5000 __except (EFAULT
) {}
5006 pipe_worker (int filedes
[2], unsigned int psize
, int mode
)
5008 fhandler_pipe
*fhs
[2];
5009 int res
= fhandler_pipe::create (fhs
, psize
, mode
);
5013 cygheap_fdnew
fdout (fdin
, false);
5014 char buf
[sizeof ("pipe:[9223372036854775807]")];
5015 __small_sprintf (buf
, "pipe:[%D]", fhs
[0]->get_plain_ino ());
5016 fhs
[0]->pc
.set_posix (buf
);
5017 __small_sprintf (buf
, "pipe:[%D]", fhs
[1]->get_plain_ino ());
5018 fhs
[1]->pc
.set_posix (buf
);
5027 /* MS compatible version of pipe. Hopefully nobody is using it... */
5029 _pipe (int filedes
[2], unsigned int psize
, int mode
)
5031 int res
= pipe_worker (filedes
, psize
, mode
);
5040 syscall_printf ("%R = _pipe([%d, %d], %u, %y)", res
, read
, write
, psize
, mode
);
5045 pipe (int filedes
[2])
5047 int res
= pipe_worker (filedes
, DEFAULT_PIPEBUFSIZE
, O_BINARY
);
5056 syscall_printf ("%R = pipe([%d, %d])", res
, read
, write
);
5061 pipe2 (int filedes
[2], int mode
)
5063 int res
= pipe_worker (filedes
, DEFAULT_PIPEBUFSIZE
, mode
);
5072 syscall_printf ("%R = pipe2([%d, %d], %y)", res
, read
, write
, mode
);
5079 char *dir
= getenv ("TMPDIR");
5082 int fd
= open (dir
, O_RDWR
| O_BINARY
| O_TMPFILE
, S_IRUSR
| S_IWUSR
);
5085 FILE *fp
= fdopen (fd
, "wb+");
5088 close (fd
); // ..will remove tmp file