change permissions before fsync()
[libi2ncommon] / src / oftmpstream.cpp
1 /*
2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
4
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
7
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
13
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
16
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
19 */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <errno.h>
25 #include <string.h>
26
27 #include <oftmpstream.hxx>
28
29 using namespace std;
30
31 void fdoutbuf::set_fd(int _fd) {
32     fd = _fd;
33 }
34
35 int fdoutbuf::overflow (int_type c) {
36     if (fd == -1)
37         return c;
38
39     if (c != EOF) {
40         char z = c;
41         if (write (fd, &z, 1) != 1) {
42             return EOF;
43         }
44     }
45     return c;
46 }
47 // write multiple characters
48 std::streamsize fdoutbuf::xsputn (const char* s,
49                                   std::streamsize num) {
50     if (fd == -1)
51         return (num);
52     
53     return write(fd,s,num);
54 }
55
56
57 oftmpstream::oftmpstream ()
58 : ostream(0)
59 , file_mode(0644)
60 {
61     fd = -1;
62     rdbuf(&buf);
63     is_open = false;
64 }
65
66 oftmpstream::oftmpstream (const std::string &name)
67 : ostream(0)
68 , file_mode(0644)
69 {
70     fd = -1;
71     rdbuf(&buf);
72     is_open = false;
73
74     open(name);
75 }
76
77 oftmpstream::~oftmpstream () {
78     close();
79 }
80
81 std::string oftmpstream::get_filename()
82 {
83     return realname;
84 }
85
86 std::string oftmpstream::get_tmp_filename()
87 {
88     return tmpname;
89 }
90
91 void oftmpstream::open (const string &name)
92 {
93     if (is_open)
94         close();
95
96     realname = name;
97     tmpname=name+".XXXXXX";
98     file_mode= 0644;
99
100     char* chbuf=new char[tmpname.size()+1];
101     tmpname.copy(chbuf,tmpname.size()+1);
102     chbuf[tmpname.size()]=0;
103     fd=mkstemp(chbuf);
104     tmpname=chbuf;
105     delete[] chbuf;
106
107     if (fd==-1)
108     {
109         string err="error creating temporary file "+tmpname;
110         err+=": ";
111         err+=strerror(errno);
112         throw ios_base::failure(err);
113     }
114     
115     buf.set_fd(fd);
116     is_open = true;
117 }
118
119 void oftmpstream::close()
120 {
121     if (!is_open)
122         return;
123
124     fchmod (fd, file_mode);    // fix/change mkstemp permissions
125     fsync(fd);
126     ::close (fd);
127
128     if (rename (tmpname.c_str(), realname.c_str()) != 0)
129     {
130         string err="error renaming temporary file "+tmpname;
131         err+=" to "+realname;
132         err+=": ";
133         err+=strerror(errno);
134         throw ios_base::failure(err);
135     }
136
137     fd = -1;
138     is_open = false;
139     file_mode= 0644;
140 }
141
142
143 /**
144  * @brief set file mode for the final file.
145  * @param mode the fin al file mode.
146  *
147  * When called after open(), it determines the file mode which should
148  * be used for the resulting file.
149  */
150 void oftmpstream::set_file_mode(int mode)
151 {
152     file_mode= mode;
153 } // eo oftmpstream::set_file_mode(int)