1 // This file is part of the ustl library, an STL implementation.
3 // Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
4 // This file is free software, distributed under the MIT License.
10 #include "uexception.h"
17 #include <sys/ioctl.h>
21 /// Default constructor.
22 fstream::fstream (void)
29 /// Opens \p filename in \p mode.
30 fstream::fstream (const char* filename
, openmode mode
)
35 open (filename
, mode
);
38 /// Attaches to \p nfd of \p filename.
39 fstream::fstream (int nfd
, const char* filename
)
44 attach (nfd
, filename
);
47 /// Destructor. Closes if still open, but without throwing.
48 fstream::~fstream (void) throw()
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");
68 if (nfd
< 0 && ios_base::set_and_throw (badbit
))
69 throw file_exception ("open", filename
);
72 m_Filename
= filename
;
75 /// Detaches from the current fd.
76 void fstream::detach (void)
82 /// Converts openmode bits into libc open flags.
83 /*static*/ int fstream::om_to_flags (openmode m
)
85 static const int s_OMFlags
[nombits
] = {
92 O_NONBLOCK
, // nonblock
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);
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");
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
);
125 set_and_throw (failbit
, "seek");
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
)
139 while ((br
< n
) & good())
140 br
+= readsome (advance (p
, br
), n
- 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
)
148 do { brn
= ::read (m_fd
, p
, n
); } while ((brn
< 0) & (errno
== EINTR
));
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);
158 /// Writes \p n bytes from \p p.
159 off_t
fstream::write (const void* p
, off_t n
)
163 const off_t
bw (n
- btw
);
164 ssize_t bwn
= ::write (m_fd
, advance(p
,bw
), btw
);
168 if (ios_base::set_and_throw (eofbit
| failbit
))
169 throw stream_bounds_exception ("write", name(), pos() - bw
, n
, bw
);
171 } else if (errno
!= EINTR
) {
173 set_and_throw (failbit
, "write");
180 /// Returns the file size.
181 off_t
fstream::size (void) const
189 /// Synchronizes the file's data and status with the disk.
190 void fstream::sync (void)
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
);
208 set_and_throw (failbit
, rname
);
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
);
217 set_and_throw (failbit
, rname
);
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");
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
);