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_buf
= (PFILE_NAMES_INFORMATION
)
622 PFILE_NAMES_INFORMATION pfni
;
623 NTSTATUS status
= NtQueryDirectoryFile (dir
, NULL
, NULL
, 0, &io
, pfni_buf
,
624 bufsiz
, FileNamesInformation
,
626 if (!NT_SUCCESS (status
))
628 debug_printf ("Checking if directory %S is empty failed, status = %y",
629 pc
.get_nt_native_path (), status
);
636 while (pfni
->NextEntryOffset
)
640 UNICODE_STRING fname
;
641 OBJECT_ATTRIBUTES attr
;
642 FILE_BASIC_INFORMATION fbi
;
644 pfni
= (PFILE_NAMES_INFORMATION
)
645 ((caddr_t
) pfni
+ pfni
->NextEntryOffset
);
646 RtlInitCountedUnicodeString(&fname
, pfni
->FileName
,
647 pfni
->FileNameLength
);
648 InitializeObjectAttributes (&attr
, &fname
, 0, dir
, NULL
);
649 status
= NtQueryAttributesFile (&attr
, &fbi
);
650 /* Intensive testing shows that sometimes directories, for which
651 the delete disposition has already been set, and the deleting
652 handle is already closed, can linger in the parent dir for a
653 couple of ms for no apparent reason (Windows Defender or other
654 real-time scanners are suspect).
656 A fast rm -r is capable to exploit this problem. Setting the
657 delete disposition of the parent dir then fails with
658 STATUS_DIRECTORY_NOT_EMPTY. Examining the content of the
659 affected dir can then show either that the dir is empty, or it
660 can contain a lingering subdir. Calling NtQueryAttributesFile
661 on that subdir returns with STATUS_DELETE_PENDING, or it
662 disappeared before that call.
664 That's what we do here. If NtQueryAttributesFile succeeded,
665 or if the error code does not indicate an already deleted
666 entry, STATUS_DIRECTORY_NOT_EMPTY is returned.
668 Otherwise STATUS_SUCCESS is returned. Read on in unlink_nt. */
669 if (status
!= STATUS_DELETE_PENDING
670 && status
!= STATUS_OBJECT_NAME_NOT_FOUND
671 && status
!= STATUS_OBJECT_PATH_NOT_FOUND
)
673 debug_printf ("Directory %S not empty, found file <%S>, "
675 pc
.get_nt_native_path (), &fname
, status
);
676 return STATUS_DIRECTORY_NOT_EMPTY
;
679 pfni
= (PFILE_NAMES_INFORMATION
) ((caddr_t
) pfni
+ pfni
->NextEntryOffset
);
682 while (NT_SUCCESS (NtQueryDirectoryFile (dir
, NULL
, NULL
, 0, &io
, pfni_buf
,
683 bufsiz
, FileNamesInformation
,
684 FALSE
, NULL
, FALSE
)));
685 return STATUS_SUCCESS
;
688 static inline NTSTATUS
689 _unlink_nt_post_dir_check (NTSTATUS status
, POBJECT_ATTRIBUTES attr
, const path_conv
&pc
)
691 /* Check for existence of remote dirs after trying to delete them.
693 - Sometimes SMB indicates failure when it really succeeds.
694 - Removing a directory on a Samba drive using an old Samba version
695 sometimes doesn't return an error, if the directory can't be removed
696 because it's not empty. */
699 FILE_BASIC_INFORMATION fbi
;
702 q_status
= NtQueryAttributesFile (attr
, &fbi
);
703 if (!NT_SUCCESS (status
) && q_status
== STATUS_OBJECT_NAME_NOT_FOUND
)
704 status
= STATUS_SUCCESS
;
705 else if (pc
.fs_is_samba ()
706 && NT_SUCCESS (status
) && NT_SUCCESS (q_status
))
707 status
= STATUS_DIRECTORY_NOT_EMPTY
;
713 unlink_nt (path_conv
&pc
, bool shareable
)
716 HANDLE fh
, fh_ro
= NULL
;
717 OBJECT_ATTRIBUTES attr
;
719 ACCESS_MASK access
= DELETE
;
720 ULONG flags
= FILE_OPEN_FOR_BACKUP_INTENT
;
721 HANDLE old_trans
= NULL
, trans
= NULL
;
723 FILE_DISPOSITION_INFORMATION disp
= { TRUE
};
725 bin_status bin_stat
= dont_move
;
727 syscall_printf ("Trying to delete %S, isdir = %d",
728 pc
.get_nt_native_path (), pc
.isdir ());
730 /* Add the reparse point flag to known reparse points, otherwise we remove
731 the target, not the reparse point. */
732 if (pc
.is_known_reparse_point ())
733 flags
|= FILE_OPEN_REPARSE_POINT
;
735 pc
.get_object_attr (attr
, sec_none_nih
);
737 /* First check if we can use POSIX unlink semantics: W10 1709+, local NTFS.
738 For the OPEN_BY_FILE_ID flag, see MINIMAL_WIN_NTFS_FLAGS comment in
739 fs_info::update. With POSIX unlink semantics the entire job gets MUCH
740 easier and faster. Just try to do it and if it fails, it fails. */
741 if (wincap
.has_posix_unlink_semantics ()
742 && !pc
.isremote () && pc
.fs_is_ntfs ()
743 && pc
.has_attribute (FILE_SUPPORTS_OPEN_BY_FILE_ID
))
745 FILE_DISPOSITION_INFORMATION_EX fdie
;
747 /* POSIX unlink semantics are nice, but they still fail if the file has
748 the R/O attribute set. If so, ignoring might be an option: W10 1809+
749 Removing the file is very much a safe bet afterwards, so, no
751 if ((pc
.file_attributes () & FILE_ATTRIBUTE_READONLY
)
752 && !wincap
.has_posix_unlink_semantics_with_ignore_readonly ())
753 access
|= FILE_WRITE_ATTRIBUTES
;
754 status
= NtOpenFile (&fh
, access
, &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
756 if (!NT_SUCCESS (status
))
758 if (access
& FILE_WRITE_ATTRIBUTES
)
760 status
= NtSetAttributesFile (fh
, pc
.file_attributes ()
761 & ~FILE_ATTRIBUTE_READONLY
);
762 if (!NT_SUCCESS (status
))
768 fdie
.Flags
= FILE_DISPOSITION_DELETE
| FILE_DISPOSITION_POSIX_SEMANTICS
;
769 if (wincap
.has_posix_unlink_semantics_with_ignore_readonly ())
770 fdie
.Flags
|= FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE
;
771 status
= NtSetInformationFile (fh
, &io
, &fdie
, sizeof fdie
,
772 FileDispositionInformationEx
);
773 /* Restore R/O attribute in case we have multiple hardlinks. */
774 if (access
& FILE_WRITE_ATTRIBUTES
)
775 NtSetAttributesFile (fh
, pc
.file_attributes ());
777 /* Trying to delete in-use executables and DLLs using
778 FILE_DISPOSITION_POSIX_SEMANTICS returns STATUS_CANNOT_DELETE.
779 Fall back to the default method. */
780 /* Additionaly that returns STATUS_INVALID_PARAMETER
781 on a bind mounted fs in hyper-v container. Falling back too. */
782 if (status
!= STATUS_CANNOT_DELETE
783 && status
!= STATUS_INVALID_PARAMETER
)
785 debug_printf ("NtSetInformationFile returns %y "
786 "with posix semantics. Disable it and retry.", status
);
791 /* If the R/O attribute is set, we have to open the file with
792 FILE_WRITE_ATTRIBUTES to be able to remove this flags before trying
793 to delete it. We do this separately because there are filesystems
794 out there (MVFS), which refuse a request to open a file for DELETE
795 if the DOS R/O attribute is set for the file. After removing the R/O
796 attribute, just re-open the file for DELETE and go ahead. */
797 if (pc
.file_attributes () & FILE_ATTRIBUTE_READONLY
)
799 FILE_STANDARD_INFORMATION fsi
;
801 /* If possible, hide the non-atomicity of the "remove R/O flag, remove
802 link to file" operation behind a transaction. */
803 if ((pc
.fs_flags () & FILE_SUPPORTS_TRANSACTIONS
))
804 start_transaction (old_trans
, trans
);
806 status
= NtOpenFile (&fh_ro
,
807 FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
,
808 &attr
, &io
, FILE_SHARE_VALID_FLAGS
, flags
);
809 if (NT_SUCCESS (status
))
811 debug_printf ("Opening %S for removing R/O succeeded",
812 pc
.get_nt_native_path ());
813 NTSTATUS status2
= NtSetAttributesFile (fh_ro
,
814 pc
.file_attributes ()
815 & ~FILE_ATTRIBUTE_READONLY
);
816 if (!NT_SUCCESS (status2
))
817 debug_printf ("Removing R/O on %S failed, status = %y",
818 pc
.get_nt_native_path (), status2
);
819 pc
.init_reopen_attr (attr
, fh_ro
);
823 debug_printf ("Opening %S for removing R/O failed, status = %y",
824 pc
.get_nt_native_path (), status
);
825 if (NT_TRANSACTIONAL_ERROR (status
) && trans
)
827 /* If NtOpenFile fails due to transactional problems, stop
828 transaction and go ahead without. */
829 stop_transaction (status
, old_trans
, trans
);
830 debug_printf ("Transaction failure. Retry open.");
834 if (pc
.is_lnk_symlink ())
836 status
= NtQueryInformationFile (fh_ro
, &io
, &fsi
, sizeof fsi
,
837 FileStandardInformation
);
838 if (NT_SUCCESS (status
))
839 num_links
= fsi
.NumberOfLinks
;
841 access
|= FILE_WRITE_ATTRIBUTES
;
843 /* First try to open the file with only allowing sharing for delete. If
844 the file has an open handle on it, other than just for deletion, this
845 will fail. That indicates that the file has to be moved to the recycle
846 bin so that it actually disappears from its directory even though its
847 in use. Otherwise, if opening doesn't fail, the file is not in use and
848 we can go straight to setting the delete disposition flag.
849 However, while we have the file open with FILE_SHARE_DELETE, using
850 this file via another hardlink for anything other than DELETE by
851 concurrent processes fails. The 'shareable' argument is to prevent this.
853 NOTE: The missing sharing modes FILE_SHARE_READ and FILE_SHARE_WRITE do
854 NOT result in a STATUS_SHARING_VIOLATION, if another handle is
855 opened for reading/writing metadata only. In other words, if
856 another handle is open, but does not have the file open with
857 FILE_READ_DATA or FILE_WRITE_DATA, the following NtOpenFile call
858 will succeed. So, apparently there is no reliable way to find out
859 if a file is already open elsewhere for other purposes than
860 reading and writing data. */
862 status
= STATUS_SHARING_VIOLATION
;
864 status
= NtOpenFile (&fh
, access
, &attr
, &io
, FILE_SHARE_DELETE
, flags
);
865 /* STATUS_SHARING_VIOLATION is what we expect. STATUS_LOCK_NOT_GRANTED can
866 be generated under not quite clear circumstances when trying to open a
867 file on NFS with FILE_SHARE_DELETE only. This has been observed with
868 SFU 3.5 if the NFS share has been mounted under a drive letter. It's
869 not generated for all files, but only for some. If it's generated once
870 for a file, it will be generated all the time. It looks as if wrong file
871 state information is stored within the NFS client which never times out.
872 Opening the file with FILE_SHARE_VALID_FLAGS will work, though, and it
873 is then possible to delete the file quite normally. */
874 if (status
== STATUS_SHARING_VIOLATION
|| status
== STATUS_LOCK_NOT_GRANTED
)
876 debug_printf ("Sharing violation when opening %S",
877 pc
.get_nt_native_path ());
878 /* We never call try_to_bin on NetApp. Netapp filesystems don't
879 understand the "move and delete" method at all and have all kinds
880 of weird effects. Just setting the delete dispositon usually
883 NFS implements its own mechanism to remove in-use files, which looks
884 quite similar to what we do in try_to_bin for remote files. However,
885 apparently it doesn't work as desired in all cases. This has been
886 observed when running the gawk 4.1.62++ testcase "testext.awk" under
887 Windows 10. So for NFS we still call try_to_bin to rename the file,
888 at least to make room for subsequent creation of a file with the
890 if (!pc
.fs_is_netapp ())
891 bin_stat
= move_to_bin
;
892 /* If the file is not a directory, of if we didn't set the move_to_bin
893 flag, just proceed with the FILE_SHARE_VALID_FLAGS set. */
894 if (!pc
.isdir () || bin_stat
== dont_move
)
895 status
= NtOpenFile (&fh
, access
, &attr
, &io
,
896 FILE_SHARE_VALID_FLAGS
, flags
);
899 /* Otherwise it's getting tricky. The directory is opened in some
900 process, so we're supposed to move it to the recycler and mark it
901 for deletion. But what if the directory is not empty? The move
902 will work, but the subsequent delete will fail. So we would
903 have to move it back. While we do that in try_to_bin, it's bad,
904 because the move results in a temporary inconsistent state.
905 So, we test first if the directory is empty. If not, we bail
906 out with STATUS_DIRECTORY_NOT_EMPTY. This avoids most of the
908 status
= NtOpenFile (&fh
, access
| FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
909 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
910 flags
| FILE_SYNCHRONOUS_IO_NONALERT
);
911 if (NT_SUCCESS (status
))
913 status
= check_dir_not_empty (fh
, pc
);
914 if (!NT_SUCCESS (status
))
926 if (!NT_SUCCESS (status
))
928 if (status
== STATUS_DELETE_PENDING
)
930 debug_printf ("Delete %S already pending", pc
.get_nt_native_path ());
931 status
= STATUS_SUCCESS
;
934 debug_printf ("Opening %S for delete failed, status = %y",
935 pc
.get_nt_native_path (), status
);
938 /* Try to move to bin if a sharing violation occured. If that worked,
940 if (bin_stat
== move_to_bin
941 && (bin_stat
= try_to_bin (pc
, fh
, access
, flags
)) >= has_been_moved
)
943 if (bin_stat
== has_been_moved
)
944 status
= STATUS_SUCCESS
;
947 status
= STATUS_DIRECTORY_NOT_EMPTY
;
954 /* Try to set delete disposition. */
955 status
= NtSetInformationFile (fh
, &io
, &disp
, sizeof disp
,
956 FileDispositionInformation
);
957 if (!NT_SUCCESS (status
))
959 debug_printf ("Setting delete disposition on %S failed, status = %y",
960 pc
.get_nt_native_path (), status
);
961 if (status
== STATUS_DIRECTORY_NOT_EMPTY
)
963 NTSTATUS status2
= STATUS_SUCCESS
;
967 /* Have to close and reopen the file from scratch, otherwise
968 we collide with the delete-only sharing mode. */
969 pc
.get_object_attr (attr
, sec_none_nih
);
971 status2
= NtOpenFile (&fh
, access
| FILE_LIST_DIRECTORY
973 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
974 flags
| FILE_SYNCHRONOUS_IO_NONALERT
);
976 if (NT_SUCCESS (status2
) && reopened
< 20)
978 /* Workaround rm -r problem:
980 Sometimes a deleted directory lingers in its parent dir
981 after the deleting handle has already been closed. This
982 can break deleting the parent dir. See the comment in
983 check_dir_not_empty for more information.
985 What we do here is this: If check_dir_not_empty returns
986 STATUS_SUCCESS, the dir is either empty, or only inhabited
987 by already deleted entries. If so, we try to move the dir
988 into the bin. This usually works.
990 However, if we're on a filesystem which doesn't support
991 the try_to_bin method, or if moving to the bin doesn't work
992 for some reason, just try to delete the directory again,
993 with a very short grace period to free the CPU for a while.
994 This gives the OS time to clean up. 5ms is enough in my
995 testing to make sure that we don't have to try more than
996 once in practically all cases.
997 While this is an extrem bordercase, we don't want to hang
998 infinitely in case a file in the directory is in the "delete
999 pending" state but an application holds an open handle to it
1000 for a longer time. So we don't try this more than 20 times,
1001 which means a process time of 100-120ms. */
1002 if (check_dir_not_empty (fh
, pc
) == STATUS_SUCCESS
)
1004 if (bin_stat
== dont_move
)
1006 bin_stat
= move_to_bin
;
1007 if (!pc
.fs_is_nfs () && !pc
.fs_is_netapp ())
1009 debug_printf ("Try-to-bin %S",
1010 pc
.get_nt_native_path ());
1011 bin_stat
= try_to_bin (pc
, fh
, access
, flags
);
1014 /* Do NOT handle bin_stat == dir_not_empty here! */
1015 if (bin_stat
== has_been_moved
)
1016 status
= STATUS_SUCCESS
;
1019 debug_printf ("Try %S again", pc
.get_nt_native_path ());
1026 else if (status2
!= STATUS_OBJECT_PATH_NOT_FOUND
1027 && status2
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1030 debug_printf ("Opening dir %S for check_dir_not_empty failed, "
1031 "status = %y", pc
.get_nt_native_path (), status2
);
1033 else /* Directory disappeared between NtClose and NtOpenFile. */
1034 status
= STATUS_SUCCESS
;
1036 /* Trying to delete a hardlink to a file in use by the system in some
1037 way (for instance, font files) by setting the delete disposition fails
1038 with STATUS_CANNOT_DELETE. Strange enough, deleting these hardlinks
1039 using delete-on-close semantic works... most of the time.
1041 Don't use delete-on-close on remote shares. If two processes
1042 have open handles on a file and one of them calls unlink, the
1043 file is removed from the remote share even though the other
1044 process still has an open handle. That process than gets Win32
1045 error 59, ERROR_UNEXP_NET_ERR when trying to access the file.
1046 Microsoft KB 837665 describes this problem as a bug in 2K3, but
1047 I have reproduced it on other systems. */
1048 else if (status
== STATUS_CANNOT_DELETE
1049 && (!pc
.isremote () || pc
.fs_is_ncfsd ()))
1053 debug_printf ("Cannot delete %S, try delete-on-close",
1054 pc
.get_nt_native_path ());
1055 /* Re-open from handle so we open the correct file no matter if it
1056 has been moved to the bin or not. */
1057 status
= NtOpenFile (&fh2
, DELETE
,
1058 pc
.init_reopen_attr (attr
, fh
), &io
,
1059 bin_stat
== move_to_bin
? FILE_SHARE_VALID_FLAGS
1060 : FILE_SHARE_DELETE
,
1061 flags
| FILE_DELETE_ON_CLOSE
);
1062 if (!NT_SUCCESS (status
))
1064 debug_printf ("Setting delete-on-close on %S failed, status = %y",
1065 pc
.get_nt_native_path (), status
);
1066 /* This is really the last chance. If it hasn't been moved
1067 to the bin already, try it now. If moving to the bin
1068 succeeds, we got rid of the file in some way, even if
1069 unlinking didn't work. */
1070 if (bin_stat
== dont_move
)
1071 bin_stat
= try_to_bin (pc
, fh
, access
, flags
);
1072 if (bin_stat
>= has_been_moved
)
1073 status
= bin_stat
== has_been_moved
1075 : STATUS_DIRECTORY_NOT_EMPTY
;
1083 if (access
& FILE_WRITE_ATTRIBUTES
)
1085 /* Restore R/O attribute if setting the delete disposition failed. */
1086 if (!NT_SUCCESS (status
))
1087 NtSetAttributesFile (fh
, pc
.file_attributes ());
1088 /* If we succeeded, restore R/O attribute to accommodate hardlinks.
1089 Only ever try to do this for our own winsymlinks, because there's
1090 a problem with setting the delete disposition:
1091 http://msdn.microsoft.com/en-us/library/ff545765%28VS.85%29.aspx
1092 "Subsequently, the only legal operation by such a caller is
1093 to close the open file handle."
1095 FIXME? We could use FILE_HARD_LINK_INFORMATION to find all
1096 hardlinks and use one of them to restore the R/O bit, after the
1097 NtClose, but before we stop the transaction. This avoids the
1098 aforementioned problem entirely . */
1099 else if (pc
.is_lnk_symlink () && num_links
> 1)
1100 NtSetAttributesFile (fh
, pc
.file_attributes ());
1107 /* Stop transaction if we started one. */
1109 stop_transaction (status
, old_trans
, trans
);
1112 status
= _unlink_nt_post_dir_check (status
, &attr
, pc
);
1114 syscall_printf ("%S, return status = %y", pc
.get_nt_native_path (), status
);
1119 unlink (const char *ourname
)
1125 path_conv
win32_name (ourname
, PC_SYM_NOFOLLOW
, stat_suffixes
);
1127 if (win32_name
.error
)
1129 set_errno (win32_name
.error
);
1133 devn
= win32_name
.get_device ();
1134 if (isproc_dev (devn
))
1139 if (isdevfd_dev (devn
) || (win32_name
.isdevice () && !win32_name
.issocket ()))
1144 if (!win32_name
.exists ())
1146 debug_printf ("unlinking a nonexistent file");
1150 else if (win32_name
.isdir ())
1152 debug_printf ("unlinking a directory");
1157 status
= unlink_nt (win32_name
, false);
1158 if (NT_SUCCESS (status
))
1161 __seterrno_from_nt_status (status
);
1164 syscall_printf ("%R = unlink(%s)", res
, ourname
);
1169 _remove_r (struct _reent
*, const char *ourname
)
1171 path_conv
win32_name (ourname
, PC_SYM_NOFOLLOW
);
1173 if (win32_name
.error
)
1175 set_errno (win32_name
.error
);
1176 syscall_printf ("%R = remove(%s)",-1, ourname
);
1180 int res
= win32_name
.isdir () ? rmdir (ourname
) : unlink (ourname
);
1181 syscall_printf ("%R = remove(%s)", res
, ourname
);
1186 remove (const char *ourname
)
1188 return _remove_r (_REENT
, ourname
);
1194 syscall_printf ("%d = getpid()", myself
->pid
);
1199 _getpid_r (struct _reent
*)
1204 /* getppid: POSIX 4.1.1.1 */
1208 syscall_printf ("%d = getppid()", myself
->ppid
);
1209 return myself
->ppid
;
1212 /* setsid: POSIX 4.3.2.1 */
1216 if (myself
->pgid
== myself
->pid
)
1217 syscall_printf ("hmm. pgid %d pid %d", myself
->pgid
, myself
->pid
);
1220 myself
->ctty
= CTTY_RELEASED
;
1221 myself
->sid
= myself
->pid
;
1222 myself
->pgid
= myself
->pid
;
1224 cygheap
->close_ctty ();
1225 syscall_printf ("sid %d, pgid %d, %s", myself
->sid
, myself
->pgid
, myctty ());
1250 syscall_printf ("%R = getsid(%d)", pid
);
1255 read (int fd
, void *ptr
, size_t len
)
1257 size_t res
= (size_t) -1;
1259 pthread_testcancel ();
1263 cygheap_fdget
cfd (fd
);
1267 if ((cfd
->get_flags () & O_PATH
)
1268 || (cfd
->get_flags () & O_ACCMODE
) == O_WRONLY
)
1274 /* Could block, so let user know we at least got here. */
1275 syscall_printf ("read(%d, %p, %d) %sblocking",
1276 fd
, ptr
, len
, cfd
->is_nonblocking () ? "non" : "");
1278 cfd
->read (ptr
, len
);
1281 __except (EFAULT
) {}
1283 syscall_printf ("%lR = read(%d, %p, %d)", res
, fd
, ptr
, len
);
1284 return (ssize_t
) res
;
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
);
1384 writev (const int fd
, const struct iovec
*const iov
, const int iovcnt
)
1388 pthread_testcancel ();
1392 const ssize_t tot
= check_iovec_for_write (iov
, iovcnt
);
1394 cygheap_fdget
cfd (fd
);
1404 if ((cfd
->get_flags () & O_PATH
)
1405 || (cfd
->get_flags () & O_ACCMODE
) == O_RDONLY
)
1411 /* Could block, so let user know we at least got here. */
1412 if (fd
== 1 || fd
== 2)
1413 paranoid_printf ("writev(%d, %p, %d)", fd
, iov
, iovcnt
);
1415 syscall_printf ("writev(%d, %p, %d)", fd
, iov
, iovcnt
);
1417 res
= cfd
->writev (iov
, iovcnt
, tot
);
1419 __except (EFAULT
) {}
1421 if (fd
== 1 || fd
== 2)
1422 paranoid_printf ("%lR = writev(%d, %p, %d)", res
, fd
, iov
, iovcnt
);
1424 syscall_printf ("%lR = writev(%d, %p, %d)", res
, fd
, iov
, iovcnt
);
1429 pwrite (int fd
, const void *ptr
, size_t len
, off_t off
)
1431 pthread_testcancel ();
1434 cygheap_fdget
cfd (fd
);
1437 else if (cfd
->get_flags () & O_PATH
)
1443 res
= cfd
->pwrite (const_cast<void *> (ptr
), len
, off
);
1445 syscall_printf ("%lR = pwrite(%d, %p, %d, %d)", res
, fd
, ptr
, len
, off
);
1450 /* newlib's fcntl.h defines _open as taking variable args so we must
1451 correspond. The third arg if it exists is: mode_t mode. */
1453 open (const char *unix_path
, int flags
, ...)
1458 fhandler_base
*fh
= NULL
;
1459 fhandler_base
*fh_file
= NULL
;
1461 pthread_testcancel ();
1465 syscall_printf ("open(%s, %y)", unix_path
, flags
);
1472 /* check for optional mode argument */
1473 va_start (ap
, flags
);
1474 mode
= va_arg (ap
, mode_t
);
1480 __leave
; /* errno already set */
1482 /* When O_PATH is specified in flags, flag bits other than O_CLOEXEC,
1483 O_DIRECTORY, and O_NOFOLLOW are ignored. */
1485 flags
&= (O_PATH
| O_CLOEXEC
| O_DIRECTORY
| O_NOFOLLOW
);
1487 int opt
= PC_OPEN
| PC_SYM_NOFOLLOW_PROCFD
;
1488 opt
|= (flags
& (O_NOFOLLOW
| O_EXCL
)) ? PC_SYM_NOFOLLOW
1491 /* If we're opening a FIFO, we will call device_access_denied
1492 below. This leads to a call to fstat, which can use the
1493 path_conv handle. */
1494 opt
|= PC_KEEP_HANDLE
;
1495 if (!(fh
= build_fh_name (unix_path
, opt
, stat_suffixes
)))
1496 __leave
; /* errno already set */
1497 opt
&= ~PC_KEEP_HANDLE
;
1499 fh
->pc
.close_conv_handle ();
1500 if ((flags
& O_NOFOLLOW
) && fh
->issymlink () && !(flags
& O_PATH
))
1505 if ((flags
& O_DIRECTORY
) && fh
->exists () && !fh
->pc
.isdir ())
1507 set_errno (ENOTDIR
);
1510 if (((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
)) && fh
->exists ())
1515 if (flags
& O_TMPFILE
)
1517 if ((flags
& O_ACCMODE
) != O_WRONLY
&& (flags
& O_ACCMODE
) != O_RDWR
)
1522 if (!fh
->pc
.isdir ())
1524 set_errno (fh
->exists () ? ENOTDIR
: ENOENT
);
1527 /* Unfortunately Windows does not allow to create a nameless file.
1528 So create unique filename instead. It starts with ".cyg_tmp_",
1529 followed by an 8 byte unique hex number, followed by an 8 byte
1530 random hex number. */
1534 new_path
= (char *) malloc (strlen (fh
->get_name ())
1537 + 16 /* 64 bit unique id as hex*/
1538 + 16 /* 64 bit random number as hex */
1539 + 1 /* trailing NUL */);
1542 fh
->set_unique_id ();
1543 RtlGenRandom (&rnd
, sizeof rnd
);
1544 __small_sprintf (new_path
, "%s/%s%016X%016X",
1545 fh
->get_name (), ".cyg_tmp_",
1546 fh
->get_unique_id (), rnd
);
1548 if (!(fh_file
= build_fh_name (new_path
, opt
, NULL
)))
1551 __leave
; /* errno already set */
1557 if (fh
->dev () == FH_PROCESSFD
&& fh
->pc
.follow_fd_symlink ())
1559 /* Reopen file by descriptor */
1560 fh_file
= fh
->fd_reopen (flags
, mode
& 07777);
1568 if (fh
->is_fs_special ())
1570 if (fh
->device_access_denied (flags
))
1571 __leave
; /* errno already set */
1572 else if (fh
->isfifo ())
1573 fh
->pc
.close_conv_handle ();
1575 if (!fh
->open_with_arch (flags
, mode
& 07777))
1576 __leave
; /* errno already set */
1578 /* Move O_TMPFILEs to the bin to avoid blocking the parent dir. */
1579 if ((flags
& O_TMPFILE
) && !fh
->pc
.isremote ())
1580 try_to_bin (fh
->pc
, fh
->get_handle (), DELETE
,
1581 FILE_OPEN_FOR_BACKUP_INTENT
);
1584 set_std_handle (fd
);
1587 __except (EFAULT
) {}
1591 syscall_printf ("%R = open(%s, %y)", res
, unix_path
, flags
);
1596 posix_getdents_lseek (cygheap_fdget
&cfd
, off_t pos
, int dir
)
1598 long cur
= cfd
->telldir (cfd
->getdents_dir ());
1604 abs_pos
= cur
+ pos
;
1612 /* First read full dir to learn end-of-dir position. */
1613 while (::readdir (cfd
->getdents_dir ()))
1615 long eod
= cfd
->telldir (cfd
->getdents_dir ());
1616 /* Seek back so it looks like nothing happend in error case */
1617 cfd
->seekdir (cfd
->getdents_dir (), cur
);
1618 if (dir
== SEEK_HOLE
)
1628 abs_pos
= eod
+ pos
;
1638 cfd
->seekdir (cfd
->getdents_dir (), abs_pos
);
1639 /* In SEEK_DATA case, check that we didn't seek beyond EOF */
1640 if (dir
== SEEK_DATA
|| dir
== SEEK_HOLE
)
1642 pos
= cfd
->telldir (cfd
->getdents_dir ());
1645 /* Seek back so it looks like nothing happend */
1646 cfd
->seekdir (cfd
->getdents_dir (), cur
);
1656 lseek (int fd
, off_t pos
, int dir
)
1660 if (dir
< SEEK_SET
|| dir
> SEEK_HOLE
)
1667 cygheap_fdget
cfd (fd
);
1670 else if (cfd
->getdents_dir ())
1671 res
= posix_getdents_lseek (cfd
, pos
, dir
);
1673 res
= cfd
->lseek (pos
, dir
);
1675 /* Can't use %R/%lR here since res is always 8 bytes */
1676 syscall_printf (res
== -1 ? "%D = lseek(%d, %D, %d), errno %d"
1677 : "%D = lseek(%d, %D, %d)",
1678 res
, fd
, pos
, dir
, get_errno ());
1688 syscall_printf ("close(%d)", fd
);
1690 pthread_testcancel ();
1692 cygheap_fdget
cfd (fd
, true);
1697 cfd
->isclosed (true);
1698 res
= cfd
->close_with_arch ();
1702 syscall_printf ("%R = close(%d)", res
, fd
);
1711 cygheap_fdget
cfd (fd
);
1715 res
= cfd
->is_tty ();
1716 syscall_printf ("%R = isatty(%d)", res
, fd
);
1721 link (const char *oldpath
, const char *newpath
)
1726 if (!(fh
= build_fh_name (oldpath
, PC_SYM_NOFOLLOW
| PC_KEEP_HANDLE
,
1732 debug_printf ("got %d error from build_fh_name", fh
->error ());
1733 set_errno (fh
->error ());
1735 else if (fh
->pc
.isdir ())
1736 set_errno (EPERM
); /* We do not permit linking directories. */
1737 else if (!fh
->pc
.exists ())
1740 res
= fh
->link (newpath
);
1744 syscall_printf ("%R = link(%s, %s)", res
, oldpath
, newpath
);
1748 /* chown: POSIX 5.6.5.1 */
1750 * chown () is only implemented for Windows NT. Under other operating
1751 * systems, it is only a stub that always returns zero.
1754 chown_worker (const char *name
, unsigned fmode
, uid_t uid
, gid_t gid
)
1759 if (!(fh
= build_fh_name (name
, fmode
, stat_suffixes
)))
1764 debug_printf ("got %d error from build_fh_name", fh
->error ());
1765 set_errno (fh
->error ());
1768 res
= fh
->fchown (uid
, gid
);
1772 syscall_printf ("%R = %schown(%s,...)",
1773 res
, (fmode
& PC_SYM_NOFOLLOW
) ? "l" : "", name
);
1778 chown (const char * name
, uid_t uid
, gid_t gid
)
1780 return chown_worker (name
, PC_SYM_FOLLOW
, uid
, gid
);
1784 lchown (const char * name
, uid_t uid
, gid_t gid
)
1786 return chown_worker (name
, PC_SYM_NOFOLLOW
, uid
, gid
);
1790 fchown (int fd
, uid_t uid
, gid_t gid
)
1792 cygheap_fdget
cfd (fd
);
1795 syscall_printf ("-1 = fchown (%d,...)", fd
);
1798 else if (cfd
->get_flags () & O_PATH
)
1804 int res
= cfd
->fchown (uid
, gid
);
1806 syscall_printf ("%R = fchown(%s,...)", res
, cfd
->get_name ());
1810 /* umask: POSIX 5.3.3.1 */
1816 oldmask
= cygheap
->umask
;
1817 cygheap
->umask
= mask
& 0777;
1821 #define FILTERED_MODE(m) ((m) & (S_ISUID | S_ISGID | S_ISVTX \
1822 | S_IRWXU | S_IRWXG | S_IRWXO))
1825 chmod_device (path_conv
& pc
, mode_t mode
)
1827 return mknod_worker (pc
, (pc
.dev
.mode () & S_IFMT
) | FILTERED_MODE (mode
),
1828 pc
.dev
.get_major (), pc
.dev
.get_minor ());
1831 /* chmod: POSIX 5.6.4.1 */
1833 chmod (const char *path
, mode_t mode
)
1837 if (!(fh
= build_fh_name (path
, PC_SYM_FOLLOW
, stat_suffixes
)))
1842 debug_printf ("got %d error from build_fh_name", fh
->error ());
1843 set_errno (fh
->error ());
1846 res
= fh
->fchmod (FILTERED_MODE (mode
));
1850 syscall_printf ("%R = chmod(%s, 0%o)", res
, path
, mode
);
1854 /* fchmod: P96 5.6.4.1 */
1857 fchmod (int fd
, mode_t mode
)
1859 cygheap_fdget
cfd (fd
);
1862 syscall_printf ("-1 = fchmod (%d, 0%o)", fd
, mode
);
1865 else if (cfd
->get_flags () & O_PATH
)
1871 return cfd
->fchmod (FILTERED_MODE (mode
));
1874 static struct stat dev_st
;
1875 static bool dev_st_inited
;
1878 fhandler_base::stat_fixup (struct stat
*buf
)
1880 /* For devices, set inode number to device number. This gives us a valid,
1881 unique inode number without having to call hash_path_name. /dev/tty needs
1882 a bit of persuasion to get the same st_ino value in stat and fstat. */
1885 if (get_major () == DEV_VIRTFS_MAJOR
)
1886 buf
->st_ino
= get_ino ();
1887 else if (dev () == FH_TTY
||
1888 ((get_major () == DEV_PTYS_MAJOR
1889 || get_major () == DEV_CONS_MAJOR
)
1890 && !strcmp (get_name (), "/dev/tty")))
1891 buf
->st_ino
= FH_TTY
;
1893 buf
->st_ino
= get_device ();
1895 /* For /dev-based devices, st_dev must be set to the device number of /dev,
1896 not it's own device major/minor numbers. What we do here to speed up
1897 the process is to fetch the device number of /dev only once, liberally
1898 assuming that /dev doesn't change over the lifetime of a process. */
1901 if (dev ().is_dev_resident ())
1905 stat ("/dev", &dev_st
);
1906 dev_st_inited
= true;
1908 buf
->st_dev
= dev_st
.st_dev
;
1911 buf
->st_dev
= get_device ();
1913 /* Only set st_rdev if it's a device. */
1914 if (!buf
->st_rdev
&& get_major () != DEV_VIRTFS_MAJOR
)
1916 buf
->st_rdev
= get_device ();
1917 /* consX, console, conin, and conout point to the same device.
1918 Make sure the link count is correct. */
1919 if (buf
->st_rdev
== (dev_t
) myself
->ctty
&& iscons_dev (myself
->ctty
))
1921 /* CD-ROM drives have two links, /dev/srX and /dev/scdX. */
1922 else if (gnu_dev_major (buf
->st_rdev
) == DEV_CDROM_MAJOR
)
1928 fstat (int fd
, struct stat
*buf
)
1932 cygheap_fdget
cfd (fd
);
1937 memset (buf
, 0, sizeof (struct stat
));
1938 res
= cfd
->fstat (buf
);
1940 cfd
->stat_fixup (buf
);
1943 syscall_printf ("%R = fstat(%d, %p)", res
, fd
, buf
);
1948 _fstat_r (struct _reent
*ptr
, int fd
, struct stat
*buf
)
1952 if ((ret
= fstat (fd
, buf
)) == -1)
1953 _REENT_ERRNO(ptr
) = get_errno ();
1957 /* fsync: P96 6.6.1.1 */
1961 pthread_testcancel ();
1962 cygheap_fdget
cfd (fd
);
1965 syscall_printf ("-1 = fsync (%d)", fd
);
1968 return cfd
->fsync ();
1972 sync_worker (HANDLE dir
, USHORT len
, LPCWSTR vol
)
1977 OBJECT_ATTRIBUTES attr
;
1978 UNICODE_STRING uvol
= { len
, len
, (WCHAR
*) vol
};
1980 InitializeObjectAttributes (&attr
, &uvol
, OBJ_CASE_INSENSITIVE
, dir
, NULL
);
1981 status
= NtOpenFile (&fh
, GENERIC_WRITE
, &attr
, &io
,
1982 FILE_SHARE_VALID_FLAGS
, 0);
1983 if (!NT_SUCCESS (status
))
1984 debug_printf ("NtOpenFile (%S), status %y", &uvol
, status
);
1987 status
= NtFlushBuffersFile (fh
, &io
);
1988 if (!NT_SUCCESS (status
))
1989 debug_printf ("NtFlushBuffersFile (%S), status %y", &uvol
, status
);
1998 OBJECT_ATTRIBUTES attr
;
2001 UNICODE_STRING device
;
2003 /* Open \Device object directory. */
2004 RtlInitUnicodeString (&device
, L
"\\Device");
2005 InitializeObjectAttributes (&attr
, &device
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
2006 status
= NtOpenDirectoryObject (&devhdl
, DIRECTORY_QUERY
, &attr
);
2007 if (!NT_SUCCESS (status
))
2009 debug_printf ("NtOpenDirectoryObject, status %y", status
);
2012 /* Traverse \Device directory ... */
2014 PDIRECTORY_BASIC_INFORMATION dbi_buf
= (PDIRECTORY_BASIC_INFORMATION
)
2016 BOOLEAN restart
= TRUE
;
2017 bool last_run
= false;
2021 status
= NtQueryDirectoryObject (devhdl
, dbi_buf
, 65536, FALSE
, restart
,
2023 if (!NT_SUCCESS (status
))
2025 debug_printf ("NtQueryDirectoryObject, status %y", status
);
2028 if (status
!= STATUS_MORE_ENTRIES
)
2031 for (PDIRECTORY_BASIC_INFORMATION dbi
= dbi_buf
;
2032 dbi
->ObjectName
.Length
> 0;
2035 /* ... and call sync_worker for each HarddiskVolumeX entry. */
2036 if (dbi
->ObjectName
.Length
>= 15 * sizeof (WCHAR
)
2037 && !wcsncasecmp (dbi
->ObjectName
.Buffer
, L
"HarddiskVolume", 14)
2038 && iswdigit (dbi
->ObjectName
.Buffer
[14]))
2039 sync_worker (devhdl
, dbi
->ObjectName
.Length
,
2040 dbi
->ObjectName
.Buffer
);
2046 /* Cygwin internal */
2048 stat_worker (path_conv
&pc
, struct stat
*buf
)
2056 debug_printf ("got %d error from path_conv", pc
.error
);
2057 set_errno (pc
.error
);
2059 else if (pc
.exists ())
2063 memset (buf
, 0, sizeof (*buf
));
2065 if (!(fh
= build_fh_pc (pc
)))
2068 debug_printf ("(%S, %p, %p), file_attributes %d",
2069 pc
.get_nt_native_path (), buf
, fh
, (DWORD
) *fh
);
2071 res
= fh
->fstat (buf
);
2073 fh
->stat_fixup (buf
);
2079 __except (EFAULT
) {}
2081 syscall_printf ("%d = (%S,%p)", res
, pc
.get_nt_native_path (), buf
);
2086 stat (const char *__restrict name
, struct stat
*__restrict buf
)
2088 syscall_printf ("entering");
2089 path_conv
pc (name
, PC_SYM_FOLLOW
| PC_POSIX
| PC_KEEP_HANDLE
2090 | PC_SYM_NOFOLLOW_PROCFD
,
2092 return stat_worker (pc
, buf
);
2096 _stat_r (struct _reent
*__restrict ptr
, const char *__restrict name
,
2101 if ((ret
= stat (name
, buf
)) == -1)
2102 _REENT_ERRNO(ptr
) = get_errno ();
2106 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
2108 lstat (const char *__restrict name
, struct stat
*__restrict buf
)
2110 syscall_printf ("entering");
2111 path_conv
pc (name
, PC_SYM_NOFOLLOW
| PC_POSIX
| PC_KEEP_HANDLE
,
2113 return stat_worker (pc
, buf
);
2117 access (const char *fn
, int flags
)
2119 // flags were incorrectly specified
2121 if (flags
& ~(F_OK
|R_OK
|W_OK
|X_OK
))
2125 fhandler_base
*fh
= build_fh_name (fn
, PC_SYM_FOLLOW
| PC_KEEP_HANDLE
,
2129 res
= fh
->fhaccess (flags
, false);
2133 debug_printf ("returning %d", res
);
2137 /* Linux provides this extension; it is basically a wrapper around the
2138 POSIX:2008 faccessat (AT_FDCWD, fn, flags, AT_EACCESS). We also
2139 provide eaccess as an alias for this, in cygwin.din. */
2141 euidaccess (const char *fn
, int flags
)
2143 // flags were incorrectly specified
2145 if (flags
& ~(F_OK
|R_OK
|W_OK
|X_OK
))
2149 fhandler_base
*fh
= build_fh_name (fn
, PC_SYM_FOLLOW
| PC_KEEP_HANDLE
,
2153 res
= fh
->fhaccess (flags
, true);
2157 debug_printf ("returning %d", res
);
2162 rename_append_suffix (path_conv
&pc
, const char *path
, size_t len
,
2167 if (ascii_strcasematch (path
+ len
- 4, ".lnk")
2168 || ascii_strcasematch (path
+ len
- 4, ".exe"))
2170 stpcpy (stpncpy (buf
, path
, len
), suffix
);
2171 pc
.check (buf
, PC_SYM_NOFOLLOW
);
2174 /* This function tests if a filename has one of the "approved" executable
2175 suffix. This list is probably not complete... */
2177 nt_path_has_executable_suffix (PUNICODE_STRING upath
)
2179 static const PUNICODE_STRING blessed_executable_suffixes
[] =
2187 USHORT pos
= upath
->Length
/ sizeof (WCHAR
);
2189 UNICODE_STRING usuf
;
2190 const PUNICODE_STRING
*suf
;
2192 /* Too short for a native path? */
2195 /* Assumption: All executable suffixes have a length of three. */
2196 path
= upath
->Buffer
+ pos
- 4;
2199 RtlInitCountedUnicodeString (&usuf
, path
, 4 * sizeof (WCHAR
));
2200 for (suf
= blessed_executable_suffixes
; *suf
; ++suf
)
2201 if (RtlEqualUnicodeString (&usuf
, *suf
, TRUE
))
2207 set_same_file_return (bool noreplace
)
2214 /* If newpath names an existing file and the RENAME_NOREPLACE flag is
2215 specified, fail with EEXIST. Exception: Don't fail if the purpose
2216 of the rename is just to change the case of oldpath on a
2217 case-insensitive file system. */
2219 rename2 (const char *oldpath
, const char *newpath
, unsigned int at2flags
)
2223 path_conv oldpc
, newpc
, new2pc
, *dstpc
, *removepc
= NULL
;
2224 bool old_dir_requested
= false, new_dir_requested
= false;
2225 bool old_explicit_suffix
= false, new_explicit_suffix
= false;
2226 bool use_posix_semantics
;
2227 bool noreplace
= at2flags
& RENAME_NOREPLACE
;
2230 NTSTATUS status
= STATUS_SUCCESS
;
2231 HANDLE fh
= NULL
, nfh
;
2232 HANDLE old_trans
= NULL
, trans
= NULL
;
2233 OBJECT_ATTRIBUTES attr
;
2235 FILE_STANDARD_INFORMATION ofsi
;
2236 PFILE_RENAME_INFORMATION pfri
;
2240 if (at2flags
& ~RENAME_NOREPLACE
)
2241 /* RENAME_NOREPLACE is the only flag currently supported. */
2246 if (!*oldpath
|| !*newpath
)
2248 /* Reject rename("","x"), rename("x",""). */
2252 if (has_dot_last_component (oldpath
, true))
2254 /* Reject rename("dir/.","x"). */
2255 oldpc
.check (oldpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2256 set_errno (oldpc
.isdir () ? EINVAL
: ENOTDIR
);
2259 if (has_dot_last_component (newpath
, true))
2261 /* Reject rename("dir","x/."). */
2262 newpc
.check (newpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2263 set_errno (!newpc
.exists () ? ENOENT
2264 : newpc
.isdir () ? EINVAL
: ENOTDIR
);
2268 /* A trailing slash requires that the pathname points to an existing
2269 directory. If it's not, it's a ENOTDIR condition. The same goes
2270 for newpath a bit further down this function. */
2271 olen
= strlen (oldpath
);
2272 if (isdirsep (oldpath
[olen
- 1]))
2275 char *p
= stpcpy (buf
= tp
.c_get (), oldpath
) - 1;
2277 while (p
>= oldpath
&& isdirsep (*p
))
2279 olen
= p
+ 1 - oldpath
;
2282 /* The root directory cannot be renamed. This also rejects
2283 the corner case of rename("/","/"), even though it is the
2288 old_dir_requested
= true;
2290 oldpc
.check (oldpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2293 set_errno (oldpc
.error
);
2296 if (!oldpc
.exists ())
2301 if (oldpc
.isspecial () && !oldpc
.issocket () && !oldpc
.is_fs_special ())
2303 /* No renames from virtual FS */
2307 if (oldpc
.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT
)
2308 && !oldpc
.issymlink ())
2310 /* Volume mount point. If we try to rename a volume mount point, NT
2311 returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==>
2312 errno EXDEV. That's bad since mv(1) will now perform a
2313 cross-device move. So what we do here is to treat the volume
2314 mount point just like Linux treats a mount point. */
2318 if (old_dir_requested
&& !oldpc
.isdir ())
2320 /* Reject rename("file/","x"). */
2321 set_errno (ENOTDIR
);
2324 if (oldpc
.known_suffix ()
2325 && (ascii_strcasematch (oldpath
+ olen
- 4, ".lnk")
2326 || ascii_strcasematch (oldpath
+ olen
- 4, ".exe")))
2327 old_explicit_suffix
= true;
2329 nlen
= strlen (newpath
);
2330 if (isdirsep (newpath
[nlen
- 1]))
2333 char *p
= stpcpy (buf
= tp
.c_get (), newpath
) - 1;
2335 while (p
>= newpath
&& isdirsep (*p
))
2337 nlen
= p
+ 1 - newpath
;
2338 if (!nlen
) /* The root directory is never empty. */
2340 set_errno (ENOTEMPTY
);
2343 new_dir_requested
= true;
2345 newpc
.check (newpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2348 set_errno (newpc
.error
);
2351 if (newpc
.isspecial () && !newpc
.issocket ())
2353 /* No renames to virtual FSes */
2357 if (new_dir_requested
&& !(newpc
.exists ()
2358 ? newpc
.isdir () : oldpc
.isdir ()))
2360 /* Reject rename("file1","file2/"), but allow rename("dir","d/"). */
2361 set_errno (newpc
.exists () ? ENOTDIR
: ENOENT
);
2365 && (oldpc
.isdir () ? !newpc
.isdir () : newpc
.isdir ()))
2367 /* Reject rename("file","dir") and rename("dir","file"). */
2368 set_errno (newpc
.isdir () ? EISDIR
: ENOTDIR
);
2371 if (newpc
.known_suffix ()
2372 && (ascii_strcasematch (newpath
+ nlen
- 4, ".lnk")
2373 || ascii_strcasematch (newpath
+ nlen
- 4, ".exe")))
2374 new_explicit_suffix
= true;
2376 /* This test is necessary in almost every case, so do it once here. */
2377 equal_path
= RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2378 newpc
.get_nt_native_path (),
2379 oldpc
.objcaseinsensitive ());
2381 /* First check if oldpath and newpath only differ by case. If so, it's
2382 just a request to change the case of the filename. By simply setting
2383 the file attributes to INVALID_FILE_ATTRIBUTES (which translates to
2384 "file doesn't exist"), all later tests are skipped. */
2385 if (oldpc
.objcaseinsensitive () && newpc
.exists () && equal_path
2386 && old_explicit_suffix
== new_explicit_suffix
)
2388 if (RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2389 newpc
.get_nt_native_path (),
2392 res
= set_same_file_return (noreplace
);
2395 newpc
.file_attributes (INVALID_FILE_ATTRIBUTES
);
2397 else if (oldpc
.isdir ())
2399 /* Check for newpath being identical or a subdir of oldpath. */
2400 if (RtlPrefixUnicodeString (oldpc
.get_nt_native_path (),
2401 newpc
.get_nt_native_path (),
2402 oldpc
.objcaseinsensitive ()))
2404 if (newpc
.get_nt_native_path ()->Length
2405 == oldpc
.get_nt_native_path ()->Length
)
2407 res
= set_same_file_return (noreplace
);
2410 if (*(PWCHAR
) ((PBYTE
) newpc
.get_nt_native_path ()->Buffer
2411 + oldpc
.get_nt_native_path ()->Length
) == L
'\\')
2418 else if (!newpc
.exists ())
2420 if (equal_path
&& old_explicit_suffix
!= new_explicit_suffix
)
2422 newpc
.check (newpath
, PC_SYM_NOFOLLOW
);
2423 if (RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2424 newpc
.get_nt_native_path (),
2425 oldpc
.objcaseinsensitive ()))
2427 res
= set_same_file_return (noreplace
);
2431 else if (oldpc
.is_lnk_special ()
2432 && !RtlEqualUnicodePathSuffix (newpc
.get_nt_native_path (),
2434 rename_append_suffix (newpc
, newpath
, nlen
, ".lnk");
2435 else if (oldpc
.is_binary () && !old_explicit_suffix
2436 && oldpc
.known_suffix ()
2437 && !nt_path_has_executable_suffix
2438 (newpc
.get_nt_native_path ()))
2439 /* Never append .exe suffix if oldpath had .exe suffix given
2440 explicitely, or if oldpath wasn't already a .exe file, or
2441 if the destination filename has one of the blessed executable
2443 Note: To rename an executable foo.exe to bar-without-suffix,
2444 the .exe suffix must be given explicitly in oldpath. */
2445 rename_append_suffix (newpc
, newpath
, nlen
, ".exe");
2449 if (equal_path
&& old_explicit_suffix
!= new_explicit_suffix
)
2451 newpc
.check (newpath
, PC_SYM_NOFOLLOW
);
2452 if (RtlEqualUnicodeString (oldpc
.get_nt_native_path (),
2453 newpc
.get_nt_native_path (),
2454 oldpc
.objcaseinsensitive ()))
2456 res
= set_same_file_return (noreplace
);
2460 else if (oldpc
.is_lnk_special ())
2462 if (!newpc
.is_lnk_special ()
2463 && !RtlEqualUnicodePathSuffix (newpc
.get_nt_native_path (),
2466 rename_append_suffix (new2pc
, newpath
, nlen
, ".lnk");
2470 else if (oldpc
.is_binary ())
2472 /* Never append .exe suffix if oldpath had .exe suffix given
2473 explicitely, or if newfile is a binary (in which case the given
2474 name probably makes sense as it is), or if the destination
2475 filename has one of the blessed executable suffixes. */
2476 if (!old_explicit_suffix
&& oldpc
.known_suffix ()
2477 && !newpc
.is_binary ()
2478 && !nt_path_has_executable_suffix
2479 (newpc
.get_nt_native_path ()))
2481 rename_append_suffix (new2pc
, newpath
, nlen
, ".exe");
2487 /* If the new path is an existing .lnk symlink or a .exe file,
2488 but the new path has not been specified with explicit suffix,
2489 rename to the new name without suffix, as expected, but also
2490 remove the clashing symlink or executable. Did I ever mention
2491 how I hate the file suffix idea? */
2492 if ((newpc
.is_lnk_special ()
2493 || RtlEqualUnicodePathSuffix (newpc
.get_nt_native_path (),
2495 && !new_explicit_suffix
)
2497 new2pc
.check (newpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
2498 newpc
.get_nt_native_path ()->Length
-= 4 * sizeof (WCHAR
);
2499 if (new2pc
.is_binary () || new2pc
.is_lnk_special ())
2504 dstpc
= (removepc
== &newpc
) ? &new2pc
: &newpc
;
2506 /* Check cross-device before touching anything. Otherwise we might end
2507 up with an unlinked target dir even if the actual rename didn't work.*/
2508 if (oldpc
.fs_type () != dstpc
->fs_type ()
2509 || oldpc
.fs_serial_number () != dstpc
->fs_serial_number ())
2515 /* Should we replace an existing file? */
2516 if ((removepc
|| dstpc
->exists ()) && noreplace
)
2522 /* POSIX semantics only on local NTFS drives. For the OPEN_BY_FILE_ID
2523 flag, see MINIMAL_WIN_NTFS_FLAGS comment in fs_info::update. */
2524 use_posix_semantics
= wincap
.has_posix_rename_semantics ()
2525 && !oldpc
.isremote ()
2526 && oldpc
.fs_is_ntfs ()
2527 && oldpc
.has_attribute (FILE_SUPPORTS_OPEN_BY_FILE_ID
);
2529 ignore_posix_semantics_retry
:
2530 /* Opening the file must be part of the transaction. It's not sufficient
2531 to call only NtSetInformationFile under the transaction. Therefore we
2532 have to start the transaction here, if necessary. Don't start
2533 transaction on W10 1709 or later on local NTFS. Use POSIX semantics
2535 if (!use_posix_semantics
2536 && (dstpc
->fs_flags () & FILE_SUPPORTS_TRANSACTIONS
)
2538 || (!removepc
&& dstpc
->has_attribute (FILE_ATTRIBUTE_READONLY
))))
2539 start_transaction (old_trans
, trans
);
2544 /* Talking about inconsistent behaviour...
2545 - DELETE is required to rename a file. So far, so good.
2546 - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the
2547 FileRenameInformation call fails with STATUS_ACCESS_DENIED. However,
2548 on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used
2549 and the file we try to rename is a symlink. Urgh.
2550 - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE
2551 mode if the file has the R/O attribute set and returns
2552 STATUS_ACCESS_DENIED in that case. */
2554 ULONG access
= DELETE
2555 | (oldpc
.fs_is_cifs () ? FILE_READ_ATTRIBUTES
: 0);
2556 ULONG sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
2557 | (oldpc
.fs_is_samba () ? 0 : FILE_SHARE_DELETE
);
2558 ULONG flags
= FILE_OPEN_FOR_BACKUP_INTENT
2559 | (oldpc
.is_known_reparse_point ()
2560 ? FILE_OPEN_REPARSE_POINT
: 0);
2561 status
= NtOpenFile (&fh
, access
,
2562 oldpc
.get_object_attr (attr
, sec_none_nih
),
2563 &io
, sharing
, flags
);
2565 if (!NT_SUCCESS (status
))
2567 debug_printf ("status %y", status
);
2568 if (status
== STATUS_SHARING_VIOLATION
2569 && cygwait (10L) != WAIT_SIGNALED
)
2571 /* Typical BLODA problem. Some virus scanners check newly
2572 generated files and while doing that disallow DELETE access.
2573 That's really bad because it breaks applications which copy
2574 files by creating a temporary filename and then rename the
2575 temp filename to the target filename. This renaming fails due
2576 to the jealous virus scanner and the application fails to
2577 create the target file.
2579 This kludge tries to work around that by yielding until the
2580 sharing violation goes away, or a signal arrived, or after
2581 about a second, give or take. */
2582 if (++retry_count
< 40)
2588 else if (NT_TRANSACTIONAL_ERROR (status
) && trans
)
2590 /* If NtOpenFile fails due to transactional problems, stop
2591 transaction and go ahead without. */
2592 stop_transaction (status
, old_trans
, trans
);
2593 debug_printf ("Transaction failure. Retry open.");
2596 __seterrno_from_nt_status (status
);
2600 if (use_posix_semantics
)
2601 goto skip_pre_W10_checks
;
2603 /* Renaming a dir to another, existing dir fails always, even if
2604 ReplaceIfExists is set to TRUE and the existing dir is empty. So
2605 we have to remove the destination dir first. This also covers the
2606 case that the destination directory is not empty. In that case,
2607 unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */
2608 if (dstpc
->isdir ())
2610 status
= unlink_nt (*dstpc
, false);
2611 if (!NT_SUCCESS (status
))
2613 __seterrno_from_nt_status (status
);
2617 /* You can't copy a file if the destination exists and has the R/O
2618 attribute set. Remove the R/O attribute first. But first check
2619 if a removepc exists. If so, dstpc points to a non-existing file
2620 due to a mangled suffix. */
2621 else if (!removepc
&& dstpc
->has_attribute (FILE_ATTRIBUTE_READONLY
))
2623 status
= NtOpenFile (&nfh
, FILE_WRITE_ATTRIBUTES
,
2624 dstpc
->get_object_attr (attr
, sec_none_nih
),
2625 &io
, FILE_SHARE_VALID_FLAGS
,
2626 FILE_OPEN_FOR_BACKUP_INTENT
2627 | (dstpc
->is_known_reparse_point ()
2628 ? FILE_OPEN_REPARSE_POINT
: 0));
2629 if (!NT_SUCCESS (status
))
2631 __seterrno_from_nt_status (status
);
2634 status
= NtSetAttributesFile (nfh
, dstpc
->file_attributes ()
2635 & ~FILE_ATTRIBUTE_READONLY
);
2637 if (!NT_SUCCESS (status
))
2639 __seterrno_from_nt_status (status
);
2644 skip_pre_W10_checks
:
2646 /* SUSv3: If the old argument and the new argument resolve to the same
2647 existing file, rename() shall return successfully and perform no
2649 The test tries to be as quick as possible. Due to the above cross
2650 device check we already know both files are on the same device. So
2651 it just tests if oldpath has more than 1 hardlink, then it opens
2652 newpath and tests for identical file ids. If so, oldpath and newpath
2653 refer to the same file. */
2654 if ((removepc
|| dstpc
->exists ())
2656 && NT_SUCCESS (NtQueryInformationFile (fh
, &io
, &ofsi
, sizeof ofsi
,
2657 FileStandardInformation
))
2658 && ofsi
.NumberOfLinks
> 1
2659 && NT_SUCCESS (NtOpenFile (&nfh
, READ_CONTROL
,
2660 (removepc
?: dstpc
)->get_object_attr (attr
, sec_none_nih
),
2661 &io
, FILE_SHARE_VALID_FLAGS
,
2662 FILE_OPEN_FOR_BACKUP_INTENT
2663 | ((removepc
?: dstpc
)->is_known_reparse_point ()
2664 ? FILE_OPEN_REPARSE_POINT
: 0))))
2666 FILE_INTERNAL_INFORMATION ofii
, nfii
;
2668 if (NT_SUCCESS (NtQueryInformationFile (fh
, &io
, &ofii
, sizeof ofii
,
2669 FileInternalInformation
))
2670 && NT_SUCCESS (NtQueryInformationFile (nfh
, &io
, &nfii
,
2672 FileInternalInformation
))
2673 && ofii
.IndexNumber
.QuadPart
== nfii
.IndexNumber
.QuadPart
)
2675 debug_printf ("%s and %s are the same file", oldpath
, newpath
);
2677 res
= set_same_file_return (noreplace
);
2682 /* Create FILE_RENAME_INFORMATION struct. Using a tmp_pathbuf area
2683 allows for paths of up to 32757 chars. This test is just for
2685 if (dstpc
->get_nt_native_path ()->Length
2686 > NT_MAX_PATH
* sizeof (WCHAR
) - sizeof (FILE_RENAME_INFORMATION
))
2688 debug_printf ("target filename too long");
2692 pfri
= (PFILE_RENAME_INFORMATION
) tp
.w_get ();
2693 if (use_posix_semantics
)
2694 pfri
->Flags
= noreplace
? 0
2695 : (FILE_RENAME_REPLACE_IF_EXISTS
2696 | FILE_RENAME_POSIX_SEMANTICS
2697 | FILE_RENAME_IGNORE_READONLY_ATTRIBUTE
);
2699 pfri
->ReplaceIfExists
= !noreplace
;
2700 pfri
->RootDirectory
= NULL
;
2701 pfri
->FileNameLength
= dstpc
->get_nt_native_path ()->Length
;
2702 memcpy (&pfri
->FileName
, dstpc
->get_nt_native_path ()->Buffer
,
2703 pfri
->FileNameLength
);
2704 /* If dstpc points to an existing file and RENAME_NOREPLACE has
2705 been specified, then we should get NT error
2706 STATUS_OBJECT_NAME_COLLISION ==> Win32 error
2707 ERROR_ALREADY_EXISTS ==> Cygwin error EEXIST. */
2708 status
= NtSetInformationFile (fh
, &io
, pfri
,
2709 sizeof *pfri
+ pfri
->FileNameLength
,
2711 ? FileRenameInformationEx
2712 : FileRenameInformation
);
2713 /* This happens if the access rights don't allow deleting the destination.
2714 Even if the handle to the original file is opened with BACKUP
2715 and/or RECOVERY, these flags don't apply to the destination of the
2716 rename operation. So, a privileged user can't rename a file to an
2717 existing file, if the permissions of the existing file aren't right.
2718 Like directories, we have to handle this separately by removing the
2719 destination before renaming. */
2720 if (status
== STATUS_ACCESS_DENIED
&& dstpc
->exists ()
2721 && !dstpc
->isdir ())
2723 bool need_open
= false;
2725 if ((dstpc
->fs_flags () & FILE_SUPPORTS_TRANSACTIONS
) && !trans
)
2727 /* As mentioned earlier, opening the file must be part of the
2728 transaction. Therefore we have to reopen the file here if the
2729 transaction hasn't been started already. Unfortunately we
2730 can't use the NT "reopen file from existing handle" feature.
2731 In that case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT.
2732 We *have* to close the handle to the file first, *then* we can
2733 re-open it. Fortunately nothing has happened yet, so the
2734 atomicity of the rename functionality is not spoiled. */
2736 start_transaction (old_trans
, trans
);
2741 status
= STATUS_SUCCESS
;
2743 status
= NtOpenFile (&fh
, DELETE
,
2744 oldpc
.get_object_attr (attr
, sec_none_nih
),
2745 &io
, FILE_SHARE_VALID_FLAGS
,
2746 FILE_OPEN_FOR_BACKUP_INTENT
2747 | (oldpc
.is_known_reparse_point ()
2748 ? FILE_OPEN_REPARSE_POINT
: 0));
2749 if (NT_SUCCESS (status
))
2751 status
= unlink_nt (*dstpc
, false);
2752 if (NT_SUCCESS (status
))
2755 if (!NT_TRANSACTIONAL_ERROR (status
) || !trans
)
2757 /* If NtOpenFile or unlink_nt fail due to transactional problems,
2758 stop transaction and retry without. */
2760 stop_transaction (status
, old_trans
, trans
);
2761 debug_printf ("Transaction failure %y. Retry open.", status
);
2763 if (NT_SUCCESS (status
))
2764 status
= NtSetInformationFile (fh
, &io
, pfri
,
2765 sizeof *pfri
+ pfri
->FileNameLength
,
2766 FileRenameInformation
);
2768 if (NT_SUCCESS (status
))
2771 unlink_nt (*removepc
, false);
2774 else if (use_posix_semantics
&& status
== STATUS_INVALID_PARAMETER
)
2776 /* NtSetInformationFile returns STATUS_INVALID_PARAMETER
2777 on a bind mounted file system in hyper-v container
2778 with FILE_RENAME_POSIX_SEMANTICS.
2779 Disable the use_posix semntics flag and retry. */
2780 debug_printf ("NtSetInformationFile failed with posix semantics. "
2781 "Disable it and retry.");
2782 use_posix_semantics
= 0;
2783 goto ignore_posix_semantics_retry
;
2786 __seterrno_from_nt_status (status
);
2795 /* Stop transaction if we started one. */
2797 stop_transaction (status
, old_trans
, trans
);
2798 if (get_errno () != EFAULT
)
2799 syscall_printf ("%R = rename(%s, %s)", res
, oldpath
, newpath
);
2804 rename (const char *oldpath
, const char *newpath
)
2806 return rename2 (oldpath
, newpath
, 0);
2810 system (const char *cmdstring
)
2812 pthread_testcancel ();
2814 if (cmdstring
== NULL
)
2818 const char* command
[4];
2824 command
[2] = cmdstring
;
2825 command
[3] = (const char *) NULL
;
2827 if ((res
= spawnvp (_P_SYSTEM
, "/bin/sh", command
)) == -1)
2829 // when exec fails, return value should be as if shell
2830 // executed exit (127)
2834 __except (EFAULT
) {}
2840 setdtablesize (int size
)
2848 if (size
<= (int) cygheap
->fdtab
.size
2849 || cygheap
->fdtab
.extend (size
- cygheap
->fdtab
.size
, OPEN_MAX
))
2864 return (size_t) wincap
.allocation_granularity ();
2867 /* FIXME: not all values are correct... */
2869 fpathconf (int fd
, int v
)
2871 cygheap_fdget
cfd (fd
);
2874 return cfd
->fpathconf (v
);
2878 pathconf (const char *file
, int v
)
2880 fhandler_base
*fh
= NULL
;
2890 if (!(fh
= build_fh_name (file
, PC_SYM_FOLLOW
, stat_suffixes
)))
2895 ret
= fh
->fpathconf (v
);
2897 __except (EFAULT
) {}
2904 ttyname_r (int fd
, char *buf
, size_t buflen
)
2910 cygheap_fdget
cfd (fd
, true);
2913 else if (!cfd
->is_tty ())
2915 else if (buflen
< strlen (cfd
->ttyname ()) + 1)
2918 strcpy (buf
, cfd
->ttyname ());
2919 debug_printf ("returning %d tty: %s", ret
, ret
? "NULL" : buf
);
2932 static char name
[TTY_NAME_MAX
];
2933 int ret
= ttyname_r (fd
, name
, TTY_NAME_MAX
);
2946 str
= _my_tls
.locals
.ttybuf
;
2947 if (!CTTY_IS_VALID (myself
->ctty
))
2948 strcpy (str
, "no tty");
2952 d
.parse (myself
->ctty
);
2953 strcpy (str
, d
.name ());
2958 /* Tells stdio if it should do the cr/lf conversion for this file */
2960 _cygwin_istext_for_stdio (int fd
)
2962 cygheap_fdget
cfd (fd
, false, false);
2965 syscall_printf ("fd %d: not open", fd
);
2970 if (cfd
->get_device () != FH_FS
)
2972 syscall_printf ("fd not disk file. Defaulting to binary.");
2977 if (cfd
->wbinary () || cfd
->rbinary ())
2979 syscall_printf ("fd %d: opened as binary", fd
);
2983 syscall_printf ("fd %d: defaulting to text", fd
);
2988 setmode_helper (struct _reent
*ptr __unused
, FILE *f
)
2990 if (fileno (f
) != _my_tls
.locals
.setmode_file
)
2992 syscall_printf ("improbable, but %d != %d", fileno (f
), _my_tls
.locals
.setmode_file
);
2995 syscall_printf ("file was %s now %s", f
->_flags
& __SCLE
? "text" : "binary",
2996 _my_tls
.locals
.setmode_mode
& O_TEXT
? "text" : "binary");
2997 if (_my_tls
.locals
.setmode_mode
& O_TEXT
)
2998 f
->_flags
|= __SCLE
;
3000 f
->_flags
&= ~__SCLE
;
3007 cygheap_fdget
cfd (fd
);
3011 return cfd
->get_flags () & (O_BINARY
| O_TEXT
);
3014 /* Set a file descriptor into text or binary mode, returning the
3018 _setmode (int fd
, int mode
)
3020 cygheap_fdget
cfd (fd
);
3023 if (mode
!= O_BINARY
&& mode
!= O_TEXT
&& mode
!= 0)
3029 /* Note that we have no way to indicate the case that writes are
3030 binary but not reads, or vice-versa. These cases can arise when
3031 using the tty or console interface. People using those
3032 interfaces should not use setmode. */
3035 if (cfd
->wbinary () && cfd
->rbinary ())
3037 else if (cfd
->wbinset () && cfd
->rbinset ())
3038 res
= O_TEXT
; /* Specifically set O_TEXT */
3043 cfd
->reset_to_open_binmode ();
3045 cfd
->set_flags ((cfd
->get_flags () & ~(O_TEXT
| O_BINARY
)) | mode
);
3047 syscall_printf ("(%d<%S>, %p) returning %s", fd
,
3048 cfd
->pc
.get_nt_native_path (), mode
,
3049 res
& O_TEXT
? "text" : "binary");
3054 cygwin_setmode (int fd
, int mode
)
3056 int res
= _setmode (fd
, mode
);
3059 _my_tls
.locals
.setmode_file
= fd
;
3060 if (_cygwin_istext_for_stdio (fd
))
3061 _my_tls
.locals
.setmode_mode
= O_TEXT
;
3063 _my_tls
.locals
.setmode_mode
= O_BINARY
;
3064 _fwalk_sglue (_GLOBAL_REENT
, setmode_helper
, &__sglue
);
3070 posix_fadvise (int fd
, off_t offset
, off_t len
, int advice
)
3073 cygheap_fdget
cfd (fd
);
3075 res
= cfd
->fadvise (offset
, len
, advice
);
3078 syscall_printf ("%R = posix_fadvice(%d, %D, %D, %d)",
3079 res
, fd
, offset
, len
, advice
);
3084 fallocate (int fd
, int mode
, off_t offset
, off_t len
)
3088 /* First check mask of allowed flags */
3089 if (mode
& ~(FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_ZERO_RANGE
3090 | FALLOC_FL_UNSHARE_RANGE
| FALLOC_FL_COLLAPSE_RANGE
3091 | FALLOC_FL_INSERT_RANGE
| FALLOC_FL_KEEP_SIZE
))
3093 /* Either FALLOC_FL_PUNCH_HOLE or FALLOC_FL_ZERO_RANGE, never both */
3094 else if ((mode
& (FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_ZERO_RANGE
))
3095 == (FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_ZERO_RANGE
))
3097 /* FALLOC_FL_PUNCH_HOLE must be ORed with FALLOC_FL_KEEP_SIZE */
3098 else if ((mode
& (FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_KEEP_SIZE
))
3099 == FALLOC_FL_PUNCH_HOLE
)
3101 else if (offset
< 0 || len
<= 0)
3103 else if (INT64_MAX
- len
< offset
)
3107 cygheap_fdget
cfd (fd
);
3109 res
= cfd
->fallocate (mode
, offset
, len
);
3120 syscall_printf ("%R = fallocate(%d, %y, %D, %D)", res
, fd
, mode
, offset
, len
);
3125 posix_fallocate (int fd
, off_t offset
, off_t len
)
3128 if (offset
< 0 || len
<= 0)
3130 else if (INT64_MAX
- len
< offset
)
3134 cygheap_fdget
cfd (fd
);
3136 res
= cfd
->fallocate (0, offset
, len
);
3142 syscall_printf ("%R = posix_fallocate(%d, %D, %D)", res
, fd
, offset
, len
);
3147 ftruncate (int fd
, off_t length
)
3150 cygheap_fdget
cfd (fd
);
3153 res
= cfd
->fallocate (__FALLOC_FL_TRUNCATE
, 0, length
);
3164 syscall_printf ("%R = ftruncate(%d, %D)", res
, fd
, length
);
3168 /* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
3170 truncate (const char *pathname
, off_t length
)
3175 fd
= open (pathname
, O_RDWR
);
3179 res
= ftruncate (fd
, length
);
3182 syscall_printf ("%R = truncate(%s, %D)", res
, pathname
, length
);
3188 _get_osfhandle (int fd
)
3192 cygheap_fdget
cfd (fd
);
3194 res
= (long) cfd
->get_handle ();
3198 syscall_printf ("%R = get_osfhandle(%d)", res
, fd
);
3203 fstatvfs (int fd
, struct statvfs
*sfs
)
3207 cygheap_fdget
cfd (fd
);
3210 return cfd
->fstatvfs (sfs
);
3212 __except (EFAULT
) {}
3218 statvfs (const char *name
, struct statvfs
*sfs
)
3221 fhandler_base
*fh
= NULL
;
3225 if (!(fh
= build_fh_name (name
, PC_SYM_FOLLOW
, stat_suffixes
)))
3230 debug_printf ("got %d error from build_fh_name", fh
->error ());
3231 set_errno (fh
->error ());
3233 else if (fh
->exists ())
3235 debug_printf ("(%s, %p), file_attributes %d", name
, sfs
, (DWORD
) *fh
);
3236 res
= fh
->fstatvfs (sfs
);
3242 __except (EFAULT
) {}
3245 if (get_errno () != EFAULT
)
3246 syscall_printf ("%R = statvfs(%s,%p)", res
, name
, sfs
);
3251 fstatfs (int fd
, struct statfs
*sfs
)
3254 int ret
= fstatvfs (fd
, &vfs
);
3257 sfs
->f_type
= vfs
.f_flag
;
3258 sfs
->f_bsize
= vfs
.f_bsize
;
3259 sfs
->f_blocks
= vfs
.f_blocks
;
3260 sfs
->f_bavail
= vfs
.f_bavail
;
3261 sfs
->f_bfree
= vfs
.f_bfree
;
3264 sfs
->f_fsid
= vfs
.f_fsid
;
3265 sfs
->f_namelen
= vfs
.f_namemax
;
3271 statfs (const char *fname
, struct statfs
*sfs
)
3274 int ret
= statvfs (fname
, &vfs
);
3277 sfs
->f_type
= vfs
.f_flag
;
3278 sfs
->f_bsize
= vfs
.f_bsize
;
3279 sfs
->f_blocks
= vfs
.f_blocks
;
3280 sfs
->f_bavail
= vfs
.f_bavail
;
3281 sfs
->f_bfree
= vfs
.f_bfree
;
3284 sfs
->f_fsid
= vfs
.f_fsid
;
3285 sfs
->f_namelen
= vfs
.f_namemax
;
3290 /* setpgid: POSIX 4.3.3.1 */
3292 setpgid (pid_t pid
, pid_t pgid
)
3304 pinfo
p (pid
, PID_MAP_RW
);
3307 else if (p
->pgid
== pgid
)
3309 /* A process may only change the process group of itself and its children */
3310 else if (p
!= myself
&& p
->ppid
!= myself
->pid
)
3315 if (p
->pid
!= p
->pgid
)
3316 p
->set_has_pgid_children (0);
3321 syscall_printf ("pid %d, pgid %d, res %d", pid
, pgid
, res
);
3343 return setpgid (0, 0);
3355 static char buf
[TTY_NAME_MAX
];
3356 return ptsname_r (fd
, buf
, sizeof (buf
)) == 0 ? buf
: NULL
;
3360 ptsname_r (int fd
, char *buf
, size_t buflen
)
3368 cygheap_fdget
cfd (fd
);
3371 return cfd
->ptsname_r (buf
, buflen
);
3375 mknod_worker (path_conv
&pc
, mode_t mode
, _major_t major
, _minor_t minor
)
3377 char buf
[sizeof (":\\00000000:00000000:00000000") + PATH_MAX
];
3378 sprintf (buf
, ":\\%x:%x:%x", major
, minor
, mode
);
3379 return symlink_worker (buf
, pc
, true);
3383 mknod (const char *path
, mode_t mode
, dev_t dev
)
3393 if (strlen (path
) >= PATH_MAX
)
3396 /* Trailing dirsep is a no-no, only errno differs. */
3397 bool has_trailing_dirsep
= isdirsep (path
[strlen (path
) - 1]);
3399 path_conv
w32path (path
, PC_SYM_NOFOLLOW
| PC_SYM_NOFOLLOW_DIR
3400 | PC_POSIX
, stat_suffixes
);
3402 if (w32path
.exists () || has_trailing_dirsep
)
3404 set_errno (w32path
.exists () ? EEXIST
: ENOENT
);
3408 mode_t type
= mode
& S_IFMT
;
3409 _major_t major
= _major (dev
);
3410 _minor_t minor
= _minor (dev
);
3418 major
= _major (FH_FIFO
);
3419 minor
= _minor (FH_FIFO
);
3425 int fd
= open (path
, O_CREAT
, mode
);
3437 return mknod_worker (w32path
, mode
, major
, minor
);
3445 mkfifo (const char *path
, mode_t mode
)
3447 return mknod (path
, (mode
& ~S_IFMT
) | S_IFIFO
, 0);
3450 /* seteuid: standards? */
3454 debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
3455 uid
, myself
->uid
, myself
->gid
);
3457 /* Same uid as we're just running under is usually a no-op.
3459 Except we have an external token which is a restricted token. Or,
3460 the external token is NULL, but the current impersonation token is
3461 a restricted token. This allows to restrict user rights temporarily
3464 cygwin_internal(CW_SET_EXTERNAL_TOKEN, restricted_token,
3465 CW_TOKEN_RESTRICTED);
3467 [...do stuff with restricted rights...]
3468 cygwin_internal(CW_SET_EXTERNAL_TOKEN, INVALID_HANDLE_VALUE,
3469 CW_TOKEN_RESTRICTED);
3472 Note that using the current uid is a requirement! We have restricted
3473 tokens galore (UAC), so this is really just a special case to restrict
3474 your own processes to lesser rights. */
3475 bool request_restricted_uid_switch
= (uid
== myself
->uid
3476 && cygheap
->user
.ext_token_is_restricted
);
3477 if (uid
== myself
->uid
&& !cygheap
->user
.groups
.ischanged
3478 && !request_restricted_uid_switch
)
3480 debug_printf ("Nothing happens");
3485 user_groups
&groups
= cygheap
->user
.groups
;
3486 HANDLE new_token
= NULL
;
3487 struct passwd
* pw_new
;
3488 bool token_is_internal
, issamesid
= false;
3490 pw_new
= internal_getpwuid (uid
);
3491 if (!usersid
.getfrompw (pw_new
))
3497 cygheap
->user
.deimpersonate ();
3499 /* Verify if the process token is suitable. */
3500 /* First of all, skip all checks if a switch to a restricted token has been
3501 requested, or if trying to switch back from it. */
3502 if (request_restricted_uid_switch
)
3504 if (cygheap
->user
.external_token
!= NO_IMPERSONATION
)
3506 debug_printf ("Switch to restricted token");
3507 new_token
= cygheap
->user
.external_token
;
3511 debug_printf ("Switch back from restricted token");
3512 new_token
= hProcToken
;
3513 cygheap
->user
.ext_token_is_restricted
= false;
3516 /* TODO, CV 2008-11-25: The check against saved_sid is a kludge and a
3517 shortcut. We must check if it's really feasible in the long run.
3518 The reason to add this shortcut is this: sshd switches back to the
3519 privileged user running sshd at least twice in the process of
3520 authentication. It calls seteuid first, then setegid. Due to this
3521 order, the setgroups group list is still active when calling seteuid
3522 and verify_token treats the original token of the privileged user as
3523 insufficient. This in turn results in creating a new user token for
3524 the privileged user instead of using the original token. This can have
3525 unfortunate side effects. The created token has different group
3526 memberships, different user rights, and misses possible network
3528 Therefore we try this shortcut now. When switching back to the
3529 privileged user, we probably always want a correct (aka original)
3530 user token for this privileged user, not only in sshd. */
3531 else if ((uid
== cygheap
->user
.saved_uid
3532 && usersid
== cygheap
->user
.saved_sid ())
3533 || verify_token (hProcToken
, usersid
, groups
))
3534 new_token
= hProcToken
;
3535 /* Verify if the external token is suitable */
3536 else if (cygheap
->user
.external_token
!= NO_IMPERSONATION
3537 && verify_token (cygheap
->user
.external_token
, usersid
, groups
))
3538 new_token
= cygheap
->user
.external_token
;
3539 /* Verify if the current token (internal or former external) is suitable */
3540 else if (cygheap
->user
.curr_primary_token
!= NO_IMPERSONATION
3541 && cygheap
->user
.curr_primary_token
!= cygheap
->user
.external_token
3542 && verify_token (cygheap
->user
.curr_primary_token
, usersid
, groups
,
3543 &token_is_internal
))
3544 new_token
= cygheap
->user
.curr_primary_token
;
3545 /* Verify if the internal token is suitable */
3546 else if (cygheap
->user
.internal_token
!= NO_IMPERSONATION
3547 && cygheap
->user
.internal_token
!= cygheap
->user
.curr_primary_token
3548 && verify_token (cygheap
->user
.internal_token
, usersid
, groups
,
3549 &token_is_internal
))
3550 new_token
= cygheap
->user
.internal_token
;
3552 debug_printf ("Found token %p", new_token
);
3554 /* If no impersonation token is available, try to authenticate using
3555 LSA private data stored password, or, if that fails, S4U logon. */
3556 if (new_token
== NULL
)
3558 if (!(new_token
= lsaprivkeyauth (pw_new
)))
3561 WCHAR domain
[MAX_DOMAIN_NAME_LEN
+ 1];
3562 WCHAR user
[UNLEN
+ 1];
3564 debug_printf ("lsaprivkeyauth failed, try s4uauth.");
3565 extract_nt_dom_user (pw_new
, domain
, user
);
3566 if (!(new_token
= s4uauth (true, domain
, user
, status
)))
3568 debug_printf ("s4uauth failed, bail out");
3569 cygheap
->user
.reimpersonate ();
3574 /* Keep at most one internal token */
3575 if (cygheap
->user
.internal_token
!= NO_IMPERSONATION
)
3576 CloseHandle (cygheap
->user
.internal_token
);
3577 cygheap
->user
.internal_token
= new_token
;
3580 if (new_token
!= hProcToken
)
3584 if (!request_restricted_uid_switch
)
3585 load_user_profile (new_token
, pw_new
, usersid
);
3587 /* Try setting owner to same value as user. */
3588 status
= NtSetInformationToken (new_token
, TokenOwner
,
3589 &usersid
, sizeof usersid
);
3590 if (!NT_SUCCESS (status
))
3591 debug_printf ("NtSetInformationToken (user.token, TokenOwner), %y",
3593 /* Try setting primary group in token to current group */
3594 status
= NtSetInformationToken (new_token
, TokenPrimaryGroup
,
3595 &groups
.pgsid
, sizeof (cygsid
));
3596 if (!NT_SUCCESS (status
))
3597 debug_printf ("NtSetInformationToken (user.token, TokenPrimaryGroup),"
3599 /* Try setting default DACL */
3600 PACL dacl_buf
= (PACL
) alloca (MAX_DACL_LEN (5));
3601 if (sec_acl (dacl_buf
, true, true, usersid
))
3603 TOKEN_DEFAULT_DACL tdacl
= { dacl_buf
};
3604 status
= NtSetInformationToken (new_token
, TokenDefaultDacl
,
3605 &tdacl
, sizeof (tdacl
));
3606 if (!NT_SUCCESS (status
))
3607 debug_printf ("NtSetInformationToken (TokenDefaultDacl), %y",
3612 issamesid
= (usersid
== cygheap
->user
.sid ());
3613 cygheap
->user
.set_sid (usersid
);
3614 cygheap
->user
.curr_primary_token
= new_token
== hProcToken
? NO_IMPERSONATION
3616 cygheap
->user
.curr_token_is_restricted
= false;
3617 cygheap
->user
.setuid_to_restricted
= false;
3618 if (cygheap
->user
.curr_imp_token
!= NO_IMPERSONATION
)
3620 CloseHandle (cygheap
->user
.curr_imp_token
);
3621 cygheap
->user
.curr_imp_token
= NO_IMPERSONATION
;
3623 if (cygheap
->user
.curr_primary_token
!= NO_IMPERSONATION
)
3625 /* HANDLE_FLAG_INHERIT may be missing in external token. */
3626 if (!SetHandleInformation (cygheap
->user
.curr_primary_token
,
3627 HANDLE_FLAG_INHERIT
, HANDLE_FLAG_INHERIT
)
3628 || !DuplicateTokenEx (cygheap
->user
.curr_primary_token
,
3629 MAXIMUM_ALLOWED
, &sec_none
,
3630 SecurityImpersonation
, TokenImpersonation
,
3631 &cygheap
->user
.curr_imp_token
))
3634 cygheap
->user
.curr_primary_token
= NO_IMPERSONATION
;
3637 cygheap
->user
.curr_token_is_restricted
= request_restricted_uid_switch
;
3638 set_cygwin_privileges (cygheap
->user
.curr_primary_token
);
3639 set_cygwin_privileges (cygheap
->user
.curr_imp_token
);
3641 if (!cygheap
->user
.reimpersonate ())
3647 cygheap
->user
.set_name (pw_new
->pw_name
);
3649 groups
.ischanged
= FALSE
;
3651 /* Recreate and fill out the user shared region for a new user. */
3652 user_info::create (true);
3656 /* setuid: POSIX 4.2.2.1 */
3660 int ret
= seteuid (uid
);
3663 cygheap
->user
.real_uid
= myself
->uid
;
3664 /* If restricted token, forget original privileges on exec (). */
3665 cygheap
->user
.setuid_to_restricted
= cygheap
->user
.curr_token_is_restricted
;
3667 debug_printf ("real: %d, effective: %d", cygheap
->user
.real_uid
, myself
->uid
);
3672 setreuid (uid_t ruid
, uid_t euid
)
3676 uid_t old_euid
= myself
->uid
;
3678 if (ruid
!= ILLEGAL_UID
&& cygheap
->user
.real_uid
!= ruid
&& euid
!= ruid
)
3679 tried
= !(ret
= seteuid (ruid
));
3680 if (!ret
&& euid
!= ILLEGAL_UID
)
3681 ret
= seteuid (euid
);
3682 if (tried
&& (ret
|| euid
== ILLEGAL_UID
) && seteuid (old_euid
))
3683 system_printf ("Cannot restore original euid %u", old_euid
);
3684 if (!ret
&& ruid
!= ILLEGAL_UID
)
3685 cygheap
->user
.real_uid
= ruid
;
3686 debug_printf ("real: %u, effective: %u", cygheap
->user
.real_uid
, myself
->uid
);
3690 /* setegid: from System V. */
3694 debug_printf ("new egid: %u current: %u", gid
, myself
->gid
);
3696 if (gid
== myself
->gid
)
3703 user_groups
* groups
= &cygheap
->user
.groups
;
3705 struct group
* gr
= internal_getgrgid (gid
);
3707 if (!gsid
.getfromgr (gr
))
3714 groups
->update_pgrp (gsid
);
3715 if (cygheap
->user
.issetuid ())
3717 /* If impersonated, update impersonation token... */
3718 status
= NtSetInformationToken (cygheap
->user
.primary_token (),
3719 TokenPrimaryGroup
, &gsid
, sizeof gsid
);
3720 if (!NT_SUCCESS (status
))
3721 debug_printf ("NtSetInformationToken (primary_token, "
3722 "TokenPrimaryGroup), %y", status
);
3723 status
= NtSetInformationToken (cygheap
->user
.imp_token (),
3724 TokenPrimaryGroup
, &gsid
, sizeof gsid
);
3725 if (!NT_SUCCESS (status
))
3726 debug_printf ("NtSetInformationToken (token, TokenPrimaryGroup), %y",
3729 cygheap
->user
.deimpersonate ();
3730 status
= NtSetInformationToken (hProcToken
, TokenPrimaryGroup
,
3731 &gsid
, sizeof gsid
);
3732 if (!NT_SUCCESS (status
))
3733 debug_printf ("NtSetInformationToken (hProcToken, TokenPrimaryGroup), %y",
3735 clear_procimptoken ();
3736 cygheap
->user
.reimpersonate ();
3740 /* setgid: POSIX 4.2.2.1 */
3744 int ret
= setegid (gid
);
3746 cygheap
->user
.real_gid
= myself
->gid
;
3751 setregid (gid_t rgid
, gid_t egid
)
3755 gid_t old_egid
= myself
->gid
;
3757 if (rgid
!= ILLEGAL_GID
&& cygheap
->user
.real_gid
!= rgid
&& egid
!= rgid
)
3758 tried
= !(ret
= setegid (rgid
));
3759 if (!ret
&& egid
!= ILLEGAL_GID
)
3760 ret
= setegid (egid
);
3761 if (tried
&& (ret
|| egid
== ILLEGAL_GID
) && setegid (old_egid
))
3762 system_printf ("Cannot restore original egid %u", old_egid
);
3763 if (!ret
&& rgid
!= ILLEGAL_GID
)
3764 cygheap
->user
.real_gid
= rgid
;
3765 debug_printf ("real: %u, effective: %u", cygheap
->user
.real_gid
, myself
->gid
);
3769 /* chroot: privileged Unix system call. */
3770 /* FIXME: Not privileged here. How should this be done? */
3772 chroot (const char *newroot
)
3774 path_conv
path (newroot
, PC_SYM_FOLLOW
| PC_POSIX
);
3778 set_errno (path
.error
);
3779 else if (!path
.exists ())
3781 else if (!path
.isdir ())
3782 set_errno (ENOTDIR
);
3783 else if (path
.isspecial ())
3787 getwinenv("PATH="); /* Save the native PATH */
3788 cygheap
->root
.set (path
.get_posix (), path
.get_win32 (),
3789 !!path
.objcaseinsensitive ());
3793 syscall_printf ("%R = chroot(%s)", ret
, newroot
?: "NULL");
3798 creat (const char *path
, mode_t mode
)
3800 return open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
3817 setpriority (int which
, id_t who
, int value
)
3819 DWORD prio
= nice_to_winprio (value
);
3827 if ((pid_t
) who
== myself
->pid
)
3829 if (!SetPriorityClass (GetCurrentProcess (), prio
))
3834 myself
->nice
= value
;
3835 debug_printf ("Set nice to %d", myself
->nice
);
3851 winpids
pids ((DWORD
) PID_MAP_RW
);
3852 for (DWORD i
= 0; i
< pids
.npids
; ++i
)
3854 _pinfo
*p
= pids
[i
];
3860 if ((pid_t
) who
!= p
->pid
)
3864 if ((pid_t
) who
!= p
->pgid
)
3868 if ((uid_t
) who
!= p
->uid
)
3872 HANDLE proc_h
= OpenProcess (PROCESS_SET_INFORMATION
, FALSE
,
3878 if (!SetPriorityClass (proc_h
, prio
))
3882 CloseHandle (proc_h
);
3896 getpriority (int which
, id_t who
)
3898 int nice
= NZERO
* 2; /* Illegal value */
3905 if ((pid_t
) who
== myself
->pid
)
3907 DWORD winprio
= GetPriorityClass(GetCurrentProcess());
3908 if (winprio
!= nice_to_winprio(myself
->nice
))
3909 myself
->nice
= winprio_to_nice(winprio
);
3910 return myself
->nice
;
3925 winpids
pids ((DWORD
) 0);
3926 for (DWORD i
= 0; i
< pids
.npids
; ++i
)
3928 _pinfo
*p
= pids
[i
];
3933 if ((pid_t
) who
== p
->pid
)
3940 if ((pid_t
) who
== p
->pgid
&& p
->nice
< nice
)
3944 if ((uid_t
) who
== p
->uid
&& p
->nice
< nice
)
3951 if (nice
== NZERO
* 2)
3962 return setpriority (PRIO_PROCESS
, myself
->pid
, myself
->nice
+ incr
);
3966 locked_append (int fd
, const void * buf
, size_t size
)
3968 struct flock lock_buffer
= {F_WRLCK
, SEEK_SET
, 0, 0, 0};
3972 if ((lock_buffer
.l_start
= lseek (fd
, 0, SEEK_END
)) != (off_t
) -1
3973 && fcntl (fd
, F_SETLKW
, &lock_buffer
) != -1)
3975 if (lseek (fd
, 0, SEEK_END
) != (off_t
) -1)
3976 write (fd
, buf
, size
);
3977 lock_buffer
.l_type
= F_UNLCK
;
3978 fcntl (fd
, F_SETLK
, &lock_buffer
);
3981 while (count
++ < 1000
3982 && (errno
== EACCES
|| errno
== EAGAIN
)
3987 updwtmp (const char *wtmp_file
, const struct utmp
*ut
)
3991 if ((fd
= open (wtmp_file
, O_WRONLY
| O_BINARY
, 0)) >= 0)
3993 locked_append (fd
, ut
, sizeof *ut
);
3998 static int utmp_fd
= -1;
3999 static bool utmp_readonly
= false;
4000 static char *utmp_file
= (char *) _PATH_UTMP
;
4003 internal_setutent (bool force_readwrite
)
4005 if (force_readwrite
&& utmp_readonly
)
4009 utmp_fd
= open (utmp_file
, O_RDWR
| O_BINARY
);
4010 /* If open fails, we assume an unprivileged process (who?). In this
4011 case we try again for reading only unless the process calls
4012 pututline() (==force_readwrite) in which case opening just fails. */
4013 if (utmp_fd
< 0 && !force_readwrite
)
4015 utmp_fd
= open (utmp_file
, O_RDONLY
| O_BINARY
);
4017 utmp_readonly
= true;
4021 lseek (utmp_fd
, 0, SEEK_SET
);
4027 internal_setutent (false);
4037 utmp_readonly
= false;
4042 utmpname (const char *file
)
4049 utmp_file
= strdup (file
);
4052 debug_printf ("New UTMP file: %s", utmp_file
);
4057 __except (EFAULT
) {}
4059 debug_printf ("Setting UTMP file failed");
4063 /* Note: do not make NO_COPY */
4064 static struct utmp utmp_data_buf
[16];
4065 static unsigned utix
= 0;
4066 #define nutdbuf (sizeof (utmp_data_buf) / sizeof (utmp_data_buf[0]))
4067 #define utmp_data ({ \
4068 if (utix >= nutdbuf) \
4070 utmp_data_buf + utix++; \
4073 static struct utmpx
*
4074 copy_ut_to_utx (struct utmp
*ut
, struct utmpx
*utx
)
4078 memcpy (utx
, ut
, sizeof *ut
);
4079 utx
->ut_tv
.tv_sec
= ut
->ut_time
;
4080 utx
->ut_tv
.tv_usec
= 0;
4084 extern "C" struct utmp
*
4089 internal_setutent (false);
4094 utmp
*ut
= utmp_data
;
4095 if (read (utmp_fd
, ut
, sizeof *ut
) != sizeof *ut
)
4100 extern "C" struct utmp
*
4101 getutid (const struct utmp
*id
)
4107 internal_setutent (false);
4111 utmp
*ut
= utmp_data
;
4112 while (read (utmp_fd
, ut
, sizeof *ut
) == sizeof *ut
)
4114 switch (id
->ut_type
)
4120 if (id
->ut_type
== ut
->ut_type
)
4127 if (strncmp (id
->ut_id
, ut
->ut_id
, UT_IDLEN
) == 0)
4135 __except (EFAULT
) {}
4140 extern "C" struct utmp
*
4141 getutline (const struct utmp
*line
)
4147 internal_setutent (false);
4152 utmp
*ut
= utmp_data
;
4153 while (read (utmp_fd
, ut
, sizeof *ut
) == sizeof *ut
)
4154 if ((ut
->ut_type
== LOGIN_PROCESS
||
4155 ut
->ut_type
== USER_PROCESS
) &&
4156 !strncmp (ut
->ut_line
, line
->ut_line
, sizeof (ut
->ut_line
)))
4159 __except (EFAULT
) {}
4164 extern "C" struct utmp
*
4165 pututline (const struct utmp
*ut
)
4169 internal_setutent (true);
4172 debug_printf ("error: utmp_fd %d", utmp_fd
);
4175 debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n",
4176 ut
->ut_type
, ut
->ut_pid
, ut
->ut_line
, ut
->ut_id
);
4177 debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n",
4178 ut
->ut_user
, ut
->ut_host
);
4181 if ((u
= getutid (ut
)))
4183 lseek (utmp_fd
, -sizeof *ut
, SEEK_CUR
);
4184 write (utmp_fd
, ut
, sizeof *ut
);
4187 locked_append (utmp_fd
, ut
, sizeof *ut
);
4188 /* The documentation says to return a pointer to this which implies that
4189 this has to be cast from a const. That doesn't seem right but the
4190 documentation seems pretty clear on this. */
4191 return (struct utmp
*) ut
;
4193 __except (EFAULT
) {}
4201 internal_setutent (false);
4210 extern "C" struct utmpx
*
4213 /* POSIX: Not required to be thread safe. */
4214 static struct utmpx utx
;
4215 return copy_ut_to_utx (getutent (), &utx
);
4218 extern "C" struct utmpx
*
4219 getutxid (const struct utmpx
*id
)
4221 /* POSIX: Not required to be thread safe. */
4222 static struct utmpx utx
;
4226 ((struct utmpx
*)id
)->ut_time
= id
->ut_tv
.tv_sec
;
4227 return copy_ut_to_utx (getutid ((struct utmp
*) id
), &utx
);
4229 __except (EFAULT
) {}
4234 extern "C" struct utmpx
*
4235 getutxline (const struct utmpx
*line
)
4237 /* POSIX: Not required to be thread safe. */
4238 static struct utmpx utx
;
4242 ((struct utmpx
*)line
)->ut_time
= line
->ut_tv
.tv_sec
;
4243 return copy_ut_to_utx (getutline ((struct utmp
*) line
), &utx
);
4245 __except (EFAULT
) {}
4250 extern "C" struct utmpx
*
4251 pututxline (const struct utmpx
*utmpx
)
4253 /* POSIX: Not required to be thread safe. */
4254 static struct utmpx utx
;
4258 ((struct utmpx
*)utmpx
)->ut_time
= utmpx
->ut_tv
.tv_sec
;
4259 return copy_ut_to_utx (pututline ((struct utmp
*) utmpx
), &utx
);
4261 __except (EFAULT
) {}
4267 updwtmpx (const char *wtmpx_file
, const struct utmpx
*utmpx
)
4269 ((struct utmpx
*)utmpx
)->ut_time
= utmpx
->ut_tv
.tv_sec
;
4270 updwtmp (wtmpx_file
, (const struct utmp
*) utmpx
);
4276 /* Fetch the globally unique MachineGuid value from
4277 HKLM/Software/Microsoft/Cryptography and hash it. */
4278 int32_t hostid
= 0x40291372; /* Choose a nice start value */
4281 reg_key
key (HKEY_LOCAL_MACHINE
, KEY_READ
,
4282 L
"SOFTWARE", L
"Microsoft", L
"Cryptography", NULL
);
4283 key
.get_string (L
"MachineGuid", wguid
, 38,
4284 L
"00000000-0000-0000-0000-000000000000");
4286 for (PWCHAR wp
= wguid
; *wp
; ++wp
)
4287 hostid
= *wp
+ (hostid
<< 6) + (hostid
<< 16) - hostid
;
4288 debug_printf ("hostid %08y from MachineGuid %W", hostid
, wguid
);
4289 return (int32_t) hostid
; /* Avoid sign extension. */
4292 #define ETC_SHELLS "/etc/shells"
4293 static int shell_index
;
4294 static FILE *shell_fp
;
4299 /* List of default shells if no /etc/shells exists, defined as on Linux.
4300 FIXME: SunOS has a far longer list, containing all shells which
4301 might be shipped with the OS. Should we do the same for the Cygwin
4302 distro, adding bash, tcsh, ksh, pdksh and zsh? */
4303 static const char *def_shells
[] = {
4310 static char buf
[PATH_MAX
];
4313 if (!shell_fp
&& !(shell_fp
= fopen (ETC_SHELLS
, "rt")))
4315 if (def_shells
[shell_index
])
4316 return strcpy (buf
, def_shells
[shell_index
++]);
4319 /* Skip white space characters. */
4320 while ((ch
= getc (shell_fp
)) != EOF
&& isspace (ch
))
4322 /* Get each non-whitespace character as part of the shell path as long as
4325 ch
!= EOF
&& !isspace (ch
) && buf_idx
< (PATH_MAX
- 1);
4326 buf_idx
++, ch
= getc (shell_fp
))
4328 /* Skip any trailing non-whitespace character not fitting in buf. If the
4329 path is longer than PATH_MAX, it's invalid anyway. */
4330 while (ch
!= EOF
&& !isspace (ch
))
4331 ch
= getc (shell_fp
);
4334 buf
[buf_idx
] = '\0';
4344 fseek (shell_fp
, 0L, SEEK_SET
);
4360 flockfile (FILE *file
)
4366 ftrylockfile (FILE *file
)
4368 return _ftrylockfile (file
);
4372 funlockfile (FILE *file
)
4374 _funlockfile (file
);
4378 popen (const char *command
, const char *in_type
)
4380 const char *type
= in_type
;
4381 char fdopen_flags
[3] = "\0\0";
4384 #define rw fdopen_flags[0]
4385 #define bintext fdopen_flags[1]
4387 /* Sanity check. GLibc allows any order and any number of repetition,
4388 as long as the string doesn't contradict itself. We do the same here. */
4391 if (*type
== 'r' || *type
== 'w')
4393 if (rw
&& rw
!= *type
)
4397 else if (*type
== 'b' || *type
== 't')
4399 if (bintext
&& bintext
!= *type
)
4403 else if (*type
== 'e')
4405 pipe_flags
= O_CLOEXEC
;
4411 if ((rw
!= 'r' && rw
!= 'w') || (*type
!= '\0'))
4418 if (pipe2 (fds
, pipe_flags
) < 0)
4421 int myix
= rw
== 'r' ? 0 : 1;
4424 FILE *fp
= fdopen (fds
[myix
], fdopen_flags
);
4427 /* If fds are in the range of stdin/stdout/stderr, move them
4428 out of the way (possibly temporarily). Otherwise, spawn_guts
4429 will be confused. We do this here rather than adding logic to
4430 spawn_guts because spawn_guts is likely to be a more frequently
4431 used routine and having stdin/stdout/stderr closed and reassigned
4432 to pipe handles is an unlikely event. */
4433 int orig_fds
[2] = {fds
[0], fds
[1]};
4434 for (int i
= 0; i
< 2; i
++)
4437 cygheap_fdnew
newfd(3);
4438 cygheap
->fdtab
.move_fd (fds
[i
], newfd
);
4442 int myfd
= fds
[myix
]; /* myfd - convenience variable for manipulation
4443 of the "parent" end of the pipe. */
4444 int stdchild
= myix
^ 1; /* stdchild denotes the index into fd for the
4445 handle which will be redirected to
4448 __std
[myix
] = -1; /* -1 means don't pass this fd to the child
4450 __std
[stdchild
] = fds
[stdchild
]; /* Do pass this as the std handle */
4452 const char *argv
[4] =
4460 /* With 'e' flag given, we have to revert the close-on-exec on the child
4461 end of the pipe. Otherwise don't pass our end of the pipe to the
4463 if (pipe_flags
& O_CLOEXEC
)
4464 fcntl (__std
[stdchild
], F_SETFD
, 0);
4466 fcntl (myfd
, F_SETFD
, FD_CLOEXEC
);
4468 /* Also don't pass the file handle currently associated with stdin/stdout
4469 to the child. This function may actually fail if the stdchild fd
4470 is closed. But that's ok. */
4471 int stdchild_state
= fcntl (stdchild
, F_GETFD
, 0);
4472 fcntl (stdchild
, F_SETFD
, stdchild_state
| FD_CLOEXEC
);
4474 /* Start a shell process to run the given command without forking. */
4475 pid_t pid
= ch_spawn
.worker ("/bin/sh", argv
, environ
, _P_NOWAIT
,
4476 __std
[0], __std
[1]);
4478 /* Reinstate the close-on-exec state */
4479 fcntl (stdchild
, F_SETFD
, stdchild_state
);
4481 /* If pid >= 0 then spawn_guts succeeded. */
4484 close (fds
[stdchild
]); /* Close the child end of the pipe. */
4485 /* Move the fd back to its original slot if it has been moved since
4486 we're always supposed to open the lowest numbered available fd
4487 and, if fds[mix] != orig_fds[myix] then orig_fds[myix] is
4488 presumably lower. */
4489 if (fds
[myix
] != orig_fds
[myix
])
4490 cygheap
->fdtab
.move_fd (fds
[myix
], myfd
= orig_fds
[myix
]);
4491 fhandler_pipe
*fh
= (fhandler_pipe
*) cygheap
->fdtab
[myfd
];
4492 /* Flag that this handle is associated with popen. */
4493 fh
->set_popen_pid (pid
);
4498 /* If we reach here we've seen an error but the pipe handles are open.
4499 Close them and return NULL. */
4500 int save_errno
= get_errno ();
4503 /* Must fclose fp to avoid memory leak. */
4505 close (fds
[myix
^ 1]);
4512 set_errno (save_errno
);
4523 fhandler_pipe
*fh
= (fhandler_pipe
*) cygheap
->fdtab
[fileno(fp
)];
4525 if (fh
->get_device () != FH_PIPEW
&& fh
->get_device () != FH_PIPER
)
4531 int pid
= fh
->get_popen_pid ();
4543 if (waitpid (pid
, &status
, 0) == pid
)
4545 else if (get_errno () == EINTR
)
4553 /* Preliminary(?) implementation of the openat family of functions. */
4556 gen_full_path_at (char *path_ret
, int dirfd
, const char *pathname
,
4559 /* futimesat allows a NULL pathname. */
4560 if (!pathname
&& !(flags
& _AT_NULL_PATHNAME_ALLOWED
))
4565 if (pathname
&& isabspath_strict (pathname
))
4566 stpcpy (path_ret
, pathname
);
4571 if (dirfd
== AT_FDCWD
)
4573 cwdstuff::acquire_read ();
4574 p
= stpcpy (path_ret
, cygheap
->cwd
.get_posix ());
4575 cwdstuff::release_read ();
4579 cygheap_fdget
cfd (dirfd
);
4582 if (!cfd
->pc
.isdir () && !(flags
& AT_EMPTY_PATH
))
4584 set_errno (ENOTDIR
);
4587 p
= stpcpy (path_ret
, cfd
->get_name ());
4593 if (flags
& AT_EMPTY_PATH
)
4598 if (strlen (pathname
) >= PATH_MAX
)
4600 set_errno (ENAMETOOLONG
);
4605 stpcpy (p
, pathname
);
4612 openat (int dirfd
, const char *pathname
, int flags
, ...)
4617 char *path
= tp
.c_get ();
4618 if (gen_full_path_at (path
, dirfd
, pathname
))
4624 va_start (ap
, flags
);
4625 mode
= va_arg (ap
, mode_t
);
4627 return open (path
, flags
, mode
);
4629 __except (EFAULT
) {}
4635 faccessat (int dirfd
, const char *pathname
, int mode
, int flags
)
4642 char *path
= tp
.c_get ();
4643 if (!gen_full_path_at (path
, dirfd
, pathname
))
4645 if ((mode
& ~(F_OK
|R_OK
|W_OK
|X_OK
))
4646 || (flags
& ~(AT_SYMLINK_NOFOLLOW
|AT_EACCESS
)))
4650 fhandler_base
*fh
= build_fh_name (path
,
4651 (flags
& AT_SYMLINK_NOFOLLOW
4658 res
= fh
->fhaccess (mode
, !!(flags
& AT_EACCESS
));
4664 __except (EFAULT
) {}
4666 debug_printf ("returning %d", res
);
4671 fchmodat (int dirfd
, const char *pathname
, mode_t mode
, int flags
)
4676 if (flags
& ~AT_SYMLINK_NOFOLLOW
)
4681 char *path
= tp
.c_get ();
4682 if (gen_full_path_at (path
, dirfd
, pathname
))
4684 if (flags
& AT_SYMLINK_NOFOLLOW
)
4686 /* BSD has lchmod, but Linux does not. POSIX says
4687 AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks.
4688 Linux blindly fails even for non-symlinks, but we allow
4690 path_conv
pc (path
, PC_SYM_NOFOLLOW
, stat_suffixes
);
4691 if (pc
.issymlink ())
4693 set_errno (EOPNOTSUPP
);
4697 return chmod (path
, mode
);
4699 __except (EFAULT
) {}
4705 fchownat (int dirfd
, const char *pathname
, uid_t uid
, gid_t gid
, int flags
)
4710 if (flags
& ~(AT_SYMLINK_NOFOLLOW
| AT_EMPTY_PATH
))
4715 char *path
= tp
.c_get ();
4716 int res
= gen_full_path_at (path
, dirfd
, pathname
, flags
);
4719 if (!*pathname
) /* Implies AT_EMPTY_PATH */
4721 /* If dirfd refers to a symlink (which was necessarily opened with
4722 O_PATH | O_NOFOLLOW), we must operate directly on that symlink. */
4723 flags
= AT_SYMLINK_NOFOLLOW
;
4725 return chown_worker (path
, (flags
& AT_SYMLINK_NOFOLLOW
)
4726 ? PC_SYM_NOFOLLOW
: PC_SYM_FOLLOW
, uid
, gid
);
4728 __except (EFAULT
) {}
4734 fstatat (int dirfd
, const char *__restrict pathname
, struct stat
*__restrict st
,
4740 if (flags
& ~(AT_SYMLINK_NOFOLLOW
| AT_EMPTY_PATH
))
4745 char *path
= tp
.c_get ();
4746 int res
= gen_full_path_at (path
, dirfd
, pathname
, flags
);
4749 path_conv
pc (path
, ((flags
& AT_SYMLINK_NOFOLLOW
)
4750 ? PC_SYM_NOFOLLOW
: PC_SYM_FOLLOW
)
4751 | PC_POSIX
| PC_KEEP_HANDLE
, stat_suffixes
);
4752 return stat_worker (pc
, st
);
4754 __except (EFAULT
) {}
4759 extern int utimens_worker (path_conv
&, const struct timespec
*);
4762 utimensat (int dirfd
, const char *pathname
, const struct timespec
*times
,
4768 char *path
= tp
.c_get ();
4769 if (flags
& ~AT_SYMLINK_NOFOLLOW
)
4774 if (gen_full_path_at (path
, dirfd
, pathname
))
4776 path_conv
win32 (path
, PC_POSIX
| ((flags
& AT_SYMLINK_NOFOLLOW
)
4777 ? PC_SYM_NOFOLLOW
: PC_SYM_FOLLOW
),
4779 return utimens_worker (win32
, times
);
4781 __except (EFAULT
) {}
4787 futimesat (int dirfd
, const char *pathname
, const struct timeval times
[2])
4792 char *path
= tp
.c_get ();
4793 if (gen_full_path_at (path
, dirfd
, pathname
, _AT_NULL_PATHNAME_ALLOWED
))
4795 return utimes (path
, times
);
4797 __except (EFAULT
) {}
4803 linkat (int olddirfd
, const char *oldpathname
,
4804 int newdirfd
, const char *newpathname
,
4808 fhandler_base
*fh
= NULL
;
4812 if (flags
& ~(AT_SYMLINK_FOLLOW
| AT_EMPTY_PATH
))
4817 char *oldpath
= tp
.c_get ();
4818 if ((flags
& AT_EMPTY_PATH
) && oldpathname
&& oldpathname
[0] == '\0')
4820 /* Operate directly on olddirfd, which can be anything
4821 except a directory. */
4822 if (olddirfd
== AT_FDCWD
)
4827 cygheap_fdget
cfd (olddirfd
);
4830 if (cfd
->pc
.isdir ())
4836 flags
= 0; /* In case AT_SYMLINK_FOLLOW was set. */
4838 else if (gen_full_path_at (oldpath
, olddirfd
, oldpathname
))
4840 char *newpath
= tp
.c_get ();
4841 if (gen_full_path_at (newpath
, newdirfd
, newpathname
))
4843 if (flags
& AT_SYMLINK_FOLLOW
)
4845 path_conv
old_name (oldpath
,
4846 PC_SYM_FOLLOW
| PC_SYM_NOFOLLOW_PROCFD
| PC_POSIX
,
4850 set_errno (old_name
.error
);
4853 strcpy (oldpath
, old_name
.get_posix ());
4856 return fh
->link (newpath
);
4857 return link (oldpath
, newpath
);
4859 __except (EFAULT
) {}
4865 mkdirat (int dirfd
, const char *pathname
, mode_t mode
)
4870 char *path
= tp
.c_get ();
4871 if (gen_full_path_at (path
, dirfd
, pathname
))
4873 return mkdir (path
, mode
);
4875 __except (EFAULT
) {}
4881 mkfifoat (int dirfd
, const char *pathname
, mode_t mode
)
4886 char *path
= tp
.c_get ();
4887 if (gen_full_path_at (path
, dirfd
, pathname
))
4889 return mkfifo (path
, mode
);
4891 __except (EFAULT
) {}
4897 mknodat (int dirfd
, const char *pathname
, mode_t mode
, dev_t dev
)
4902 char *path
= tp
.c_get ();
4903 if (gen_full_path_at (path
, dirfd
, pathname
))
4905 return mknod (path
, mode
, dev
);
4907 __except (EFAULT
) {}
4913 readlinkat (int dirfd
, const char *__restrict pathname
, char *__restrict buf
,
4919 char *path
= tp
.c_get ();
4920 int save_errno
= errno
;
4921 int res
= gen_full_path_at (path
, dirfd
, pathname
);
4924 if (errno
!= ENOENT
&& errno
!= ENOTDIR
)
4926 /* pathname is an empty string. This is OK if dirfd refers
4927 to a symlink that was opened with O_PATH | O_NOFOLLOW.
4928 In this case, readlinkat operates on the symlink.
4929 Don't propagate errors from gen_full_path_at after this point. */
4931 cygheap_fdget
cfd (dirfd
);
4933 || (!(cfd
->issymlink ()
4934 && cfd
->get_flags () & O_PATH
4935 && cfd
->get_flags () & O_NOFOLLOW
)))
4940 strcpy (path
, cfd
->get_name ());
4942 return readlink (path
, buf
, bufsize
);
4944 __except (EFAULT
) {}
4950 renameat2 (int olddirfd
, const char *oldpathname
,
4951 int newdirfd
, const char *newpathname
, unsigned int flags
)
4956 char *oldpath
= tp
.c_get ();
4957 if (gen_full_path_at (oldpath
, olddirfd
, oldpathname
))
4959 char *newpath
= tp
.c_get ();
4960 if (gen_full_path_at (newpath
, newdirfd
, newpathname
))
4962 return rename2 (oldpath
, newpath
, flags
);
4964 __except (EFAULT
) {}
4970 renameat (int olddirfd
, const char *oldpathname
,
4971 int newdirfd
, const char *newpathname
)
4973 return renameat2 (olddirfd
, oldpathname
, newdirfd
, newpathname
, 0);
4977 scandirat (int dirfd
, const char *pathname
, struct dirent
***namelist
,
4978 int (*select
) (const struct dirent
*),
4979 int (*compar
) (const struct dirent
**, const struct dirent
**))
4984 char *path
= tp
.c_get ();
4985 if (gen_full_path_at (path
, dirfd
, pathname
))
4987 return scandir (path
, namelist
, select
, compar
);
4989 __except (EFAULT
) {}
4995 symlinkat (const char *oldpath
, int newdirfd
, const char *newpathname
)
5000 char *newpath
= tp
.c_get ();
5001 if (gen_full_path_at (newpath
, newdirfd
, newpathname
))
5003 return symlink (oldpath
, newpath
);
5005 __except (EFAULT
) {}
5011 unlinkat (int dirfd
, const char *pathname
, int flags
)
5016 if (flags
& ~AT_REMOVEDIR
)
5021 char *path
= tp
.c_get ();
5022 if (gen_full_path_at (path
, dirfd
, pathname
))
5024 return (flags
& AT_REMOVEDIR
) ? rmdir (path
) : unlink (path
);
5026 __except (EFAULT
) {}
5032 pipe_worker (int filedes
[2], unsigned int psize
, int mode
)
5034 fhandler_pipe
*fhs
[2];
5035 int res
= fhandler_pipe::create (fhs
, psize
, mode
);
5039 cygheap_fdnew
fdout (fdin
, false);
5040 char buf
[sizeof ("pipe:[9223372036854775807]")];
5041 __small_sprintf (buf
, "pipe:[%D]", fhs
[0]->get_plain_ino ());
5042 fhs
[0]->pc
.set_posix (buf
);
5043 __small_sprintf (buf
, "pipe:[%D]", fhs
[1]->get_plain_ino ());
5044 fhs
[1]->pc
.set_posix (buf
);
5053 /* MS compatible version of pipe. Hopefully nobody is using it... */
5055 _pipe (int filedes
[2], unsigned int psize
, int mode
)
5057 int res
= pipe_worker (filedes
, psize
, mode
);
5066 syscall_printf ("%R = _pipe([%d, %d], %u, %y)", res
, read
, write
, psize
, mode
);
5071 pipe (int filedes
[2])
5073 int res
= pipe_worker (filedes
, DEFAULT_PIPEBUFSIZE
, O_BINARY
);
5082 syscall_printf ("%R = pipe([%d, %d])", res
, read
, write
);
5087 pipe2 (int filedes
[2], int mode
)
5089 int res
= pipe_worker (filedes
, DEFAULT_PIPEBUFSIZE
, mode
);
5098 syscall_printf ("%R = pipe2([%d, %d], %y)", res
, read
, write
, mode
);
5105 char *dir
= getenv ("TMPDIR");
5108 int fd
= open (dir
, O_RDWR
| O_BINARY
| O_TMPFILE
, S_IRUSR
| S_IWUSR
);
5111 FILE *fp
= fdopen (fd
, "wb+");
5114 close (fd
); // ..will remove tmp file
5119 EXPORT_ALIAS (close
, _close
)
5120 EXPORT_ALIAS (fsync
, fdatasync
)
5121 EXPORT_ALIAS (isatty
, _isatty
)
5122 EXPORT_ALIAS (lseek
, _lseek
)
5123 EXPORT_ALIAS (open
, _open
)
5124 EXPORT_ALIAS (read
, _read
)
5125 EXPORT_ALIAS (utmpname
, utmpxname
)
5126 EXPORT_ALIAS (write
, _write
)