Hi folks,
Attached is a changeset that fixes two problems with uploads
("attachments" in Swiki).
1. Older versions of the same file are renamed instead of overwritten.
For example, if "bla.gif" gets uploaded again, the first version is
renamed to "bla.1.gif".
[This uses the existing nextFilename logic, but I fixed it to allow
empty extensions (bla -> bla.1 -> bla.2)]
2. Does not create zero-length files.
For example, in Netscape you can just type "bla" and hit "upload".
A post is performed even if that file didn't exist at the client side,
so Comanche created an empty file "bla" in this case. Now the post is
ignored.
You can try it at http://swiki.gsug.org:8888/gsug/attachments as usual.
Enjoy!
-Bert-
'From Squeak2.7 of 5 January 2000 [latest update: #1770] on 7 April 2000 at 11:22:02
am'!
!FileDirectory methodsFor: 'file name utilities' stamp: 'bf 4/7/2000 10:41'!
nextNameFor: fileName
"Assumes a file name includes a version number encoded as '.'
followed by digits
preceding the file extension. Increment the version number
and answer the new file name.
If a version number is not found, set the version
to 1 and answer a new file name"
| split |
split _ self
splitNameVersionExtensionFor: fileName.
^self nextNameFor: split first extension:
split last.! !
!FileDirectory methodsFor: 'file name utilities' stamp: 'bf 4/7/2000
10:47'!
nextNameFor: baseFileName extension: extension
"Assumes a file name includes
a version number encoded as '.' followed by digits
preceding the file
extension. Increment the version number and answer the new file name.
If a
version number is not found, set the version to 1 and answer a new file name"
|
files splits version dotExtension |
dotExtension _ extension isEmpty
ifTrue: [extension]
ifFalse: [self class dot, extension].
files _ self
fileNamesMatching: (baseFileName,'*', dotExtension).
splits _ files
collect: [:file | self splitNameVersionExtensionFor: file]
thenSelect: [:split | (split at: 1) = baseFileName].
splits _ splits
asSortedCollection: [:a :b | (a at: 2) < (b at: 2)].
splits isEmpty
ifTrue: [version _ 1]
ifFalse: [version _ (splits last at:
2) + 1].
^ (baseFileName, '.', version asString, dotExtension) asFileName! !
!FileDirectory methodsFor: 'file name utilities' stamp: 'bf 4/7/2000 10:54'!
splitNameVersionExtensionFor: fileName
" answer an array with the root name,
version # and extension.
See comment in nextSequentialNameFor: for more details"
| baseName version extension i j |
baseName _ self class baseNameFor:
fileName.
extension _ self class extensionFor: fileName.
(extension isAllDigits
and: [extension isEmpty not])
ifTrue: [^Array with: baseName with:
extension asNumber with: ''].
i _ j _ baseName findLast: [:c | c isDigit not].
i = 0
ifTrue: [version _ 0]
ifFalse:
[(baseName at: i) = $.
ifTrue:
[version _ (baseName copyFrom: i+1 to: baseName size) asNumber.
j _ j - 1]
ifFalse: [version _
0].
baseName _ baseName copyFrom: 1 to: j].
^ Array
with: baseName with: version with: extension! !
!MultipartPostModule methodsFor:
'processing' stamp: 'bf 4/7/2000 11:20'!
openFile: fileName
(FileStream
isAFileNamed: (workDir fullNameFor: fileName))
ifTrue: [workDir rename:
fileName
toBe: (workDir nextNameFor: fileName)].
^workDir fileNamed: fileName! !
!MultipartPostModule methodsFor: 'processing'
stamp: 'bf 4/7/2000 11:21'!
process: request
" process multipart form data "
" save files in the work directory "
" TODO: save other form data "
| hdr body
boundary str idx origFileName fileName file fieldName contentType formDict doc |
#todo. "allow saving elsewhere first"
(request method = 'POST' and: [request
contentType = MIMEDocument contentTypeMultipart])
ifFalse: [^nil].
formDict _ Dictionary new.
boundary _ request multipartBoundary.
"Transcript
show: 'Boundary = ', boundary; cr."
[hdr _ request stream getSubHeader.
hdr
isEmptyOrNil ifTrue: [request privPostFields: formDict. ^nil].
"Transcript show: hdr
asString; cr."
str _ (hdr at: 'content-disposition' ifAbsent: ['']).
fileName _ fieldName _ ''.
file _ nil.
idx _ str findString: 'filename='.
idx > 0 ifTrue: [fileName _ str copyFrom: idx + 10 to: (str indexOf: $" startingAt:
idx+10) - 1].
idx _ str findString: 'name='.
idx > 0 ifTrue: [fieldName _ str
copyFrom: idx + 6 to: (str indexOf: $" startingAt: idx+6) - 1].
contentType _
hdr at: 'content-type' ifAbsent: [MIMEDocument defaultContentType].
"Transcript show:
'field=', fieldName; cr; show: 'file=', fileName; cr;
show: 'content-type=',
contentType; cr."
origFileName _ fileName.
(fileName size > 0 and:
[Comanche allowUploads])
ifTrue: [fileName _ (fileName findTokens:
':/\') last.
fileName _ (FileDirectory checkName: fileName fixErrors:
true) asLowercase unescapePercents]
ifFalse: [fileName _ nil].
" TODO:
parse regular form data "
" TODO: create IgnoreStream "
"Transcript show: 'reading
body...'; cr."
body _ request stream nextChunk.
"IE4 for Mac appends 128
bytes of Mac file system info - must remove"
"this fix assumes that body size >=
128"
((body at: 1) asciiValue = 0
and: [(body at: 2)
asciiValue = origFileName size
and: [(body copyFrom: 3
to: origFileName size + 2) = origFileName]])
ifTrue: [body _ body copyFrom:
129 to: body size].
[(idx _ body findString: boundary) = 0]
whileTrue:
[idx _ body size - boundary size + 1 max: 1.
str _ request stream nextChunk.
fileName ifNotNil: [
file ifNil: [file _ self openFile: fileName].
file nextPutAll: (body copyFrom: 1 to: idx - 1)].
body _ (body copyFrom: idx to: body size) , str].
fileName ifNotNil: [
(file isNil and: [idx>5]) ifTrue: [file _ self openFile: fileName].
file
ifNotNil: [
" save the last chunk in the file "
file nextPutAll: (body copyFrom: 1 to: idx-5). " idx-1 - String crlf size "
file close.
doc _ MIMEDocument contentType:
contentType content: ''
url: (String streamContents:
[:stream |
stream nextPutAll: 'file://'.
(workDir pathName findTokens: FileDirectory slash)
do: [:piece |
stream nextPutAll: piece; nextPut: $/].
stream nextPutAll: fileName]).
formDict at: fieldName put:
doc]].
request stream putDataBack: (body copyFrom: idx-4 to: body size).
request stream atEnd or: [hdr isNil]
] whileFalse.
request privPostFields:
formDict.
^nil! !