...

Source file src/github.com/spf13/afero/gcsfs/file_info.go

Documentation: github.com/spf13/afero/gcsfs

     1  // Copyright © 2021 Vasily Ovchinnikov <vasily@remerge.io>.
     2  //
     3  // The code in this file is derived from afero fork github.com/Zatte/afero by Mikael Rapp
     4  // licensed under Apache License 2.0.
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  // http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package gcsfs
    18  
    19  import (
    20  	"os"
    21  	"path/filepath"
    22  	"strings"
    23  	"time"
    24  
    25  	"cloud.google.com/go/storage"
    26  )
    27  
    28  const (
    29  	folderSize = 42
    30  )
    31  
    32  type FileInfo struct {
    33  	name     string
    34  	size     int64
    35  	updated  time.Time
    36  	isDir    bool
    37  	fileMode os.FileMode
    38  }
    39  
    40  func newFileInfo(name string, fs *Fs, fileMode os.FileMode) (*FileInfo, error) {
    41  	res := &FileInfo{
    42  		name:     name,
    43  		size:     folderSize,
    44  		updated:  time.Time{},
    45  		isDir:    false,
    46  		fileMode: fileMode,
    47  	}
    48  
    49  	obj, err := fs.getObj(name)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	objAttrs, err := obj.Attrs(fs.ctx)
    55  	if err != nil {
    56  		if err.Error() == ErrEmptyObjectName.Error() {
    57  			// It's a root folder here, we return right away
    58  			res.name = fs.ensureTrailingSeparator(res.name)
    59  			res.isDir = true
    60  			return res, nil
    61  		} else if err.Error() == ErrObjectDoesNotExist.Error() {
    62  			// Folders do not actually "exist" in GCloud, so we have to check, if something exists with
    63  			// such a prefix
    64  			bucketName, bucketPath := fs.splitName(name)
    65  			it := fs.client.Bucket(bucketName).Objects(
    66  				fs.ctx, &storage.Query{Delimiter: fs.separator, Prefix: bucketPath, Versions: false})
    67  			if _, err = it.Next(); err == nil {
    68  				res.name = fs.ensureTrailingSeparator(res.name)
    69  				res.isDir = true
    70  				return res, nil
    71  			}
    72  
    73  			return nil, ErrFileNotFound
    74  		}
    75  		return nil, err
    76  	}
    77  
    78  	res.size = objAttrs.Size
    79  	res.updated = objAttrs.Updated
    80  
    81  	return res, nil
    82  }
    83  
    84  func newFileInfoFromAttrs(objAttrs *storage.ObjectAttrs, fileMode os.FileMode) *FileInfo {
    85  	res := &FileInfo{
    86  		name:     objAttrs.Name,
    87  		size:     objAttrs.Size,
    88  		updated:  objAttrs.Updated,
    89  		isDir:    false,
    90  		fileMode: fileMode,
    91  	}
    92  
    93  	if res.name == "" {
    94  		if objAttrs.Prefix != "" {
    95  			// It's a virtual folder! It does not have a name, but prefix - this is how GCS API
    96  			// deals with them at the moment
    97  			res.name = objAttrs.Prefix
    98  			res.size = folderSize
    99  			res.isDir = true
   100  		}
   101  	}
   102  
   103  	return res
   104  }
   105  
   106  func (fi *FileInfo) Name() string {
   107  	return filepath.Base(filepath.FromSlash(fi.name))
   108  }
   109  
   110  func (fi *FileInfo) Size() int64 {
   111  	return fi.size
   112  }
   113  
   114  func (fi *FileInfo) Mode() os.FileMode {
   115  	if fi.IsDir() {
   116  		return os.ModeDir | fi.fileMode
   117  	}
   118  	return fi.fileMode
   119  }
   120  
   121  func (fi *FileInfo) ModTime() time.Time {
   122  	return fi.updated
   123  }
   124  
   125  func (fi *FileInfo) IsDir() bool {
   126  	return fi.isDir
   127  }
   128  
   129  func (fi *FileInfo) Sys() interface{} {
   130  	return nil
   131  }
   132  
   133  type ByName []*FileInfo
   134  
   135  func (a ByName) Len() int { return len(a) }
   136  func (a ByName) Swap(i, j int) {
   137  	a[i].name, a[j].name = a[j].name, a[i].name
   138  	a[i].size, a[j].size = a[j].size, a[i].size
   139  	a[i].updated, a[j].updated = a[j].updated, a[i].updated
   140  	a[i].isDir, a[j].isDir = a[j].isDir, a[i].isDir
   141  }
   142  func (a ByName) Less(i, j int) bool { return strings.Compare(a[i].Name(), a[j].Name()) == -1 }
   143  

View as plain text