Handle symlinks properly in the directory browser.

This change properly handles symlinks by expanding any it finds in the path
and issuing a redirect to the canonical location.

Whilst we're here, display links as such on the pages, sort directory listings
so the parent link is always at the top, and avoid unnecessary redirects caused
by missing /'s on URLs.
This commit is contained in:
Dave Page
2016-11-30 17:48:35 +09:00
parent 71cecf91d2
commit 92dcb0a23d
4 changed files with 42 additions and 8 deletions

BIN
media/img/ftp/symlink.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 B

View File

@ -1,3 +1,4 @@
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponse, Http404, HttpResponseRedirect
from pgweb.util.decorators import login_required
@ -40,16 +41,45 @@ def ftpbrowser(request, subpath):
except Exception, e:
return HttpServerError("Failed to load ftp site information: %s" % e)
if not allnodes.has_key(subpath):
raise Http404
# An incoming subpath may either be canonical, or have one or more elements
# present that are actually symlinks. For each element of the path, test to
# see if it is present in the pickle. If not, look for a symlink entry with
# and if present, replace the original entry with the symlink target.
canonpath = ''
if subpath != '':
parent = ''
for d in subpath.split('/'):
# Check if allnodes contains a node matching the path
if allnodes[parent].has_key(d):
if allnodes[parent][d]['t'] == 'd':
canonpath = os.path.join(canonpath, d)
elif allnodes[parent][d]['t'] == 'l':
canonpath = os.path.join(canonpath, allnodes[parent][d]['d'])
else:
# There's a matching node, but it's not a link or a directory
raise Http404
parent = canonpath
else:
# There's no matching node
raise Http404
# If we wound up with a canonical path that doesn't match the original request,
# redirect the user
canonpath = canonpath.strip('/')
if subpath != canonpath:
return HttpResponseRedirect('/ftp/' + canonpath)
node = allnodes[subpath]
del allnodes
# Add all directories
directories = [{'link': k, 'url': k} for k,v in node.items() if v['t'] == 'd']
# Add all symlinks (only directoreis supported)
directories.extend([{'link': k, 'url': v['d']} for k,v in node.items() if v['t'] == 'l'])
directories = [{'link': k, 'url': k, 'type': 'd'} for k,v in node.items() if v['t'] == 'd']
# Add all symlinks (only directories supported)
directories.extend([{'link': k, 'url': v['d'], 'type': 'l'} for k,v in node.items() if v['t'] == 'l'])
# A ittle early sorting wouldn't go amiss, so .. ends up at the top
directories.sort(key = version_sort, reverse=True)
# Add a link to the parent directory
if subpath:
@ -80,7 +110,7 @@ def ftpbrowser(request, subpath):
return render_to_response('downloads/ftpbrowser.html', {
'basepath': subpath.rstrip('/'),
'directories': sorted(directories, key = version_sort, reverse=True),
'directories': directories,
'files': sorted(files),
'breadcrumbs': breadcrumbs,
'readme': file_readme,

View File

@ -41,7 +41,7 @@ def version_sort(l):
"""
map a directory name to a format that will show up sensibly in an ascii sort
"""
mkey = l['url']
mkey = l['link']
m = re.match('v([0-9]+)\.([0-9]+)\.([0-9]+)$',l['url'])
if m:
mkey = m.group(1) + '%02d' % int(m.group(2)) + '%02d' % int(m.group(3));

View File

@ -9,7 +9,11 @@
<div>
<table border="0" cellpadding="0" cellspacing="0" width="90%">
{%for dir in directories%}
<tr><td><a href="{{dir.url}}"><img src="/media/img/ftp/folder.png" alt="{{dir.link}}" /></a>&nbsp;<a href="{{dir.url}}">{{dir.link}}</a></td></tr>
{% if dir.type == 'd' or dir.link = '[Parent Directory]' %}
<tr><td><a href="{{dir.url}}/"><img src="/media/img/ftp/folder.png" alt="{{dir.link}}" /></a>&nbsp;<a href="{{dir.url}}/">{{dir.link}}</a></td></tr>
{%else%}
<tr><td><a href="{{dir.url}}/"><img src="/media/img/ftp/symlink.png" alt="{{dir.link}} -&gt; {{dir.url}}" /></a>&nbsp;<a href="{{dir.url}}/">{{dir.link}}</a> -&gt; {{dir.url}}</td></tr>
{%endif%}
{%endfor%}
</table>
</div>