Handle self-destruct packages
[cygwin-setup.git] / io_stream.cc
blobb77346b031721040e3e084dfadf1caa0e957c2d5
1 /*
2 * Copyright (c) 2001, 2002, Robert Collins.
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.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by Robert Collins <rbtcollins@hotmail.com>
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.
22 #include "LogSingleton.h"
24 #include "io_stream.h"
26 #include <stdexcept>
27 #include "IOStreamProvider.h"
28 #include <map>
29 #include "String++.h"
31 typedef std::map <std::string, IOStreamProvider *, casecompare_lt_op> providersType;
32 static providersType *providers;
33 static size_t longestPrefix = 0;
34 static int inited = 0;
36 void
37 io_stream::registerProvider (IOStreamProvider &theProvider,
38 const std::string& urlPrefix)
40 if (!inited)
42 providers = new providersType;
43 inited = true;
45 theProvider.key = urlPrefix;
46 if (providers->find (urlPrefix) != providers->end())
47 throw new std::invalid_argument ("urlPrefix already registered!");
48 (*providers)[urlPrefix] = &theProvider;
49 if (urlPrefix.size() > longestPrefix)
50 longestPrefix = urlPrefix.size();
53 static IOStreamProvider const *
54 findProvider (const std::string& path)
56 if (path.size() < longestPrefix)
57 return NULL;
58 for (providersType::const_iterator i = providers->begin();
59 i != providers->end(); ++i)
61 if (!casecompare(path, i->first, i->first.size()))
62 return i->second;
64 return NULL;
67 /* Static members */
68 io_stream *
69 io_stream::factory (io_stream * parent)
71 /* something like,
72 * if !next_file_name
73 * return NULL
74 * switch (magic_id(peek (parent), max_magic_length))
75 * case io_stream * foo = new tar
76 * case io_stream * foo = new bz2
77 * return foo
79 Log (LOG_TIMESTAMP) << "io_stream::factory has been called" << endLog;
80 return NULL;
83 #define url_scheme_not_registered(name) \
84 throw new std::invalid_argument ((std::string("URL Scheme for '")+ \
85 name+"' not registered!").c_str())
87 io_stream *
88 io_stream::open (const std::string& name, const std::string& mode, mode_t perms)
90 IOStreamProvider const *p = findProvider (name);
91 if (!p)
92 url_scheme_not_registered (name);
93 io_stream *rv = p->open (&name.c_str()[p->key.size()], mode, perms);
94 if (!rv->error ())
95 return rv;
96 delete rv;
97 return NULL;
101 io_stream::mkpath_p (path_type_t isadir, const std::string& name, mode_t mode)
103 IOStreamProvider const *p = findProvider (name);
104 if (!p)
105 url_scheme_not_registered (name);
106 return p->mkdir_p (isadir, &name.c_str()[p->key.size()], mode);
109 /* remove a file or directory. */
111 io_stream::remove (const std::string& name)
113 IOStreamProvider const *p = findProvider (name);
114 if (!p)
115 url_scheme_not_registered (name);
116 return p->remove (&name.c_str()[p->key.size()]);
120 io_stream::mklink (const std::string& from, const std::string& to,
121 io_stream_link_t linktype)
123 Log (LOG_BABBLE) << "io_stream::mklink (" << from << "->" << to << ")"
124 << endLog;
125 IOStreamProvider const *fromp = findProvider (from);
126 IOStreamProvider const *top = findProvider (to);
127 if (!fromp)
128 url_scheme_not_registered (from);
129 if (!top)
130 url_scheme_not_registered (to);
131 if (fromp != top)
132 throw new std::invalid_argument ("Attempt to link across url providers.");
133 return fromp->mklink (&from.c_str()[fromp->key.size()],
134 &to.c_str()[top->key.size()], linktype);
138 io_stream::move_copy (const std::string& from, const std::string& to)
140 /* parameters are ok - checked before calling us, and we are private */
141 io_stream *in = io_stream::open (to, "wb", 0644);
142 io_stream *out = io_stream::open (from, "rb", 0);
143 if (io_stream::copy (in, out))
145 Log (LOG_TIMESTAMP) << "Failed copy of " << from << " to " << to
146 << endLog;
147 delete out;
148 io_stream::remove (to);
149 delete in;
150 return 1;
152 /* TODO:
153 out->set_mtime (in->get_mtime ());
155 delete in;
156 delete out;
157 io_stream::remove (from);
158 return 0;
161 ssize_t io_stream::copy (io_stream * in, io_stream * out)
163 if (!in || !out)
164 return -1;
165 char
166 buffer[65536];
167 ssize_t
168 countin,
169 countout;
170 while ((countin = in->read (buffer, sizeof(buffer))) > 0)
172 countout = out->write (buffer, countin);
173 if (countout != countin)
175 Log (LOG_TIMESTAMP) << "io_stream::copy failed to write "
176 << countin << " bytes" << endLog;
177 return countout ? countout : -1;
182 Loop above ends with countin = 0 if we have reached EOF, or -1 if an
183 read error occurred.
185 if (countin < 0)
186 return -1;
188 /* Here it would be nice to be able to do something like
189 TODO:
190 out->set_mtime (in->get_mtime ());
192 return 0;
196 io_stream::move (const std::string& from, const std::string& to)
198 IOStreamProvider const *fromp = findProvider (from);
199 IOStreamProvider const *top = findProvider (to);
200 if (!fromp)
201 url_scheme_not_registered (from);
202 if (!top)
203 url_scheme_not_registered (to);
204 if (fromp != top)
205 return io_stream::move_copy (from, to);
206 return fromp->move (&from.c_str()[fromp->key.size()],
207 &to.c_str()[top->key.size()]);
210 char *
211 io_stream::gets (char *buffer, size_t length)
213 char *pos = buffer;
214 size_t count = 0;
215 while (count + 1 < length && read (pos, 1) == 1)
217 count++;
218 pos++;
219 if (*(pos - 1) == '\n')
221 --pos; /* end of line, remove from buffer */
222 if (pos > buffer && *(pos - 1) == '\r')
223 --pos;
224 break;
227 if (count == 0 || error ())
228 /* EOF when no chars found, or an error */
229 return NULL;
230 *pos = '\0';
231 return buffer;
235 io_stream::exists (const std::string& name)
237 IOStreamProvider const *p = findProvider (name);
238 if (!p)
239 url_scheme_not_registered (name);
240 return p->exists (&name.c_str()[p->key.size()]);
243 /* virtual members */
245 io_stream::~io_stream () {}