1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use os
::windows
::prelude
::*;
17 use io
::{self, Error, SeekFrom}
;
18 use libc
::{self, HANDLE}
;
20 use path
::{Path, PathBuf}
;
24 use sys
::handle
::Handle
;
26 use sys_common
::FromInner
;
29 pub struct File { handle: Handle }
32 data
: c
::WIN32_FILE_ATTRIBUTE_DATA
,
33 reparse_tag
: libc
::DWORD
,
36 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
38 Dir
, File
, Symlink
, ReparsePoint
, MountPoint
,
42 handle
: FindNextFileHandle
,
44 first
: Option
<libc
::WIN32_FIND_DATAW
>,
47 struct FindNextFileHandle(libc
::HANDLE
);
49 unsafe impl Send
for FindNextFileHandle {}
50 unsafe impl Sync
for FindNextFileHandle {}
54 data
: libc
::WIN32_FIND_DATAW
,
57 #[derive(Clone, Default)]
58 pub struct OpenOptions
{
64 desired_access
: Option
<libc
::DWORD
>,
65 share_mode
: Option
<libc
::DWORD
>,
66 creation_disposition
: Option
<libc
::DWORD
>,
67 flags_and_attributes
: Option
<libc
::DWORD
>,
68 security_attributes
: usize, // *mut T doesn't have a Default impl
71 #[derive(Clone, PartialEq, Eq, Debug)]
72 pub struct FilePermissions { attrs: libc::DWORD }
74 pub struct DirBuilder
;
76 impl Iterator
for ReadDir
{
77 type Item
= io
::Result
<DirEntry
>;
78 fn next(&mut self) -> Option
<io
::Result
<DirEntry
>> {
79 if let Some(first
) = self.first
.take() {
80 if let Some(e
) = DirEntry
::new(&self.root
, &first
) {
85 let mut wfd
= mem
::zeroed();
87 if libc
::FindNextFileW(self.handle
.0, &mut wfd
) == 0 {
88 if libc
::GetLastError() ==
89 c
::ERROR_NO_MORE_FILES
as libc
::DWORD
{
92 return Some(Err(Error
::last_os_error()))
95 if let Some(e
) = DirEntry
::new(&self.root
, &wfd
) {
103 impl Drop
for FindNextFileHandle
{
105 let r
= unsafe { libc::FindClose(self.0) }
;
106 debug_assert
!(r
!= 0);
111 fn new(root
: &Arc
<PathBuf
>, wfd
: &libc
::WIN32_FIND_DATAW
) -> Option
<DirEntry
> {
112 match &wfd
.cFileName
[0..3] {
113 // check for '.' and '..'
115 [46, 46, 0, ..] => return None
,
125 pub fn path(&self) -> PathBuf
{
126 self.root
.join(&self.file_name())
129 pub fn file_name(&self) -> OsString
{
130 let filename
= super::truncate_utf16_at_nul(&self.data
.cFileName
);
131 OsString
::from_wide(filename
)
134 pub fn file_type(&self) -> io
::Result
<FileType
> {
135 Ok(FileType
::new(self.data
.dwFileAttributes
,
136 /* reparse_tag = */ self.data
.dwReserved0
))
139 pub fn metadata(&self) -> io
::Result
<FileAttr
> {
141 data
: c
::WIN32_FILE_ATTRIBUTE_DATA
{
142 dwFileAttributes
: self.data
.dwFileAttributes
,
143 ftCreationTime
: self.data
.ftCreationTime
,
144 ftLastAccessTime
: self.data
.ftLastAccessTime
,
145 ftLastWriteTime
: self.data
.ftLastWriteTime
,
146 nFileSizeHigh
: self.data
.nFileSizeHigh
,
147 nFileSizeLow
: self.data
.nFileSizeLow
,
149 reparse_tag
: self.data
.dwReserved0
,
155 pub fn new() -> OpenOptions { Default::default() }
156 pub fn read(&mut self, read
: bool
) { self.read = read; }
157 pub fn write(&mut self, write
: bool
) { self.write = write; }
158 pub fn append(&mut self, append
: bool
) { self.append = append; }
159 pub fn create(&mut self, create
: bool
) { self.create = create; }
160 pub fn truncate(&mut self, truncate
: bool
) { self.truncate = truncate; }
161 pub fn creation_disposition(&mut self, val
: u32) {
162 self.creation_disposition
= Some(val
);
164 pub fn flags_and_attributes(&mut self, val
: u32) {
165 self.flags_and_attributes
= Some(val
);
167 pub fn desired_access(&mut self, val
: u32) {
168 self.desired_access
= Some(val
);
170 pub fn share_mode(&mut self, val
: u32) {
171 self.share_mode
= Some(val
);
173 pub fn security_attributes(&mut self, attrs
: libc
::LPSECURITY_ATTRIBUTES
) {
174 self.security_attributes
= attrs
as usize;
177 fn get_desired_access(&self) -> libc
::DWORD
{
178 self.desired_access
.unwrap_or({
179 let mut base
= if self.read {libc::FILE_GENERIC_READ}
else {0}
|
180 if self.write {libc::FILE_GENERIC_WRITE}
else {0}
;
182 base
&= !libc
::FILE_WRITE_DATA
;
183 base
|= libc
::FILE_APPEND_DATA
;
189 fn get_share_mode(&self) -> libc
::DWORD
{
190 // libuv has a good comment about this, but the basic idea is that
191 // we try to emulate unix semantics by enabling all sharing by
192 // allowing things such as deleting a file while it's still open.
193 self.share_mode
.unwrap_or(libc
::FILE_SHARE_READ
|
194 libc
::FILE_SHARE_WRITE
|
195 libc
::FILE_SHARE_DELETE
)
198 fn get_creation_disposition(&self) -> libc
::DWORD
{
199 self.creation_disposition
.unwrap_or({
200 match (self.create
, self.truncate
) {
201 (true, true) => libc
::CREATE_ALWAYS
,
202 (true, false) => libc
::OPEN_ALWAYS
,
203 (false, false) => libc
::OPEN_EXISTING
,
205 if self.write
&& !self.append
{
208 libc
::TRUNCATE_EXISTING
215 fn get_flags_and_attributes(&self) -> libc
::DWORD
{
216 self.flags_and_attributes
.unwrap_or(libc
::FILE_ATTRIBUTE_NORMAL
)
221 fn open_reparse_point(path
: &Path
, write
: bool
) -> io
::Result
<File
> {
222 let mut opts
= OpenOptions
::new();
225 opts
.flags_and_attributes(c
::FILE_FLAG_OPEN_REPARSE_POINT
|
226 c
::FILE_FLAG_BACKUP_SEMANTICS
);
227 File
::open(path
, &opts
)
230 pub fn open(path
: &Path
, opts
: &OpenOptions
) -> io
::Result
<File
> {
231 let path
= to_utf16(path
);
232 let handle
= unsafe {
233 libc
::CreateFileW(path
.as_ptr(),
234 opts
.get_desired_access(),
235 opts
.get_share_mode(),
236 opts
.security_attributes
as *mut _
,
237 opts
.get_creation_disposition(),
238 opts
.get_flags_and_attributes(),
241 if handle
== libc
::INVALID_HANDLE_VALUE
{
242 Err(Error
::last_os_error())
244 Ok(File { handle: Handle::new(handle) }
)
248 pub fn fsync(&self) -> io
::Result
<()> {
249 try
!(cvt(unsafe { libc::FlushFileBuffers(self.handle.raw()) }
));
253 pub fn datasync(&self) -> io
::Result
<()> { self.fsync() }
255 pub fn truncate(&self, size
: u64) -> io
::Result
<()> {
256 let mut info
= c
::FILE_END_OF_FILE_INFO
{
257 EndOfFile
: size
as libc
::LARGE_INTEGER
,
259 let size
= mem
::size_of_val(&info
);
261 c
::SetFileInformationByHandle(self.handle
.raw(),
262 c
::FileEndOfFileInfo
,
263 &mut info
as *mut _
as *mut _
,
269 pub fn file_attr(&self) -> io
::Result
<FileAttr
> {
271 let mut info
: c
::BY_HANDLE_FILE_INFORMATION
= mem
::zeroed();
272 try
!(cvt(c
::GetFileInformationByHandle(self.handle
.raw(),
274 let mut attr
= FileAttr
{
275 data
: c
::WIN32_FILE_ATTRIBUTE_DATA
{
276 dwFileAttributes
: info
.dwFileAttributes
,
277 ftCreationTime
: info
.ftCreationTime
,
278 ftLastAccessTime
: info
.ftLastAccessTime
,
279 ftLastWriteTime
: info
.ftLastWriteTime
,
280 nFileSizeHigh
: info
.nFileSizeHigh
,
281 nFileSizeLow
: info
.nFileSizeLow
,
285 if attr
.is_reparse_point() {
286 let mut b
= [0; c
::MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
287 if let Ok((_
, buf
)) = self.reparse_point(&mut b
) {
288 attr
.reparse_tag
= buf
.ReparseTag
;
295 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
296 self.handle
.read(buf
)
299 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
300 self.handle
.write(buf
)
303 pub fn flush(&self) -> io
::Result
<()> { Ok(()) }
305 pub fn seek(&self, pos
: SeekFrom
) -> io
::Result
<u64> {
306 let (whence
, pos
) = match pos
{
307 SeekFrom
::Start(n
) => (libc
::FILE_BEGIN
, n
as i64),
308 SeekFrom
::End(n
) => (libc
::FILE_END
, n
),
309 SeekFrom
::Current(n
) => (libc
::FILE_CURRENT
, n
),
311 let pos
= pos
as libc
::LARGE_INTEGER
;
314 libc
::SetFilePointerEx(self.handle
.raw(), pos
,
320 pub fn handle(&self) -> &Handle { &self.handle }
322 pub fn into_handle(self) -> Handle { self.handle }
324 fn reparse_point
<'a
>(&self,
325 space
: &'a
mut [u8; c
::MAXIMUM_REPARSE_DATA_BUFFER_SIZE
])
326 -> io
::Result
<(libc
::DWORD
, &'a c
::REPARSE_DATA_BUFFER
)> {
330 c
::DeviceIoControl(self.handle
.raw(),
331 c
::FSCTL_GET_REPARSE_POINT
,
334 space
.as_mut_ptr() as *mut _
,
335 space
.len() as libc
::DWORD
,
339 Ok((bytes
, &*(space
.as_ptr() as *const c
::REPARSE_DATA_BUFFER
)))
343 fn readlink(&self) -> io
::Result
<PathBuf
> {
344 let mut space
= [0u8; c
::MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
345 let (_bytes
, buf
) = try
!(self.reparse_point(&mut space
));
346 if buf
.ReparseTag
!= c
::IO_REPARSE_TAG_SYMLINK
{
347 return Err(io
::Error
::new(io
::ErrorKind
::Other
, "not a symlink"))
351 let info
: *const c
::SYMBOLIC_LINK_REPARSE_BUFFER
=
352 &buf
.rest
as *const _
as *const _
;
353 let path_buffer
= &(*info
).PathBuffer
as *const _
as *const u16;
354 let subst_off
= (*info
).SubstituteNameOffset
/ 2;
355 let subst_ptr
= path_buffer
.offset(subst_off
as isize);
356 let subst_len
= (*info
).SubstituteNameLength
/ 2;
357 let subst
= slice
::from_raw_parts(subst_ptr
, subst_len
as usize);
359 Ok(PathBuf
::from(OsString
::from_wide(subst
)))
364 impl FromInner
<libc
::HANDLE
> for File
{
365 fn from_inner(handle
: libc
::HANDLE
) -> File
{
366 File { handle: Handle::new(handle) }
370 impl fmt
::Debug
for File
{
371 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
372 // FIXME(#24570): add more info here (e.g. mode)
373 let mut b
= f
.debug_struct("File");
374 b
.field("handle", &self.handle
.raw());
375 if let Ok(path
) = get_path(&self) {
376 b
.field("path", &path
);
382 pub fn to_utf16(s
: &Path
) -> Vec
<u16> {
383 s
.as_os_str().encode_wide().chain(Some(0)).collect()
387 pub fn size(&self) -> u64 {
388 ((self.data
.nFileSizeHigh
as u64) << 32) | (self.data
.nFileSizeLow
as u64)
391 pub fn perm(&self) -> FilePermissions
{
392 FilePermissions { attrs: self.data.dwFileAttributes }
395 pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 }
397 pub fn file_type(&self) -> FileType
{
398 FileType
::new(self.data
.dwFileAttributes
, self.reparse_tag
)
401 pub fn created(&self) -> u64 { self.to_u64(&self.data.ftCreationTime) }
402 pub fn accessed(&self) -> u64 { self.to_u64(&self.data.ftLastAccessTime) }
403 pub fn modified(&self) -> u64 { self.to_u64(&self.data.ftLastWriteTime) }
405 fn to_u64(&self, ft
: &libc
::FILETIME
) -> u64 {
406 (ft
.dwLowDateTime
as u64) | ((ft
.dwHighDateTime
as u64) << 32)
409 fn is_reparse_point(&self) -> bool
{
410 self.data
.dwFileAttributes
& libc
::FILE_ATTRIBUTE_REPARSE_POINT
!= 0
414 impl FilePermissions
{
415 pub fn readonly(&self) -> bool
{
416 self.attrs
& c
::FILE_ATTRIBUTE_READONLY
!= 0
419 pub fn set_readonly(&mut self, readonly
: bool
) {
421 self.attrs
|= c
::FILE_ATTRIBUTE_READONLY
;
423 self.attrs
&= !c
::FILE_ATTRIBUTE_READONLY
;
429 fn new(attrs
: libc
::DWORD
, reparse_tag
: libc
::DWORD
) -> FileType
{
430 if attrs
& libc
::FILE_ATTRIBUTE_REPARSE_POINT
!= 0 {
432 c
::IO_REPARSE_TAG_SYMLINK
=> FileType
::Symlink
,
433 c
::IO_REPARSE_TAG_MOUNT_POINT
=> FileType
::MountPoint
,
434 _
=> FileType
::ReparsePoint
,
436 } else if attrs
& c
::FILE_ATTRIBUTE_DIRECTORY
!= 0 {
443 pub fn is_dir(&self) -> bool { *self == FileType::Dir }
444 pub fn is_file(&self) -> bool { *self == FileType::File }
445 pub fn is_symlink(&self) -> bool
{
446 *self == FileType
::Symlink
|| *self == FileType
::MountPoint
451 pub fn new() -> DirBuilder { DirBuilder }
453 pub fn mkdir(&self, p
: &Path
) -> io
::Result
<()> {
456 libc
::CreateDirectoryW(p
.as_ptr(), ptr
::null_mut())
462 pub fn readdir(p
: &Path
) -> io
::Result
<ReadDir
> {
463 let root
= p
.to_path_buf();
464 let star
= p
.join("*");
465 let path
= to_utf16(&star
);
468 let mut wfd
= mem
::zeroed();
469 let find_handle
= libc
::FindFirstFileW(path
.as_ptr(), &mut wfd
);
470 if find_handle
!= libc
::INVALID_HANDLE_VALUE
{
472 handle
: FindNextFileHandle(find_handle
),
473 root
: Arc
::new(root
),
477 Err(Error
::last_os_error())
482 pub fn unlink(p
: &Path
) -> io
::Result
<()> {
483 let p_utf16
= to_utf16(p
);
484 try
!(cvt(unsafe { libc::DeleteFileW(p_utf16.as_ptr()) }
));
488 pub fn rename(old
: &Path
, new
: &Path
) -> io
::Result
<()> {
489 let old
= to_utf16(old
);
490 let new
= to_utf16(new
);
492 libc
::MoveFileExW(old
.as_ptr(), new
.as_ptr(),
493 libc
::MOVEFILE_REPLACE_EXISTING
)
498 pub fn rmdir(p
: &Path
) -> io
::Result
<()> {
500 try
!(cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) }
));
504 pub fn readlink(p
: &Path
) -> io
::Result
<PathBuf
> {
505 let file
= try
!(File
::open_reparse_point(p
, false));
509 pub fn symlink(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
510 symlink_inner(src
, dst
, false)
513 pub fn symlink_inner(src
: &Path
, dst
: &Path
, dir
: bool
) -> io
::Result
<()> {
514 let src
= to_utf16(src
);
515 let dst
= to_utf16(dst
);
516 let flags
= if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY }
else { 0 }
;
518 c
::CreateSymbolicLinkW(dst
.as_ptr(), src
.as_ptr(), flags
) as libc
::BOOL
523 pub fn link(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
524 let src
= to_utf16(src
);
525 let dst
= to_utf16(dst
);
527 libc
::CreateHardLinkW(dst
.as_ptr(), src
.as_ptr(), ptr
::null_mut())
532 pub fn stat(p
: &Path
) -> io
::Result
<FileAttr
> {
533 let attr
= try
!(lstat(p
));
535 // If this is a reparse point, then we need to reopen the file to get the
536 // actual destination. We also pass the FILE_FLAG_BACKUP_SEMANTICS flag to
537 // ensure that we can open directories (this path may be a directory
538 // junction). Once the file is opened we ask the opened handle what its
539 // metadata information is.
540 if attr
.is_reparse_point() {
541 let mut opts
= OpenOptions
::new();
542 opts
.flags_and_attributes(c
::FILE_FLAG_BACKUP_SEMANTICS
);
543 let file
= try
!(File
::open(p
, &opts
));
550 pub fn lstat(p
: &Path
) -> io
::Result
<FileAttr
> {
551 let utf16
= to_utf16(p
);
553 let mut attr
: FileAttr
= mem
::zeroed();
554 try
!(cvt(c
::GetFileAttributesExW(utf16
.as_ptr(),
555 c
::GetFileExInfoStandard
,
556 &mut attr
.data
as *mut _
as *mut _
)));
557 if attr
.is_reparse_point() {
558 attr
.reparse_tag
= File
::open_reparse_point(p
, false).and_then(|f
| {
559 let mut b
= [0; c
::MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
560 f
.reparse_point(&mut b
).map(|(_
, b
)| b
.ReparseTag
)
567 pub fn set_perm(p
: &Path
, perm
: FilePermissions
) -> io
::Result
<()> {
570 try
!(cvt(c
::SetFileAttributesW(p
.as_ptr(), perm
.attrs
)));
575 pub fn utimes(p
: &Path
, atime
: u64, mtime
: u64) -> io
::Result
<()> {
576 let atime
= super::ms_to_filetime(atime
);
577 let mtime
= super::ms_to_filetime(mtime
);
579 let mut o
= OpenOptions
::new();
581 let f
= try
!(File
::open(p
, &o
));
583 c
::SetFileTime(f
.handle
.raw(), 0 as *const _
, &atime
, &mtime
)
588 fn get_path(f
: &File
) -> io
::Result
<PathBuf
> {
589 super::fill_utf16_buf(|buf
, sz
| unsafe {
590 c
::GetFinalPathNameByHandleW(f
.handle
.raw(), buf
, sz
,
591 libc
::VOLUME_NAME_DOS
)
593 PathBuf
::from(OsString
::from_wide(buf
))
597 pub fn canonicalize(p
: &Path
) -> io
::Result
<PathBuf
> {
598 let mut opts
= OpenOptions
::new();
600 let f
= try
!(File
::open(p
, &opts
));
604 pub fn copy(from
: &Path
, to
: &Path
) -> io
::Result
<u64> {
605 unsafe extern "system" fn callback(
606 _TotalFileSize
: libc
::LARGE_INTEGER
,
607 TotalBytesTransferred
: libc
::LARGE_INTEGER
,
608 _StreamSize
: libc
::LARGE_INTEGER
,
609 _StreamBytesTransferred
: libc
::LARGE_INTEGER
,
610 _dwStreamNumber
: libc
::DWORD
,
611 _dwCallbackReason
: libc
::DWORD
,
612 _hSourceFile
: HANDLE
,
613 _hDestinationFile
: HANDLE
,
614 lpData
: libc
::LPVOID
,
616 *(lpData
as *mut i64) = TotalBytesTransferred
;
619 let pfrom
= to_utf16(from
);
620 let pto
= to_utf16(to
);
623 c
::CopyFileExW(pfrom
.as_ptr(), pto
.as_ptr(), Some(callback
),
624 &mut size
as *mut _
as *mut _
, ptr
::null_mut(), 0)
630 fn directory_junctions_are_directories() {
633 use rand
::{self, StdRng, Rng}
;
636 ($e
:expr
) => (match $e
{
638 Err(e
) => panic
!("{} failed with: {}", stringify
!($e
), e
),
642 let d
= DirBuilder
::new();
643 let p
= env
::temp_dir();
644 let mut r
= rand
::thread_rng();
645 let ret
= p
.join(&format
!("rust-{}", r
.next_u32()));
646 let foo
= ret
.join("foo");
647 let bar
= ret
.join("bar");
652 t
!(create_junction(&bar
, &foo
));
653 let metadata
= stat(&bar
);
654 t
!(delete_junction(&bar
));
660 let metadata
= t
!(metadata
);
661 assert
!(metadata
.file_type().is_dir());
663 // Creating a directory junction on windows involves dealing with reparse
664 // points and the DeviceIoControl function, and this code is a skeleton of
665 // what can be found here:
667 // http://www.flexhex.com/docs/articles/hard-links.phtml
668 fn create_junction(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
669 let f
= try
!(opendir(src
, true));
670 let h
= f
.handle().raw();
673 let mut data
= [0u8; c
::MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
674 let mut db
= data
.as_mut_ptr()
675 as *mut c
::REPARSE_MOUNTPOINT_DATA_BUFFER
;
676 let mut buf
= &mut (*db
).ReparseTarget
as *mut _
;
679 let v
= v
.iter().map(|x
| *x
as u16);
680 for c
in v
.chain(dst
.as_os_str().encode_wide()) {
686 (*db
).ReparseTag
= c
::IO_REPARSE_TAG_MOUNT_POINT
;
687 (*db
).ReparseTargetMaximumLength
= (i
* 2) as libc
::WORD
;
688 (*db
).ReparseTargetLength
= ((i
- 1) * 2) as libc
::WORD
;
689 (*db
).ReparseDataLength
=
690 (*db
).ReparseTargetLength
as libc
::DWORD
+ 12;
693 cvt(c
::DeviceIoControl(h
as *mut _
,
694 c
::FSCTL_SET_REPARSE_POINT
,
695 data
.as_ptr() as *mut _
,
696 (*db
).ReparseDataLength
+ 8,
699 0 as *mut _
)).map(|_
| ())
703 fn opendir(p
: &Path
, write
: bool
) -> io
::Result
<File
> {
705 let mut token
= 0 as *mut _
;
706 let mut tp
: c
::TOKEN_PRIVILEGES
= mem
::zeroed();
707 try
!(cvt(c
::OpenProcessToken(c
::GetCurrentProcess(),
708 c
::TOKEN_ADJUST_PRIVILEGES
,
710 let name
: &OsStr
= if write
{
711 "SeRestorePrivilege".as_ref()
713 "SeBackupPrivilege".as_ref()
715 let name
= name
.encode_wide().chain(Some(0)).collect
::<Vec
<_
>>();
716 try
!(cvt(c
::LookupPrivilegeValueW(0 as *const _
,
718 &mut tp
.Privileges
[0].Luid
)));
719 tp
.PrivilegeCount
= 1;
720 tp
.Privileges
[0].Attributes
= c
::SE_PRIVILEGE_ENABLED
;
721 let size
= mem
::size_of
::<c
::TOKEN_PRIVILEGES
>() as libc
::DWORD
;
722 try
!(cvt(c
::AdjustTokenPrivileges(token
, libc
::FALSE
, &mut tp
, size
,
723 0 as *mut _
, 0 as *mut _
)));
724 try
!(cvt(libc
::CloseHandle(token
)));
726 File
::open_reparse_point(p
, write
)
730 fn delete_junction(p
: &Path
) -> io
::Result
<()> {
732 let f
= try
!(opendir(p
, true));
733 let h
= f
.handle().raw();
734 let mut data
= [0u8; c
::MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
735 let mut db
= data
.as_mut_ptr()
736 as *mut c
::REPARSE_MOUNTPOINT_DATA_BUFFER
;
737 (*db
).ReparseTag
= c
::IO_REPARSE_TAG_MOUNT_POINT
;
739 cvt(c
::DeviceIoControl(h
as *mut _
,
740 c
::FSCTL_DELETE_REPARSE_POINT
,
741 data
.as_ptr() as *mut _
,
742 (*db
).ReparseDataLength
+ 8,
745 0 as *mut _
)).map(|_
| ())