revert jeff's last commit since it breaks the build
[moon.git] / src / file-downloader.cpp
blob04538908e0040b0d299c964914781e9c93da717b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * file-downloader.cpp: File Downloader class.
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
15 #include <config.h>
17 #include <glib/gstdio.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <string.h>
22 #include "file-downloader.h"
23 #include "zip/unzip.h"
24 #include "utils.h"
25 #include "error.h"
27 //TODO: Move all the zip related semantics in here to clean up downloader.cpp
29 FileDownloader::FileDownloader (Downloader *dl) : InternalDownloader (dl, Type::FILEDOWNLOADER)
31 filename = NULL;
32 unzipdir = NULL;
33 uri = NULL;
35 unzipped = false;
36 unlinkit = false;
39 FileDownloader::~FileDownloader ()
41 CleanupUnzipDir ();
43 if (filename) {
44 if (unlinkit)
45 unlink (filename);
46 g_free (filename);
50 void
51 FileDownloader::CleanupUnzipDir ()
53 if (!unzipdir)
54 return;
56 RemoveDir (unzipdir);
57 g_free (unzipdir);
58 unzipped = false;
59 unzipdir = NULL;
62 bool
63 FileDownloader::DownloadedFileIsZipped ()
65 unzFile zipfile;
67 if (!filename)
68 return false;
70 if (!(zipfile = unzOpen (filename)))
71 return false;
73 unzClose (zipfile);
75 return true;
78 char *
79 FileDownloader::GetResponseText (const char *partname, gint64 *size)
81 TextStream *stream;
82 char buffer[4096];
83 GByteArray *buf;
84 struct stat st;
85 ssize_t nread;
86 char *data;
87 char *path;
89 if (!(path = GetDownloadedFilename (partname)))
90 return NULL;
92 if (g_stat (path, &st) == -1) {
93 g_free (path);
94 return NULL;
97 if (st.st_size > 0) {
98 stream = new TextStream ();
100 if (!stream->OpenFile (path, true)) {
101 delete stream;
102 g_free (path);
103 return NULL;
106 g_free (path);
108 buf = g_byte_array_new ();
109 while ((nread = stream->Read (buffer, sizeof (buffer))) > 0)
110 g_byte_array_append (buf, (const guint8 *) buffer, nread);
112 *size = buf->len;
114 g_byte_array_append (buf, (const guint8 *) "", 1);
115 data = (char *) buf->data;
117 g_byte_array_free (buf, false);
118 delete stream;
119 } else {
120 data = g_strdup ("");
121 *size = 0;
124 return data;
127 const char *
128 FileDownloader::GetDownloadedFile ()
130 return filename;
133 char *
134 FileDownloader::GetDownloadedFilename (const char *partname)
136 char *dirname, *path, *part;
137 unzFile zipfile;
138 struct stat st;
139 int rv, fd;
141 if (!filename)
142 return NULL;
144 if (!partname || !partname[0])
145 return g_strdup (filename);
147 if (!DownloadedFileIsZipped ())
148 return NULL;
150 if (!unzipdir && !(unzipdir = CreateTempDir (filename)))
151 return NULL;
153 part = g_ascii_strdown (partname, -1);
154 path = g_build_filename (unzipdir, part, NULL);
155 if ((rv = g_stat (path, &st)) == -1 && errno == ENOENT) {
156 if (strchr (part, '/') != NULL) {
157 // create the directory path
158 dirname = g_path_get_dirname (path);
159 rv = g_mkdir_with_parents (dirname, 0700);
160 g_free (dirname);
162 if (rv == -1 && errno != EEXIST)
163 goto exception1;
166 // open the zip archive...
167 if (!(zipfile = unzOpen (filename)))
168 goto exception1;
170 // locate the file we want to extract... (2 = case-insensitive)
171 if (unzLocateFile (zipfile, partname, 2) != UNZ_OK)
172 goto exception2;
174 // open the requested part within the zip file
175 if (unzOpenCurrentFile (zipfile) != UNZ_OK)
176 goto exception2;
178 // open the output file
179 if ((fd = g_open (path, O_CREAT | O_WRONLY | O_TRUNC, 0600)) == -1)
180 goto exception3;
182 // extract the file from the zip archive... (closes the fd on success and fail)
183 if (!ExtractFile (zipfile, fd))
184 goto exception3;
186 unzCloseCurrentFile (zipfile);
187 unzClose (zipfile);
188 } else if (rv == -1) {
189 // irrecoverable error
190 goto exception0;
193 g_free (part);
195 return path;
197 exception3:
199 unzCloseCurrentFile (zipfile);
201 exception2:
203 unzClose (zipfile);
205 exception1:
207 g_free (part);
209 exception0:
211 g_free (path);
213 return NULL;
216 const char *
217 FileDownloader::GetUnzippedPath ()
219 char filename[256], *p;
220 unz_file_info info;
221 const char *name;
222 GString *path;
223 unzFile zip;
224 size_t len;
225 int fd;
227 if (!this->filename)
228 return NULL;
230 if (!DownloadedFileIsZipped ())
231 return this->filename;
233 if (!unzipdir && !(unzipdir = CreateTempDir (this->filename)))
234 return NULL;
236 if (unzipped)
237 return unzipdir;
239 // open the zip archive...
240 if (!(zip = unzOpen (this->filename)))
241 return NULL;
243 path = g_string_new (unzipdir);
244 g_string_append_c (path, G_DIR_SEPARATOR);
245 len = path->len;
247 unzipped = true;
249 // extract all the parts
250 do {
251 if (unzOpenCurrentFile (zip) != UNZ_OK)
252 break;
254 unzGetCurrentFileInfo (zip, &info, filename, sizeof (filename),
255 NULL, 0, NULL, 0);
257 // convert filename to lowercase
258 for (p = filename; *p; p++) {
259 if (*p >= 'A' && *p <= 'Z')
260 *p += 0x20;
263 if ((name = strrchr (filename, '/'))) {
264 // make sure the full directory path exists, if not create it
265 g_string_append_len (path, filename, name - filename);
266 g_mkdir_with_parents (path->str, 0700);
267 g_string_append (path, name);
268 } else {
269 g_string_append (path, filename);
272 if ((fd = g_open (path->str, O_WRONLY | O_CREAT | O_EXCL, 0600)) != -1) {
273 if (!ExtractFile (zip, fd))
274 unzipped = false;
275 } else if (errno != EEXIST) {
276 unzipped = false;
279 g_string_truncate (path, len);
280 unzCloseCurrentFile (zip);
281 } while (unzGoToNextFile (zip) == UNZ_OK);
283 g_string_free (path, true);
284 unzClose (zip);
286 return unzipdir;
289 void
290 FileDownloader::Open (const char *verb, const char *uri)
292 CleanupUnzipDir ();
294 if (filename) {
295 if (unlinkit)
296 unlink (filename);
297 g_free (filename);
300 unlinkit = false;
301 unzipped = false;
303 filename = NULL;
305 dl->InternalOpen (verb, uri);
308 void
309 FileDownloader::Write (void *buf, gint32 offset, gint32 n)
311 dl->InternalWrite (buf, offset, n);