Rename file if it exists.

S

Stephen Reese

The script below uploads files to a web server. Currently it
overwrites a file if it already exists. I'm instead trying to rename
the old file with an appended date/timestamp before the new file is
uploaded. I *think* I have the idea down but it's not be implemented
in the script correctly. Any hints would be great, thanks.

#!/usr/bin/env python
import cgi, os
import cgitb; cgitb.enable()
#import os.path
import hashlib
import datetime

try: # Windows needs stdio set for binary mode.
import msvcrt
msvcrt.setmode (0, os.O_BINARY) # stdin = 0
msvcrt.setmode (1, os.O_BINARY) # stdout = 1
except ImportError:
pass

form = cgi.FieldStorage()

# Generator to buffer file chunks
def fbuffer(f, chunk_size=10000):
while True:
chunk = f.read(chunk_size)
if not chunk: break
yield chunk

# A nested FieldStorage instance holds the file
fileitem = form['file']

# Test if the file was uploaded
if fileitem.filename:

# Test to determine if file name already exists in destination and
rename if it does exist to include date.
if os.path.isfile(file):
os.rename(file,file + "date")
else:

# strip leading path from file name to avoid directory traversal attacks
fn = os.path.basename(fileitem.filename)
f = open('/var/www/dropbox/' + fn, 'wb', 10000)

h = hashlib.md5()
datalength = 0

# Read the file in chunks
for chunk in fbuffer(fileitem.file):
f.write(chunk)
h.update(chunk)
datalength += len(chunk)
hexdigest = h.hexdigest()
f.close()

message = 'The file "' + fn + '" was uploaded successfully with a
MD5 hash value of ' + hexdigest + ', click <a href="#">here</a> to go
back.'

else:
message = 'No file was uploaded'

print """\
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
 
D

Diez B. Roggisch

Stephen said:
The script below uploads files to a web server. Currently it
overwrites a file if it already exists. I'm instead trying to rename
the old file with an appended date/timestamp before the new file is
uploaded. I *think* I have the idea down but it's not be implemented
in the script correctly. Any hints would be great, thanks.

#!/usr/bin/env python
import cgi, os
import cgitb; cgitb.enable()
#import os.path
import hashlib
import datetime

try: # Windows needs stdio set for binary mode.
import msvcrt
msvcrt.setmode (0, os.O_BINARY) # stdin = 0
msvcrt.setmode (1, os.O_BINARY) # stdout = 1
except ImportError:
pass

form = cgi.FieldStorage()

# Generator to buffer file chunks
def fbuffer(f, chunk_size=10000):
while True:
chunk = f.read(chunk_size)
if not chunk: break
yield chunk

# A nested FieldStorage instance holds the file
fileitem = form['file']

# Test if the file was uploaded
if fileitem.filename:

# Test to determine if file name already exists in destination and
rename if it does exist to include date.
if os.path.isfile(file):
os.rename(file,file + "date")
else:

This isn't working because the else: is dangling. And I think your logic
is flawed (I might be wrong of course) because you rename the *existing*
file instead of giving the new one a new data.

Thus e.g. a link to the file (if it's a webserver) will suddenly deliver
a different file. I doubt that's what you wanted. And you also can only
upload one file per *day*. Which doesn't sound good to me. You should
disambiguate further. And if it's ok to append a date, I suggest you do
that always.

So instead, the logic should be something like this:

import datetime

basename = ... # however you get to that

basename = basename + "_" + datetime.datetime.now().strftime("%Y-%m-%d")

count = 0
filename = basename
while os.path.isfile(filename):
filename = basename + "." + count
count += 1


Diez
 
S

Stephen Reese

This isn't working because the else: is dangling. And I think your logic is
flawed (I might be wrong of course) because you rename the *existing* file
instead of giving the new one a new data.

Thus e.g. a link to the file (if it's a webserver) will suddenly deliver a
different file. I doubt that's what you wanted. And you also can only upload
one file per *day*. Which doesn't sound good to me. You should disambiguate
further. And if it's ok to append a date, I suggest you do that always.

So instead, the logic should be something like this:

import datetime

basename = ... # however you get to that

basename = basename + "_" + datetime.datetime.now().strftime("%Y-%m-%d")

count = 0
filename = basename
while os.path.isfile(filename):
   filename = basename + "." + count
   count += 1


Diez

Diez,

Ahh that would be much easier to just date the file upon upload. My
initial concern was that renaming the file would alter the hash value,
obviously I didn't think this one through too well.

I adjusted the code and tried to incorporate your recommendation but
still no go. Anything else obviously wrong with the following snippet?

Thanks


# Test if the file was uploaded
if fileitem.filename:

# strip leading path from file name to avoid directory traversal attacks
fn = os.path.basename(fileitem.filename)

# Include date in filename.
basename = fn
basename = basename + "_" + datetime.datetime.now().strftime("%Y-%m-%d")
count = 0
fn = basename
while os.path.isfile(fn):
fn = basename + "." + count
count += 1

# Open file for writing
f = open('/var/www/dropbox/' + fn, 'wb', 10000)
h = hashlib.md5()
datalength = 0

# Read the file in chunks
for chunk in fbuffer(fileitem.file):
f.write(chunk)
h.update(chunk)
datalength += len(chunk)
hexdigest = h.hexdigest()
f.close()

message = 'The file "' + fn + '" was uploaded successfully with a
MD5 hash value of ' + hexdigest + ', click <a href="#">here</a> to go
back.'
 
D

Dave Angel

Stephen said:
The script is working and appending the date to newly uploaded files
but it is not adding the count? Any recommendations? Is the problem
due to os.path.isfile(fn): being just the file name and not the full
path? Thanks.

# strip leading path from file name to avoid directory traversal attacks
fn =s.path.basename(fileitem.filename)

# Include date in filename.
basename =n
basename =asename + "_" + datetime.datetime.now().strftime("%Y-%m-%d")
count =
fn =asename
while os.path.isfile(fn):
fn = basename + "." + count
count +=

# Open the file for writing
f =pen('/var/www/apache2-default/' + fn, 'wb', 10000)
Clearly, the os.path.isfile() is never returning true, because once it
does, you'll get a string error on the next line. You need

fn = basename + "." + str(count)

or something similar.

Anyway, isfile() needs a complete path, there's no way it can guess what directory you plan to use.

To build a complete path, you need something like:

fullname = os.path.join('/var/www/apache2-default/', fn)

You ought to use that on the actual open as well. As long as you're hard-coding the path prefix, plain string concatenation can work, but eventually you'll get the string from somewhere else, and what happens if someone forgets the trailing slash?
 
S

Stephen Reese

Clearly, the os.path.isfile() is never returning true, because once it does,
you'll get a string error on the next line.  You need

    fn = basename + "." + str(count)

or something similar.

Anyway, isfile() needs a complete path, there's no way it can guess what
directory you plan to use.

To build a complete path, you need something like:

  fullname = os.path.join('/var/www/apache2-default/', fn)

You ought to use that on the actual open as well.  As long as you're
hard-coding the path prefix, plain string concatenation can work, but
eventually you'll get the string from somewhere else, and what happens if
someone forgets the trailing slash?

Thanks Dave, got it working with the following bit:

# strip leading path from file name to avoid directory traversal attacks
fn = os.path.basename(fileitem.filename)
path = '/var/www/apache2-default/'
filepath = path + fn

# Include date in filename.
filepath = filepath + "_" + datetime.datetime.now().strftime("%Y-%m-%d")

count = 0
tmp_fn = filepath + "." + str(count)
while os.path.isfile(tmp_fn):
count += 1
tmp_fn = filepath + "." + str(count)
filepath = tmp_fn

# Get the new filename for the users viewing pleasure
displaypath, tmp_split = os.path.split(filepath)

# Open the file for writing
f = open(filepath , 'wb', 10000)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,709
Latest member
AustinMudi

Latest Threads

Top