/*********************************************************************** * * 27.filebuf.members.stdcxx-308.cpp - regression test for STDCXX-308 * http://issues.apache.org/jira/browse/STDCXX-308 * * $Id: 27.filebuf.members.stdcxx-308.cpp 648752 2008-04-16 17:01:56Z faridz $ * *********************************************************************** * * 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 // for assert() #include // for remove(), size_t #include // for filebuf #if !defined (_WIN32) || defined (__CYGWIN__) # include // for getrlimit(), rlim_t # include // 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; }