/** # Copyright 2024 NVIDIA CORPORATION # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. **/ package toolkit import ( "fmt" "io" "os" "path/filepath" "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" ) type fileInstaller struct { logger logger.Interface // sourceRoot specifies the root that is searched for the components to install. sourceRoot string } // installFileToFolder copies a source file to a destination folder. // The path of the input file is ignored. // e.g. installFileToFolder("/some/path/file.txt", "/output/path") // will result in a file "/output/path/file.txt" being generated func (t *fileInstaller) installFileToFolder(destFolder string, src string) (string, error) { name := filepath.Base(src) return t.installFileToFolderWithName(destFolder, name, src) } // cp src destFolder/name func (t *fileInstaller) installFileToFolderWithName(destFolder string, name, src string) (string, error) { dest := filepath.Join(destFolder, name) err := t.installFile(dest, src) if err != nil { return "", fmt.Errorf("error copying '%v' to '%v': %v", src, dest, err) } return dest, nil } // installFile copies a file from src to dest and maintains // file modes func (t *fileInstaller) installFile(dest string, src string) error { src = filepath.Join(t.sourceRoot, src) t.logger.Infof("Installing '%v' to '%v'", src, dest) source, err := os.Open(src) if err != nil { return fmt.Errorf("error opening source: %v", err) } defer source.Close() destination, err := os.Create(dest) if err != nil { return fmt.Errorf("error creating destination: %v", err) } defer destination.Close() _, err = io.Copy(destination, source) if err != nil { return fmt.Errorf("error copying file: %v", err) } err = applyModeFromSource(dest, src) if err != nil { return fmt.Errorf("error setting destination file mode: %v", err) } return nil } // applyModeFromSource sets the file mode for a destination file // to match that of a specified source file func applyModeFromSource(dest string, src string) error { sourceInfo, err := os.Stat(src) if err != nil { return fmt.Errorf("error getting file info for '%v': %v", src, err) } err = os.Chmod(dest, sourceInfo.Mode()) if err != nil { return fmt.Errorf("error setting mode for '%v': %v", dest, err) } return nil }