mirror of
https://github.com/dart-lang/sdk
synced 2024-10-01 19:29:09 +00:00
Add PathExistsException and PathAccessException FileSystemException subclasses.
Bug:https://github.com/dart-lang/sdk/issues/50436 Change-Id: Ie2954f162c01189cd0d817f58606529acdc13416 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/269240 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Brian Quinlan <bquinlan@google.com>
This commit is contained in:
parent
cef6e432eb
commit
8df8bbf0de
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -124,11 +124,15 @@
|
|||
|
||||
[#49878]: https://github.com/dart-lang/sdk/issues/49878
|
||||
|
||||
- When a `dart:io` operation fails because a file is not found, throw
|
||||
`PathNotFoundException`, a `FileSystemException` subclass, to make it
|
||||
easier to handle "file not found" errors.
|
||||
- Adds three new `FileSystemException` subclasses to handle common error
|
||||
cases:
|
||||
|
||||
- `PathAccessException`: The necessary access rights are not available.
|
||||
- `PathExistsException`: The path being created already exists.
|
||||
- `PathNotFoundException`: The path being accessed does not exist.
|
||||
|
||||
[#12461]: https://github.com/dart-lang/sdk/issues/12461
|
||||
[#50436]: https://github.com/dart-lang/sdk/issues/50436
|
||||
|
||||
#### `dart:isolate`
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ abstract class _FileSystemWatcher {
|
|||
_newWatcher();
|
||||
} on dynamic catch (e) {
|
||||
_broadcastController.addError(FileSystemException._fromOSError(
|
||||
e, "Failed to initialize file system entity watcher", null));
|
||||
e, "Failed to initialize file system entity watcher", _path));
|
||||
_broadcastController.close();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -17,17 +17,30 @@ const int _osErrorResponseMessage = 2;
|
|||
|
||||
// POSIX error codes.
|
||||
// See https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
|
||||
const _ePerm = 1;
|
||||
const _eNoEnt = 2;
|
||||
const _eAccess = 13;
|
||||
const _eExist = 17;
|
||||
|
||||
// Windows error codes.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
|
||||
const _errorFileNotFound = 2;
|
||||
const _errorPathNotFound = 3;
|
||||
const _errorAccessDenied = 5;
|
||||
const _errorInvalidDrive = 15;
|
||||
const _errorCurrentDirectory = 16;
|
||||
const _errorNoMoreFiles = 18;
|
||||
const _errorWriteProtect = 19;
|
||||
const _errorBadLength = 24;
|
||||
const _errorSharingViolation = 32;
|
||||
const _errorLockViolation = 33;
|
||||
const _errorBadNetpath = 53;
|
||||
const _errorNetworkAccessDenied = 65;
|
||||
const _errorBadNetName = 67;
|
||||
const _errorFileExists = 80;
|
||||
const _errorDriveLocked = 108;
|
||||
const _errorBadPathName = 161;
|
||||
const _errorAlreadyExists = 183;
|
||||
const _errorFilenameExedRange = 206;
|
||||
|
||||
/// If the [response] is an error, throws an [Exception] or an [Error].
|
||||
|
|
|
@ -222,7 +222,7 @@ abstract class File implements FileSystemEntity {
|
|||
/// non-existing parent paths are created first.
|
||||
///
|
||||
/// If [exclusive] is `true` and to-be-created file already exists, this
|
||||
/// operation completes the future with a [FileSystemException].
|
||||
/// operation completes the future with a [PathExistsException].
|
||||
///
|
||||
/// If [exclusive] is `false`, existing files are left untouched by [create].
|
||||
/// Calling [create] on an existing file still might fail if there are
|
||||
|
@ -900,9 +900,21 @@ class FileSystemException implements IOException {
|
|||
/// will be returned.
|
||||
@pragma("vm:entry-point")
|
||||
factory FileSystemException._fromOSError(
|
||||
OSError err, String message, String? path) {
|
||||
OSError err, String message, String path) {
|
||||
if (Platform.isWindows) {
|
||||
switch (err.errorCode) {
|
||||
case _errorAccessDenied:
|
||||
case _errorCurrentDirectory:
|
||||
case _errorWriteProtect:
|
||||
case _errorBadLength:
|
||||
case _errorSharingViolation:
|
||||
case _errorLockViolation:
|
||||
case _errorNetworkAccessDenied:
|
||||
case _errorDriveLocked:
|
||||
return PathAccessException(path, err, message);
|
||||
case _errorFileExists:
|
||||
case _errorAlreadyExists:
|
||||
return PathExistsException(path, err, message);
|
||||
case _errorFileNotFound:
|
||||
case _errorPathNotFound:
|
||||
case _errorInvalidDrive:
|
||||
|
@ -911,14 +923,19 @@ class FileSystemException implements IOException {
|
|||
case _errorBadNetName:
|
||||
case _errorBadPathName:
|
||||
case _errorFilenameExedRange:
|
||||
return PathNotFoundException(path!, err, message);
|
||||
return PathNotFoundException(path, err, message);
|
||||
default:
|
||||
return FileSystemException(message, path, err);
|
||||
}
|
||||
} else {
|
||||
switch (err.errorCode) {
|
||||
case _ePerm:
|
||||
case _eAccess:
|
||||
return PathAccessException(path, err, message);
|
||||
case _eExist:
|
||||
return PathExistsException(path, err, message);
|
||||
case _eNoEnt:
|
||||
return PathNotFoundException(path!, err, message);
|
||||
return PathNotFoundException(path, err, message);
|
||||
default:
|
||||
return FileSystemException(message, path, err);
|
||||
}
|
||||
|
@ -952,6 +969,24 @@ class FileSystemException implements IOException {
|
|||
}
|
||||
}
|
||||
|
||||
/// Exception thrown when a file operation fails because the necessary access
|
||||
/// rights are not available.
|
||||
class PathAccessException extends FileSystemException {
|
||||
const PathAccessException(String path, OSError osError, [String message = ""])
|
||||
: super(message, path, osError);
|
||||
|
||||
String toString() => _toStringHelper("PathAccessException");
|
||||
}
|
||||
|
||||
/// Exception thrown when a file operation fails because the target path
|
||||
/// already exists.
|
||||
class PathExistsException extends FileSystemException {
|
||||
const PathExistsException(String path, OSError osError, [String message = ""])
|
||||
: super(message, path, osError);
|
||||
|
||||
String toString() => _toStringHelper("PathExistsException");
|
||||
}
|
||||
|
||||
/// Exception thrown when a file operation fails because a file or
|
||||
/// directory does not exist.
|
||||
class PathNotFoundException extends FileSystemException {
|
||||
|
@ -959,9 +994,7 @@ class PathNotFoundException extends FileSystemException {
|
|||
[String message = ""])
|
||||
: super(message, path, osError);
|
||||
|
||||
String toString() {
|
||||
return _toStringHelper("PathNotFoundException");
|
||||
}
|
||||
String toString() => _toStringHelper("PathNotFoundException");
|
||||
}
|
||||
|
||||
/// The "read" end of an [Pipe] created by [Pipe.create].
|
||||
|
|
|
@ -436,6 +436,31 @@ testReadSyncClosedFile() {
|
|||
});
|
||||
}
|
||||
|
||||
void testCreateExistingFile() {
|
||||
createTestFile((file, done) {
|
||||
Expect.throws<PathExistsException>(() => file.createSync(exclusive: true));
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
void testDeleteDirectoryWithoutPermissions() {
|
||||
if (Platform.isMacOS) {
|
||||
createTestFile((file, done) async {
|
||||
Process.runSync('chflags', ['uchg', file.path]);
|
||||
Expect.throws<PathAccessException>(file.deleteSync);
|
||||
Process.runSync('chflags', ['nouchg', file.path]);
|
||||
done();
|
||||
});
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
final oldCurrent = Directory.current;
|
||||
Directory.current = tempDir();
|
||||
// Cannot delete the current working directory in Windows.
|
||||
Expect.throws<PathAccessException>(Directory.current.deleteSync);
|
||||
Directory.current = oldCurrent;
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
testOpenBlankFilename();
|
||||
testOpenNonExistent();
|
||||
|
@ -453,4 +478,6 @@ main() {
|
|||
testRepeatedlyCloseFile();
|
||||
testRepeatedlyCloseFileSync();
|
||||
testReadSyncClosedFile();
|
||||
testCreateExistingFile();
|
||||
testDeleteDirectoryWithoutPermissions();
|
||||
}
|
||||
|
|
|
@ -438,6 +438,31 @@ testReadSyncClosedFile() {
|
|||
});
|
||||
}
|
||||
|
||||
void testCreateExistingFile() {
|
||||
createTestFile((file, done) {
|
||||
Expect.throws<PathExistsException>(() => file.createSync(exclusive: true));
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
void testDeleteDirectoryWithoutPermissions() {
|
||||
if (Platform.isMacOS) {
|
||||
createTestFile((file, done) async {
|
||||
Process.runSync('chflags', ['uchg', file.path]);
|
||||
Expect.throws<PathAccessException>(file.deleteSync);
|
||||
Process.runSync('chflags', ['nouchg', file.path]);
|
||||
done();
|
||||
});
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
final oldCurrent = Directory.current;
|
||||
Directory.current = tempDir();
|
||||
// Cannot delete the current working directory in Windows.
|
||||
Expect.throws<PathAccessException>(Directory.current.deleteSync);
|
||||
Directory.current = oldCurrent;
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
testOpenBlankFilename();
|
||||
testOpenNonExistent();
|
||||
|
@ -455,4 +480,6 @@ main() {
|
|||
testRepeatedlyCloseFile();
|
||||
testRepeatedlyCloseFileSync();
|
||||
testReadSyncClosedFile();
|
||||
testCreateExistingFile();
|
||||
testDeleteDirectoryWithoutPermissions();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue