Skip to content

Commit

Permalink
Bugfixes: Reg accessor dealing with keys and values of same name (#3713)
Browse files Browse the repository at this point in the history
Sometime keys and values have the same name in the registry. This
requires the registry accessor to expose the UniqueName() API to allow
glob to handle different entitied with the same name.

Also GUI fixes:

* Restore focus on artifact search textbox when the wizard step appears.
* Proper URL handling in the "url" column type - only replace org_id if
it is not already set.
* Fix CSV/JSON download in VFS file list tables.
  • Loading branch information
scudette authored Aug 29, 2024
1 parent b3bffba commit d88fd8e
Show file tree
Hide file tree
Showing 16 changed files with 329 additions and 222 deletions.
143 changes: 65 additions & 78 deletions accessors/raw_registry/raw_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ var (
)

type RawRegKeyInfo struct {
mu sync.Mutex

_full_path *accessors.OSPath
_data *ordereddict.Dict
_modtime time.Time
Expand All @@ -87,16 +89,26 @@ func (self *RawRegKeyInfo) IsDir() bool {
}

func (self *RawRegKeyInfo) Data() *ordereddict.Dict {
self.mu.Lock()
defer self.mu.Unlock()

if self._data == nil {
self._data = ordereddict.NewDict().Set("type", "Key")
}

return self._data
}

func (self *RawRegKeyInfo) Size() int64 {
return 0
}

func (self *RawRegKeyInfo) UniqueName() string {
// Key names can not have \ in them so it is safe to add this
// without risk of collisions.
return self._full_path.String() + "\\"
}

func (self *RawRegKeyInfo) FullPath() string {
return self._full_path.String()
}
Expand Down Expand Up @@ -175,6 +187,10 @@ func (self *RawRegValueInfo) IsDir() bool {
return false
}

func (self *RawRegValueInfo) UniqueName() string {
return self._full_path.String()
}

func (self *RawRegValueInfo) Mode() os.FileMode {
return 0644
}
Expand All @@ -188,6 +204,9 @@ func (self *RawRegValueInfo) Size() int64 {
}

func (self *RawRegValueInfo) Data() *ordereddict.Dict {
self.mu.Lock()
defer self.mu.Unlock()

if self._data != nil {
return self._data
}
Expand All @@ -213,6 +232,7 @@ func (self *RawRegValueInfo) Data() *ordereddict.Dict {
result.Set("value", value_data.Data)
}
}

self._data = result
return result
}
Expand Down Expand Up @@ -353,83 +373,23 @@ func (self *RawRegFileSystemAccessor) ReadDir(key_path string) (
return self.ReadDirWithOSPath(full_path)
}

// Get the default value of a Registry Key if possible.
func (self *RawRegFileSystemAccessor) getDefaultValue(
full_path *accessors.OSPath) (result *RawRegValueInfo, err error) {

// A Key has a default value if its parent directory contains a
// value with the same name as the key.
basename := full_path.Basename()
contents, _, err := self._readDirWithOSPath(full_path.Dirname())
if err != nil {
return nil, err
}

for _, item := range contents {
value_item, ok := item.(*RawRegValueInfo)
if !ok {
continue
}

if strings.EqualFold(item.Name(), basename) {
item_copy := value_item.Copy()
item_copy._full_path = item_copy._full_path.Append("@")
return item_copy, nil
}
}

return nil, utils.NotFoundError
}

func (self *RawRegFileSystemAccessor) ReadDirWithOSPath(
full_path *accessors.OSPath) (result []accessors.FileInfo, err error) {

// Add the default value if the key has one
default_value, err := self.getDefaultValue(full_path)
if err == nil {
result = append(result, default_value)
}

contents, _, err := self._readDirWithOSPath(full_path)
if err != nil {
return nil, err
}

seen := make(map[string]bool)

for _, item := range contents {
basename := item.Name()

// Does this value have the same name as one of the keys? We
// special case it as a subdirectory with a file called @ in
// it:
// Subkeys: A, B, C
// Values: B -> Means Subkey B has default values.
//
// This will end up being:
// A/ -> Directory
// B/ -> Directory
// C/ -> Directory
// B/@ -> File
//
// Therefore skip such values at this level - a Glob will
// fetch them at the next level down.
_, pres := seen[basename]
if pres {
continue
}

seen[basename] = true

result = append(result, item)
}

return result, nil
return contents, err
}

// Return all the contents in the directory including all keys and all
// values, even if some keys have a default value.
// Additionally returns the CM_KEY_NODE for this actual directory.

// This function is recursive! It ascends to the root cell recursively
// and resolves all keys along the path to the required key. On each
// level the function tries the LRU to avoid further recursion. This
// means that in practice most of the time we wont actually be
// recursing more than a few levels because top level keys will be
// cached in the LRU.
func (self *RawRegFileSystemAccessor) _readDirWithOSPath(
full_path *accessors.OSPath) (result []accessors.FileInfo, key *regparser.CM_KEY_NODE, err error) {

Expand Down Expand Up @@ -517,6 +477,9 @@ func (self *RawRegFileSystemAccessor) _readDirFromKey(
key_mod_time := key.LastWriteTime().Time
for _, value := range key.Values() {
basename := value.ValueName()
if basename == "" {
basename = "@"
}
value_obj := &RawRegValueInfo{
RawRegKeyInfo: &RawRegKeyInfo{
_full_path: parent.Append(basename),
Expand Down Expand Up @@ -549,20 +512,24 @@ func (self *RawRegFileSystemAccessor) Open(path string) (

func (self *RawRegFileSystemAccessor) OpenWithOSPath(path *accessors.OSPath) (
accessors.ReadSeekCloser, error) {
stat, err := self.LstatWithOSPath(path)
stats, err := self.multiLstat(path)
if err != nil {
return nil, err
}

value_info, ok := stat.(*RawRegValueInfo)
if ok {
return NewValueBuffer(
value_info._value.ValueData().Data, stat), nil
// We are looking for a value to open try to find one but if now,
// just serialize the key data.
for _, stat := range stats {
value_info, ok := stat.(*RawRegValueInfo)
if ok {
return NewValueBuffer(
value_info._value.ValueData().Data, stat), nil
}
}

// Keys do not have any data.
serialized, _ := json.Marshal(stat.Data)
return NewValueBuffer(serialized, stat), nil
serialized, _ := json.Marshal(stats[0].Data)
return NewValueBuffer(serialized, stats[0]), nil
}

func (self *RawRegFileSystemAccessor) Lstat(filename string) (
Expand All @@ -579,20 +546,36 @@ func (self *RawRegFileSystemAccessor) LstatWithOSPath(
full_path *accessors.OSPath) (
accessors.FileInfo, error) {

// Top level stat
if len(full_path.Components) == 0 {
return &accessors.VirtualFileInfo{
Path: full_path,
IsDir_: true,
}, nil
}

res, err := self.multiLstat(full_path)
if err != nil {
return nil, err
}

// Return the first one.
return res[0], nil
}

// The registry can have keys and values named the same so an Lstat
// can actually return two separate entities. This function returns
// both.
func (self *RawRegFileSystemAccessor) multiLstat(
full_path *accessors.OSPath) (res []accessors.FileInfo, err error) {

name := full_path.Basename()
container := full_path.Dirname()

// If the full_path refers to the default value of the key, return
// it.
if name == "@" {
return self.getDefaultValue(container)
name = ""
}

children, err := self.ReadDirWithOSPath(container)
Expand All @@ -602,11 +585,15 @@ func (self *RawRegFileSystemAccessor) LstatWithOSPath(

for _, child := range children {
if strings.EqualFold(child.Name(), name) {
return child, nil
res = append(res, child)
}
}

return nil, errors.New("Key not found")
if len(res) == 0 {
return nil, errors.New("Key not found")
}

return res, nil
}

func init() {
Expand Down
Loading

0 comments on commit d88fd8e

Please sign in to comment.