Skip to content

Commit 00739a8

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 00739a8

2 files changed

Lines changed: 345 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 fs::Permissions {
440+
fn file_attributes(&self) {
441+
self.as_inner().attrs()
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: 256 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,11 +1162,266 @@ 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(&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(&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(&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(&self, normal: bool) {
1243+
self.attrs = c::FILE_ATTRIBUTE_NORMAL;
1244+
}
1245+
1246+
fn temporary(&self) -> bool {
1247+
self.attrs & c::FILE_ATTRIBUTE_TEMPORARY != 0
1248+
}
1249+
1250+
fn set_temporary(&self, temporary: bool) {
1251+
if temporary {
1252+
// According to SetFileAttributes, any other values
1253+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1254+
if self.normal() {
1255+
self.attrs = c::FILE_ATTRIBUTE_TEMPORARY;
1256+
} else {
1257+
self.attrs |= c::FILE_ATTRIBUTE_TEMPORARY;
1258+
}
1259+
} else {
1260+
self.attrs &= !c::FILE_ATTRIBUTE_TEMPORARY;
1261+
}
1262+
}
1263+
1264+
fn offline(&self) -> bool {
1265+
self.attrs & c::FILE_ATTRIBUTE_OFFLINE != 0
1266+
}
1267+
1268+
fn set_offline(&self, offline: bool) {
1269+
if offline {
1270+
// According to SetFileAttributes, any other values
1271+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1272+
if self.normal() {
1273+
self.attrs = c::FILE_ATTRIBUTE_OFFLINE;
1274+
} else {
1275+
self.attrs |= c::FILE_ATTRIBUTE_OFFLINE;
1276+
}
1277+
} else {
1278+
self.attrs &= !c::FILE_ATTRIBUTE_OFFLINE;
1279+
}
1280+
}
1281+
1282+
fn not_content_indexed(&self) -> bool {
1283+
self.attrs & c::FILE_ATTRIBUTE_OFFLINE != 0
1284+
}
1285+
1286+
fn set_not_content_indexed(&self, not_content_indexed: bool) {
1287+
if not_content_indexed {
1288+
// According to SetFileAttributes, any other values
1289+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1290+
if self.normal() {
1291+
self.attrs = c::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1292+
} else {
1293+
self.attrs |= c::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1294+
}
1295+
} else {
1296+
self.attrs &= !c::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1297+
}
1298+
}
1299+
1300+
// This flag is not supported until Windows 8 and Windows Server 2012
1301+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1302+
// Windows Vista, Windows Server 2003 and Windows XP)
1303+
fn integrity_stream(&self) -> bool {
1304+
self.attrs & c::FILE_ATTRIBUTE_INTEGRITY_STREAM != 0
1305+
}
1306+
1307+
// This flag is not supported until Windows 8 and Windows Server 2012
1308+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1309+
// Windows Vista, Windows Server 2003 and Windows XP)
1310+
fn set_integrity_stream(&self, integrity_stream: bool) {
1311+
if integrity_stream {
1312+
// According to SetFileAttributes, any other values
1313+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1314+
if self.normal() {
1315+
self.attrs = c::FILE_ATTRIBUTE_INTEGRITY_STREAM;
1316+
} else {
1317+
self.attrs |= c::FILE_ATTRIBUTE_INTEGRITY_STREAM;
1318+
}
1319+
} else {
1320+
self.attrs &= !c::FILE_ATTRIBUTE_INTEGRITY_STREAM;
1321+
}
1322+
}
1323+
1324+
// This flag is not supported until Windows 8 and Windows Server 2012
1325+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1326+
// Windows Vista, Windows Server 2003 and Windows XP)
1327+
fn no_scrub_data(&self) -> bool {
1328+
self.attrs & c::FILE_ATTRIBUTE_NO_SCRUB_DATA != 0
1329+
}
1330+
1331+
// This flag is not supported until Windows 8 and Windows Server 2012
1332+
// (not supported on Windows Server 2008 R2, Windows 7, Windows Server 2008,
1333+
// Windows Vista, Windows Server 2003 and Windows XP)
1334+
fn set_no_scrub_data(&self, no_scrub_data: bool) {
1335+
if integrity_stream {
1336+
// According to SetFileAttributes, any other values
1337+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1338+
if self.normal() {
1339+
self.attrs = c::FILE_ATTRIBUTE_NO_SCRUB_DATA;
1340+
} else {
1341+
self.attrs |= c::FILE_ATTRIBUTE_NO_SCRUB_DATA;
1342+
}
1343+
} else {
1344+
self.attrs &= !c::FILE_ATTRIBUTE_NO_SCRUB_DATA;
1345+
}
1346+
}
1347+
1348+
// This flag was introduced in Windows 10, version 1703
1349+
fn pinned(&self) -> bool {
1350+
self.attrs & c::FILE_ATTRIBUTE_PINNED != 0
1351+
}
1352+
1353+
// This flag was introduced in Windows 10, version 1703
1354+
fn set_pinned(&self, pinned: bool) {
1355+
if pinned {
1356+
// According to SetFileAttributes, any other values
1357+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1358+
if self.normal() {
1359+
self.attrs = c::FILE_ATTRIBUTE_PINNED;
1360+
} else {
1361+
self.attrs |= c::FILE_ATTRIBUTE_PINNED;
1362+
}
1363+
} else {
1364+
self.attrs &= !c::FILE_ATTRIBUTE_PINNED;
1365+
}
1366+
}
1367+
1368+
// This flag was introduced in Windows 10, version 1703
1369+
fn unpinned(&self) -> bool {
1370+
self.attrs & c::FILE_ATTRIBUTE_UNPINNED != 0
1371+
}
1372+
1373+
// This flag was introduced in Windows 10, version 1703
1374+
fn set_unpinned(&self, unpinned: bool) {
1375+
if unpinned {
1376+
// According to SetFileAttributes, any other values
1377+
// passed to this should override FILE_ATTRIBUTE_NORMAL
1378+
if self.normal() {
1379+
self.attrs = c::FILE_ATTRIBUTE_UNPINNED;
1380+
} else {
1381+
self.attrs |= c::FILE_ATTRIBUTE_UNPINNED;
1382+
}
1383+
} else {
1384+
self.attrs &= !c::FILE_ATTRIBUTE_UNPINNED;
1385+
}
1386+
}
1387+
1388+
// We don't have a FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL (aka "SMR Blob")
1389+
// flag yet in `std/src/sys/pal/windows/c/windows_sys.rs`
1390+
// This is a flag that is settable by `attrib` command on Windows
1391+
// Note that this attribute was introduced in Windows 10, version unsure
1392+
// Also see
1393+
// - http://justsolve.archiveteam.org/wiki/DOS/Windows_file_attributes
1394+
// - https://superuser.com/questions/44812/windows-explorers-file-attribute-column-values
1395+
// fn strictly_sequential(&self) -> bool {
1396+
// self.attrs & c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL != 0
1397+
// }
1398+
1399+
// fn set_strictly_sequential(&self, pinned: bool) {
1400+
// if pinned {
1401+
// // According to SetFileAttributes, any other values
1402+
// // passed to this should override FILE_ATTRIBUTE_NORMAL
1403+
// if self.normal() {
1404+
// self.attrs = c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL;
1405+
// } else {
1406+
// self.attrs |= c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL;
1407+
// }
1408+
// } else {
1409+
// self.attrs &= !c::FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL;
1410+
// }
1411+
// }
1412+
1413+
// No set_recall_on_data_access because that's settable only by the
1414+
// OS (e.g. OneDrive filter driver)
1415+
// No encrypted, compressed, device, etc. setter attributes because
1416+
// reasons mentioned here: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesa
1417+
// However, should we have methods that sees if these attributes
1418+
// are set?
1419+
}
1420+
1421+
impl FromInner<u32> for FilePermissions {
1422+
fn from_inner(attr: u32) -> FilePermissions {
1423+
FilePermissions { attr }
1424+
}
11701425
}
11711426

11721427
impl FileTimes {

0 commit comments

Comments
 (0)