You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailscale-android/libtailscale/fileops.go

101 lines
2.5 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package libtailscale
import (
"encoding/json"
"io"
"os"
"time"
"tailscale.com/feature/taildrop"
)
// androidFileOps implements [taildrop.FileOps] using the Android ShareFileHelper.
type androidFileOps struct {
helper ShareFileHelper
}
var _ taildrop.FileOps = (*androidFileOps)(nil)
func newAndroidFileOps(helper ShareFileHelper) *androidFileOps {
return &androidFileOps{helper: helper}
}
func (ops *androidFileOps) OpenWriter(name string, offset int64, _ os.FileMode) (io.WriteCloser, string, error) {
wc, err := ops.helper.OpenFileWriter(name, offset)
if err != nil {
return nil, "", err
}
uri, err := ops.helper.GetFileURI(name)
if err != nil {
wc.Close()
return nil, "", err
}
return wc, uri, nil
}
func (ops *androidFileOps) Remove(baseName string) error {
uri, err := ops.helper.GetFileURI(baseName)
if err != nil {
return err
}
return ops.helper.DeleteFile(uri)
}
func (ops *androidFileOps) Rename(oldPath, newName string) (string, error) {
return ops.helper.RenameFile(oldPath, newName)
}
func (ops *androidFileOps) ListFiles() ([]string, error) {
namesJSON, err := ops.helper.ListFilesJSON("")
if err != nil {
return nil, err
}
var names []string
if err := json.Unmarshal([]byte(namesJSON), &names); err != nil {
return nil, err
}
return names, nil
}
func (ops *androidFileOps) OpenReader(name string) (io.ReadCloser, error) {
in, err := ops.helper.OpenFileReader(name)
if err != nil {
return nil, err
}
return adaptInputStream(in), nil
}
func (ops *androidFileOps) Stat(name string) (os.FileInfo, error) {
infoJSON, err := ops.helper.GetFileInfo(name)
if err != nil {
return nil, err
}
var fi androidFileInfo
if err := json.Unmarshal([]byte(infoJSON), &fi); err != nil {
return nil, err
}
return &fi, nil
}
type androidFileInfoJSON struct {
Name string `json:"name"`
Size int64 `json:"size"`
ModTime int64 `json:"modTime"`
}
type androidFileInfo struct {
data androidFileInfoJSON
}
// compile-time check
var _ os.FileInfo = (*androidFileInfo)(nil)
func (fi *androidFileInfo) Name() string { return fi.data.Name }
func (fi *androidFileInfo) Size() int64 { return fi.data.Size }
func (fi *androidFileInfo) Mode() os.FileMode { return 0o600 }
func (fi *androidFileInfo) ModTime() time.Time { return time.UnixMilli(fi.data.ModTime) }
func (fi *androidFileInfo) IsDir() bool { return false }
func (fi *androidFileInfo) Sys() any { return nil }