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
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
22 #include "LogSingleton.h"
24 #include "io_stream.h"
27 #include "IOStreamProvider.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;
37 io_stream::registerProvider (IOStreamProvider
&theProvider
,
38 const std::string
& urlPrefix
)
42 providers
= new providersType
;
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
)
58 for (providersType::const_iterator i
= providers
->begin();
59 i
!= providers
->end(); ++i
)
61 if (!casecompare(path
, i
->first
, i
->first
.size()))
69 io_stream::factory (io_stream
* parent
)
74 * switch (magic_id(peek (parent), max_magic_length))
75 * case io_stream * foo = new tar
76 * case io_stream * foo = new bz2
79 Log (LOG_TIMESTAMP
) << "io_stream::factory has been called" << endLog
;
83 #define url_scheme_not_registered(name) \
84 throw new std::invalid_argument ((std::string("URL Scheme for '")+ \
85 name+"' not registered!").c_str())
88 io_stream::open (const std::string
& name
, const std::string
& mode
, mode_t perms
)
90 IOStreamProvider
const *p
= findProvider (name
);
92 url_scheme_not_registered (name
);
93 io_stream
*rv
= p
->open (&name
.c_str()[p
->key
.size()], mode
, perms
);
101 io_stream::mkpath_p (path_type_t isadir
, const std::string
& name
, mode_t mode
)
103 IOStreamProvider
const *p
= findProvider (name
);
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
);
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
<< ")"
125 IOStreamProvider
const *fromp
= findProvider (from
);
126 IOStreamProvider
const *top
= findProvider (to
);
128 url_scheme_not_registered (from
);
130 url_scheme_not_registered (to
);
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
148 io_stream::remove (to
);
153 out->set_mtime (in->get_mtime ());
157 io_stream::remove (from
);
161 ssize_t
io_stream::copy (io_stream
* in
, io_stream
* out
)
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
188 /* Here it would be nice to be able to do something like
190 out->set_mtime (in->get_mtime ());
196 io_stream::move (const std::string
& from
, const std::string
& to
)
198 IOStreamProvider
const *fromp
= findProvider (from
);
199 IOStreamProvider
const *top
= findProvider (to
);
201 url_scheme_not_registered (from
);
203 url_scheme_not_registered (to
);
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()]);
211 io_stream::gets (char *buffer
, size_t length
)
215 while (count
+ 1 < length
&& read (pos
, 1) == 1)
219 if (*(pos
- 1) == '\n')
221 --pos
; /* end of line, remove from buffer */
222 if (pos
> buffer
&& *(pos
- 1) == '\r')
227 if (count
== 0 || error ())
228 /* EOF when no chars found, or an error */
235 io_stream::exists (const std::string
& name
)
237 IOStreamProvider
const *p
= findProvider (name
);
239 url_scheme_not_registered (name
);
240 return p
->exists (&name
.c_str()[p
->key
.size()]);
243 /* virtual members */
245 io_stream::~io_stream () {}