mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-18 20:39:33 +08:00
* fhandler_disk_file.cc (fhandler_disk_file::link): Use FILE_ANY_ACCESS.
(fhandler_base::utimes_fs): Fix white space. (fhandler_disk_file::lock): Remove 9x blurb from comment. (fhandler_disk_file::mkdir): Use NtCreateFile/NtClose instead of CreateDirectoryA. (fhandler_disk_file::rmdir): Accommodate changes to unlink_nt. Simplify post-delete SMB-related tests. Use NtQueryAttributesFile instead of GetFileAttributes. * ntdll.h (STATUS_DIRECTORY_NOT_EMPTY): Define. (NtQueryAttributesFile): Declare. * syscalls.cc (unlink_nt): Return NTSTATUS. Drop setattrs parameter. Never use FILE_DELETE_ON_CLOSE, always use NtSetInformationFile(FileDispositionInformation) instead. Check for R/O attributes and open file with FILE_WRITE_ATTRIBUTES access if any of them are set. Remove R/O attributes before marking for delete if necessary. Revert them afterwards if necessary. (unlink): Accommodate changes to unlink_nt.
This commit is contained in:
parent
4368984a7b
commit
ed7ec849f6
@ -1,3 +1,23 @@
|
||||
2007-07-29 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* fhandler_disk_file.cc (fhandler_disk_file::link): Use FILE_ANY_ACCESS.
|
||||
(fhandler_base::utimes_fs): Fix white space.
|
||||
(fhandler_disk_file::lock): Remove 9x blurb from comment.
|
||||
(fhandler_disk_file::mkdir): Use NtCreateFile/NtClose instead of
|
||||
CreateDirectoryA.
|
||||
(fhandler_disk_file::rmdir): Accommodate changes to unlink_nt.
|
||||
Simplify post-delete SMB-related tests. Use NtQueryAttributesFile
|
||||
instead of GetFileAttributes.
|
||||
* ntdll.h (STATUS_DIRECTORY_NOT_EMPTY): Define.
|
||||
(NtQueryAttributesFile): Declare.
|
||||
* syscalls.cc (unlink_nt): Return NTSTATUS. Drop setattrs parameter.
|
||||
Never use FILE_DELETE_ON_CLOSE, always use
|
||||
NtSetInformationFile(FileDispositionInformation) instead.
|
||||
Check for R/O attributes and open file with FILE_WRITE_ATTRIBUTES
|
||||
access if any of them are set. Remove R/O attributes before
|
||||
marking for delete if necessary. Revert them afterwards if necessary.
|
||||
(unlink): Accommodate changes to unlink_nt.
|
||||
|
||||
2007-07-29 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* fhandler_disk_file.cc: Use get_handle throughout.
|
||||
|
@ -1094,7 +1094,8 @@ fhandler_disk_file::link (const char *newpath)
|
||||
NTSTATUS status;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
IO_STATUS_BLOCK io;
|
||||
status = NtOpenFile (&fh, 0, pc.get_object_attr (attr, sec_none_nih), &io,
|
||||
status = NtOpenFile (&fh, FILE_ANY_ACCESS,
|
||||
pc.get_object_attr (attr, sec_none_nih), &io,
|
||||
FILE_SHARE_VALID_FLAGS,
|
||||
FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
|
||||
if (!NT_SUCCESS (status))
|
||||
@ -1182,7 +1183,7 @@ fhandler_base::utimes_fs (const struct timeval *tvp)
|
||||
IO_STATUS_BLOCK io;
|
||||
FILE_BASIC_INFORMATION fbi;
|
||||
fbi.CreationTime.QuadPart = 0LL;
|
||||
fbi.LastAccessTime= lastaccess;
|
||||
fbi.LastAccessTime = lastaccess;
|
||||
fbi.LastWriteTime = lastwrite;
|
||||
fbi.ChangeTime.QuadPart = 0LL;
|
||||
fbi.FileAttributes = 0;
|
||||
@ -1318,11 +1319,7 @@ fhandler_disk_file::pwrite (void *buf, size_t count, _off64_t offset)
|
||||
/* FIXME: The correct way to do this to get POSIX locking semantics is to
|
||||
keep a linked list of posix lock requests and map them into Win32 locks.
|
||||
he problem is that Win32 does not deal correctly with overlapping lock
|
||||
requests. Also another pain is that Win95 doesn't do non-blocking or
|
||||
non-exclusive locks at all. For '95 just convert all lock requests into
|
||||
blocking,exclusive locks. This shouldn't break many apps but denying all
|
||||
locking would. For now just convert to Win32 locks and hope for
|
||||
the best. */
|
||||
requests. */
|
||||
|
||||
int
|
||||
fhandler_disk_file::lock (int cmd, struct __flock64 *fl)
|
||||
@ -1471,17 +1468,31 @@ fhandler_disk_file::mkdir (mode_t mode)
|
||||
set_security_attribute (S_IFDIR | ((mode & 07777) & ~cygheap->umask),
|
||||
&sa, sd);
|
||||
|
||||
if (CreateDirectoryA (get_win32_name (), &sa))
|
||||
{
|
||||
NTSTATUS status;
|
||||
HANDLE dir;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
IO_STATUS_BLOCK io;
|
||||
ULONG fattr = FILE_ATTRIBUTE_DIRECTORY;
|
||||
#ifdef HIDDEN_DOT_FILES
|
||||
char *c = strrchr (real_dir.get_win32 (), '\\');
|
||||
if ((c && c[1] == '.') || *get_win32_name () == '.')
|
||||
SetFileAttributes (get_win32_name (), FILE_ATTRIBUTE_HIDDEN);
|
||||
UNICODE_STRING basename;
|
||||
|
||||
RtlSplitUnicodePath (pc.get_nt_native_path (), NULL, &basename);
|
||||
if (basename.Buffer[0] == L'.')
|
||||
fattr |= FILE_ATTRIBUTE_HIDDEN;
|
||||
#endif
|
||||
status = NtCreateFile (&dir, FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
||||
pc.get_object_attr (attr, sa), &io, NULL,
|
||||
fattr, FILE_SHARE_VALID_FLAGS, FILE_CREATE,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
|
||||
| FILE_OPEN_FOR_BACKUP_INTENT,
|
||||
NULL, 0);
|
||||
if (NT_SUCCESS (status))
|
||||
{
|
||||
NtClose (dir);
|
||||
res = 0;
|
||||
}
|
||||
else
|
||||
__seterrno ();
|
||||
__seterrno_from_nt_status (status);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -1489,47 +1500,43 @@ fhandler_disk_file::mkdir (mode_t mode)
|
||||
int
|
||||
fhandler_disk_file::rmdir ()
|
||||
{
|
||||
extern DWORD unlink_nt (path_conv &win32_name, bool setattrs);
|
||||
|
||||
int res = -1;
|
||||
extern NTSTATUS unlink_nt (path_conv &pc);
|
||||
|
||||
if (!pc.isdir ())
|
||||
{
|
||||
set_errno (ENOTDIR);
|
||||
return -1;
|
||||
}
|
||||
/* Even own directories can't be removed if R/O attribute is set. */
|
||||
if (pc.has_attribute (FILE_ATTRIBUTE_READONLY))
|
||||
SetFileAttributes (get_win32_name (),
|
||||
(DWORD) pc & ~FILE_ATTRIBUTE_READONLY);
|
||||
|
||||
DWORD err, att = 0;
|
||||
|
||||
int rc = !(err = unlink_nt (pc, pc.has_attribute (FILE_ATTRIBUTE_READONLY)));
|
||||
if (err)
|
||||
SetLastError (err);
|
||||
|
||||
if (isremote () && exists ())
|
||||
att = GetFileAttributes (get_win32_name ());
|
||||
|
||||
/* Sometimes smb indicates failure when it really succeeds, so check for
|
||||
this case specifically. */
|
||||
if (rc || att == INVALID_FILE_ATTRIBUTES)
|
||||
if (!pc.exists ())
|
||||
{
|
||||
/* RemoveDirectory on a samba drive doesn't return an error if the
|
||||
directory can't be removed because it's not empty. Checking for
|
||||
existence afterwards keeps us informed about success. */
|
||||
if (!isremote () || att == INVALID_FILE_ATTRIBUTES)
|
||||
return 0;
|
||||
|
||||
err = ERROR_DIR_NOT_EMPTY;
|
||||
set_errno (ENOENT);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
err = GetLastError ();
|
||||
|
||||
__seterrno_from_win_error (err);
|
||||
NTSTATUS status = unlink_nt (pc);
|
||||
|
||||
return res;
|
||||
/* Check for existence of remote dirs after trying to delete them.
|
||||
Two reasons:
|
||||
- Sometimes SMB indicates failure when it really succeeds.
|
||||
- Removeing a directory on a samba drive doesn't return an error if the
|
||||
directory can't be removed because it's not empty. */
|
||||
if (isremote ())
|
||||
{
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
FILE_BASIC_INFORMATION fbi;
|
||||
|
||||
if (NT_SUCCESS (NtQueryAttributesFile
|
||||
(pc.get_object_attr (attr, sec_none_nih), &fbi)))
|
||||
status = STATUS_DIRECTORY_NOT_EMPTY;
|
||||
else
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
__seterrno_from_nt_status (status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is the minimal number of entries which fit into the readdir cache.
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056)
|
||||
#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1)
|
||||
#define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xc00000bb)
|
||||
#define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xc0000101)
|
||||
#define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106)
|
||||
#define STATUS_INVALID_LEVEL ((NTSTATUS) 0xc0000148)
|
||||
#define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006)
|
||||
@ -752,6 +753,8 @@ extern "C"
|
||||
BOOLEAN, PULONG, PULONG);
|
||||
NTSTATUS NTAPI NtQueryEaFile (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG,
|
||||
BOOLEAN, PVOID, ULONG, PULONG, BOOLEAN);
|
||||
NTSTATUS NTAPI NtQueryAttributesFile (POBJECT_ATTRIBUTES,
|
||||
PFILE_BASIC_INFORMATION);
|
||||
NTSTATUS NTAPI NtQueryFullAttributesFile (POBJECT_ATTRIBUTES,
|
||||
PFILE_NETWORK_OPEN_INFORMATION);
|
||||
NTSTATUS NTAPI NtQueryInformationFile (HANDLE, PIO_STATUS_BLOCK, PVOID,
|
||||
|
@ -228,43 +228,31 @@ try_to_bin (path_conv &win32_path, HANDLE h)
|
||||
recycler, status);
|
||||
}
|
||||
|
||||
DWORD
|
||||
unlink_nt (path_conv &win32_name, bool setattrs)
|
||||
NTSTATUS
|
||||
unlink_nt (path_conv &pc)
|
||||
{
|
||||
NTSTATUS status;
|
||||
HANDLE fh;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
IO_STATUS_BLOCK io;
|
||||
NTSTATUS status;
|
||||
HANDLE h;
|
||||
FILE_BASIC_INFORMATION fbi;
|
||||
|
||||
ACCESS_MASK access = DELETE;
|
||||
/* If one of the R/O attributes is set, we have to open the file with
|
||||
FILE_WRITE_ATTRIBUTES to be able to remove these flags before trying
|
||||
to delete it. */
|
||||
if (pc.file_attributes () & (FILE_ATTRIBUTE_READONLY
|
||||
| FILE_ATTRIBUTE_SYSTEM
|
||||
| FILE_ATTRIBUTE_HIDDEN))
|
||||
access |= FILE_WRITE_ATTRIBUTES;
|
||||
|
||||
ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
|
||||
/* Don't open directories with "delete on close", because the NT internal
|
||||
semantic is apparently different from the file semantic. If a directory
|
||||
is opened "delete on close", the rename operation in try_to_bin fails
|
||||
with STATUS_ACCESS_DENIED. So directories must be deleted using
|
||||
NtSetInformationFile, class FileDispositionInformation, which works fine.
|
||||
|
||||
Correction, moving a directory opened with delete-on-close fails ONLY
|
||||
on XP. Note to myself: Never take anything for granted on Windows!
|
||||
|
||||
Don't try "delete on close" if the file is on a remote share. If two
|
||||
processes have open handles on a file and one of them calls unlink, then
|
||||
it happens that the file is removed from the remote share even though the
|
||||
other process still has an open handle. This other process than gets
|
||||
Win32 error 59, ERROR_UNEXP_NET_ERR when trying to access the file. That
|
||||
does not happen when using NtSetInformationFile, class
|
||||
FileDispositionInformation, which nicely succeeds but still, the file is
|
||||
available for the other process. Microsoft KB 837665 describes this
|
||||
problem as a bug in 2K3, but I have reproduced it on shares on Samba
|
||||
2.2.8, Samba 3.0.2, NT4SP6, XP64SP1 and 2K3 and in all cases, DeleteFile
|
||||
works, "delete on close" does not. */
|
||||
if (!win32_name.isdir () && !win32_name.isremote ())
|
||||
flags |= FILE_DELETE_ON_CLOSE;
|
||||
/* Add the reparse point flag to native symlinks, otherwise we remove the
|
||||
target, not the symlink. */
|
||||
if (win32_name.is_rep_symlink ())
|
||||
if (pc.is_rep_symlink ())
|
||||
flags |= FILE_OPEN_REPARSE_POINT;
|
||||
|
||||
win32_name.get_object_attr (attr, sec_none_nih);
|
||||
pc.get_object_attr (attr, sec_none_nih);
|
||||
/* First try to open the file with sharing not allowed. If the file
|
||||
has an open handle on it, this will fail. That indicates that the
|
||||
file has to be moved to the recycle bin so that it actually disappears
|
||||
@ -272,13 +260,13 @@ unlink_nt (path_conv &win32_name, bool setattrs)
|
||||
doesn't fail, the file is not in use and by simply closing the handle
|
||||
the file will disappear. */
|
||||
bool move_to_bin = false;
|
||||
status = NtOpenFile (&h, DELETE, &attr, &io, 0, flags);
|
||||
status = NtOpenFile (&fh, access, &attr, &io, 0, flags);
|
||||
if (status == STATUS_SHARING_VIOLATION)
|
||||
{
|
||||
move_to_bin = true;
|
||||
if (!win32_name.isdir () || win32_name.isremote ())
|
||||
status = NtOpenFile (&h, DELETE, &attr, &io, FILE_SHARE_VALID_FLAGS,
|
||||
flags);
|
||||
if (!pc.isdir () || pc.isremote ())
|
||||
status = NtOpenFile (&fh, access, &attr, &io,
|
||||
FILE_SHARE_VALID_FLAGS, flags);
|
||||
else
|
||||
{
|
||||
/* It's getting tricky. The directory is opened in some process,
|
||||
@ -293,7 +281,7 @@ unlink_nt (path_conv &win32_name, bool setattrs)
|
||||
and another one. Three entries means, not empty. This doesn't
|
||||
work for the root directory of a drive, but the root dir can
|
||||
neither be deleted, nor moved anyway. */
|
||||
status = NtOpenFile (&h, DELETE | SYNCHRONIZE | FILE_LIST_DIRECTORY,
|
||||
status = NtOpenFile (&fh, access | FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
||||
&attr, &io, FILE_SHARE_VALID_FLAGS,
|
||||
flags | FILE_SYNCHRONOUS_IO_NONALERT);
|
||||
if (NT_SUCCESS (status))
|
||||
@ -302,15 +290,15 @@ unlink_nt (path_conv &win32_name, bool setattrs)
|
||||
+ 3 * NAME_MAX * sizeof (WCHAR);
|
||||
PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION)
|
||||
alloca (bufsiz);
|
||||
status = NtQueryDirectoryFile (h, NULL, NULL, 0, &io, pfni,
|
||||
status = NtQueryDirectoryFile (fh, NULL, NULL, 0, &io, pfni,
|
||||
bufsiz, FileNamesInformation,
|
||||
FALSE, NULL, TRUE);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
NtClose (h);
|
||||
NtClose (fh);
|
||||
syscall_printf ("Checking if directory is empty failed, "
|
||||
"status = %p", status);
|
||||
return RtlNtStatusToDosError (status);
|
||||
return status;
|
||||
}
|
||||
int cnt = 1;
|
||||
while (pfni->NextEntryOffset)
|
||||
@ -321,9 +309,9 @@ unlink_nt (path_conv &win32_name, bool setattrs)
|
||||
}
|
||||
if (cnt > 2)
|
||||
{
|
||||
NtClose (h);
|
||||
NtClose (fh);
|
||||
syscall_printf ("Directory not empty");
|
||||
return ERROR_DIR_NOT_EMPTY;
|
||||
return STATUS_DIRECTORY_NOT_EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -332,46 +320,46 @@ unlink_nt (path_conv &win32_name, bool setattrs)
|
||||
{
|
||||
if (status == STATUS_DELETE_PENDING)
|
||||
{
|
||||
syscall_printf ("Delete already pending, status = %p", status);
|
||||
syscall_printf ("Delete already pending");
|
||||
return 0;
|
||||
}
|
||||
syscall_printf ("Opening file for delete failed, status = %p", status);
|
||||
return RtlNtStatusToDosError (status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (setattrs)
|
||||
SetFileAttributes (win32_name, (DWORD) win32_name);
|
||||
if (move_to_bin && !pc.isremote ())
|
||||
try_to_bin (pc, fh);
|
||||
|
||||
if (move_to_bin && !win32_name.isremote ())
|
||||
try_to_bin (win32_name, h);
|
||||
|
||||
DWORD lasterr = 0;
|
||||
|
||||
if (win32_name.isdir () || win32_name.isremote ())
|
||||
/* Get rid of read-only attributes. */
|
||||
if (access & FILE_WRITE_ATTRIBUTES)
|
||||
{
|
||||
FILE_DISPOSITION_INFORMATION disp = { TRUE };
|
||||
status = NtSetInformationFile (h, &io, &disp, sizeof disp,
|
||||
FileDispositionInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
syscall_printf ("Setting delete disposition failed, status = %p",
|
||||
status);
|
||||
lasterr = RtlNtStatusToDosError (status);
|
||||
FILE_BASIC_INFORMATION fbi;
|
||||
fbi.CreationTime.QuadPart = fbi.LastAccessTime.QuadPart =
|
||||
fbi.LastWriteTime.QuadPart = fbi.ChangeTime.QuadPart = 0LL;
|
||||
fbi.FileAttributes = pc.file_attributes ()
|
||||
& ~(FILE_ATTRIBUTE_READONLY
|
||||
| FILE_ATTRIBUTE_SYSTEM
|
||||
| FILE_ATTRIBUTE_HIDDEN);
|
||||
NtSetInformationFile (fh, &io, &fbi, sizeof fbi, FileBasicInformation);
|
||||
}
|
||||
|
||||
FILE_DISPOSITION_INFORMATION disp = { TRUE };
|
||||
status = NtSetInformationFile (fh, &io, &disp, sizeof disp,
|
||||
FileDispositionInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
syscall_printf ("Setting delete disposition failed, status = %p", status);
|
||||
/* Restore R/O attributes. */
|
||||
if (access & FILE_WRITE_ATTRIBUTES)
|
||||
{
|
||||
fbi.FileAttributes = pc.file_attributes ();
|
||||
NtSetInformationFile (fh, &io, &fbi, sizeof fbi,
|
||||
FileBasicInformation);
|
||||
}
|
||||
}
|
||||
|
||||
status = NtClose (h);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
/* Maybe that's really paranoid, but not being able to close the file
|
||||
also means that deleting fails. */
|
||||
syscall_printf ("%p = NtClose (%p)", status, h);
|
||||
if (!lasterr)
|
||||
lasterr = RtlNtStatusToDosError (status);
|
||||
}
|
||||
|
||||
syscall_printf ("Deleting succeeded");
|
||||
return lasterr;
|
||||
NtClose (fh);
|
||||
return status;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
@ -379,7 +367,7 @@ unlink (const char *ourname)
|
||||
{
|
||||
int res = -1;
|
||||
DWORD devn;
|
||||
DWORD lasterr;
|
||||
NTSTATUS status;
|
||||
|
||||
path_conv win32_name (ourname, PC_SYM_NOFOLLOW,
|
||||
transparent_exe ? stat_suffixes : NULL);
|
||||
@ -412,30 +400,13 @@ unlink (const char *ourname)
|
||||
goto done;
|
||||
}
|
||||
|
||||
bool setattrs;
|
||||
if (!((DWORD) win32_name & (FILE_ATTRIBUTE_READONLY
|
||||
| FILE_ATTRIBUTE_SYSTEM
|
||||
| FILE_ATTRIBUTE_HIDDEN)))
|
||||
setattrs = false;
|
||||
else
|
||||
{
|
||||
/* Allow us to delete even if read-only */
|
||||
setattrs = SetFileAttributes (win32_name,
|
||||
(DWORD) win32_name
|
||||
& ~(FILE_ATTRIBUTE_READONLY
|
||||
| FILE_ATTRIBUTE_SYSTEM
|
||||
| FILE_ATTRIBUTE_HIDDEN));
|
||||
}
|
||||
|
||||
lasterr = unlink_nt (win32_name, setattrs);
|
||||
if (!lasterr)
|
||||
status = unlink_nt (win32_name);
|
||||
if (NT_SUCCESS (status))
|
||||
res = 0;
|
||||
else
|
||||
{
|
||||
SetFileAttributes (win32_name, (DWORD) win32_name);
|
||||
|
||||
/* FIXME: Can we get rid of the delqueue now? */
|
||||
if (lasterr == ERROR_SHARING_VIOLATION)
|
||||
if (status == STATUS_SHARING_VIOLATION)
|
||||
{
|
||||
/* Add file to the "to be deleted" queue. */
|
||||
syscall_printf ("Sharing violation, couldn't delete file");
|
||||
@ -443,7 +414,7 @@ unlink (const char *ourname)
|
||||
res = 0;
|
||||
}
|
||||
else
|
||||
__seterrno_from_win_error (lasterr);
|
||||
__seterrno_from_nt_status (status);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -1467,7 +1438,7 @@ rename (const char *oldpath, const char *newpath)
|
||||
else if (MoveFileEx (real_old.get_win32 (), real_new.get_win32 (),
|
||||
MOVEFILE_REPLACE_EXISTING))
|
||||
res = 0;
|
||||
else if ((lasterr = unlink_nt (real_new, false)))
|
||||
else if ((lasterr = unlink_nt (real_new)))
|
||||
{
|
||||
SetLastError (lasterr);
|
||||
syscall_printf ("Can't remove target file/dir, %E");
|
||||
@ -1503,7 +1474,7 @@ done:
|
||||
if (lnk_suffix)
|
||||
{
|
||||
*lnk_suffix = '.';
|
||||
unlink_nt (real_new, false);
|
||||
unlink_nt (real_new);
|
||||
}
|
||||
/* Shortcut hack, No. 3, part 2 */
|
||||
/* If a file with the given name exists, it must be deleted after the
|
||||
@ -1515,7 +1486,7 @@ done:
|
||||
{
|
||||
lnk_suffix = strrchr (real_new.get_win32 (), '.');
|
||||
*lnk_suffix = '\0';
|
||||
unlink_nt (real_new, false);
|
||||
unlink_nt (real_new);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user