]> cygwin.com Git - cygwin-apps/setup.git/blob - io_stream.cc
Use solver to check for problems and produce a list of package transactions
[cygwin-apps/setup.git] / io_stream.cc
1 /*
2 * Copyright (c) 2001, 2002, Robert Collins.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Robert Collins <rbtcollins@hotmail.com>
13 *
14 */
15
16 /* this is the parent class for all IO operations. It's flexable enough to be cover for
17 * HTTP access, local file access, and files being extracted from archives.
18 * It also encapsulates the idea of an archive, and all non-archives become the special
19 * case.
20 */
21
22 #include "LogSingleton.h"
23
24 #include "io_stream.h"
25
26 #include <stdexcept>
27 #include "IOStreamProvider.h"
28 #include <map>
29 #include "String++.h"
30
31 using namespace std;
32
33 typedef map <std::string, IOStreamProvider *, casecompare_lt_op> providersType;
34 static providersType *providers;
35 static size_t longestPrefix = 0;
36 static int inited = 0;
37
38 void
39 io_stream::registerProvider (IOStreamProvider &theProvider,
40 const std::string& urlPrefix)
41 {
42 if (!inited)
43 {
44 providers = new providersType;
45 inited = true;
46 }
47 theProvider.key = urlPrefix;
48 if (providers->find (urlPrefix) != providers->end())
49 throw new invalid_argument ("urlPrefix already registered!");
50 (*providers)[urlPrefix] = &theProvider;
51 if (urlPrefix.size() > longestPrefix)
52 longestPrefix = urlPrefix.size();
53 }
54
55 static IOStreamProvider const *
56 findProvider (const std::string& path)
57 {
58 if (path.size() < longestPrefix)
59 return NULL;
60 for (providersType::const_iterator i = providers->begin();
61 i != providers->end(); ++i)
62 {
63 if (!casecompare(path, i->first, i->first.size()))
64 return i->second;
65 }
66 return NULL;
67 }
68
69 /* Static members */
70 io_stream *
71 io_stream::factory (io_stream * parent)
72 {
73 /* something like,
74 * if !next_file_name
75 * return NULL
76 * switch (magic_id(peek (parent), max_magic_length))
77 * case io_stream * foo = new tar
78 * case io_stream * foo = new bz2
79 * return foo
80 */
81 Log (LOG_TIMESTAMP) << "io_stream::factory has been called" << endLog;
82 return NULL;
83 }
84
85 #define url_scheme_not_registered(name) \
86 throw new invalid_argument ((std::string("URL Scheme for '")+ \
87 name+"' not registered!").c_str())
88
89 io_stream *
90 io_stream::open (const std::string& name, const std::string& mode, mode_t perms)
91 {
92 IOStreamProvider const *p = findProvider (name);
93 if (!p)
94 url_scheme_not_registered (name);
95 io_stream *rv = p->open (&name.c_str()[p->key.size()], mode, perms);
96 if (!rv->error ())
97 return rv;
98 delete rv;
99 return NULL;
100 }
101
102 int
103 io_stream::mkpath_p (path_type_t isadir, const std::string& name, mode_t mode)
104 {
105 IOStreamProvider const *p = findProvider (name);
106 if (!p)
107 url_scheme_not_registered (name);
108 return p->mkdir_p (isadir, &name.c_str()[p->key.size()], mode);
109 }
110
111 /* remove a file or directory. */
112 int
113 io_stream::remove (const std::string& name)
114 {
115 IOStreamProvider const *p = findProvider (name);
116 if (!p)
117 url_scheme_not_registered (name);
118 return p->remove (&name.c_str()[p->key.size()]);
119 }
120
121 int
122 io_stream::mklink (const std::string& from, const std::string& to,
123 io_stream_link_t linktype)
124 {
125 Log (LOG_BABBLE) << "io_stream::mklink (" << from << "->" << to << ")"
126 << endLog;
127 IOStreamProvider const *fromp = findProvider (from);
128 IOStreamProvider const *top = findProvider (to);
129 if (!fromp)
130 url_scheme_not_registered (from);
131 if (!top)
132 url_scheme_not_registered (to);
133 if (fromp != top)
134 throw new invalid_argument ("Attempt to link across url providers.");
135 return fromp->mklink (&from.c_str()[fromp->key.size()],
136 &to.c_str()[top->key.size()], linktype);
137 }
138
139 int
140 io_stream::move_copy (const std::string& from, const std::string& to)
141 {
142 /* parameters are ok - checked before calling us, and we are private */
143 io_stream *in = io_stream::open (to, "wb", 0644);
144 io_stream *out = io_stream::open (from, "rb", 0);
145 if (io_stream::copy (in, out))
146 {
147 Log (LOG_TIMESTAMP) << "Failed copy of " << from << " to " << to
148 << endLog;
149 delete out;
150 io_stream::remove (to);
151 delete in;
152 return 1;
153 }
154 /* TODO:
155 out->set_mtime (in->get_mtime ());
156 */
157 delete in;
158 delete out;
159 io_stream::remove (from);
160 return 0;
161 }
162
163 ssize_t io_stream::copy (io_stream * in, io_stream * out)
164 {
165 if (!in || !out)
166 return -1;
167 char
168 buffer[65536];
169 ssize_t
170 countin,
171 countout;
172 while ((countin = in->read (buffer, sizeof(buffer))) > 0)
173 {
174 countout = out->write (buffer, countin);
175 if (countout != countin)
176 {
177 Log (LOG_TIMESTAMP) << "io_stream::copy failed to write "
178 << countin << " bytes" << endLog;
179 return countout ? countout : -1;
180 }
181 }
182
183 /*
184 Loop above ends with countin = 0 if we have reached EOF, or -1 if an
185 read error occurred.
186 */
187 if (countin < 0)
188 return -1;
189
190 /* Here it would be nice to be able to do something like
191 TODO:
192 out->set_mtime (in->get_mtime ());
193 */
194 return 0;
195 }
196
197 int
198 io_stream::move (const std::string& from, const std::string& to)
199 {
200 IOStreamProvider const *fromp = findProvider (from);
201 IOStreamProvider const *top = findProvider (to);
202 if (!fromp)
203 url_scheme_not_registered (from);
204 if (!top)
205 url_scheme_not_registered (to);
206 if (fromp != top)
207 return io_stream::move_copy (from, to);
208 return fromp->move (&from.c_str()[fromp->key.size()],
209 &to.c_str()[top->key.size()]);
210 }
211
212 char *
213 io_stream::gets (char *buffer, size_t length)
214 {
215 char *pos = buffer;
216 size_t count = 0;
217 while (count + 1 < length && read (pos, 1) == 1)
218 {
219 count++;
220 pos++;
221 if (*(pos - 1) == '\n')
222 {
223 --pos; /* end of line, remove from buffer */
224 if (pos > buffer && *(pos - 1) == '\r')
225 --pos;
226 break;
227 }
228 }
229 if (count == 0 || error ())
230 /* EOF when no chars found, or an error */
231 return NULL;
232 *pos = '\0';
233 return buffer;
234 }
235
236 int
237 io_stream::exists (const std::string& name)
238 {
239 IOStreamProvider const *p = findProvider (name);
240 if (!p)
241 url_scheme_not_registered (name);
242 return p->exists (&name.c_str()[p->key.size()]);
243 }
244
245 /* virtual members */
246
247 io_stream::~io_stream () {}
This page took 0.044984 seconds and 5 git commands to generate.