Skip to content

Commit

Permalink
Implemented Btime for VFS view. (Velocidex#889)
Browse files Browse the repository at this point in the history
Also fixed bug in MacOS timestamps.
  • Loading branch information
scudette authored Jan 22, 2021
1 parent 5f9a732 commit 0becc89
Show file tree
Hide file tree
Showing 21 changed files with 112 additions and 11 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ references:
release:
go run make.go -v release

# Basic darwin binary - no yara.
darwin:
go run make.go -v DarwinBase

linux:
go run make.go -v linux

Expand Down
3 changes: 2 additions & 1 deletion artifacts/definitions/System/VFS/ListDirectory.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ sources:
Name, Size, Mode.String AS Mode,
Mtime as mtime,
Atime as atime,
Ctime as ctime
Ctime as ctime,
Btime AS btime
FROM glob(
globs=if(condition=Depth,
then=format(format='/**%v', args=Depth),
Expand Down
4 changes: 4 additions & 0 deletions file_store/api/accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func (self *FileStoreFileInfo) FullPath() string {
return self.FullPath_
}

func (self *FileStoreFileInfo) Btime() utils.TimeVal {
return utils.TimeVal{}
}

func (self *FileStoreFileInfo) Mtime() utils.TimeVal {
return utils.TimeVal{}
}
Expand Down
4 changes: 4 additions & 0 deletions file_store/api/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ func (self FileInfoAdapter) FullPath() string {
return self.full_path
}

func (self FileInfoAdapter) Btime() utils.TimeVal {
return utils.TimeVal{}
}

func (self FileInfoAdapter) Mtime() utils.TimeVal {
return utils.TimeVal{}
}
Expand Down
7 changes: 7 additions & 0 deletions file_store/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ func (self *MysqlFileStoreFileInfo) Mtime() utils.TimeVal {
}
}

func (self *MysqlFileStoreFileInfo) Btime() utils.TimeVal {
return utils.TimeVal{
Sec: self.timestamp,
Nsec: self.timestamp * 1000000000,
}
}

func (self MysqlFileStoreFileInfo) Atime() utils.TimeVal {
return utils.TimeVal{}
}
Expand Down
27 changes: 21 additions & 6 deletions glob/accessor_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,42 @@ func (self *OSFileInfo) FullPath() string {
return self._full_path
}

func (self *OSFileInfo) Btime() utils.TimeVal {
ts := self.sys().Birthtimespec
return utils.TimeVal{
Sec: ts.Sec,
Nsec: ts.Nsec + ts.Sec*1000000000,
}
}

func (self *OSFileInfo) Mtime() utils.TimeVal {
ts := self.sys().Mtimespec
return utils.TimeVal{
Sec: int64(self.sys().Mtimespec.Sec),
Nsec: int64(self.sys().Mtimespec.Nsec),
Sec: ts.Sec,
Nsec: ts.Nsec + ts.Sec*1000000000,
}
}

func (self *OSFileInfo) Ctime() utils.TimeVal {
ts := self.sys().Ctimespec
return utils.TimeVal{
Sec: int64(self.sys().Ctimespec.Sec),
Nsec: int64(self.sys().Ctimespec.Nsec),
Sec: ts.Sec,
Nsec: ts.Nsec + ts.Sec*1000000000,
}
}

func (self *OSFileInfo) Atime() utils.TimeVal {
ts := self.sys().Atimespec
return utils.TimeVal{
Sec: int64(self.sys().Atimespec.Sec),
Nsec: int64(self.sys().Atimespec.Nsec),
Sec: ts.Sec,
Nsec: ts.Nsec + ts.Sec*1000000000,
}
}

func (self *OSFileInfo) _Sys() *syscall.Stat_t {
return self.sys()
}

func (self *OSFileInfo) Data() interface{} {
return nil
}
Expand Down
8 changes: 8 additions & 0 deletions glob/accessor_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ func (self *OSFileInfo) FullPath() string {
return self._full_path
}

// On Linux we need xstat() support to get birth time.
func (self *OSFileInfo) Btime() utils.TimeVal {
return utils.TimeVal{
Sec: 0,
Nsec: 0,
}
}

func (self *OSFileInfo) Mtime() utils.TimeVal {
ts := int64(self._Sys().Mtim.Sec)
return utils.TimeVal{
Expand Down
4 changes: 4 additions & 0 deletions glob/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ func (self *VirtualDirectoryPath) Mtime() utils.TimeVal {
return utils.TimeVal{}
}

func (self *VirtualDirectoryPath) Btime() utils.TimeVal {
return utils.TimeVal{}
}

func (self *VirtualDirectoryPath) Ctime() utils.TimeVal {
return utils.TimeVal{}
}
Expand Down
5 changes: 5 additions & 0 deletions glob/glob.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ type FileInfo interface {
Name() string
ModTime() time.Time
FullPath() string

// Time the file was birthed (initially created)
Btime() utils.TimeVal
Mtime() utils.TimeVal

// Time the inode was changed.
Ctime() utils.TimeVal
Atime() utils.TimeVal
Data() interface{}
Expand Down
3 changes: 2 additions & 1 deletion gui/velociraptor/src/components/vfs/file-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ class VeloFileList extends Component {
{dataField: "Mode", text: "Mode", sort: true},
{dataField: "mtime", text: "mtime", sort: true},
{dataField: "atime", text: "atime", sort: true},
{dataField: "ctime", text: "ctime", sort: true}
{dataField: "ctime", text: "ctime", sort: true},
{dataField: "btime", text: "btime", sort: true}
]);

return (
Expand Down
1 change: 0 additions & 1 deletion services/vfs_service/vfs_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ func (self *VFSService) ProcessListDirectory(
var current_vfs_components []string = nil

for row := range row_chan {
utils.Debug(row)
full_path, _ := row.GetString("_FullPath")
accessor, _ := row.GetString("_Accessor")
name, _ := row.GetString("Name")
Expand Down
5 changes: 5 additions & 0 deletions utils/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ func (self *DataFileInfo) ModTime() time.Time {
func (self *DataFileInfo) FullPath() string {
return string(self.data)
}

func (self *DataFileInfo) Btime() TimeVal {
return TimeVal{}
}

func (self *DataFileInfo) Mtime() TimeVal {
return TimeVal{}
}
Expand Down
4 changes: 4 additions & 0 deletions vql/filesystem/gzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ func (self *GzipFileInfo) Mtime() utils.TimeVal {
return self._modtime
}

func (self *GzipFileInfo) Btime() utils.TimeVal {
return self._modtime
}

func (self *GzipFileInfo) Ctime() utils.TimeVal {
return self._modtime
}
Expand Down
4 changes: 4 additions & 0 deletions vql/filesystem/raw_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ func (self *RawRegKeyInfo) Ctime() utils.TimeVal {
return self.Mtime()
}

func (self *RawRegKeyInfo) Btime() utils.TimeVal {
return self.Mtime()
}

func (self *RawRegKeyInfo) Atime() utils.TimeVal {
return self.Mtime()
}
Expand Down
4 changes: 4 additions & 0 deletions vql/filesystem/zip.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ func (self *ZipFileInfo) Ctime() utils.TimeVal {
return self.Mtime()
}

func (self *ZipFileInfo) Btime() utils.TimeVal {
return self.Mtime()
}

func (self *ZipFileInfo) Atime() utils.TimeVal {
return self.Mtime()
}
Expand Down
2 changes: 1 addition & 1 deletion vql/protocols.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (self _GlobFileInfoAssociative) Associative(
// FROM ...
func (self _GlobFileInfoAssociative) GetMembers(
scope vfilter.Scope, a vfilter.Any) []string {
return []string{"Name", "ModTime", "FullPath", "Mtime",
return []string{"Name", "ModTime", "FullPath", "Mtime", "Btime",
"Ctime", "Atime", "Data", "Size",
"IsDir", "IsLink", "Mode", "Sys"}
}
Expand Down
8 changes: 8 additions & 0 deletions vql/windows/filesystems/ntfs_lazy_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ func (self *LazyNTFSFileInfo) Mtime() utils.TimeVal {
}
}

func (self *LazyNTFSFileInfo) Btime() utils.TimeVal {
self.ensureCachedInfo()

return utils.TimeVal{
Sec: self.cached_info.Btime.Unix(),
}
}

func (self *LazyNTFSFileInfo) Ctime() utils.TimeVal {
self.ensureCachedInfo()

Expand Down
8 changes: 8 additions & 0 deletions vql/windows/filesystems/ntfs_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ func (self *NTFSFileInfo) FullPath() string {
return self._full_path
}

func (self *NTFSFileInfo) Btime() utils.TimeVal {
nsec := self.info.Btime.UnixNano()
return utils.TimeVal{
Sec: nsec / 1000000000,
Nsec: nsec,
}
}

func (self *NTFSFileInfo) Mtime() utils.TimeVal {
nsec := self.info.Mtime.UnixNano()
return utils.TimeVal{
Expand Down
13 changes: 12 additions & 1 deletion vql/windows/filesystems/os_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ func (self *OSFileInfo) Data() interface{} {
return ordereddict.NewDict()
}

func (self *OSFileInfo) Btime() utils.TimeVal {
nsec := self.sys().CreationTime.Nanoseconds()
return utils.TimeVal{
Sec: nsec / 1000000000,
Nsec: nsec,
}
}


func (self *OSFileInfo) Mtime() utils.TimeVal {
nsec := self.sys().LastWriteTime.Nanoseconds()
return utils.TimeVal{
Expand All @@ -72,8 +81,10 @@ func (self *OSFileInfo) Mtime() utils.TimeVal {
}
}

// Windows does not provide the ctime (inode change time) using the
// APIs.
func (self *OSFileInfo) Ctime() utils.TimeVal {
nsec := self.sys().CreationTime.Nanoseconds()
nsec := self.sys().LastWriteTime.Nanoseconds()
return utils.TimeVal{
Sec: nsec / 1000000000,
Nsec: nsec,
Expand Down
4 changes: 4 additions & 0 deletions vql/windows/filesystems/registry_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func (self *RegKeyInfo) Mtime() utils.TimeVal {
}
}

func (self *RegKeyInfo) Btime() utils.TimeVal {
return self.Mtime()
}

func (self *RegKeyInfo) Ctime() utils.TimeVal {
return self.Mtime()
}
Expand Down
1 change: 1 addition & 0 deletions vtesting/file_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func (self MockFileInfo) ModTime() time.Time { return time.Time{} }
func (self MockFileInfo) IsDir() bool { return true }
func (self MockFileInfo) Sys() interface{} { return nil }
func (self MockFileInfo) FullPath() string { return self.FullPath_ }
func (self MockFileInfo) Btime() utils.TimeVal { return utils.TimeVal{} }
func (self MockFileInfo) Mtime() utils.TimeVal { return utils.TimeVal{} }
func (self MockFileInfo) Atime() utils.TimeVal { return utils.TimeVal{} }
func (self MockFileInfo) Ctime() utils.TimeVal { return utils.TimeVal{} }
Expand Down

0 comments on commit 0becc89

Please sign in to comment.