github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/pkg/mount/libmount/mount_table_diff.go (about)

     1  /*
     2  Copyright 2020 The OpenEBS Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package libmount
    18  
    19  import "sort"
    20  
    21  type MountAction uint8
    22  
    23  const (
    24  	MountActionMount MountAction = iota
    25  	MountActionUmount
    26  	MountActionMove
    27  	MountActionRemount
    28  )
    29  
    30  // MountTabDiffEntry represents a single change entry in the MounTabDiff
    31  type MountTabDiffEntry struct {
    32  	oldFs  *Filesystem
    33  	newFs  *Filesystem
    34  	action MountAction
    35  }
    36  
    37  // MountTabDiff is the list of all changes between two mount tabs.
    38  type MountTabDiff []*MountTabDiffEntry
    39  
    40  // NewMountTabDiff returns a new and empty MountTabDiff
    41  func NewMountTabDiff() MountTabDiff {
    42  	tabDiff := make(MountTabDiff, 0)
    43  	return tabDiff
    44  }
    45  
    46  // AddDiffEntry returns a new MountTabDiff containing all the entries
    47  // of the current MountTabDiff and a new entry appended based on the parametrs.
    48  func (md MountTabDiff) AddDiffEntry(oldFs *Filesystem, newFs *Filesystem, action MountAction) MountTabDiff {
    49  	return append(md, &MountTabDiffEntry{oldFs, newFs, action})
    50  }
    51  
    52  func (md MountTabDiff) getMountEntry(source string, id int) *MountTabDiffEntry {
    53  	for _, diffEntry := range md {
    54  		if diffEntry.action == MountActionMount &&
    55  			diffEntry.newFs != nil &&
    56  			diffEntry.newFs.GetID() == id &&
    57  			diffEntry.newFs.GetSource() == source {
    58  			return diffEntry
    59  		}
    60  	}
    61  	return nil
    62  }
    63  
    64  // GenerateDiff returns a list of changes between the old mount tab
    65  // and the new mount tab in the form of a MountTabDiff. A nil value
    66  // for any of the parameters is valid and is treated as a mount tab
    67  // with no entries.
    68  func GenerateDiff(oldTab *MountTab, newTab *MountTab) MountTabDiff {
    69  	diffTable := NewMountTabDiff()
    70  	if oldTab == nil {
    71  		oldTab = &MountTab{}
    72  	}
    73  	if newTab == nil {
    74  		newTab = &MountTab{}
    75  	}
    76  	oldTabSize := oldTab.Size()
    77  	newTabSize := newTab.Size()
    78  
    79  	// Both tables empty
    80  	if newTabSize == 0 && oldTabSize == 0 {
    81  		return diffTable
    82  	}
    83  	// Old table empty => all entries in new table are new mounts
    84  	if oldTabSize == 0 {
    85  		for _, entry := range newTab.entries {
    86  			diffTable = diffTable.AddDiffEntry(nil, entry, MountActionMount)
    87  		}
    88  		return diffTable
    89  	}
    90  	// New table empty => all entries in old table were unmounted
    91  	if newTabSize == 0 {
    92  		for _, entry := range oldTab.entries {
    93  			diffTable = diffTable.AddDiffEntry(entry, nil, MountActionUmount)
    94  		}
    95  		return diffTable
    96  	}
    97  
    98  	// Search newly mounted or modified entries
    99  	for _, newFs := range newTab.entries {
   100  		oldFs := oldTab.Find(SourceFilter(newFs.GetSource()), TargetFilter(newFs.GetTarget()))
   101  		if oldFs == nil {
   102  			diffTable = diffTable.AddDiffEntry(nil, newFs, MountActionMount)
   103  		} else if oldFs.GetVFSOptions() != newFs.GetVFSOptions() ||
   104  			oldFs.GetFSOptions() != newFs.GetFSOptions() {
   105  			diffTable = diffTable.AddDiffEntry(oldFs, newFs, MountActionRemount)
   106  		}
   107  	}
   108  
   109  	// Search umounted or moved entries
   110  	for _, oldFs := range oldTab.entries {
   111  		newFs := newTab.Find(SourceFilter(oldFs.GetSource()), TargetFilter(oldFs.GetTarget()))
   112  		if newFs == nil {
   113  			de := diffTable.getMountEntry(oldFs.GetSource(), oldFs.GetID())
   114  			// fs umounted
   115  			if de == nil {
   116  				diffTable = diffTable.AddDiffEntry(oldFs, nil, MountActionUmount)
   117  			} else {
   118  				// else moved
   119  				de.oldFs = oldFs
   120  				de.action = MountActionMove
   121  			}
   122  		}
   123  	}
   124  
   125  	return diffTable
   126  }
   127  
   128  // GetAction returns the type of change - mount, umount, move, remount
   129  func (mde *MountTabDiffEntry) GetAction() MountAction {
   130  	return mde.action
   131  }
   132  
   133  // GetOldFs returns a pointer to the old filesystem that changed
   134  func (mde *MountTabDiffEntry) GetOldFs() *Filesystem {
   135  	if mde.oldFs == nil {
   136  		return nil
   137  	}
   138  	fs := *mde.oldFs
   139  	return &fs
   140  }
   141  
   142  // GetNewFs returns a pointer to the new filesystem that the old filesystem
   143  // changed to.
   144  func (mde *MountTabDiffEntry) GetNewFs() *Filesystem {
   145  	if mde.newFs == nil {
   146  		return nil
   147  	}
   148  	fs := *mde.newFs
   149  	return &fs
   150  }
   151  
   152  // ListSources lists all affected sources in the diff, i.e., all
   153  // sources that were mounted/umounted/remounted/moved in the diff.
   154  func (md MountTabDiff) ListSources() []string {
   155  	var src string
   156  	uniqueSources := make(map[string]struct{})
   157  	sourcesList := make([]string, 0)
   158  
   159  	for _, diff := range md {
   160  		if diff.action == MountActionUmount {
   161  			src = diff.oldFs.GetSource()
   162  		} else {
   163  			src = diff.newFs.GetSource()
   164  		}
   165  		if _, ok := uniqueSources[src]; !ok {
   166  			uniqueSources[src] = struct{}{}
   167  		}
   168  	}
   169  
   170  	for src = range uniqueSources {
   171  		sourcesList = append(sourcesList, src)
   172  	}
   173  	sort.Strings(sourcesList)
   174  
   175  	return sourcesList
   176  }