| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:async'; | |
| import 'dart:io'; | |
| /// What type of permission is granted to a file based on file permission roles. | |
| enum _FilePermission { | |
| execute, | |
| // Although these two values are unused, their positions in the enum are | |
| // meaningful. | |
| write, // ignore: unused_field | |
| read, // ignore: unused_field | |
| setGid, | |
| setUid, | |
| sticky, | |
| } | |
| /// What type of role is assigned to a file. | |
| enum _FilePermissionRole { | |
| world, | |
| group, | |
| user, | |
| } | |
| /// Returns whether file [stat] has [permission] for a [role] type. | |
| bool _hasPermission( | |
| FileStat stat, | |
| _FilePermission permission, { | |
| _FilePermissionRole role = _FilePermissionRole.world, | |
| }) { | |
| final index = _permissionBitIndex(permission, role); | |
| return (stat.mode & (1 << index)) != 0; | |
| } | |
| int _permissionBitIndex(_FilePermission permission, _FilePermissionRole role) => | |
| switch (permission) { | |
| _FilePermission.setUid => 11, | |
| _FilePermission.setGid => 10, | |
| _FilePermission.sticky => 9, | |
| _ => (role.index * 3) + permission.index | |
| }; | |
| /// Returns whether [path] is considered an executable file on this OS. | |
| /// | |
| /// May optionally define how to implement [getStat] or whether to execute based | |
| /// on whether this is the windows platform ([isWindows]) - if not set it is | |
| /// automatically extracted from `dart:io#Platform`. | |
| /// | |
| /// **NOTE**: On windows this always returns `true`. | |
| FutureOr<bool> isExecutable( | |
| String path, { | |
| bool? isWindows, | |
| FutureOr<FileStat> Function(String path) getStat = FileStat.stat, | |
| }) { | |
| // Windows has no concept of executable. | |
| if (isWindows ?? Platform.isWindows) return true; | |
| final stat = getStat(path); | |
| if (stat is FileStat) { | |
| return _isExecutable(stat); | |
| } | |
| return stat.then(_isExecutable); | |
| } | |
| bool _isExecutable(FileStat stat) => | |
| stat.type == FileSystemEntityType.file && | |
| _FilePermissionRole.values.any( | |
| (role) => _hasPermission(stat, _FilePermission.execute, role: role)); |