Release version 1.2
[ustl.git] / fstream.cc
blob8817c41e51e6191ddf2c3d04a9d6fc45b18156c6
1 // This file is part of the ustl library, an STL implementation.
2 //
3 // Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
4 // This file is free software, distributed under the MIT License.
5 //
6 // file.cc
7 //
9 #include "fstream.h"
10 #include "uexception.h"
11 #include "uutility.h"
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <sys/stat.h>
16 #include <sys/mman.h>
17 #include <sys/ioctl.h>
19 namespace ustl {
21 /// Default constructor.
22 fstream::fstream (void)
23 : ios_base (),
24 m_fd (-1),
25 m_Filename ()
29 /// Opens \p filename in \p mode.
30 fstream::fstream (const char* filename, openmode mode)
31 : ios_base (),
32 m_fd (-1),
33 m_Filename ()
35 open (filename, mode);
38 /// Attaches to \p nfd of \p filename.
39 fstream::fstream (int nfd, const char* filename)
40 : ios_base (),
41 m_fd (-1),
42 m_Filename ()
44 attach (nfd, filename);
47 /// Destructor. Closes if still open, but without throwing.
48 fstream::~fstream (void) throw()
50 clear (goodbit);
51 exceptions (goodbit);
52 close();
53 assert (!(rdstate() & badbit) && "close failed in the destructor! This may lead to loss of user data. Please call close() manually and either enable exceptions or check the badbit.");
56 /// Sets state \p s and throws depending on the exception setting.
57 void fstream::set_and_throw (iostate s, const char* op)
59 if (ios_base::set_and_throw (s))
60 throw file_exception (op, name());
63 /// Attaches to the given \p nfd.
64 void fstream::attach (int nfd, const char* filename)
66 assert (filename && "Don't do that");
67 clear (goodbit);
68 if (nfd < 0 && ios_base::set_and_throw (badbit))
69 throw file_exception ("open", filename);
70 close();
71 m_fd = nfd;
72 m_Filename = filename;
75 /// Detaches from the current fd.
76 void fstream::detach (void)
78 m_fd = -1;
79 m_Filename.clear();
82 /// Converts openmode bits into libc open flags.
83 /*static*/ int fstream::om_to_flags (openmode m)
85 static const int s_OMFlags [nombits] = {
86 0, // in
87 O_CREAT, // out
88 O_APPEND, // app
89 O_APPEND, // ate
90 0, // binary
91 O_TRUNC, // trunc
92 O_NONBLOCK, // nonblock
93 0, // nocreate
94 O_NOCTTY // noctty
96 int flags = (m - 1) & O_ACCMODE; // in and out
97 for (uoff_t i = 0; i < VectorSize(s_OMFlags); ++ i)
98 flags |= s_OMFlags[i] & (!(m & (1 << i)) - 1);
99 if (m & nocreate)
100 flags &= ~O_CREAT;
101 return (flags);
104 /// \brief Opens \p filename in the given mode.
105 /// \warning The string at \p filename must exist until the object is closed.
106 void fstream::open (const char* filename, openmode mode, mode_t perms)
108 int nfd = ::open (filename, om_to_flags(mode), perms);
109 attach (nfd, filename);
112 /// Closes the file and throws on error.
113 void fstream::close (void)
115 if (m_fd >= 0 && ::close(m_fd))
116 set_and_throw (badbit | failbit, "close");
117 detach();
120 /// Moves the current file position to \p n.
121 off_t fstream::seek (off_t n, seekdir whence)
123 off_t p = lseek (m_fd, n, whence);
124 if (p < 0)
125 set_and_throw (failbit, "seek");
126 return (p);
129 /// Returns the current file position.
130 off_t fstream::pos (void) const
132 return (lseek (m_fd, 0, SEEK_CUR));
135 /// Reads \p n bytes into \p p.
136 off_t fstream::read (void* p, off_t n)
138 off_t br (0);
139 while ((br < n) & good())
140 br += readsome (advance (p, br), n - br);
141 return (br);
144 /// Reads at most \p n bytes into \p p, stopping when it feels like it.
145 off_t fstream::readsome (void* p, off_t n)
147 ssize_t brn;
148 do { brn = ::read (m_fd, p, n); } while ((brn < 0) & (errno == EINTR));
149 if (brn > 0)
150 return (brn);
151 else if ((brn < 0) & (errno != EAGAIN))
152 set_and_throw (failbit, "read");
153 else if (!brn && ios_base::set_and_throw (eofbit | failbit))
154 throw stream_bounds_exception ("read", name(), pos(), n, 0);
155 return (0);
158 /// Writes \p n bytes from \p p.
159 off_t fstream::write (const void* p, off_t n)
161 off_t btw (n);
162 while (btw) {
163 const off_t bw (n - btw);
164 ssize_t bwn = ::write (m_fd, advance(p,bw), btw);
165 if (bwn > 0)
166 btw -= bwn;
167 else if (!bwn) {
168 if (ios_base::set_and_throw (eofbit | failbit))
169 throw stream_bounds_exception ("write", name(), pos() - bw, n, bw);
170 break;
171 } else if (errno != EINTR) {
172 if (errno != EAGAIN)
173 set_and_throw (failbit, "write");
174 break;
177 return (n - btw);
180 /// Returns the file size.
181 off_t fstream::size (void) const
183 struct stat st;
184 st.st_size = 0;
185 stat (st);
186 return (st.st_size);
189 /// Synchronizes the file's data and status with the disk.
190 void fstream::sync (void)
192 if (fsync (m_fd))
193 set_and_throw (failbit, "sync");
196 /// Get the stat structure.
197 void fstream::stat (struct stat& rs) const
199 if (fstat (m_fd, &rs))
200 throw file_exception ("stat", name());
203 /// Calls the given ioctl. Use IOCTLID macro to pass in both \p name and \p request.
204 int fstream::ioctl (const char* rname, int request, long argument)
206 int rv = ::ioctl (m_fd, request, argument);
207 if (rv < 0)
208 set_and_throw (failbit, rname);
209 return (rv);
212 /// Calls the given fcntl. Use FCNTLID macro to pass in both \p name and \p request.
213 int fstream::fcntl (const char* rname, int request, long argument)
215 int rv = ::fcntl (m_fd, request, argument);
216 if (rv < 0)
217 set_and_throw (failbit, rname);
218 return (rv);
221 /// Memory-maps the file and returns a link to it.
222 memlink fstream::mmap (off_t n, off_t offset)
224 void* result = ::mmap (NULL, n, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, offset);
225 if (result == MAP_FAILED)
226 set_and_throw (failbit, "mmap");
227 return (memlink (result, n));
230 /// Unmaps a memory-mapped area.
231 void fstream::munmap (memlink& l)
233 if (::munmap (l.data(), l.size()))
234 set_and_throw (failbit, "munmap");
235 l.unlink();
238 /// Synchronizes a memory-mapped area.
239 void fstream::msync (memlink& l)
241 if (::msync (l.data(), l.size(), MS_ASYNC | MS_INVALIDATE))
242 set_and_throw (failbit, "msync");
245 void fstream::set_nonblock (bool v)
247 int curf = max (0, fcntl (FCNTLID (F_GETFL)));
248 if (v) curf |= O_NONBLOCK;
249 else curf &= ~O_NONBLOCK;
250 fcntl (FCNTLID (F_SETFL), curf);
253 } // namespace ustl