Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
e3c4dd6f
Commit
e3c4dd6f
authored
Oct 24, 2016
by
Kenton Varda
Committed by
Kenton Varda
Apr 27, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement the actual Filesystem interface for disks.
parent
20148c78
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
108 additions
and
17 deletions
+108
-17
filesystem-disk.c++
c++/src/kj/filesystem-disk.c++
+91
-1
filesystem.h
c++/src/kj/filesystem.h
+17
-16
No files found.
c++/src/kj/filesystem-disk.c++
View file @
e3c4dd6f
...
@@ -31,6 +31,7 @@
...
@@ -31,6 +31,7 @@
#include <errno.h>
#include <errno.h>
#include <dirent.h>
#include <dirent.h>
#include <syscall.h>
#include <syscall.h>
#include <stdlib.h>
#include "vector.h"
#include "vector.h"
#include "miniposix.h"
#include "miniposix.h"
...
@@ -950,7 +951,7 @@ public:
...
@@ -950,7 +951,7 @@ public:
// Check for broken link.
// Check for broken link.
if
(
!
has
(
mode
,
WriteMode
::
MODIFY
)
&&
if
(
!
has
(
mode
,
WriteMode
::
MODIFY
)
&&
faccessat
(
fd
,
path
.
toString
()
.
cStr
(),
F_OK
,
AT_SYMLINK_NOFOLLOW
)
>=
0
)
{
faccessat
(
fd
,
filename
.
cStr
(),
F_OK
,
AT_SYMLINK_NOFOLLOW
)
>=
0
)
{
// Yep. We treat this as already-exists, which means in CREATE-only mode this is a
// Yep. We treat this as already-exists, which means in CREATE-only mode this is a
// simple failure.
// simple failure.
return
nullptr
;
return
nullptr
;
...
@@ -1542,6 +1543,91 @@ public:
...
@@ -1542,6 +1543,91 @@ public:
}
}
};
};
class
DiskFilesystem
final
:
public
Filesystem
{
public
:
DiskFilesystem
()
:
root
(
openDir
(
"/"
)),
current
(
openDir
(
"."
)),
currentPath
(
computeCurrentPath
())
{}
Directory
&
getRoot
()
override
{
return
root
;
}
Directory
&
getCurrent
()
override
{
return
current
;
}
PathPtr
getCurrentPath
()
override
{
return
currentPath
;
}
private
:
DiskDirectory
root
;
DiskDirectory
current
;
Path
currentPath
;
static
AutoCloseFd
openDir
(
const
char
*
dir
)
{
int
newFd
;
KJ_SYSCALL
(
newFd
=
open
(
dir
,
O_RDONLY
|
MAYBE_O_CLOEXEC
|
MAYBE_O_DIRECTORY
));
AutoCloseFd
result
(
newFd
);
#ifndef O_CLOEXEC
setCloexec
(
result
);
#endif
return
result
;
}
static
Path
computeCurrentPath
()
{
// If env var PWD is set and points to the current directory, use it. This captures the current
// path according to the user's shell, which may differ from the kernel's idea in the presence
// of symlinks.
const
char
*
pwd
=
getenv
(
"PWD"
);
if
(
pwd
!=
nullptr
)
{
Path
result
=
nullptr
;
struct
stat
pwdStat
,
dotStat
;
KJ_IF_MAYBE
(
e
,
kj
::
runCatchingExceptions
([
&
]()
{
KJ_ASSERT
(
pwd
[
0
]
==
'/'
)
{
return
;
}
result
=
Path
::
parse
(
pwd
+
1
);
KJ_SYSCALL
(
lstat
(
result
.
toString
(
true
).
cStr
(),
&
pwdStat
),
result
)
{
return
;
}
KJ_SYSCALL
(
lstat
(
"."
,
&
dotStat
))
{
return
;
}
}))
{
// failed, give up on PWD
KJ_LOG
(
WARNING
,
"PWD environment variable seems invalid"
,
pwd
,
*
e
);
}
else
{
if
(
pwdStat
.
st_ino
==
dotStat
.
st_ino
&&
pwdStat
.
st_dev
==
dotStat
.
st_dev
)
{
return
kj
::
mv
(
result
);
}
else
{
KJ_LOG
(
WARNING
,
"PWD environment variable doesn't match current directory"
,
pwd
);
}
}
}
size_t
size
=
256
;
retry:
KJ_STACK_ARRAY
(
char
,
buf
,
size
,
256
,
4096
);
if
(
getcwd
(
buf
.
begin
(),
size
)
==
nullptr
)
{
int
error
=
errno
;
if
(
error
==
ENAMETOOLONG
)
{
size
*=
2
;
goto
retry
;
}
else
{
KJ_FAIL_SYSCALL
(
"getcwd()"
,
error
);
}
}
StringPtr
path
=
buf
.
begin
();
// On Linux, the path will start with "(unreachable)" if the working directory is not a subdir
// of the root directory, which is possible via chroot() or mount namespaces.
KJ_ASSERT
(
!
path
.
startsWith
(
"(unreachable)"
),
"working directory is not reachable from root"
,
path
);
KJ_ASSERT
(
path
.
startsWith
(
"/"
),
"current directory is not absolute"
,
path
);
return
Path
::
parse
(
path
.
slice
(
1
));
}
};
}
// namespace
}
// namespace
Own
<
ReadableFile
>
newDiskReadableFile
(
kj
::
AutoCloseFd
fd
)
{
Own
<
ReadableFile
>
newDiskReadableFile
(
kj
::
AutoCloseFd
fd
)
{
...
@@ -1560,4 +1646,8 @@ Own<Directory> newDiskDirectory(kj::AutoCloseFd fd) {
...
@@ -1560,4 +1646,8 @@ Own<Directory> newDiskDirectory(kj::AutoCloseFd fd) {
return
heap
<
DiskDirectory
>
(
kj
::
mv
(
fd
));
return
heap
<
DiskDirectory
>
(
kj
::
mv
(
fd
));
}
}
Own
<
Filesystem
>
newDiskFilesystem
()
{
return
heap
<
DiskFilesystem
>
();
}
}
// namespace kj
}
// namespace kj
c++/src/kj/filesystem.h
View file @
e3c4dd6f
...
@@ -775,25 +775,16 @@ private:
...
@@ -775,25 +775,16 @@ private:
class
Filesystem
{
class
Filesystem
{
public
:
public
:
virtual
Directory
&
getRoot
()
=
0
;
virtual
Directory
&
getRoot
()
=
0
;
// Get the filesystem's root directory.
// Get the filesystem's root directory, as of the time the Filesystem object was created.
//
// `getRoot()` returns a special directory for which `getFd()` throws. You may call
// `getRoot().openSubdir(nullptr)` to get a Directory representing the root which has a valid
// file descriptor (and which isn't affected by `chroot()`).
virtual
Directory
&
getCurrent
()
=
0
;
virtual
Directory
&
getCurrent
()
=
0
;
// Get the filesystem's current directory.
// Get the filesystem's current directory, as of the time the Filesystem object was created.
//
// The returned Directory object is a special one for which a call to the `chdir()` syscall will
// change the Directory's target. We recommend against using `chdir()` in KJ code, but if you
// want a Directory that avoids this behavior, you can call `.openSubdir(nullptr)` on it to
// reopen itself. Additionally, `getCurrent()` returns a directory for which `getFd()` throws;
// `openSubdir(nullptr)` solves that problem as well.
virtual
Path
getCurrentPath
()
=
0
;
virtual
PathPtr
getCurrentPath
()
=
0
;
// Get the path from the root to the current directory. Note that because a `Directory` does not
// Get the path from the root to the current directory, as of the time the Filesystem object was
// provide access to its parent, if you want to follow `..` from the current directory, you must
// created. Note that because a `Directory` does not provide access to its parent, if you want to
// use `getCurrentPath().eval("..")` or `getCurrentPath().parent()`.
// follow `..` from the current directory, you must use `getCurrentPath().eval("..")` or
// `getCurrentPath().parent()`.
//
//
// This function attempts to determine the path as it appeared in the user's shell before this
// This function attempts to determine the path as it appeared in the user's shell before this
// program was started. That means, if the user had `cd`ed into a symlink, the path through that
// program was started. That means, if the user had `cd`ed into a symlink, the path through that
...
@@ -837,8 +828,18 @@ Own<AppendableFile> newDiskAppendableFile(kj::AutoCloseFd fd);
...
@@ -837,8 +828,18 @@ Own<AppendableFile> newDiskAppendableFile(kj::AutoCloseFd fd);
Own
<
File
>
newDiskFile
(
kj
::
AutoCloseFd
fd
);
Own
<
File
>
newDiskFile
(
kj
::
AutoCloseFd
fd
);
Own
<
ReadableDirectory
>
newDiskReadableDirectory
(
kj
::
AutoCloseFd
fd
);
Own
<
ReadableDirectory
>
newDiskReadableDirectory
(
kj
::
AutoCloseFd
fd
);
Own
<
Directory
>
newDiskDirectory
(
kj
::
AutoCloseFd
fd
);
Own
<
Directory
>
newDiskDirectory
(
kj
::
AutoCloseFd
fd
);
// Wrap a file descriptor as various filesystem types.
Own
<
Filesystem
>
newDiskFilesystem
();
Own
<
Filesystem
>
newDiskFilesystem
();
// Get at implementation of `Filesystem` representing the real filesystem.
//
// DO NOT CALL THIS except at the top level of your program, e.g. in main(). Anywhere else, you
// should instead have your caller pass in a Filesystem object, or a specific Directory object,
// or whatever it is that your code needs. This ensures that your code supports dependency
// injection, which makes it more reusable and testable.
//
// newDiskFilesystem() reads the current working directory at the time it is called. The returned
// object is not affected by subsequent calls to chdir().
// =======================================================================================
// =======================================================================================
// inline implementation details
// inline implementation details
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment