...

Source file src/github.com/Microsoft/hcsshim/internal/wclayer/baselayerreader.go

Documentation: github.com/Microsoft/hcsshim/internal/wclayer

     1  package wclayer
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"syscall"
    10  
    11  	"github.com/Microsoft/go-winio"
    12  	"github.com/Microsoft/hcsshim/internal/longpath"
    13  	"github.com/Microsoft/hcsshim/internal/oc"
    14  	"go.opencensus.io/trace"
    15  )
    16  
    17  type baseLayerReader struct {
    18  	s            *trace.Span
    19  	root         string
    20  	result       chan *fileEntry
    21  	proceed      chan bool
    22  	currentFile  *os.File
    23  	backupReader *winio.BackupFileReader
    24  }
    25  
    26  func newBaseLayerReader(root string, s *trace.Span) (r *baseLayerReader) {
    27  	r = &baseLayerReader{
    28  		s:       s,
    29  		root:    root,
    30  		result:  make(chan *fileEntry),
    31  		proceed: make(chan bool),
    32  	}
    33  	go r.walk()
    34  	return r
    35  }
    36  
    37  func (r *baseLayerReader) walkUntilCancelled() error {
    38  	root, err := longpath.LongAbs(r.root)
    39  	if err != nil {
    40  		return err
    41  	}
    42  
    43  	r.root = root
    44  
    45  	err = filepath.Walk(filepath.Join(r.root, filesPath), func(path string, info os.FileInfo, err error) error {
    46  		if err != nil {
    47  			return err
    48  		}
    49  
    50  		// Indirect fix for https://github.com/moby/moby/issues/32838#issuecomment-343610048.
    51  		// Handle failure from what may be a golang bug in the conversion of
    52  		// UTF16 to UTF8 in files which are left in the recycle bin. Os.Lstat
    53  		// which is called by filepath.Walk will fail when a filename contains
    54  		// unicode characters. Skip the recycle bin regardless which is goodness.
    55  		if strings.EqualFold(path, filepath.Join(r.root, `Files\$Recycle.Bin`)) && info.IsDir() {
    56  			return filepath.SkipDir
    57  		}
    58  
    59  		r.result <- &fileEntry{path, info, nil}
    60  		if !<-r.proceed {
    61  			return errorIterationCanceled
    62  		}
    63  
    64  		return nil
    65  	})
    66  
    67  	if err == errorIterationCanceled {
    68  		return nil
    69  	}
    70  
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	utilityVMAbsPath := filepath.Join(r.root, utilityVMPath)
    76  	utilityVMFilesAbsPath := filepath.Join(r.root, utilityVMFilesPath)
    77  
    78  	// Ignore a UtilityVM without Files, that's not _really_ a UtiltyVM
    79  	if _, err = os.Lstat(utilityVMFilesAbsPath); err != nil {
    80  		if os.IsNotExist(err) {
    81  			return io.EOF
    82  		}
    83  		return err
    84  	}
    85  
    86  	err = filepath.Walk(utilityVMAbsPath, func(path string, info os.FileInfo, err error) error {
    87  		if err != nil {
    88  			return err
    89  		}
    90  
    91  		if path != utilityVMAbsPath && path != utilityVMFilesAbsPath && !hasPathPrefix(path, utilityVMFilesAbsPath) {
    92  			if info.IsDir() {
    93  				return filepath.SkipDir
    94  			}
    95  			return nil
    96  		}
    97  
    98  		r.result <- &fileEntry{path, info, nil}
    99  		if !<-r.proceed {
   100  			return errorIterationCanceled
   101  		}
   102  
   103  		return nil
   104  	})
   105  
   106  	if err == errorIterationCanceled {
   107  		return nil
   108  	}
   109  
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	return io.EOF
   115  }
   116  
   117  func (r *baseLayerReader) walk() {
   118  	defer close(r.result)
   119  	if !<-r.proceed {
   120  		return
   121  	}
   122  
   123  	err := r.walkUntilCancelled()
   124  	if err != nil {
   125  		for {
   126  			r.result <- &fileEntry{err: err}
   127  			if !<-r.proceed {
   128  				return
   129  			}
   130  		}
   131  	}
   132  }
   133  
   134  func (r *baseLayerReader) reset() {
   135  	if r.backupReader != nil {
   136  		r.backupReader.Close()
   137  		r.backupReader = nil
   138  	}
   139  	if r.currentFile != nil {
   140  		r.currentFile.Close()
   141  		r.currentFile = nil
   142  	}
   143  }
   144  
   145  func (r *baseLayerReader) Next() (path string, size int64, fileInfo *winio.FileBasicInfo, err error) {
   146  	r.reset()
   147  	r.proceed <- true
   148  	fe := <-r.result
   149  	if fe == nil {
   150  		err = errors.New("BaseLayerReader closed")
   151  		return
   152  	}
   153  	if fe.err != nil {
   154  		err = fe.err
   155  		return
   156  	}
   157  
   158  	path, err = filepath.Rel(r.root, fe.path)
   159  	if err != nil {
   160  		return
   161  	}
   162  
   163  	f, err := openFileOrDir(fe.path, syscall.GENERIC_READ, syscall.OPEN_EXISTING)
   164  	if err != nil {
   165  		return
   166  	}
   167  	defer func() {
   168  		if f != nil {
   169  			f.Close()
   170  		}
   171  	}()
   172  
   173  	fileInfo, err = winio.GetFileBasicInfo(f)
   174  	if err != nil {
   175  		return
   176  	}
   177  
   178  	size = fe.fi.Size()
   179  	r.backupReader = winio.NewBackupFileReader(f, true)
   180  
   181  	r.currentFile = f
   182  	f = nil
   183  	return
   184  }
   185  
   186  func (r *baseLayerReader) LinkInfo() (uint32, *winio.FileIDInfo, error) {
   187  	fileStandardInfo, err := winio.GetFileStandardInfo(r.currentFile)
   188  	if err != nil {
   189  		return 0, nil, err
   190  	}
   191  	fileIDInfo, err := winio.GetFileID(r.currentFile)
   192  	if err != nil {
   193  		return 0, nil, err
   194  	}
   195  	return fileStandardInfo.NumberOfLinks, fileIDInfo, nil
   196  }
   197  
   198  func (r *baseLayerReader) Read(b []byte) (int, error) {
   199  	if r.backupReader == nil {
   200  		return 0, io.EOF
   201  	}
   202  	return r.backupReader.Read(b)
   203  }
   204  
   205  func (r *baseLayerReader) Close() (err error) {
   206  	defer r.s.End()
   207  	defer func() {
   208  		oc.SetSpanStatus(r.s, err)
   209  		close(r.proceed)
   210  	}()
   211  	r.proceed <- false
   212  	// The r.result channel will be closed once walk() returns
   213  	<-r.result
   214  	r.reset()
   215  	return nil
   216  }
   217  

View as plain text