func()

in internal/fs/inode/file.go [686:770]


func (f *FileInode) SetMtime(
	ctx context.Context,
	mtime time.Time) (err error) {
	if f.IsUnlinked() {
		// No need to update mtime on GCS for unlinked file.
		return
	}

	// When bufferedWritesHandler instance is not nil, set time on bwh.
	// It will not be nil in 2 cases when bufferedWrites are enabled:
	// 1. local files
	// 2. After first write on empty GCS files.
	if f.bwh != nil {
		f.bwh.SetMtime(mtime)
		return
	}

	// If we have a local temp file, stat it.
	var sr gcsx.StatResult
	if f.content != nil {
		sr, err = f.content.Stat()
		if err != nil {
			err = fmt.Errorf("stat: %w", err)
			return
		}
	}

	// 1. If the local content is dirty, simply update its mtime and return. This
	// will cause the object in the bucket to be updated once we sync. If we lose
	// power or something the mtime update will be lost, but so will the file
	// data modifications so this doesn't seem so bad. It's worth saving the
	// round trip to GCS for the common case of Linux writeback caching, where we
	// always receive a setattr request just before a flush of a dirty file.
	//
	// 2. If the file is local, that means its not yet synced to GCS. Just update
	// the mtime locally, it will be synced when the object is created on GCS.
	if sr.Mtime != nil || f.IsLocal() {
		f.content.SetMtime(mtime)
		return
	}

	// Otherwise, update the backing object's metadata.
	formatted := mtime.UTC().Format(time.RFC3339Nano)
	srcGen := f.SourceGeneration()

	req := &gcs.UpdateObjectRequest{
		Name:                       f.src.Name,
		Generation:                 srcGen.Object,
		MetaGenerationPrecondition: &srcGen.Metadata,
		Metadata: map[string]*string{
			FileMtimeMetadataKey: &formatted,
		},
	}

	o, err := f.bucket.UpdateObject(ctx, req)
	if err == nil {
		var minObj gcs.MinObject
		minObjPtr := storageutil.ConvertObjToMinObject(o)
		if minObjPtr != nil {
			minObj = *minObjPtr
		}
		f.src = minObj
		f.updateMRDWrapper()
		return
	}

	var notFoundErr *gcs.NotFoundError
	if errors.As(err, &notFoundErr) {
		// Special case: silently ignore not found errors, which mean the file has
		// been unlinked.
		err = nil
		return
	}

	var preconditionErr *gcs.PreconditionError
	if errors.As(err, &preconditionErr) {
		// Special case: silently ignore precondition errors, which we also take to
		// mean the file has been unlinked.
		err = nil
		return
	}

	err = fmt.Errorf("UpdateObject: %w", err)
	return
}