Skip to content

Commit 2daf248

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 2daf248

2 files changed

Lines changed: 351 additions & 1 deletion

File tree

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,95 @@ 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+
pub trait PermissionsExt: Sealed {
425+
/// Returns the file attribute bits.
426+
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
427+
fn file_attributes(&self) -> u32;
428+
429+
// QUESTION: Should this be renamed as from_file_attributes()?
430+
// and modify the signature of set_file_attributes() to take a
431+
// &mut self like how unix uses `set_mode()`?
432+
// (Note to self: if we do the above, I need to make changes to
433+
// the doc comments).
434+
/// Sets the file attribute bits.
435+
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
436+
fn set_file_attributes(mask: u32) -> Self;
437+
}
438+
439+
impl PermissionsExt for Permissions {
440+
fn file_attributes(&self) -> u32 {
441+
self.as_inner().file_attributes()
442+
}
443+
444+
fn set_file_attributes(mask: u32) -> Self {
445+
Permissions::from_inner(FromInner::from_inner(mask))
446+
}
447+
}
448+
360449
/// Windows-specific extensions to [`fs::Metadata`].
361450
///
362451
/// The data members that this trait exposes correspond to the members

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

Lines changed: 262 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,11 +1162,272 @@ impl FilePermissions {
11621162

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

11721433
impl FileTimes {

0 commit comments

Comments
 (0)