// Returns true if there is a failure due to missing computed files. func (sub *Sub) buildUpdateRequest(image *image.Image, request *subproto.UpdateRequest, deleteMissingComputedFiles bool, logger *log.Logger) bool { sub.requiredFS = image.FileSystem sub.filter = image.Filter request.Triggers = image.Triggers sub.requiredInodeToSubInode = make(map[uint64]uint64) sub.inodesChanged = make(map[uint64]bool) sub.inodesCreated = make(map[uint64]string) sub.subObjectCacheUsage = make(map[hash.Hash]uint64, len(sub.ObjectCache)) // Populate subObjectCacheUsage. for _, hash := range sub.ObjectCache { sub.subObjectCacheUsage[hash] = 0 } if !filesystem.CompareDirectoriesMetadata(&sub.FileSystem.DirectoryInode, &sub.requiredFS.DirectoryInode, nil) { makeDirectory(request, &sub.requiredFS.DirectoryInode, "/", false) } if sub.compareDirectories(request, &sub.FileSystem.DirectoryInode, &sub.requiredFS.DirectoryInode, "/", deleteMissingComputedFiles, logger) { return true } // Look for multiply used objects and tell the sub. for obj, useCount := range sub.subObjectCacheUsage { if useCount > 1 { if request.MultiplyUsedObjects == nil { request.MultiplyUsedObjects = make(map[hash.Hash]uint64) } request.MultiplyUsedObjects[obj] = useCount } } return false }
func addDirectory(dirent, oldDirent *filesystem.DirectoryEntry, fileSystem, oldFS *FileSystem, directoryPathName string, stat *syscall.Stat_t) error { myPathName := path.Join(directoryPathName, dirent.Name) if stat.Ino == fileSystem.inodeNumber { return errors.New("Recursive directory: " + myPathName) } if _, ok := fileSystem.InodeTable[stat.Ino]; ok { return errors.New("Hardlinked directory: " + myPathName) } inode := new(filesystem.DirectoryInode) dirent.SetInode(inode) fileSystem.InodeTable[stat.Ino] = inode inode.Mode = filesystem.FileMode(stat.Mode) inode.Uid = stat.Uid inode.Gid = stat.Gid var oldInode *filesystem.DirectoryInode if oldDirent != nil { if oi, ok := oldDirent.Inode().(*filesystem.DirectoryInode); ok { oldInode = oi } } err, copied := scanDirectory(inode, oldInode, fileSystem, oldFS, myPathName) if err != nil { return err } if copied && filesystem.CompareDirectoriesMetadata(inode, oldInode, nil) { dirent.SetInode(oldInode) fileSystem.InodeTable[stat.Ino] = oldInode } fileSystem.DirectoryCount++ return nil }
func compareDirectories(request *subproto.UpdateRequest, state *state, subDirectory, requiredDirectory *filesystem.Directory, parentName string, filter *filter.Filter) { requiredPathName := path.Join(parentName, requiredDirectory.Name) // First look for entries that should be deleted. makeSubDirectory := false if subDirectory == nil { makeSubDirectory = true } else { subPathName := path.Join(parentName, subDirectory.Name) for name, subEntry := range subDirectory.EntriesByName { pathname := path.Join(subPathName, entryName(subEntry)) if filter.Match(pathname) { continue } if _, ok := requiredDirectory.EntriesByName[name]; !ok { request.PathsToDelete = append(request.PathsToDelete, pathname) fmt.Printf("Delete: %s\n", pathname) // HACK } } if !filesystem.CompareDirectoriesMetadata(subDirectory, requiredDirectory, os.Stdout) { fmt.Printf("Different directory: %s...\n", requiredPathName) // HACK makeSubDirectory = true // TODO(rgooch): Update metadata. } } if makeSubDirectory { var newdir subproto.Directory newdir.Name = requiredPathName newdir.Mode = requiredDirectory.Mode newdir.Uid = requiredDirectory.Uid newdir.Gid = requiredDirectory.Gid request.DirectoriesToMake = append(request.DirectoriesToMake, newdir) } for name, requiredEntry := range requiredDirectory.EntriesByName { pathname := path.Join(requiredPathName, entryName(requiredEntry)) if filter.Match(pathname) { continue } if subDirectory == nil { compareEntries(request, state, nil, requiredEntry, requiredPathName, filter) } else { if subEntry, ok := subDirectory.EntriesByName[name]; ok { compareEntries(request, state, subEntry, requiredEntry, requiredPathName, filter) } else { compareEntries(request, state, nil, requiredEntry, requiredPathName, filter) } } } }