//
// aegis - project change supervisor
// Copyright (C) 1994, 1995, 1998, 1999, 2001, 2003-2006, 2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include
#include
#include
#include
#include // for assert
#include
#include
#include
#include
#include
#include
#include
#include
#include
input_file::~input_file()
{
trace(("input_file::~input_file()\n{\n"));
if (fd >= 0)
{
if (glue_close(fd))
{
int errno_old = errno;
sub_context_ty *scp = sub_context_new();
sub_errno_setx(scp, errno_old);
sub_var_set_string(scp, "File_Name", path);
fatal_intl(scp, i18n("close $filename: $errno"));
// NOTREACHED
}
// The file only exists if fd>=0
if (unlink_on_close_flag)
os_unlink_errok(path);
fd = -1;
}
trace(("}\n"));
}
static int
open_with_stale_nfs_retry(const char *path, int mode)
{
trace(("open_with_stale_nfs_retry(path = \"%s\", mode = %d)\n{\n", path,
mode));
//
// Try to open the file.
//
errno = 0;
int perms = 0666;
int fd = glue_open(path, mode, perms);
//
// Keep trying for one minute if we get a Stale NFS file handle
// error. Some systems suffer from this in a Very Bad Way.
//
#ifdef ESTALE
const int nsecs = 5;
for (int ntries = 0; ntries < 60; ntries += nsecs)
{
if (fd >= 0)
break;
if (errno != ESTALE)
break;
sleep(nsecs);
errno = 0;
fd = glue_open(path, mode, perms);
}
#endif
//
// Return the result, both success and failure.
// Errors are handled elsewhere.
//
trace(("return %d\n", fd));
trace(("}\n"));
return fd;
}
input_file::input_file(const nstring &arg1, bool arg2, bool empty_if_absent) :
path(arg1),
fd(-1),
unlink_on_close_flag(arg2),
pos(0)
{
trace(("input_file::input_file(\"%s\")\n{\n", arg1.c_str()));
os_become_must_be_active();
int mode = O_RDONLY;
#if defined(__CYGWIN__) || defined(__CYGWIN32__)
// I'm not sure whether MacOsX uses \r or \n in its native text
// files, so I'm reluctant to always use the O_BINARY mode bit.
mode |= O_BINARY;
#endif
fd = open_with_stale_nfs_retry(path.c_str(), mode);
if (fd < 0)
{
int errno_old = errno;
if (!empty_if_absent || errno_old != ENOENT)
{
sub_context_ty sc(__FILE__, __LINE__);
sc.errno_setx(errno_old);
sc.var_set_string("File_Name", path);
sc.fatal_intl(i18n("open $filename: $errno"));
// NOTREACHED
}
}
trace(("}\n"));
}
long
input_file::read_inner(void *data, size_t len)
{
trace(("input_file::read_inner()\n"));
assert(reference_count_valid());
os_become_must_be_active();
if (len == 0)
return 0;
if (fd < 0)
return 0;
long result = glue_read(fd, data, len);
if (result < 0)
{
int errno_old = errno;
sub_context_ty sc;
sc.errno_setx(errno_old);
sc.var_set_string("File_Name", path);
sc.fatal_intl(i18n("read $filename: $errno"));
// NOTREACHED
}
pos += result;
return result;
}
long
input_file::ftell_inner()
{
assert(reference_count_valid());
return pos;
}
nstring
input_file::name()
{
assert(reference_count_valid());
return path;
}
long
input_file::length()
{
assert(reference_count_valid());
if (fd < 0)
return 0;
return os_file_size(path.get_ref());
}
void
input_file::keepalive()
{
assert(reference_count_valid());
if (fd >= 0)
{
int on = 1;
// ignore any error
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on));
}
}
void
input_file::unlink_on_close()
{
assert(reference_count_valid());
unlink_on_close_flag = true;
}
input
input_file_open(const nstring &fn, bool unlink_on_close, bool empty_if_absent)
{
os_become_must_be_active();
if (fn.empty() || fn == "-")
return new input_stdin();
if (input_curl::looks_likely(fn))
return new input_curl(fn);
return new input_file(fn, unlink_on_close, empty_if_absent);
}
input
input_file_open(string_ty *fn, bool unlink_on_close)
{
return input_file_open(nstring(fn), unlink_on_close);
}