diff --git a/scripts/upload.cgi/upload.cgi b/scripts/upload.cgi/upload.cgi index 74cb2bb..0921597 100644 --- a/scripts/upload.cgi/upload.cgi +++ b/scripts/upload.cgi/upload.cgi @@ -4,78 +4,47 @@ # is nothing really complex here other than tedious checking of our # every step along the way... # -# $Id: upload.cgi,v 1.10 2005/04/15 23:44:24 gafton Exp $ # License: GPL import os import sys import cgi -import stat -import md5 import tempfile -import StringIO import grp +try: + import hashlib + md5_constructor = hashlib.md5 +except ImportError: + import md5 + md5_constructor = md5.new -# reading buffer size +# Reading buffer size BUFFER_SIZE = 4096 -# Debugging version -DEBUG = 0 - # We check modules exist from this dircetory -CVSREPO = "/cvs/pkgs/rpms" +CVSREPO = '/cvs/pkgs/rpms' + +# Lookaside cache directory +CACHE_DIR = '/srv/cache/lookaside/pkgs' # Fedora Packager Group -PACKAGER_GROUP = "packager" +PACKAGER_GROUP = 'packager' -# log a trace of what we're doing -def log_msg(*msgs): - s = StringIO.StringIO() - for m in msgs: - s.write("%s " % (m,)) - sys.stderr.write("%s\n" % (s.getvalue(),)) - del s - -os.umask(002) - -# log the entire environment -def log_environ(): - for k in os.environ.keys(): - log_msg("%s=%s" % (k, os.environ[k])) - return - -# abort running the script def send_error(text): - print "Content-type: text/plain\n" + print 'Content-type: text/plain' + print print text sys.exit(1) -# prepare to exit graciously -def send_ok(text): - print "Content-type: text/plain\n" - if text: - print text - -# check and validate that all the fields are present -def check_form(var): +def check_form(form, var): if not form.has_key(var): - send_error("Required field '%s' is not present" % (var,)) + send_error('Required field "%s" is not present.' % var) ret = form.getvalue(var) - if type(ret) == list: - send_error("Multiple values given for '%s'. Aborting" % (var,)) - ret = os.path.basename(ret) # this is a path component + if isinstance(ret, list): + send_error('Multiple values given for "%s". Aborting.' % var) return ret -# if a directory exists, check that it has the proper permissions -def check_dir(tmpdir, wok = os.W_OK): - if not os.access(tmpdir, os.F_OK): - return 0 - if not os.access(tmpdir, os.R_OK|os.X_OK|wok): - send_error("Unable to write to %s repository." % ( - tmpdir,)) - if not os.path.isdir(tmpdir): - send_error("Path %s is not a directory." % (tmpdir,)) - return 1 +os.umask(002) authenticated = False @@ -84,127 +53,105 @@ if os.environ.has_key('SSL_CLIENT_S_DN_CN'): if auth_username in grp.getgrnam(PACKAGER_GROUP)[3]: authenticated = True -pieces = os.environ['REQUEST_URI'].split('/') -assert pieces[1] == 'repo' - -if not authenticated - print """Status: 403 Forbidden -Content-type: text/plain - -You must be in the %s group to upload. -""" % PACKAGER_GROUP +if not authenticated: + print 'Status: 403 Forbidden' + print 'Content-type: text/plain' + print + print 'You must be in the %s group to upload.' % PACKAGER_GROUP sys.exit(0) +print 'Content-Type: text/plain' +print + +assert os.environ['REQUEST_URI'].split('/')[1] == 'repo' + form = cgi.FieldStorage() -NAME = check_form("name") -MD5SUM = check_form("md5sum") +name = check_form(form, 'name') +md5sum = check_form(form, 'md5sum') + +action = None +upload_file = None +filename = None # Is this a submission or a test? -# in a test, we don't get a FILE, just a FILENAME. -# In a submission, we don;t get a FILENAME, just the FILE. -FILE = None -FILENAME = None - -if form.has_key("filename"): - # check the presence of the file - FILENAME = check_form("filename") - log_msg("Checking file status", "NAME=%s FILENAME=%s MD5SUM=%s" % (NAME,FILENAME,MD5SUM)) +# in a test, we don't get a file, just a filename. +# In a submission, we don;t get a filename, just the file. +if form.has_key('filename'): + action = 'check' + filename = check_form('filename') + filename = os.path.basename(filename) + print >> sys.stderr, 'Checking file status: NAME=%s FILENAME=%s MD5SUM=%s' % (name, filename, md5sum) else: - if form.has_key("file"): - FILE = form["file"] - if not FILE.file: - send_error("No file given for upload. Aborting") + action = 'upload' + if form.has_key('file'): + upload_file = form['file'] + if not upload_file.file: + send_error('No file given for upload. Aborting.') try: - FILENAME = os.path.basename(FILE.filename) + filename = os.path.basename(upload_file.filename) except: - send_error("Could not extract the filename for upload. Aborting") + send_error('Could not extract the filename for upload. Aborting.') else: - send_error("required field '%s' is not present" % ("file", )) - log_msg("Processing upload request", "NAME=%s FILENAME=%s MD5SUM=%s" % (NAME,FILENAME,MD5SUM)) + send_error('Required field "file" is not present.') + print >> sys.stderr, 'Processing upload request: NAME=%s FILENAME=%s MD5SUM=%s' % (name, filename, md5sum) -# Now that all the fields are valid, figure out our operating environment -if not os.environ.has_key("SCRIPT_FILENAME"): - send_error("My running environment is funky. Aborting") - -# start processing this request -my_script = os.environ["SCRIPT_FILENAME"] - -# the module's top level directory -my_topdir = os.path.dirname(my_script) -my_moddir = "%s/%s" % (my_topdir, NAME) -my_filedir = "%s/%s" % (my_moddir, FILENAME) -my_md5dir = "%s/%s" % (my_filedir, MD5SUM) +module_dir = os.path.join(CACHE_DIR, name) +file_dir = os.path.join(module_dir, filename) +md5_dir = os.path.join(file_dir, md5sum) # first test if the module really exists -if not check_dir("%s/%s" % (CVSREPO, NAME), 0): - log_msg("Unknown module", NAME) - send_ok("Module '%s' does not exist!" % (NAME,)) +cvs_dir = os.path.join(CVSREPO, name) +if not os.path.isdir(cvs_dir): + print >> sys.stderr, 'Unknown module: %s' % name + print 'Module "%s" does not exist!' % name sys.exit(-9) # try to see if we already have this file... -file_dest = "%s/%s/%s/%s/%s" % (my_topdir, NAME, FILENAME, MD5SUM, FILENAME) -if os.access(file_dest, os.F_OK | os.R_OK): - # already there, spare the effort - s = os.stat(file_dest) - # if we're just checking we need to be rather terse - if FILE is None: - message = "Available" +dest_file = os.path.join(md5_dir, filename) +if os.path.exists(dest_file): + if action == 'check': + print 'Available' else: - FILE.file.close() - message = "File %s already exists\nFile: %s Size: %d" % (FILENAME, file_dest, s[stat.ST_SIZE]) - send_ok(message) + upload_file.file.close() + dest_file_stat = os.stat(dest_file) + print 'File %s already exists' % filename + print 'File: %s Size: %d' % (dest_file, dest_file_stat.st_size) sys.exit(0) - -# just checking? -if FILE is None: - send_ok("Missing") +elif action == 'check': + print 'Missing' sys.exit(-9) # check that all directories are in place -for tmpdir in [my_topdir, my_moddir, my_filedir, my_md5dir]: - if not check_dir(tmpdir): - # we agree to create this directory if the corresponding cvs module dir exists - if tmpdir == my_moddir: - # W_OK access is not necessary for this cgi - if check_dir("%s/%s" % (CVSREPO, NAME), 0): - os.mkdir(tmpdir, 02775) - log_msg("mkdir", tmpdir) - continue - if tmpdir in [ my_filedir, my_md5dir ]: - # don't require those directories just yet - continue - send_error("Directory %s does not exist and I won't create it" % (tmpdir,)) - +if not os.path.isdir(module_dir): + os.makedirs(module_dir, 02775) + # grab a temporary filename and dump our file in there tempfile.tempdir = my_moddir -tmpfile = tempfile.mktemp(MD5SUM) -tmpfd = open(tmpfile, "wb+") +tmpfile = tempfile.mktemp(md5sum) +tmpfd = open(tmpfile, 'w') + # now read the whole file in -m = md5.new() -FILELENGTH=0 -while 1: - s = FILE.file.read(BUFFER_SIZE) +m = md5_constructor() +filesize = 0 +while s = upload_file.file.read(BUFFER_SIZE): if not s: break tmpfd.write(s) m.update(s) - FILELENGTH = FILELENGTH + len(s) + filesize += len(s) # now we're done reading, check the MD5 sum of what we got tmpfd.close() -my_md5sum = m.hexdigest() -if MD5SUM != my_md5sum: - send_error("MD5 check failed. Received %s instead of %s" % ( - my_md5sum, MD5SUM)) +check_md5sum = m.hexdigest() +if md5sum != check_md5sum + send_error("MD5 check failed. Received %s instead of %s." % (check_md5sum, md5sum)) # wow, even the MD5SUM matches. make sure full path is valid now -for tmpdir in [ my_moddir, my_filedir, my_md5dir ]: - if not check_dir(tmpdir): - os.mkdir(tmpdir, 02775) - log_msg("mkdir", tmpdir) -# and move our file to the final location +if not os.path.isdir(md5_dir): + os.mkdirs(md5_dir, 02775) + print >> sys.stderr, 'mkdir %s' % md5_dir -os.rename(tmpfile, file_dest) -log_msg("Stored filesize", FILELENGTH, file_dest) +os.rename(tmpfile, dest_file) +print >> sys.stderr, 'Stored %s (%d bytes)' % (dest_file, filesize) +print 'File %s size %d MD5 %s stored OK' % (filename, filesize, md5sum) -send_ok("File %s size %d MD5 %s stored OK" % (FILENAME, FILELENGTH, MD5SUM))