Skip to content

Commit 696ce60

Browse files
committed
Implemented PermissionsExt to Windows and added some file attribute private methods in FilePermissions struct (to be decided in PR whether to use or remove)
1 parent 0376d43 commit 696ce60

2 files changed

Lines changed: 356 additions & 3 deletions

File tree

library/std/src/os/windows/fs.rs

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
55
#![stable(feature = "rust1", since = "1.0.0")]
66

7-
use crate::fs::{self, Metadata, OpenOptions};
7+
use crate::fs::{self, Metadata, OpenOptions, Permissions};
88
use crate::io::BorrowedCursor;
99
use crate::path::Path;
1010
use crate::sealed::Sealed;
11-
use crate::sys::{AsInner, AsInnerMut, IntoInner};
11+
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
1212
use crate::time::SystemTime;
1313
use crate::{io, sys};
1414

@@ -357,6 +357,97 @@ impl OpenOptionsExt for OpenOptions {
357357
}
358358
}
359359

360+
/// Windows-specific extensions to [`fs::Permissions`].
361+
/// # Examples
362+
///
363+
/// ```no_run
364+
/// use std::fs::{File, Permissions};
365+
/// use std::io::{ErrorKind, Result as IoResult};
366+
/// use std::os::windows::fs::PermissionsExt;
367+
///
368+
/// fn main() -> IoResult<()> {
369+
/// let name = "test_file_for_permissions";
370+
///
371+
/// // make sure file does not exist
372+
/// let _ = std::fs::remove_file(name);
373+
/// assert_eq!(
374+
/// File::open(name).unwrap_err().kind(),
375+
/// ErrorKind::NotFound,
376+
/// "file already exists"
377+
/// );
378+
///
379+
/// // readonly and hidden file attributes that we
380+
/// // want to add to existing file
381+
/// let my_file_attr = 0x1 | 0x2;
382+
///
383+
/// // create new file with specified permissions
384+
/// {
385+
/// let file = File::create(name)?;
386+
/// let mut permissions = file.metadata()?.permissions();
387+
/// eprintln!("Current file attributes: {:o}", permissions.file_attributes());
388+
///
389+
/// // make sure new permissions are not already set
390+
/// assert!(
391+
/// permissions.file_attributes() & my_file_attr != my_file_attr,
392+
/// "file attributes already set"
393+
/// );
394+
///
395+
/// // or use `set_file_attributes` to construct a new Permissions struct
396+
/// permissions = Permissions::set_file_attributes(permissions.file_attributes() | my_file_attr);
397+
///
398+
/// // write new permissions to file
399+
/// file.set_permissions(permissions)?;
400+
/// }
401+
///
402+
/// let permissions = File::open(name)?.metadata()?.permissions();
403+
/// eprintln!("New file attributes: {:o}", permissions.mode());
404+
///
405+
/// // assert new file attributes were set
406+
/// assert_eq!(
407+
/// permissions.mode() & my_file_attr,
408+
/// my_file_attr,
409+
/// "new file attributes not set"
410+
/// );
411+
/// Ok(())
412+
/// }
413+
/// ```
414+
///
415+
/// ```no_run
416+
/// use std::fs::Permissions;
417+
/// use std::os::windows::fs::PermissionsExt;
418+
///
419+
/// // system and archive file attributes
420+
/// let my_file_attr = 0x4 | 0x20;
421+
/// let mut permissions = Permissions::set_file_attributes(my_file_attr);
422+
/// assert_eq!(permissions.mode(), my_file_attr);
423+
/// ```
424+
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
425+
pub trait PermissionsExt {
426+
/// Returns the file attribute bits.
427+
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
428+
fn file_attributes(&self) -> u32;
429+
430+
// QUESTION: Should this be renamed as from_file_attributes()?
431+
// and modify the signature of set_file_attributes() to take a
432+
// &mut self like how unix uses `set_mode()`?
433+
// (Note to self: if we do the above, I need to make changes to
434+
// the doc comments).
435+
/// Sets the file attribute bits.
436+
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
437+
fn set_file_attributes(mask: u32) -> Self;
438+
}
439+
440+
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
441+
impl PermissionsExt for Permissions {
442+
fn file_attributes(&self) -> u32 {
443+
self.as_inner().file_attributes()
444+
}
445+
446+
fn set_file_attributes(mask: u32) -> Self {
447+
Permissions::from_inner(FromInner::from_inner(mask))
448+
}
449+
}
450+
360451
/// Windows-specific extensions to [`fs::Metadata`].
361452
///
362453
/// The data members that this trait exposes correspond to the members

library/std/src/sys/fs/windows.rs

Lines changed: 263 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1155,18 +1155,280 @@ fn to_u64(ft: &c::FILETIME) -> u64 {
11551155
(ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32)
11561156
}
11571157

1158+
#[allow(dead_code)]
11581159
impl FilePermissions {
11591160
pub fn readonly(&self) -> bool {
11601161
self.attrs & c::FILE_ATTRIBUTE_READONLY != 0
11611162
}
11621163

11631164
pub fn set_readonly(&mut self, readonly: bool) {
11641165
if readonly {
1165-
self.attrs |= c::FILE_ATTRIBUTE_READONLY;
1166+
// According to SetFileAttributes, any other values
1167+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1168+
if self.normal() {
1169+
self.attrs = c::FILE_ATTRIBUTE_READONLY;
1170+
} else {
1171+
self.attrs |= c::FILE_ATTRIBUTE_READONLY;
1172+
}
11661173
} else {
11671174
self.attrs &= !c::FILE_ATTRIBUTE_READONLY;
11681175
}
11691176
}
1177+
1178+
fn hidden(&self) -> bool {
1179+
self.attrs & c::FILE_ATTRIBUTE_HIDDEN != 0
1180+
}
1181+
1182+
fn set_hidden(&mut self, hidden: bool) {
1183+
if hidden {
1184+
// According to SetFileAttributes, any other values
1185+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1186+
if self.normal() {
1187+
self.attrs = c::FILE_ATTRIBUTE_HIDDEN;
1188+
} else {
1189+
self.attrs |= c::FILE_ATTRIBUTE_HIDDEN;
1190+
}
1191+
} else {
1192+
self.attrs &= !c::FILE_ATTRIBUTE_HIDDEN;
1193+
}
1194+
}
1195+
1196+
fn system(&self) -> bool {
1197+
self.attrs & c::FILE_ATTRIBUTE_SYSTEM != 0
1198+
}
1199+
1200+
fn set_system(&mut self, system: bool) {
1201+
if system {
1202+
// According to SetFileAttributes, any other values
1203+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1204+
if self.normal() {
1205+
self.attrs = c::FILE_ATTRIBUTE_SYSTEM;
1206+
} else {
1207+
self.attrs |= c::FILE_ATTRIBUTE_SYSTEM;
1208+
}
1209+
} else {
1210+
self.attrs &= !c::FILE_ATTRIBUTE_SYSTEM;
1211+
}
1212+
}
1213+
1214+
fn archive(&self) -> bool {
1215+
self.attrs & c::FILE_ATTRIBUTE_ARCHIVE != 0
1216+
}
1217+
1218+
fn set_archive(&mut self, archive: bool) {
1219+
if archive {
1220+
// According to SetFileAttributes, any other values
1221+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1222+
if self.normal() {
1223+
self.attrs = c::FILE_ATTRIBUTE_ARCHIVE;
1224+
} else {
1225+
self.attrs |= c::FILE_ATTRIBUTE_ARCHIVE;
1226+
}
1227+
} else {
1228+
self.attrs &= !c::FILE_ATTRIBUTE_ARCHIVE;
1229+
}
1230+
}
1231+
1232+
// This file attribute is only valid when used alone
1233+
// There should be no other file attribute set.
1234+
fn normal(&self) -> bool {
1235+
self.attrs == c::FILE_ATTRIBUTE_NORMAL
1236+
}
1237+
1238+
// According to Microsoft docs here:
1239+
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
1240+
// This file attribute is valid only when used alone.
1241+
// The SetFileAttributes seems to recognize this as a
1242+
// reset/zero out flag.
1243+
fn set_normal(&mut self, normal: bool) {
1244+
if normal {
1245+
self.attrs = c::FILE_ATTRIBUTE_NORMAL;
1246+
}
1247+
}
1248+
1249+
fn temporary(&self) -> bool {
1250+
self.attrs & c::FILE_ATTRIBUTE_TEMPORARY != 0
1251+
}
1252+
1253+
fn set_temporary(&mut self, temporary: bool) {
1254+
if temporary {
1255+
// According to SetFileAttributes, any other values
1256+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1257+
if self.normal() {
1258+
self.attrs = c::FILE_ATTRIBUTE_TEMPORARY;
1259+
} else {
1260+
self.attrs |= c::FILE_ATTRIBUTE_TEMPORARY;
1261+
}
1262+
} else {
1263+
self.attrs &= !c::FILE_ATTRIBUTE_TEMPORARY;
1264+
}
1265+
}
1266+
1267+
fn offline(&self) -> bool {
1268+
self.attrs & c::FILE_ATTRIBUTE_OFFLINE != 0
1269+
}
1270+
1271+
fn set_offline(&mut self, offline: bool) {
1272+
if offline {
1273+
// According to SetFileAttributes, any other values
1274+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1275+
if self.normal() {
1276+
self.attrs = c::FILE_ATTRIBUTE_OFFLINE;
1277+
} else {
1278+
self.attrs |= c::FILE_ATTRIBUTE_OFFLINE;
1279+
}
1280+
} else {
1281+
self.attrs &= !c::FILE_ATTRIBUTE_OFFLINE;
1282+
}
1283+
}
1284+
1285+
fn not_content_indexed(&self) -> bool {
1286+
self.attrs & c::FILE_ATTRIBUTE_OFFLINE != 0
1287+
}
1288+
1289+
fn set_not_content_indexed(&mut self, not_content_indexed: bool) {
1290+
if not_content_indexed {
1291+
// According to SetFileAttributes, any other values
1292+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1293+
if self.normal() {
1294+
self.attrs = c::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1295+
} else {
1296+
self.attrs |= c::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1297+
}
1298+
} else {
1299+
self.attrs &= !c::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1300+
}
1301+
}
1302+
1303+
// This flag is not supported until Windows 8 and Windows Server 2012
1304+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1305+
// Windows Vista, Windows Server 2003 and Windows XP)
1306+
fn integrity_stream(&self) -> bool {
1307+
self.attrs & c::FILE_ATTRIBUTE_INTEGRITY_STREAM != 0
1308+
}
1309+
1310+
// This flag is not supported until Windows 8 and Windows Server 2012
1311+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1312+
// Windows Vista, Windows Server 2003 and Windows XP)
1313+
fn set_integrity_stream(&mut self, integrity_stream: bool) {
1314+
if integrity_stream {
1315+
// According to SetFileAttributes, any other values
1316+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1317+
if self.normal() {
1318+
self.attrs = c::FILE_ATTRIBUTE_INTEGRITY_STREAM;
1319+
} else {
1320+
self.attrs |= c::FILE_ATTRIBUTE_INTEGRITY_STREAM;
1321+
}
1322+
} else {
1323+
self.attrs &= !c::FILE_ATTRIBUTE_INTEGRITY_STREAM;
1324+
}
1325+
}
1326+
1327+
// This flag is not supported until Windows 8 and Windows Server 2012
1328+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1329+
// Windows Vista, Windows Server 2003 and Windows XP)
1330+
fn no_scrub_data(&self) -> bool {
1331+
self.attrs & c::FILE_ATTRIBUTE_NO_SCRUB_DATA != 0
1332+
}
1333+
1334+
// This flag is not supported until Windows 8 and Windows Server 2012
1335+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1336+
// Windows Vista, Windows Server 2003 and Windows XP)
1337+
fn set_no_scrub_data(&mut self, no_scrub_data: bool) {
1338+
if no_scrub_data {
1339+
// According to SetFileAttributes, any other values
1340+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1341+
if self.normal() {
1342+
self.attrs = c::FILE_ATTRIBUTE_NO_SCRUB_DATA;
1343+
} else {
1344+
self.attrs |= c::FILE_ATTRIBUTE_NO_SCRUB_DATA;
1345+
}
1346+
} else {
1347+
self.attrs &= !c::FILE_ATTRIBUTE_NO_SCRUB_DATA;
1348+
}
1349+
}
1350+
1351+
// This flag was introduced in Windows 10, version 1703
1352+
fn pinned(&self) -> bool {
1353+
self.attrs & c::FILE_ATTRIBUTE_PINNED != 0
1354+
}
1355+
1356+
// This flag was introduced in Windows 10, version 1703
1357+
fn set_pinned(&mut self, pinned: bool) {
1358+
if pinned {
1359+
// According to SetFileAttributes, any other values
1360+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1361+
if self.normal() {
1362+
self.attrs = c::FILE_ATTRIBUTE_PINNED;
1363+
} else {
1364+
self.attrs |= c::FILE_ATTRIBUTE_PINNED;
1365+
}
1366+
} else {
1367+
self.attrs &= !c::FILE_ATTRIBUTE_PINNED;
1368+
}
1369+
}
1370+
1371+
// This flag was introduced in Windows 10, version 1703
1372+
fn unpinned(&self) -> bool {
1373+
self.attrs & c::FILE_ATTRIBUTE_UNPINNED != 0
1374+
}
1375+
1376+
// This flag was introduced in Windows 10, version 1703
1377+
fn set_unpinned(&mut self, unpinned: bool) {
1378+
if unpinned {
1379+
// According to SetFileAttributes, any other values
1380+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1381+
if self.normal() {
1382+
self.attrs = c::FILE_ATTRIBUTE_UNPINNED;
1383+
} else {
1384+
self.attrs |= c::FILE_ATTRIBUTE_UNPINNED;
1385+
}
1386+
} else {
1387+
self.attrs &= !c::FILE_ATTRIBUTE_UNPINNED;
1388+
}
1389+
}
1390+
1391+
// We don't have a FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL (aka "SMR Blob")
1392+
// flag yet in `std/src/sys/pal/windows/c/windows_sys.rs`
1393+
// This is a flag that is settable by `attrib` command on Windows
1394+
// Note that this attribute was introduced in Windows 10, version unsure
1395+
// Also see
1396+
// - http://justsolve.archiveteam.org/wiki/DOS/Windows_file_attributes
1397+
// - https://superuser.com/questions/44812/windows-explorers-file-attribute-column-values
1398+
// fn strictly_sequential(&self) -> bool {
1399+
// self.attrs & c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL != 0
1400+
// }
1401+
1402+
// fn set_strictly_sequential(&mut self, pinned: bool) {
1403+
// if pinned {
1404+
// // According to SetFileAttributes, any other values
1405+
// // passed to this should override FILE_ATTRIBUTE_NORMAL
1406+
// if self.normal() {
1407+
// self.attrs = c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL;
1408+
// } else {
1409+
// self.attrs |= c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL;
1410+
// }
1411+
// } else {
1412+
// self.attrs &= !c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL;
1413+
// }
1414+
// }
1415+
1416+
// No set_recall_on_data_access because that's settable only by the
1417+
// OS (e.g. OneDrive filter driver)
1418+
// No encrypted, compressed, device, etc. setter attributes because
1419+
// reasons mentioned here: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesa
1420+
// However, should we have methods that sees if these attributes
1421+
// are set?
1422+
1423+
pub fn file_attributes(&self) -> u32 {
1424+
self.attrs as u32
1425+
}
1426+
}
1427+
1428+
impl FromInner<u32> for FilePermissions {
1429+
fn from_inner(attrs: u32) -> FilePermissions {
1430+
FilePermissions { attrs }
1431+
}
11701432
}
11711433

11721434
impl FileTimes {

0 commit comments

Comments
 (0)