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

I hope I can explain this right. The code sniplet below works fine except for when the user wants to delete a duplicate entry, which I give them a warning message that they have to do that manually, and it does not remove any entries in the file. But when the user goes to remove the file lock (2nd code sniplet)it delets everything in the file. I've been looking at this code for a few days now and cannot find where or why it is doing this. If a user tries to hit the back button instead they get a "file locked" message, then if they delete the lock everything works as coded. Can anyone see what I have done wrong?
########################################################### This subro +utine writes the item list for a given filter section. sub write_items { my ($chk_header) = @_; my $tmp_count = 0; my $tmp_header = param('SecName'); my $t_items = param('display_items'); my @tmp_items = split("-endofline-",$t_items); my $t_write_items; my $tmp_item; my $c = 0; my $tmp_item; my $tmp_name; my $tmp_hold; my $tmp_ct; my @item_list = ""; #Initialize the item_line array. for ($c=0; $c<1; $c++) { $item_line[$c] = ""; } # tmp_header is the filter that has been modified. Check each head +er (chk_header) # to see if it is the one that has been modified. if ($chk_header eq $tmp_header) { for($c=0; $c<1; $c++) { $tmp_name ="item_" . $c; #This section writes the content +for the section being modified. $tmp_hold = param($tmp_name); chomp $tmp_hold; $tmp_ct = 0; $tmp_ct++ while $tmp_hold =~ /./g; if ($tmp_ct >= 1) { $item_list[$c] = $tmp_hold; }#end if }#end for }#end if else { $t_write_items = $tmp_items[$a]; @item_list = split("\",\"",$t_write_items); } foreach $tmp_item (@item_list) { if ($tmp_count > 4) { $tmp_count = 0; } if ($tmp_item eq "") {next;} if ($tmp_item ne "") { $item_line[$line_count] = $item_line[$line_count] . $tmp_item +; } $tmp_count++; }#end foreach } ###################################################### sub deleted_section { my ($chk_header) = @_; my $tmp_header = param('SecName'); if ($chk_header eq $tmp_header) { # This is the section header that we want to delete. 1; } else { 0; } } ################################### sub write_filter { my $name = param('header_name'); my $ttl = param('total_headers'); my $if_act = param('action_line'); my @act = split("-endofline-",$if_act); my $if_tmp = param('if_line'); my @if = split("-endofline-",$if_tmp); my $write_header; my $write_action; my $write_if; my $header_line; my $j = "#"; $a=0; my $delete_only_once = 0; @tmp_headers = split("-endofline-",$name); chdir "$home_dir"; open FILE, ">$filename" or die "Could not open file '$filename' for + appending: $! "; print FILE "########## Spamassassin White List ##########\n\n"; while($a<=$ttl) { if (deleted_section($tmp_headers[$a])) { $delete_only_once++; if ( $delete_only_once > 1 ) { # error msg sieve_util_generic_error("Duplicate Section Name: $tmp_ +headers[$a] Delete from UNIX command line.<br><br> Go To the Miscell +aneous link and click the 'Remove whitelist lock'"); } } $a++; } $a = 0; while($a<=$ttl) { $line_count = 0; $write_header = $j . $tmp_headers[$a] . $j; $write_if = $if[$a]; $write_action = $act[$a]; # Write out only those sections that weren't deleted. if (!deleted_section($tmp_headers[$a])) { # Write Section Header #print FILE "$write_header\n"; # Create item list for the individual section write_items($tmp_headers[$a]); my $t = -1; while ($t++ <= $line_count) { if ($item_line[$t] ne "") { print FILE "$item_line[$t]\n\n"; } } } $a++; }#end while close FILE; }#end sub

This is the remove code in a different file

################################# sub sieve_util_remove_filter { my ($relay, $relay_dir, $filename, $home_dir, @lock) = @_; my $lt = localtime(); my @tmp = split " ", $lt; my @online; foreach my $filelock (@lock) { $tmp[3] =~ s/\:/_/g; my $tdate = $tmp[4] . $tmp[1] . $tmp[2] . "_" . $tmp[3]; my $flag_stamp = $filename . $tdate; $| = 1; chdir "$home_dir"; if (my $ftp = Net::FTP->new($filelock)) { #next; die "Cannot login: $@ "unless $ftp; if ($ftp->login("$uid", "$pass")) { if ($ftp->cwd($relay_dir)) { $ftp->binary; @check_dir = $ftp->ls($relay_dir); # File name(s) you want to download foreach $chk (@check_dir) { if ($chk =~ m/$flag_file/) { $ftp->delete($flag_file) }#end if }#end foreach $ftp->quit; } else { sieve_util_generic_error ("Unable to switch to $relay_dir."); } } else { sieve_util_generic_error ("Unable to login to $relay."); } } else { next; } } #end foreach return ($uid,$pass); }

update (broquaint): added <readmore> tag

Replies are listed 'Best First'.
Re: Need help! Data in file getting deleted
by Abigail-II (Bishop) on Nov 19, 2003 at 16:35 UTC
    open FILE, ">$filename" or die "Could not open file '$filename' for ap +pending: $! ";
    That doesn't open the file for appending, it opens it for writing. The entire content of the file will be deleted at this point.

    Abigail

      Right on
      You should use  >> instead.

       open (FILE, ">>$filename") or die "$!";

      Entities should not be multiplied unnecessarily.
        If I do the

        open (FILE, ">>$filename") or die "$!";

        I have two sets of the data in my file. I only want one. It works fine as long as the user doesn't try to delete a duplicate. The duplicate is causing my issues.

Re: Need help! Data in file getting deleted
by graff (Chancellor) on Nov 20, 2003 at 02:16 UTC
    I hope I can explain this right.

    I wish you could have, but... You seem to focus on the condition that causes this error message:

    Duplicate Section Name: (some_parameter_string) Delete from UNIX command line.

    Go To the Miscellaneous link and click the 'Remove whitelist lock'

    and you seem to think this has something to do with file locking. But there is nothing in the code provided that has anything to do with file locking. Your "seive_until_remove_filter" sub has an array called "@lock" and a variable called $filelock, but these appear to contain FTP host names, because your code goes like this:

    sub seive_until_remove_filter { my ($relay, $relay_dir, $filename, $home_dir, @lock) = @_; ... foreach my $filelock ( @lock ) { ... if ( my $ftp = Net::FTP->new($filelock)) { ... ## delete some "flag" file(s) from some path } else { sieve_util_generic_error ("Unable to login to $relay."); } ...

    Could it be you're just using the wrong variable as the ftp host to connect to? What file is it that's getting truncated -- one that is specifically opened in the code shown, or some other file whose name is passed around in one of the parameter strings?

    Maybe you'd better start from first principles. What is this app supposed to do? What conditions are in place when it begins, what user input/decisions are required to make it work, and how are conditions different when it's done? What are the specific boundary conditions or exceptions that will alter its behavior and results? Which of those is causing the trouble?

    Try running it from the command line with "perl -d" to step through the conditional block and/or sub that is supposed to handle the problem case, and check whether the relevant variables have the values you expect, whether the conditionals are evaluating the way you intend, etc. If you've been "looking at this code for a few days" without using the debugger to step through it, you're wasting your time.