diff --git a/deb/index_files.go b/deb/index_files.go index 10ef1787..944727f5 100644 --- a/deb/index_files.go +++ b/deb/index_files.go @@ -186,24 +186,27 @@ func packageIndexByHash(file *indexFile, ext string, hash string, sum string) er src = src + file.parent.suffix + ext filedir := filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath)) dst := filepath.Join(filedir, "by-hash", hash) + sumfilePath := filepath.Join(dst, sum) // link already exists? do nothing - if file.parent.publishedStorage.FileExists(filepath.Join(dst, sum)) { + if file.parent.publishedStorage.FileExists(sumfilePath) { return nil } // create the link - err := file.parent.publishedStorage.HardLink(src, filepath.Join(dst, sum)) + err := file.parent.publishedStorage.HardLink(src, sumfilePath) if err != nil { - return fmt.Errorf("Access-By-Hash: error creating hardlink %s: %s", filepath.Join(dst, sum), err) + return fmt.Errorf("Access-By-Hash: error creating hardlink %s: %s", sumfilePath, err) } - // if exists, backup symlink + // if a previous index file already exists exists, backup symlink if file.parent.publishedStorage.FileExists(filepath.Join(dst, indexfile)) { // if exists, remove old symlink if file.parent.publishedStorage.FileExists(filepath.Join(dst, indexfile+".old")) { - link, _ := file.parent.publishedStorage.ReadLink(filepath.Join(dst, indexfile+".old")) - file.parent.publishedStorage.Remove(filepath.Join(dst, link)) + link, err := file.parent.publishedStorage.ReadLink(filepath.Join(dst, indexfile+".old")) + if err != nil { + file.parent.publishedStorage.Remove(link) + } file.parent.publishedStorage.Remove(filepath.Join(dst, indexfile+".old")) } file.parent.publishedStorage.RenameFile(filepath.Join(dst, indexfile), diff --git a/s3/public.go b/s3/public.go index 8621284f..8a222c8b 100644 --- a/s3/public.go +++ b/s3/public.go @@ -385,26 +385,65 @@ func (storage *PublishedStorage) RenameFile(oldName, newName string) error { return storage.Remove(oldName) } -// SymLink creates a symbolic link, which can be read with ReadLink +// SymLink creates a copy of src file and adds link information as meta data func (storage *PublishedStorage) SymLink(src string, dst string) error { - // TODO: create a file containing dst - return fmt.Errorf("s3: symlinks not implemented") + + params := &s3.CopyObjectInput{ + Bucket: aws.String(storage.bucket), + CopySource: aws.String(src), + Key: aws.String(filepath.Join(storage.prefix, dst)), + ACL: aws.String(storage.acl), + Metadata: map[string]*string{ + "SymLink": aws.String(src), + }, + MetadataDirective: aws.String("REPLACE"), + } + + if storage.storageClass != "" { + params.StorageClass = aws.String(storage.storageClass) + } + if storage.encryptionMethod != "" { + params.ServerSideEncryption = aws.String(storage.encryptionMethod) + } + + _, err := storage.s3.CopyObject(params) + if err != nil { + return fmt.Errorf("error symlinking %s -> %s in %s: %s", src, dst, storage, err) + } + + return err } -// HardLink creates a hardlink of a file +// HardLink using symlink functionality as hard links do not exist func (storage *PublishedStorage) HardLink(src string, dst string) error { - // TODO: create a copy of the file - return fmt.Errorf("s3: hardlinks not implemented") + return storage.SymLink(src, dst) } // FileExists returns true if path exists func (storage *PublishedStorage) FileExists(path string) bool { - // TODO: implement - return false + params := &s3.HeadObjectInput{ + Bucket: aws.String(storage.bucket), + Key: aws.String(filepath.Join(storage.prefix, path)), + } + _, err := storage.s3.HeadObject(params) + if err != nil { + return false + } + + return true } -// ReadLink returns the symbolic link pointed to by path +// ReadLink returns the symbolic link pointed to by path. +// This simply reads text file created with SymLink func (storage *PublishedStorage) ReadLink(path string) (string, error) { - // TODO: read the path and return the content of the file - return "", fmt.Errorf("s3: ReadLink not implemented") + params := &s3.HeadObjectInput{ + Bucket: aws.String(storage.bucket), + Key: aws.String(filepath.Join(storage.prefix, path)), + } + output, err := storage.s3.HeadObject(params) + if err != nil { + return "", err + } + + return aws.StringValue(output.Metadata["SymLink"]), nil } diff --git a/s3/public_test.go b/s3/public_test.go index 7339ac4a..7d9f790e 100644 --- a/s3/public_test.go +++ b/s3/public_test.go @@ -280,3 +280,29 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(s.GetFile(c, "lala/pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) } + +func (s *PublishedStorageSuite) TestSymLink(c *C) { + s.PutFile(c, "a/b", []byte("test")) + + var err error + err = s.storage.SymLink("a/b", "a/b.link") + c.Check(err, IsNil) + + var link string + link, err = s.storage.ReadLink("a/b.link") + c.Check(err, IsNil) + c.Check(link, Equals, "a/b") + + c.Skip("copy not available in s3test") +} + + +func (s *PublishedStorageSuite) TestFileExists(c *C) { + s.PutFile(c, "a/b", []byte("test")) + + exists := s.storage.FileExists("a/b") + c.Check(exists, Equals, true) + + exists = s.storage.FileExists("a/b.invalid") + c.Check(exists, Equals, false) +}