( ctx context.Context, srcPath string, filePath string, destPath string, allowParentDirPath bool, )
| 134 | } |
| 135 | |
| 136 | func (c *Client) LocalFileExport( |
| 137 | ctx context.Context, |
| 138 | srcPath string, |
| 139 | filePath string, |
| 140 | destPath string, |
| 141 | allowParentDirPath bool, |
| 142 | ) (rerr error) { |
| 143 | ctx = slog.WithLogger(ctx, slog.FromContext(ctx).With( |
| 144 | "export_path", destPath, |
| 145 | "file_path", filePath, |
| 146 | "allow_parent_dir_path", allowParentDirPath, |
| 147 | )) |
| 148 | slog.DebugContext(ctx, "exporting local file") |
| 149 | defer func() { |
| 150 | slog.TraceContext(ctx, "finished exporting local file", "err", rerr) |
| 151 | }() |
| 152 | |
| 153 | ctx, cancel, err := c.withClientCloseCancel(ctx) |
| 154 | if err != nil { |
| 155 | return err |
| 156 | } |
| 157 | defer cancel(errors.New("local file export done")) |
| 158 | |
| 159 | destPath = path.Clean(destPath) |
| 160 | |
| 161 | file, err := os.Open(srcPath) |
| 162 | if err != nil { |
| 163 | return fmt.Errorf("failed to open file: %w", err) |
| 164 | } |
| 165 | defer file.Close() |
| 166 | stat, err := file.Stat() |
| 167 | if err != nil { |
| 168 | return fmt.Errorf("failed to stat file: %w", err) |
| 169 | } |
| 170 | |
| 171 | ctx = engine.LocalExportOpts{ |
| 172 | Path: destPath, |
| 173 | IsFileStream: true, |
| 174 | FileOriginalName: filepath.Base(filePath), |
| 175 | AllowParentDirPath: allowParentDirPath, |
| 176 | FileMode: stat.Mode().Perm(), |
| 177 | }.AppendToOutgoingContext(ctx) |
| 178 | |
| 179 | clientCaller, err := c.GetSessionCaller(ctx) |
| 180 | if err != nil { |
| 181 | return fmt.Errorf("failed to get requester session: %w", err) |
| 182 | } |
| 183 | diffCopyClient, err := filesync.NewFileSendClient(clientCaller.Conn()).DiffCopy(ctx) |
| 184 | if err != nil { |
| 185 | return fmt.Errorf("failed to create diff copy client: %w", err) |
| 186 | } |
| 187 | defer diffCopyClient.CloseSend() |
| 188 | |
| 189 | fileSizeLeft := stat.Size() |
| 190 | chunkSize := int64(MaxFileContentsChunkSize) |
| 191 | for fileSizeLeft > 0 { |
| 192 | buf := new(bytes.Buffer) // TODO: more efficient to use bufio.Writer, reuse buffers, sync.Pool, etc. |
| 193 | n, err := io.CopyN(buf, file, chunkSize) |
no test coverage detected