Skip to content

Commit dcdc798

Browse files
authored
Support long paths and getting/setting the current working directory (#236)
1 parent b4408c0 commit dcdc798

30 files changed

+813
-105
lines changed

pkgs/io_file/constants.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353
"O_TRUNC",
5454
"O_WRONLY"
5555
],
56+
"<limits.h>": [
57+
"PATH_MAX"
58+
],
5659
"<dirent.h>" : [
5760
"DT_BLK",
5861
"DT_CHR",

pkgs/io_file/dart_test.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
concurrency: 1
2+
reporter: compact
3+
test-randomize-ordering-seed: random

pkgs/io_file/lib/src/constant_bindings.g.dart

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkgs/io_file/lib/src/constants.g.dart

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkgs/io_file/lib/src/file_system.dart

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,13 @@ class WriteMode {
132132
///
133133
/// TODO(brianquinlan): Far now, this class is not meant to be implemented,
134134
/// extended outside of this package. Clarify somewhere that people implementing
135-
/// this class should reach out to be.
135+
/// this class should reach out to me.
136+
///
137+
/// On Windows, paths refering to objects in the
138+
/// [win32 device namespace](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#win32-device-namespaces),
139+
/// such as named pipes, physical disks, and serial comnmunications ports
140+
/// (e.g. 'COM1'), must be prefixed with `r'\\.\'`. For example, `'COM1'` would
141+
/// be refered to by the path `r'\\.\COM1'`.
136142
@sealed
137143
abstract class FileSystem {
138144
/// Create a directory at the given path.
@@ -186,6 +192,19 @@ abstract class FileSystem {
186192
/// written to is to attempt to open it.
187193
Metadata metadata(String path);
188194

195+
/// The current
196+
/// [working directory](https://en.wikipedia.org/wiki/Working_directory) of
197+
/// the Dart process.
198+
///
199+
/// Setting the value of this field will change the working directory for
200+
/// *all* isolates.
201+
///
202+
/// On Windows, unless
203+
/// [long paths are enabled](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation),
204+
/// the maximum length of the [currentDirectory] path is 260 characters.
205+
String get currentDirectory;
206+
set currentDirectory(String path);
207+
189208
/// Deletes the directory at the given path.
190209
///
191210
/// If `path` is a directory but the directory is not empty, then

pkgs/io_file/lib/src/libc_bindings.g.dart

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkgs/io_file/lib/src/vm_posix_file_system.dart

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const _nanosecondsPerSecond = 1000000000;
2626
bool _isDotOrDotDot(Pointer<Char> s) => // ord('.') == 46
2727
s[0] == 46 && ((s[1] == 0) || (s[1] == 46 && s[2] == 0));
2828

29-
Exception _getError(int err, String message, String path) {
29+
Exception _getError(int err, String message, [String? path]) {
3030
// TODO(brianquinlan): In the long-term, do we need to avoid exceptions that
3131
// are part of `dart:io`? Can we move those exceptions into a different
3232
// namespace?
@@ -35,12 +35,16 @@ Exception _getError(int err, String message, String path) {
3535
err,
3636
);
3737

38-
if (err == libc.EPERM || err == libc.EACCES) {
39-
return io.PathAccessException(path, osError, message);
40-
} else if (err == libc.EEXIST) {
41-
return io.PathExistsException(path, osError, message);
42-
} else if (err == libc.ENOENT) {
43-
return io.PathNotFoundException(path, osError, message);
38+
if (path != null) {
39+
if (err == libc.EPERM || err == libc.EACCES) {
40+
return io.PathAccessException(path, osError, message);
41+
} else if (err == libc.EEXIST) {
42+
return io.PathExistsException(path, osError, message);
43+
} else if (err == libc.ENOENT) {
44+
return io.PathNotFoundException(path, osError, message);
45+
} else {
46+
return io.FileSystemException(message, path, osError);
47+
}
4448
} else {
4549
return io.FileSystemException(message, path, osError);
4650
}
@@ -241,6 +245,24 @@ final class PosixFileSystem extends FileSystem {
241245
}
242246
});
243247

248+
@override
249+
set currentDirectory(String path) => ffi.using((arena) {
250+
if (libc.chdir(path.toNativeUtf8(allocator: arena).cast()) == -1) {
251+
final errno = libc.errno;
252+
throw _getError(errno, 'chdir failed', path);
253+
}
254+
});
255+
256+
@override
257+
String get currentDirectory => ffi.using((arena) {
258+
final buffer = arena<Char>(libc.PATH_MAX);
259+
if (libc.getcwd(buffer, libc.PATH_MAX) == nullptr) {
260+
final errno = libc.errno;
261+
throw _getError(errno, 'getcwd failed', null);
262+
}
263+
return buffer.cast<ffi.Utf8>().toDartString();
264+
});
265+
244266
@override
245267
String createTemporaryDirectory({String? parent, String? prefix}) =>
246268
ffi.using((arena) {

0 commit comments

Comments
 (0)