Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions core/coreapi/interface/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package iface
import "errors"

var (
ErrIsDir = errors.New("object is a directory")
ErrOffline = errors.New("can't resolve, ipfs node is offline")
ErrIsDir = errors.New("object is a directory")
ErrOffline = errors.New("can't resolve, ipfs node is offline")
ErrIsSymLink = errors.New("object is a symbolic link")
)
3 changes: 3 additions & 0 deletions core/coreapi/interface/unixfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ type UnixfsAPI interface {

// Ls returns the list of links in a directory
Ls(context.Context, Path) ([]*ipld.Link, error)

// ReadSymLink returns the contents of a symbolic link
ReadSymLink(context.Context, Path) (string, error)
}
38 changes: 34 additions & 4 deletions core/coreapi/unixfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package coreapi

import (
"context"
"errors"
"io"

coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
mdag "github.com/ipfs/go-ipfs/merkledag"
uio "github.com/ipfs/go-ipfs/unixfs/io"
ftpb "github.com/ipfs/go-ipfs/unixfs/pb"

proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
ipld "gx/ipfs/Qme5bWv7wtjUNGsK2BNGVUFPKiuxWrsqrtvYwCLRw8YFES/go-ipld-format"
)
Expand Down Expand Up @@ -38,12 +42,14 @@ func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Read
}

r, err := uio.NewDagReader(ctx, dagnode, dget)
if err == uio.ErrIsDir {
switch err {
case uio.ErrIsDir:
return nil, coreiface.ErrIsDir
} else if err != nil {
return nil, err
case uio.ErrCantReadSymlinks:
return nil, coreiface.ErrIsSymLink
default:
}
return r, nil
return r, err
}

// Ls returns the contents of an IPFS or IPNS object(s) at path p, with the format:
Expand Down Expand Up @@ -76,6 +82,30 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path) ([]*ipld.Link, e
return links, nil
}

var NotASymLink = errors.New("not a symbolic link")

func (api *UnixfsAPI) ReadSymLink(ctx context.Context, p coreiface.Path) (string, error) {
dagnode, err := api.core().ResolveNode(ctx, p)
if err != nil {
return "", err
}
switch n := dagnode.(type) {
case *mdag.ProtoNode:
pb := new(ftpb.Data)
if err := proto.Unmarshal(n.Data(), pb); err != nil {
return "", err
}
switch pb.GetType() {
case ftpb.Data_Symlink:
return string(pb.GetData()), nil
default:
return "", NotASymLink
}
default:
return "", NotASymLink
}
}

func (api *UnixfsAPI) core() coreiface.CoreAPI {
return (*CoreAPI)(api)
}
15 changes: 15 additions & 0 deletions core/corehttp/gateway_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,15 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr

dr, err := i.api.Unixfs().Cat(ctx, resolvedPath)
dir := false
symLink := false
switch err {
case nil:
// Cat() worked
defer dr.Close()
case coreiface.ErrIsDir:
dir = true
case coreiface.ErrIsSymLink:
symLink = true
default:
webError(w, "ipfs cat "+escapedURLPath, err, http.StatusNotFound)
return
Expand Down Expand Up @@ -266,6 +269,18 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
modtime = time.Unix(1, 0)
}

if symLink {
link, err := i.api.Unixfs().ReadSymLink(ctx, resolvedPath)
if err != nil {
internalWebError(w, err)
return
}
newPath := gopath.Join(gopath.Dir(urlPath), link)
http.Redirect(w, r, newPath, 302)
log.Debugf("symlink: redirect to %s", newPath)
return
}

if !dir {
name := gopath.Base(urlPath)
i.serveFile(w, r, name, modtime, dr)
Expand Down
40 changes: 40 additions & 0 deletions test/sharness/t0110-gateway.sh
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,46 @@ test_expect_success "GET compact blocks succeeds" '
test_cmp expected actual
'

#
#
#

test_expect_success "create dir with symbolic links" '
mkdir dirwlinks/ &&
( cd dirwlinks &&
echo "A Simple File" > afile &&
ln -s afile linktofile &&
mkdir adir &&
echo "Another File" > adir/bfile &&
ln -s adir linktodir
)
'

test_expect_success "add dir with symbolic links" '
DIRHASH=$(ipfs add -Q -r dirwlinks)
echo $DIRHASH
'

test_expect_success "getting afile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/afile" &&
test_cmp dirwlinks/afile actual
'

test_expect_success "getting linktofile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/linktofile" &&
test_cmp dirwlinks/afile actual
'

test_expect_success "getting adir/bfile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/adir/bfile" &&
test_cmp dirwlinks/adir/bfile actual
'

test_expect_failure "getting linktodir/bfile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/linktodir/bfile" &&
test_cmp dirwlinks/adir/bfile actual
'

test_kill_ipfs_daemon

test_done