func()

in component/file_cache/file_cache.go [1369:1424]


func (fc *FileCache) GetAttr(options internal.GetAttrOptions) (*internal.ObjAttr, error) {
	log.Trace("FileCache::GetAttr : %s", options.Name)

	// For get attr, there are three different path situations we have to potentially handle.
	// 1. Path in storage but not in local cache
	// 2. Path not in storage but in local cache (this could happen if we recently created the file [and are currently writing to it]) (also supports immutable containers)
	// 3. Path in storage and in local cache (this could result in dirty properties on the service if we recently wrote to the file)

	// To cover case 1, get attributes from storage
	var exists bool
	attrs, err := fc.NextComponent().GetAttr(options)
	if err != nil {
		if err == syscall.ENOENT || os.IsNotExist(err) {
			log.Debug("FileCache::GetAttr : %s does not exist in storage", options.Name)
			exists = false
		} else {
			log.Err("FileCache::GetAttr : Failed to get attr of %s [%s]", options.Name, err.Error())
			return &internal.ObjAttr{}, err
		}
	} else {
		exists = true
	}

	// To cover cases 2 and 3, grab the attributes from the local cache
	localPath := filepath.Join(fc.tmpPath, options.Name)
	info, err := os.Lstat(localPath)
	// All directory operations are guaranteed to be synced with storage so they cannot be in a case 2 or 3 state.
	if (err == nil || os.IsExist(err)) && !info.IsDir() {
		if exists { // Case 3 (file in storage and in local cache) so update the relevant attributes
			// Return from local cache only if file is not under download or deletion
			// If file is under download then taking size or mod time from it will be incorrect.
			if !fc.fileLocks.Locked(options.Name) {
				log.Debug("FileCache::GetAttr : updating %s from local cache", options.Name)
				attrs.Size = info.Size()
				attrs.Mtime = info.ModTime()
			} else {
				log.Debug("FileCache::GetAttr : %s is locked, use storage attributes", options.Name)
			}
		} else { // Case 2 (file only in local cache) so create a new attributes and add them to the storage attributes
			if !strings.Contains(localPath, fc.tmpPath) {
				// Here if the path is going out of the temp directory then return ENOENT
				exists = false
			} else {
				log.Debug("FileCache::GetAttr : serving %s attr from local cache", options.Name)
				exists = true
				attrs = newObjAttr(options.Name, info)
			}
		}
	}

	if !exists {
		return &internal.ObjAttr{}, syscall.ENOENT
	}

	return attrs, nil
}