@@ -16,9 +16,12 @@ import (
1616 "github.com/OpenListTeam/OpenList/v4/pkg/cron"
1717 "github.com/OpenListTeam/OpenList/v4/pkg/utils"
1818 "github.com/OpenListTeam/OpenList/v4/server/common"
19+ "github.com/aws/aws-sdk-go/aws"
20+ "github.com/aws/aws-sdk-go/aws/awserr"
1921 "github.com/aws/aws-sdk-go/aws/session"
2022 "github.com/aws/aws-sdk-go/service/s3"
2123 "github.com/aws/aws-sdk-go/service/s3/s3manager"
24+ "github.com/pkg/errors"
2225 log "github.com/sirupsen/logrus"
2326)
2427
@@ -243,4 +246,73 @@ func (d *S3) GetDirectUploadInfo(ctx context.Context, _ string, dstDir model.Obj
243246 }, nil
244247}
245248
249+ // implements driver.Getter interface
250+ func (d * S3 ) Get (ctx context.Context , path string ) (model.Obj , error ) {
251+ // try to get object as a file using HeadObject
252+ key := getKey (stdpath .Join (d .GetRootPath (), path ), false )
253+ headInput := & s3.HeadObjectInput {
254+ Bucket : & d .Bucket ,
255+ Key : & key ,
256+ }
257+ headOutput , err := d .client .HeadObjectWithContext (ctx , headInput )
258+ if err == nil {
259+ // Object exists as a file
260+ fileName := stdpath .Base (path )
261+ return & model.Object {
262+ Name : fileName ,
263+ Size : * headOutput .ContentLength ,
264+ Modified : * headOutput .LastModified ,
265+ Path : path ,
266+ }, nil
267+ }
268+ var awsErr awserr.Error
269+ if errors .As (err , & awsErr ) && awsErr .Code () != "NotFound" {
270+ return nil , errors .WithMessage (err , "failed to head object" )
271+ }
272+
273+ // If HeadObject fails with 404, check if it's a directory
274+ prefix := getKey (path , true )
275+ var contents []* s3.Object
276+ var commonPrefixes []* s3.CommonPrefix
277+ switch d .ListObjectVersion {
278+ case "v1" :
279+ listInput := & s3.ListObjectsInput {
280+ Bucket : & d .Bucket ,
281+ Prefix : & prefix ,
282+ MaxKeys : aws .Int64 (1 ), // Only need to check if at least one object exists
283+ }
284+ listResult , err := d .client .ListObjectsWithContext (ctx , listInput )
285+ if err != nil {
286+ return nil , errors .WithMessage (err , "failed to list objects with prefix" )
287+ }
288+ contents = listResult .Contents
289+ commonPrefixes = listResult .CommonPrefixes
290+ case "v2" :
291+ listInput := & s3.ListObjectsV2Input {
292+ Bucket : & d .Bucket ,
293+ Prefix : & prefix ,
294+ MaxKeys : aws .Int64 (1 ),
295+ }
296+ listResult , err := d .client .ListObjectsV2WithContext (ctx , listInput )
297+ if err != nil {
298+ return nil , errors .WithMessage (err , "failed to list objects v2 with prefix" )
299+ }
300+ contents = listResult .Contents
301+ commonPrefixes = listResult .CommonPrefixes
302+ default :
303+ return nil , fmt .Errorf ("unsupported ListObjectVersion: %s" , d .ListObjectVersion )
304+ }
305+ if len (contents ) > 0 || len (commonPrefixes ) > 0 {
306+ dirName := stdpath .Base (path + "/" )
307+ return & model.Object {
308+ Name : dirName ,
309+ Modified : d .Modified ,
310+ IsFolder : true ,
311+ Path : path ,
312+ }, nil
313+ }
314+ return nil , errs .ObjectNotFound
315+ }
316+
246317var _ driver.Driver = (* S3 )(nil )
318+ var _ driver.Getter = (* S3 )(nil )
0 commit comments