Willman023 has asked for the wisdom of the Perl Monks concerning the following question:

Ok, I'm trying to do something very simple and I can't seem to figure out where I'm going wrong. I simply would like add a feature to my upload script and if a file with the same name already exists append a ~1 similar I guess to MSDOS 8.3, only I don't have a 8 character restriction. So here's my code, and after uploading the same file twice for some reason I get filename~3 instead of starting at ~1 like I would expect. Thanks!

if (-e <$upload_dir/$filename2>) { my $inc; # incrementor for($inc = 1; -e <$upload_dir/$filename2 . "~" . $inc>; $inc++) { # Check for previous incremented filenames } $filename2 = $filename2 . "~" . $inc; }

bW

Perl - the breakfast of Champions!

Replies are listed 'Best First'.
Re: Overwrite file protection
by sgifford (Prior) on Jun 16, 2003 at 22:17 UTC

    Note that there's a race condition in this technique. User 1 uploads a file called "hello", it doesn't exist, we fall out of the if statement, then User 1's process goes to sleep. User 2 logs in, uploads a file called "hello", it doesn't exist, we fall out, and User 2's process creates hello. Now User 1 wakes back up, and happily overwrites User 2's hello.

    To solve this (with has nothing to do with your original question, I know) you'll need to use sysopen with the O_EXCL flag, use some kind of file locking, or else write to a temp file with a unique name and use link to rename it to the ~1-style name.

Re: Overwrite file protection
by monsieur_champs (Curate) on Jun 16, 2003 at 20:02 UTC

    Hello,

    I don't see the point in using '<' and '>' for the filename, inside the for loop.

    This do the trick:

    if( -e $upload_dir.'/'.$filename2 ){ my $inc = '1'; while( -e $upload_dir . '/' . $filename2 . '~' .$inc ){ $inc++; } # Use "${upload_dir}/${filename2}~${inc}" as the filename. }

    Warning: untested code. Please pay attention to possible mispells and errors.

    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Just Another Perl Monk

      It's funny you guys recommended using a while loop, as thats originally what I did in fact use. I'm assuming that when I had: -e <$upload_dir/$filename2 . "~" . $inc>; compared to your -e $upload_dir . '/' . $filename2 . '~' . $inc that it was possibly not matching the appended string correctly, and that may be where my problem was. But, after pasting in monsieur's code I was in fact incrementing correctly, Thanks Alot guys!

      bW

      Perl - the breakfast of Champions!

        I'm sorry. I should explain what's going on behind the scene:

        When you surround your filename expression (actually, a scalar holding the filename) with '<' and '>', what you get is a file glob. That's the name of this use of '<' and '>' surrounding a scalar designing a filename or something that looks like a file name set (think on it as the equivalent of using dir *.txt on the old D.O.S.).

        File globbing is used to do strange (not that strange, indeed) things with sets of filenames.

        The strange behavior of your script was because the file name globbing was working when you didin't like it to.

        Maybe I should rewrite this comment, I feel that it may confuse you. If it do so, please let me know and I will try to fix it up

        =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        Just Another Perl Monk

Re: Overwrite file protection
by benn (Vicar) on Jun 16, 2003 at 20:02 UTC
    You have to remember that $inc++ is performed each time round the loop,like so:
    $inc = 1; -e < $filename~1 >;$inc++; # file exists, $inc now 2 $inc = 2; -e < $filename~2 >;$inc++; # file doesn't exist, $inc now 3
    You may be better off using something like..
    $inc = 1; while (-e $filename."~".$inc) { $inc++;}
    Cheers, Ben.

      Or, in a way that reads more naturally (to me, at least)

      my $inc; $inc++ until ( not -e "$filename~$inc" );
      Note that starting with an undefined $inc eliminates the need for the first check. In other words, the whole sub would be as easy as:
      sub good_filename { my $filename = shift; my $inc; $inc++ until ( not -e "$filename~$inc" ); return "$filename~$inc"; }
      -sauoq
      "My two cents aren't worth a dime.";