blob: 35ef988a791443df8afd5589db3735babcd212e8 [file] [log] [blame]
/***********************************************************************
*
* 27.filebuf.members.stdcxx-308.cpp - regression test for STDCXX-308
* http://issues.apache.org/jira/browse/STDCXX-308
*
* $Id$
*
***********************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2008 Rogue Wave Software, Inc.
*
***********************************************************************
*
* Test description:
* Sets a maxinum file size limit, forces filebuf to exceed the limit,
* causing the class dtor to fail to flush the excess data. Verifies
* that the dtor closes the associated file descriptor regardless of
* the failure as required by the resolution of LWG issue 622:
* http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#622
*
***********************************************************************/
#include <cassert> // for assert()
#include <cstdio> // for remove(), size_t
#include <fstream> // for filebuf
#if !defined (_WIN32) || defined (__CYGWIN__)
# include <sys/resource.h> // for getrlimit(), rlim_t
# include <unistd.h> // for close(), write(), ssize_t
#endif // !_WIN32 || __CYGWIN__
int write_bytes (const char *fname, std::size_t nbytes)
{
std::filebuf fb;
if ( 0 == fb.pubsetbuf (0, nbytes + 1)
|| 0 == fb.open (fname, std::ios::out))
return -1;
#if defined (_RWSTD_VER) && !defined (_RWSTD_NO_EXT_FILEBUF)
// use the filebuf::fd() extension to get the filebuf's
// associated file descriptor
const int fd = fb.fd ();
#else // if defined (RWSTD_NO_EXT_FILEBUF)
// assume fd is the next available file descriptor after
// STDIN_FILENO, _FILENO_STDOUT, and STDERR_FILENO
const int fd = 3;
#endif // RWSTD_NO_EXT_FILEBUF
if (0 < fd) {
// fill up the filebuf's character buffer without
// overflowing
for (std::size_t i = 0; i != nbytes; ++i)
fb.sputc ('*');
}
// have filebuf dtor try to flush the object's character
// buffer and expect it to fail (and flush out only the
// number specified by RLIMIT_FSIZE)
// return the file descriptor to the caller so that it can
// verify that it has been closed
return fd;
}
int main ()
{
#if !defined (_WIN32) || defined (__CYGWIN__)
const char fname[] = "testfile.text";
std::remove (fname);
rlimit rl;
int status;
// retrieve the current file size limits
status = getrlimit (RLIMIT_FSIZE, &rl);
if (status) {
std::perror ("getrlimit(RLIMIT_FSIZE, ...)");
return 1;
}
// uncomment for debugging
// std::printf ("file size limits = %ld, %ld\n",
// long (rl.rlim_cur), long (rl.rlim_max));
const rlim_t rlim_cur_saved = rl.rlim_cur;
rl.rlim_cur = 32;
// set a new file size limit
status = setrlimit (RLIMIT_FSIZE, &rl);
if (status) {
std::perror ("setrlimit(RLIMIT_FSIZE, ...)");
return 1;
}
// uncomment for debugging
// status = getrlimit (RLIMIT_FSIZE, &rl);
// if (status) {
// std::perror ("getrlimit(RLIMIT_FSIZE, ...)");
// return 1;
// }
// std::printf ("file size limits = %ld, %ld\n",
// long (rl.rlim_cur), long (rl.rlim_max));
// try to write more bytes than the current soft limit using
// filebuf, expecting the class dtor to fail but close the
// associated file descriptor
const int fd = write_bytes (fname, std::size_t (rl.rlim_cur + 1));
if (fd < 0) {
std::perror ("filebuf::~filebuf()");
std::remove (fname);
return 1;
}
// restore the previous soft limit
rl.rlim_cur = rlim_cur_saved;
status = setrlimit (RLIMIT_FSIZE, &rl);
if (status) {
std::perror ("setrlimit(RLIMIT_FSIZE, ...)");
close (fd);
std::remove (fname);
return 1;
}
// try to write to the filebuf's file descriptor, expecting
// the write() to fail
const ssize_t nwrote = write (fd, "<", 1);
assert (-1 == nwrote);
// close file descriptor before removing the file (it's okay
// if the call fails because the fd has already been closed)
close (fd);
std::remove (fname);
#else // Windows
// See about implementing using SetFileValidData():
// http://msdn.microsoft.com/en-us/library/aa365544(VS.85).aspx
#endif // !_WIN32 || __CYGWIN__
return 0;
}