github.com/Cloud-Foundations/Dominator@v0.3.4/lib/filesystem/util/computedFiles.go (about) 1 package util 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "os" 8 "path" 9 "sort" 10 "strings" 11 12 "github.com/Cloud-Foundations/Dominator/lib/filesystem" 13 "github.com/Cloud-Foundations/Dominator/lib/fsutil" 14 "github.com/Cloud-Foundations/Dominator/lib/json" 15 ) 16 17 func spliceComputedFiles(fs *filesystem.FileSystem, 18 computedFileList []ComputedFile) error { 19 if len(computedFileList) < 1 { 20 return nil 21 } 22 filenameToInodeTable := fs.FilenameToInodeTable() 23 inodeToFilenamesTable := fs.InodeToFilenamesTable() 24 for _, computedFile := range computedFileList { 25 inum, ok := filenameToInodeTable[computedFile.Filename] 26 if !ok { 27 return errors.New(computedFile.Filename + ": missing from image") 28 } 29 if filenames, ok := inodeToFilenamesTable[inum]; !ok { 30 panic(computedFile.Filename + ": no corresponding list of files") 31 } else if len(filenames) != 1 { 32 return fmt.Errorf("%s: multiple inodes: %d", computedFile.Filename, 33 len(filenames)) 34 } 35 if inode, ok := 36 fs.InodeTable[inum].(*filesystem.ComputedRegularInode); ok { 37 inode.Source = computedFile.Source 38 continue 39 } 40 if oldInode, ok := fs.InodeTable[inum].(*filesystem.RegularInode); !ok { 41 return fmt.Errorf("%s: type: %T is not a regular inode", 42 computedFile.Filename, fs.InodeTable[inum]) 43 } else { 44 newInode := new(filesystem.ComputedRegularInode) 45 newInode.Mode = oldInode.Mode 46 newInode.Uid = oldInode.Uid 47 newInode.Gid = oldInode.Gid 48 newInode.Source = computedFile.Source 49 fs.InodeTable[inum] = newInode 50 } 51 } 52 fs.ComputeTotalDataBytes() 53 clearInodePointers(&fs.DirectoryInode, "") 54 return fs.RebuildInodePointers() 55 } 56 57 func loadComputedFiles(filename string) ([]ComputedFile, error) { 58 var computedFileList []ComputedFile 59 if strings.HasSuffix(filename, ".json") { 60 file, err := os.Open(filename) 61 if err != nil { 62 return nil, err 63 } 64 defer file.Close() 65 reader := bufio.NewReader(file) 66 if err := json.Read(reader, &computedFileList); err != nil { 67 return nil, errors.New("error decoding computed files list " + 68 err.Error()) 69 } 70 } else { 71 lines, err := fsutil.LoadLines(filename) 72 if err != nil { 73 return nil, err 74 } 75 for _, line := range lines { 76 fields := strings.Fields(line) 77 if len(fields) != 2 { 78 return nil, fmt.Errorf("bad line: %s", line) 79 } 80 computedFileList = append(computedFileList, 81 ComputedFile{fields[0], fields[1]}) 82 } 83 } 84 return computedFileList, nil 85 } 86 87 func clearInodePointers(directoryInode *filesystem.DirectoryInode, 88 name string) { 89 for _, dirent := range directoryInode.EntryList { 90 if inode, ok := dirent.Inode().(*filesystem.DirectoryInode); ok { 91 clearInodePointers(inode, path.Join(name, dirent.Name)) 92 } 93 dirent.SetInode(nil) 94 } 95 } 96 97 func mergeComputedFiles(base, overlay []ComputedFile) []ComputedFile { 98 computedFilesMap := make(map[string]string) 99 for _, computedFile := range base { 100 computedFilesMap[computedFile.Filename] = computedFile.Source 101 } 102 for _, computedFile := range overlay { 103 computedFilesMap[computedFile.Filename] = computedFile.Source 104 } 105 filenames := make([]string, 0, len(computedFilesMap)) 106 for filename := range computedFilesMap { 107 filenames = append(filenames, filename) 108 } 109 sort.Strings(filenames) 110 newList := make([]ComputedFile, 0, len(computedFilesMap)) 111 for _, filename := range filenames { 112 newList = append(newList, ComputedFile{ 113 Filename: filename, 114 Source: computedFilesMap[filename], 115 }) 116 } 117 return newList 118 }