in reply to using online translation engines with perl

Aldebaran:

Regarding part of your your question "I'm looking for a way to make the failure of mkdir more informative for the case that the directory already exists. I keep the mkdir line so that it will work the first time it is used. Every subsequent time, it fails, and $! is stone silent.", I'd suggest creating a function that checks whether the directory exists before creating it, something like (untested):

sub createDir { my $dirName = shift; if (-e $dirName) { if (-d $dirName) { return "Directory $dirName already exists!"; } else { return "Can't create $dirName because there's a file in th +e way!"; } } mkdir $dirName or return $!; }

...roboticus

When your only tool is a hammer, all problems look like your thumb.

Replies are listed 'Best First'.
Re^2: using online translation engines with perl
by afoken (Chancellor) on Nov 08, 2018 at 20:38 UTC

    I'd suggest creating a function that checks whether the directory exists before creating it

    sub createDir { my $dirName = shift; if (-e $dirName) { if (-d $dirName) { return "Directory $dirName already exists!"; } else { return "Can't create $dirName because there's a file in th +e way!"; } } mkdir $dirName or return $!; }

    No. Just no. Or in more words: TOCTTOU.

    The only sane way to do this is to run mkdir and have it fail in case the target already exists. This way, the operating system guarantees that there won't be a race.

    mkdir $path or die "Can't mkdir $path: $!";

    It will fail with EEXISTS at least on Unix and Windows if the target already exists. There are several more possible errors, e.g. lack of permissions, filesystem problems. See POSIX.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      Thx for your response, alexander, I rewrote the function to reflect $sftp->error as a first best way to get useful error info from Net::SFTP::Foreign. As I started to test the new create directory, I did discover that having a plain file as the directory one wants to create causes an error, but I have played enough with this race condition that I don't want to play anymore. I'm reminded of John van Neumann's adage: "Don't play bad logic games."

      I also made a first attempt at handling the error. One is left to ponder how an sftp method call to mkdir might fail and what a person with perl can do about it. It's common for the wireless to give out, as the laptop roams with me at tortoise speed. It's a hard thing to try to induce at a critical moment against the swiftness of machine instructions.

      I'm going to revert to an architecture where I deal with the consequences of the mkdir as the critical path. I tried to write a code to remove the file, and wanted to try to do some other things if I lose my sftp connection. It's a big mess. I also tried to limit processes to reasonable amounts of time, but I haven't figured out how to handle $SIG{ALRM} yet, as none of these processes terminates. I'm gonna put abridged output and then source between readmore tags and pull out a couple issues.

      Let me just ask: do people ping anymore, or is that an old-fashioned way to see if one has internet connectivity? For example, I pinged perlmonks and got no answer, and had my terminal tied up. Might a person use curl instead?

      What would I have to add for any of those alarms to terminate the process in which they are set?

      Thanks all for comments

        Let me just ask: do people ping anymore, or is that an old-fashioned way to see if one has internet connectivity?

        I still use ping for this as it gives more useful diagnostics than many other methods and it doesn't fail due to certificate failures, etc.

        For example, I pinged perlmonks and got no answer, and had my terminal tied up.

        You need to know how to use the tool of your choice. If you just run something like you have as

        my $trial = system("ping www.google.com");

        how do you expect it ever to finish? Using some of the options restricts the action to a finite process:

        $ ping -nc1 perlmonks.org PING perlmonks.org (209.197.123.153) 56(84) bytes of data. 64 bytes from 209.197.123.153: icmp_seq=1 ttl=57 time=90.1 ms --- perlmonks.org ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 90.195/90.195/90.195/0.000 ms $

        Response received, data displayed, no tying up the terminal forever. Alternatively, see Net::Ping.

Re^2: using online translation engines with perl
by Aldebaran (Curate) on Nov 07, 2018 at 00:19 UTC

    Thx roboticus, people might have different needs for their mkdir capability. Given that I'm the only person running this script, I don't see how this can create a race condition.

    #load html file to server my $server_dir = $vars{"server_dir"}; say "server dir is $server_dir"; my $return1 = createDir( $server_dir, $sftp ); say "return1 is $return1"; $sftp->setcwd("/$server_dir") or warn "setcwd1 failed $!\n"; $sftp->put( $vars{html_file} ) or die "html put failed $!\n"; #load css file to server $sftp->setcwd("/css") or warn "setcwd2 failed $@\n"; my $path3 = path( $vars{css_path}, $vars{"css_file"} ); say "path3 is $path3"; my $remote_css = $vars{"css_file"}; $sftp->put( "$path3", $remote_css ) or warn "css put failed $@\n"; # upload images my $image_dir = $vars{"image_dir"}; say "image dir is $image_dir"; my $return2 = createDir( $image_dir, $sftp ); say "return2 is $return2"; $sftp->setcwd("/$image_dir") or warn "setcwd2 failed $!\n"; my $return3 = createDir( $vars{remote_dir}, $sftp ); say "return3 is $return3"; $sftp->setcwd( $vars{remote_dir} ) or warn "setcwd3 failed $!\n"; print $sftp->cwd(), "\n";

    I had to make the logic work for Net::SFTP::Foreign:

    sub createDir { use 5.011; use Net::SFTP::Foreign; my ( $dirName, $sftp ) = @_; if ( $sftp->test_e($dirName)) { if ( $sftp->test_d($dirName)) { say "execution was here"; return "Directory $dirName already exists!"; } else { return "Can't create $dirName because there's a file in the way! +"; } } my $success = $sftp->mkdir($dirName) or return $!; return $success; }

    Output:

    Put file to server(y/n)?: y server dir is perlmonks execution was here return1 is Directory perlmonks already exists! path3 is /home/bob/2.scripts/pages/1.timeout/template_stuff/1.timeout1 +.css image dir is pmimage execution was here return2 is Directory pmimage already exists! return3 is 1 /pmimage/1.timeout6

    I think that's got it. Thank you.