diff options
Diffstat (limited to 'linden/indra/llmessage/llassetstorage.cpp')
-rw-r--r-- | linden/indra/llmessage/llassetstorage.cpp | 1183 |
1 files changed, 1183 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llassetstorage.cpp b/linden/indra/llmessage/llassetstorage.cpp new file mode 100644 index 0000000..eb26157 --- /dev/null +++ b/linden/indra/llmessage/llassetstorage.cpp | |||
@@ -0,0 +1,1183 @@ | |||
1 | /** | ||
2 | * @file llassetstorage.cpp | ||
3 | * @brief Implementation of the base asset storage system. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | // system library includes | ||
31 | #include <stdlib.h> | ||
32 | #include <stdio.h> | ||
33 | #include <sys/types.h> | ||
34 | #include <sys/stat.h> | ||
35 | #include <algorithm> | ||
36 | |||
37 | #include "llassetstorage.h" | ||
38 | |||
39 | // linden library includes | ||
40 | #include "llmath.h" | ||
41 | #include "llstring.h" | ||
42 | #include "lldir.h" | ||
43 | #include "llsd.h" | ||
44 | |||
45 | // this library includes | ||
46 | #include "message.h" | ||
47 | #include "llxfermanager.h" | ||
48 | #include "llvfile.h" | ||
49 | #include "llvfs.h" | ||
50 | #include "lldbstrings.h" | ||
51 | |||
52 | #include "lltransfersourceasset.h" | ||
53 | #include "lltransfertargetvfile.h" // For debugging | ||
54 | |||
55 | LLAssetStorage *gAssetStorage = NULL; | ||
56 | |||
57 | const LLUUID CATEGORIZE_LOST_AND_FOUND_ID("00000000-0000-0000-0000-000000000010"); | ||
58 | |||
59 | const F32 LL_ASSET_STORAGE_TIMEOUT = 300.0f; // anything that takes longer than this will abort | ||
60 | |||
61 | |||
62 | |||
63 | ///---------------------------------------------------------------------------- | ||
64 | /// LLAssetInfo | ||
65 | ///---------------------------------------------------------------------------- | ||
66 | |||
67 | LLAssetInfo::LLAssetInfo( void ) | ||
68 | : mDescription(), | ||
69 | mName(), | ||
70 | mUuid(), | ||
71 | mCreatorID(), | ||
72 | mType( LLAssetType::AT_NONE ) | ||
73 | { } | ||
74 | |||
75 | LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id, | ||
76 | LLAssetType::EType type, const char* name, | ||
77 | const char* desc ) | ||
78 | : mUuid( object_id ), | ||
79 | mCreatorID( creator_id ), | ||
80 | mType( type ) | ||
81 | { | ||
82 | setName( name ); | ||
83 | setDescription( desc ); | ||
84 | } | ||
85 | |||
86 | LLAssetInfo::LLAssetInfo( const LLNameValue& nv ) | ||
87 | { | ||
88 | setFromNameValue( nv ); | ||
89 | } | ||
90 | |||
91 | // make sure the name is short enough, and strip all pipes since they | ||
92 | // are reserved characters in our inventory tracking system. | ||
93 | void LLAssetInfo::setName( const std::string& name ) | ||
94 | { | ||
95 | if( !name.empty() ) | ||
96 | { | ||
97 | mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) ); | ||
98 | mName.erase( std::remove(mName.begin(), mName.end(), '|'), | ||
99 | mName.end() ); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | // make sure the name is short enough, and strip all pipes since they | ||
104 | // are reserved characters in our inventory tracking system. | ||
105 | void LLAssetInfo::setDescription( const std::string& desc ) | ||
106 | { | ||
107 | if( !desc.empty() ) | ||
108 | { | ||
109 | mDescription.assign( desc, 0, llmin((U32)desc.size(), | ||
110 | (U32)DB_INV_ITEM_DESC_STR_LEN) ); | ||
111 | mDescription.erase( std::remove(mDescription.begin(), | ||
112 | mDescription.end(), '|'), | ||
113 | mDescription.end() ); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | // Assets (aka potential inventory items) can be applied to an | ||
118 | // object in the world. We'll store that as a string name value | ||
119 | // pair where the name encodes part of asset info, and the value | ||
120 | // the rest. LLAssetInfo objects will be responsible for parsing | ||
121 | // the meaning out froman LLNameValue object. See the inventory | ||
122 | // design docs for details. Briefly: | ||
123 | // name=<inv_type>|<uuid> | ||
124 | // value=<creatorid>|<name>|<description>| | ||
125 | void LLAssetInfo::setFromNameValue( const LLNameValue& nv ) | ||
126 | { | ||
127 | std::string str; | ||
128 | std::string buf; | ||
129 | std::string::size_type pos1; | ||
130 | std::string::size_type pos2; | ||
131 | |||
132 | // convert the name to useful information | ||
133 | str.assign( nv.mName ); | ||
134 | pos1 = str.find('|'); | ||
135 | buf.assign( str, 0, pos1++ ); | ||
136 | mType = LLAssetType::lookup( buf.c_str() ); | ||
137 | buf.assign( str, pos1, std::string::npos ); | ||
138 | mUuid.set( buf.c_str() ); | ||
139 | |||
140 | // convert the value to useful information | ||
141 | str.assign( nv.getAsset() ); | ||
142 | pos1 = str.find('|'); | ||
143 | buf.assign( str, 0, pos1++ ); | ||
144 | mCreatorID.set( buf.c_str() ); | ||
145 | pos2 = str.find( '|', pos1 ); | ||
146 | buf.assign( str, pos1, (pos2++) - pos1 ); | ||
147 | setName( buf.c_str() ); | ||
148 | buf.assign( str, pos2, std::string::npos ); | ||
149 | setDescription( buf.c_str() ); | ||
150 | llinfos << "uuid: " << mUuid << llendl; | ||
151 | llinfos << "creator: " << mCreatorID << llendl; | ||
152 | } | ||
153 | |||
154 | ///---------------------------------------------------------------------------- | ||
155 | /// LLAssetRequest | ||
156 | ///---------------------------------------------------------------------------- | ||
157 | |||
158 | LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) | ||
159 | : mUUID(uuid), | ||
160 | mType(type), | ||
161 | mDownCallback( NULL ), | ||
162 | mUpCallback( NULL ), | ||
163 | mInfoCallback( NULL ), | ||
164 | mUserData( NULL ), | ||
165 | mHost(), | ||
166 | mIsTemp( FALSE ), | ||
167 | mIsLocal(FALSE), | ||
168 | mIsPriority(FALSE), | ||
169 | mDataSentInFirstPacket(FALSE), | ||
170 | mDataIsInVFS( FALSE ) | ||
171 | { | ||
172 | // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been | ||
173 | // running a message system loop. | ||
174 | mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); | ||
175 | } | ||
176 | |||
177 | LLAssetRequest::~LLAssetRequest() | ||
178 | { | ||
179 | } | ||
180 | |||
181 | |||
182 | ///---------------------------------------------------------------------------- | ||
183 | /// LLInvItemRequest | ||
184 | ///---------------------------------------------------------------------------- | ||
185 | |||
186 | LLInvItemRequest::LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType type) | ||
187 | : mUUID(uuid), | ||
188 | mType(type), | ||
189 | mDownCallback( NULL ), | ||
190 | mUserData( NULL ), | ||
191 | mHost(), | ||
192 | mIsTemp( FALSE ), | ||
193 | mIsPriority(FALSE), | ||
194 | mDataSentInFirstPacket(FALSE), | ||
195 | mDataIsInVFS( FALSE ) | ||
196 | { | ||
197 | // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been | ||
198 | // running a message system loop. | ||
199 | mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); | ||
200 | } | ||
201 | |||
202 | LLInvItemRequest::~LLInvItemRequest() | ||
203 | { | ||
204 | } | ||
205 | |||
206 | ///---------------------------------------------------------------------------- | ||
207 | /// LLEstateAssetRequest | ||
208 | ///---------------------------------------------------------------------------- | ||
209 | |||
210 | LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType atype, | ||
211 | EstateAssetType etype) | ||
212 | : mUUID(uuid), | ||
213 | mAType(atype), | ||
214 | mEstateAssetType(etype), | ||
215 | mDownCallback( NULL ), | ||
216 | mUserData( NULL ), | ||
217 | mHost(), | ||
218 | mIsTemp( FALSE ), | ||
219 | mIsPriority(FALSE), | ||
220 | mDataSentInFirstPacket(FALSE), | ||
221 | mDataIsInVFS( FALSE ) | ||
222 | { | ||
223 | // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been | ||
224 | // running a message system loop. | ||
225 | mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); | ||
226 | } | ||
227 | |||
228 | LLEstateAssetRequest::~LLEstateAssetRequest() | ||
229 | { | ||
230 | } | ||
231 | |||
232 | |||
233 | ///---------------------------------------------------------------------------- | ||
234 | /// LLAssetStorage | ||
235 | ///---------------------------------------------------------------------------- | ||
236 | |||
237 | // since many of these functions are called by the messaging and xfer systems, | ||
238 | // they are declared as static and are passed a "this" handle | ||
239 | // it's a C/C++ mish-mash! | ||
240 | |||
241 | // TODO: permissions on modifications - maybe don't allow at all? | ||
242 | // TODO: verify that failures get propogated down | ||
243 | // TODO: rework tempfile handling? | ||
244 | |||
245 | |||
246 | LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, const LLHost &upstream_host) | ||
247 | { | ||
248 | _init(msg, xfer, vfs, upstream_host); | ||
249 | } | ||
250 | |||
251 | |||
252 | LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, | ||
253 | LLVFS *vfs) | ||
254 | { | ||
255 | _init(msg, xfer, vfs, LLHost::invalid); | ||
256 | } | ||
257 | |||
258 | |||
259 | void LLAssetStorage::_init(LLMessageSystem *msg, | ||
260 | LLXferManager *xfer, | ||
261 | LLVFS *vfs, | ||
262 | const LLHost &upstream_host) | ||
263 | { | ||
264 | mShutDown = FALSE; | ||
265 | mMessageSys = msg; | ||
266 | mXferManager = xfer; | ||
267 | mVFS = vfs; | ||
268 | |||
269 | setUpstream(upstream_host); | ||
270 | msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this); | ||
271 | } | ||
272 | |||
273 | LLAssetStorage::~LLAssetStorage() | ||
274 | { | ||
275 | mShutDown = TRUE; | ||
276 | |||
277 | _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE); | ||
278 | |||
279 | if (gMessageSystem) | ||
280 | { | ||
281 | // Warning! This won't work if there's more than one asset storage. | ||
282 | // unregister our callbacks with the message system | ||
283 | gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | void LLAssetStorage::setUpstream(const LLHost &upstream_host) | ||
288 | { | ||
289 | llinfos << "AssetStorage: Setting upstream provider to " << upstream_host << llendl; | ||
290 | |||
291 | mUpstreamHost = upstream_host; | ||
292 | } | ||
293 | |||
294 | void LLAssetStorage::checkForTimeouts() | ||
295 | { | ||
296 | _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT); | ||
297 | } | ||
298 | |||
299 | void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) | ||
300 | { | ||
301 | const S32 NUM_QUEUES = 3; | ||
302 | F64 mt_secs = LLMessageSystem::getMessageTimeSeconds(); | ||
303 | |||
304 | std::list<LLAssetRequest*>* requests[NUM_QUEUES]; | ||
305 | requests[0] = &mPendingDownloads; | ||
306 | requests[1] = &mPendingUploads; | ||
307 | requests[2] = &mPendingLocalUploads; | ||
308 | static const char* REQUEST_TYPE[NUM_QUEUES] = { "download", "upload", "localuploads"}; | ||
309 | |||
310 | std::list<LLAssetRequest*> timed_out; | ||
311 | |||
312 | for (S32 ii = 0; ii < NUM_QUEUES; ++ii) | ||
313 | { | ||
314 | for (std::list<LLAssetRequest*>::iterator iter = requests[ii]->begin(); | ||
315 | iter != requests[ii]->end(); ) | ||
316 | { | ||
317 | std::list<LLAssetRequest*>::iterator curiter = iter++; | ||
318 | LLAssetRequest* tmp = *curiter; | ||
319 | // if all is true, we want to clean up everything | ||
320 | // otherwise just check for timed out requests | ||
321 | // EXCEPT for upload timeouts | ||
322 | if (all | ||
323 | || ((0 == ii) | ||
324 | && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) | ||
325 | { | ||
326 | llwarns << "Asset " << REQUEST_TYPE[ii] << " request " | ||
327 | << (all ? "aborted" : "timed out") << " for " | ||
328 | << tmp->getUUID() << "." | ||
329 | << LLAssetType::lookup(tmp->getType()) << llendl; | ||
330 | |||
331 | timed_out.push_front(tmp); | ||
332 | iter = requests[ii]->erase(curiter); | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | |||
337 | LLAssetInfo info; | ||
338 | for (std::list<LLAssetRequest*>::iterator iter = timed_out.begin(); | ||
339 | iter != timed_out.end(); ) | ||
340 | { | ||
341 | std::list<LLAssetRequest*>::iterator curiter = iter++; | ||
342 | LLAssetRequest* tmp = *curiter; | ||
343 | if (tmp->mUpCallback) | ||
344 | { | ||
345 | tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error); | ||
346 | } | ||
347 | if (tmp->mDownCallback) | ||
348 | { | ||
349 | tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error); | ||
350 | } | ||
351 | if (tmp->mInfoCallback) | ||
352 | { | ||
353 | tmp->mInfoCallback(&info, tmp->mUserData, error); | ||
354 | } | ||
355 | delete tmp; | ||
356 | } | ||
357 | |||
358 | } | ||
359 | |||
360 | BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) | ||
361 | { | ||
362 | return mVFS->getExists(uuid, type); | ||
363 | } | ||
364 | |||
365 | /////////////////////////////////////////////////////////////////////////// | ||
366 | // GET routines | ||
367 | /////////////////////////////////////////////////////////////////////////// | ||
368 | |||
369 | // IW - uuid is passed by value to avoid side effects, please don't re-add & | ||
370 | void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *,S32), void *user_data, BOOL is_priority) | ||
371 | { | ||
372 | lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl; | ||
373 | |||
374 | if (mShutDown) | ||
375 | { | ||
376 | return; // don't get the asset or do any callbacks, we are shutting down | ||
377 | } | ||
378 | |||
379 | if (uuid.isNull()) | ||
380 | { | ||
381 | // Special case early out for NULL uuid | ||
382 | if (callback) | ||
383 | { | ||
384 | callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE); | ||
385 | } | ||
386 | return; | ||
387 | } | ||
388 | |||
389 | BOOL exists = mVFS->getExists(uuid, type); | ||
390 | LLVFile file(mVFS, uuid, type); | ||
391 | U32 size = exists ? file.getSize() : 0; | ||
392 | |||
393 | if (size < 1) | ||
394 | { | ||
395 | if (exists) | ||
396 | { | ||
397 | llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl; | ||
398 | file.remove(); | ||
399 | } | ||
400 | |||
401 | BOOL duplicate = FALSE; | ||
402 | |||
403 | // check to see if there's a pending download of this uuid already | ||
404 | for (std::list<LLAssetRequest*>::iterator iter = mPendingDownloads.begin(); | ||
405 | iter != mPendingDownloads.end(); ++iter ) | ||
406 | { | ||
407 | LLAssetRequest *tmp = *iter; | ||
408 | if ((type == tmp->getType()) && (uuid == tmp->getUUID())) | ||
409 | { | ||
410 | if (callback == tmp->mDownCallback && user_data == tmp->mUserData) | ||
411 | { | ||
412 | // this is a duplicate from the same subsystem - throw it away | ||
413 | llinfos << "Discarding duplicate request for UUID " << uuid << llendl; | ||
414 | return; | ||
415 | } | ||
416 | else | ||
417 | { | ||
418 | llinfos << "Adding additional non-duplicate request for UUID " << uuid << llendl; | ||
419 | } | ||
420 | |||
421 | // this is a duplicate request | ||
422 | // queue the request, but don't actually ask for it again | ||
423 | duplicate = TRUE; | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | // This can be overridden by subclasses | ||
429 | _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); | ||
430 | } | ||
431 | else | ||
432 | { | ||
433 | // we've already got the file | ||
434 | // theoretically, partial files w/o a pending request shouldn't happen | ||
435 | // unless there's a weird error | ||
436 | if (callback) | ||
437 | { | ||
438 | callback(mVFS, uuid, type, user_data, LL_ERR_NOERR); | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | |||
443 | void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype, | ||
444 | LLGetAssetCallback callback, | ||
445 | void *user_data, BOOL duplicate, | ||
446 | BOOL is_priority) | ||
447 | { | ||
448 | if (mUpstreamHost.isOk()) | ||
449 | { | ||
450 | // stash the callback info so we can find it after we get the response message | ||
451 | LLAssetRequest *req = new LLAssetRequest(uuid, atype); | ||
452 | req->mDownCallback = callback; | ||
453 | req->mUserData = user_data; | ||
454 | req->mIsPriority = is_priority; | ||
455 | |||
456 | mPendingDownloads.push_back(req); | ||
457 | |||
458 | if (!duplicate) | ||
459 | { | ||
460 | // send request message to our upstream data provider | ||
461 | // Create a new asset transfer. | ||
462 | LLTransferSourceParamsAsset spa; | ||
463 | spa.setAsset(uuid, atype); | ||
464 | |||
465 | // Set our destination file, and the completion callback. | ||
466 | LLTransferTargetParamsVFile tpvf; | ||
467 | tpvf.setAsset(uuid, atype); | ||
468 | tpvf.setCallback(downloadCompleteCallback, req); | ||
469 | |||
470 | llinfos << "Starting transfer for " << uuid << llendl; | ||
471 | LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); | ||
472 | ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); | ||
473 | } | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | // uh-oh, we shouldn't have gotten here | ||
478 | llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; | ||
479 | if (callback) | ||
480 | { | ||
481 | callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE); | ||
482 | } | ||
483 | } | ||
484 | } | ||
485 | |||
486 | |||
487 | void LLAssetStorage::downloadCompleteCallback( | ||
488 | S32 result, | ||
489 | const LLUUID& file_id, | ||
490 | LLAssetType::EType file_type, | ||
491 | void* user_data) | ||
492 | { | ||
493 | lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id | ||
494 | << "," << LLAssetType::lookup(file_type) << llendl; | ||
495 | LLAssetRequest* req = (LLAssetRequest*)user_data; | ||
496 | if(!req) | ||
497 | { | ||
498 | llwarns << "LLAssetStorage::downloadCompleteCallback called without" | ||
499 | "a valid request." << llendl; | ||
500 | return; | ||
501 | } | ||
502 | if (!gAssetStorage) | ||
503 | { | ||
504 | llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl; | ||
505 | return; | ||
506 | } | ||
507 | |||
508 | req->setUUID(file_id); | ||
509 | req->setType(file_type); | ||
510 | if (LL_ERR_NOERR == result) | ||
511 | { | ||
512 | // we might have gotten a zero-size file | ||
513 | LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); | ||
514 | if (vfile.getSize() <= 0) | ||
515 | { | ||
516 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl; | ||
517 | |||
518 | result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; | ||
519 | vfile.remove(); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | // find and callback ALL pending requests for this UUID | ||
524 | // SJB: We process the callbacks in reverse order, I do not know if this is important, | ||
525 | // but I didn't want to mess with it. | ||
526 | std::list<LLAssetRequest*> requests; | ||
527 | for (std::list<LLAssetRequest*>::iterator iter = gAssetStorage->mPendingDownloads.begin(); | ||
528 | iter != gAssetStorage->mPendingDownloads.end(); ) | ||
529 | { | ||
530 | std::list<LLAssetRequest*>::iterator curiter = iter++; | ||
531 | LLAssetRequest* tmp = *curiter; | ||
532 | if ((tmp->getUUID() == req->getUUID()) && (tmp->getType()== req->getType())) | ||
533 | { | ||
534 | requests.push_front(tmp); | ||
535 | iter = gAssetStorage->mPendingDownloads.erase(curiter); | ||
536 | } | ||
537 | } | ||
538 | for (std::list<LLAssetRequest*>::iterator iter = requests.begin(); | ||
539 | iter != requests.end(); ) | ||
540 | { | ||
541 | std::list<LLAssetRequest*>::iterator curiter = iter++; | ||
542 | LLAssetRequest* tmp = *curiter; | ||
543 | if (tmp->mDownCallback) | ||
544 | { | ||
545 | tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result); | ||
546 | } | ||
547 | delete tmp; | ||
548 | } | ||
549 | } | ||
550 | |||
551 | void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, | ||
552 | const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype, | ||
553 | LLGetAssetCallback callback, void *user_data, BOOL is_priority) | ||
554 | { | ||
555 | lldebugs << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << llendl; | ||
556 | |||
557 | // | ||
558 | // Probably will get rid of this early out? | ||
559 | // | ||
560 | if (asset_id.isNull()) | ||
561 | { | ||
562 | // Special case early out for NULL uuid | ||
563 | if (callback) | ||
564 | { | ||
565 | callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE); | ||
566 | } | ||
567 | return; | ||
568 | } | ||
569 | |||
570 | BOOL exists = mVFS->getExists(asset_id, atype); | ||
571 | LLVFile file(mVFS, asset_id, atype); | ||
572 | U32 size = exists ? file.getSize() : 0; | ||
573 | |||
574 | if (size < 1) | ||
575 | { | ||
576 | if (exists) | ||
577 | { | ||
578 | llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl; | ||
579 | file.remove(); | ||
580 | } | ||
581 | |||
582 | // See whether we should talk to the object's originating sim, or the upstream provider. | ||
583 | LLHost source_host; | ||
584 | if (object_sim.isOk()) | ||
585 | { | ||
586 | source_host = object_sim; | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | source_host = mUpstreamHost; | ||
591 | } | ||
592 | if (source_host.isOk()) | ||
593 | { | ||
594 | // stash the callback info so we can find it after we get the response message | ||
595 | LLEstateAssetRequest *req = new LLEstateAssetRequest(asset_id, atype, etype); | ||
596 | req->mDownCallback = callback; | ||
597 | req->mUserData = user_data; | ||
598 | req->mIsPriority = is_priority; | ||
599 | |||
600 | // send request message to our upstream data provider | ||
601 | // Create a new asset transfer. | ||
602 | LLTransferSourceParamsEstate spe; | ||
603 | spe.setAgentSession(agent_id, session_id); | ||
604 | spe.setEstateAssetType(etype); | ||
605 | |||
606 | // Set our destination file, and the completion callback. | ||
607 | LLTransferTargetParamsVFile tpvf; | ||
608 | tpvf.setAsset(asset_id, atype); | ||
609 | tpvf.setCallback(downloadEstateAssetCompleteCallback, req); | ||
610 | |||
611 | llinfos << "Starting transfer for " << asset_id << llendl; | ||
612 | LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); | ||
613 | ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f)); | ||
614 | } | ||
615 | else | ||
616 | { | ||
617 | // uh-oh, we shouldn't have gotten here | ||
618 | llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; | ||
619 | if (callback) | ||
620 | { | ||
621 | callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE); | ||
622 | } | ||
623 | } | ||
624 | } | ||
625 | else | ||
626 | { | ||
627 | // we've already got the file | ||
628 | // theoretically, partial files w/o a pending request shouldn't happen | ||
629 | // unless there's a weird error | ||
630 | if (callback) | ||
631 | { | ||
632 | callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR); | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | |||
637 | void LLAssetStorage::downloadEstateAssetCompleteCallback( | ||
638 | S32 result, | ||
639 | const LLUUID& file_id, | ||
640 | LLAssetType::EType file_type, | ||
641 | void* user_data) | ||
642 | { | ||
643 | LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data; | ||
644 | if(!req) | ||
645 | { | ||
646 | llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" | ||
647 | " without a valid request." << llendl; | ||
648 | return; | ||
649 | } | ||
650 | if (!gAssetStorage) | ||
651 | { | ||
652 | llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" | ||
653 | " without any asset system, aborting!" << llendl; | ||
654 | return; | ||
655 | } | ||
656 | |||
657 | req->setUUID(file_id); | ||
658 | req->setType(file_type); | ||
659 | if (LL_ERR_NOERR == result) | ||
660 | { | ||
661 | // we might have gotten a zero-size file | ||
662 | LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); | ||
663 | if (vfile.getSize() <= 0) | ||
664 | { | ||
665 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; | ||
666 | |||
667 | result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; | ||
668 | vfile.remove(); | ||
669 | } | ||
670 | } | ||
671 | |||
672 | req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result); | ||
673 | } | ||
674 | |||
675 | void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, | ||
676 | const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id, | ||
677 | const LLUUID &asset_id, LLAssetType::EType atype, | ||
678 | LLGetAssetCallback callback, void *user_data, BOOL is_priority) | ||
679 | { | ||
680 | lldebugs << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << llendl; | ||
681 | |||
682 | // | ||
683 | // Probably will get rid of this early out? | ||
684 | // | ||
685 | //if (asset_id.isNull()) | ||
686 | //{ | ||
687 | // // Special case early out for NULL uuid | ||
688 | // if (callback) | ||
689 | // { | ||
690 | // callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE); | ||
691 | // } | ||
692 | // return; | ||
693 | //} | ||
694 | |||
695 | bool exists = false; | ||
696 | U32 size = 0; | ||
697 | |||
698 | if(asset_id.notNull()) | ||
699 | { | ||
700 | exists = mVFS->getExists(asset_id, atype); | ||
701 | LLVFile file(mVFS, asset_id, atype); | ||
702 | size = exists ? file.getSize() : 0; | ||
703 | if(exists && size < 1) | ||
704 | { | ||
705 | llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl; | ||
706 | file.remove(); | ||
707 | } | ||
708 | |||
709 | } | ||
710 | |||
711 | if (size < 1) | ||
712 | { | ||
713 | // See whether we should talk to the object's originating sim, | ||
714 | // or the upstream provider. | ||
715 | LLHost source_host; | ||
716 | if (object_sim.isOk()) | ||
717 | { | ||
718 | source_host = object_sim; | ||
719 | } | ||
720 | else | ||
721 | { | ||
722 | source_host = mUpstreamHost; | ||
723 | } | ||
724 | if (source_host.isOk()) | ||
725 | { | ||
726 | // stash the callback info so we can find it after we get the response message | ||
727 | LLInvItemRequest *req = new LLInvItemRequest(asset_id, atype); | ||
728 | req->mDownCallback = callback; | ||
729 | req->mUserData = user_data; | ||
730 | req->mIsPriority = is_priority; | ||
731 | |||
732 | // send request message to our upstream data provider | ||
733 | // Create a new asset transfer. | ||
734 | LLTransferSourceParamsInvItem spi; | ||
735 | spi.setAgentSession(agent_id, session_id); | ||
736 | spi.setInvItem(owner_id, task_id, item_id); | ||
737 | spi.setAsset(asset_id, atype); | ||
738 | |||
739 | // Set our destination file, and the completion callback. | ||
740 | LLTransferTargetParamsVFile tpvf; | ||
741 | tpvf.setAsset(asset_id, atype); | ||
742 | tpvf.setCallback(downloadInvItemCompleteCallback, req); | ||
743 | |||
744 | llinfos << "Starting transfer for inventory asset " | ||
745 | << item_id << " owned by " << owner_id << "," << task_id | ||
746 | << llendl; | ||
747 | LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); | ||
748 | ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f)); | ||
749 | } | ||
750 | else | ||
751 | { | ||
752 | // uh-oh, we shouldn't have gotten here | ||
753 | llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; | ||
754 | if (callback) | ||
755 | { | ||
756 | callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE); | ||
757 | } | ||
758 | } | ||
759 | } | ||
760 | else | ||
761 | { | ||
762 | // we've already got the file | ||
763 | // theoretically, partial files w/o a pending request shouldn't happen | ||
764 | // unless there's a weird error | ||
765 | if (callback) | ||
766 | { | ||
767 | callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR); | ||
768 | } | ||
769 | } | ||
770 | } | ||
771 | |||
772 | |||
773 | void LLAssetStorage::downloadInvItemCompleteCallback( | ||
774 | S32 result, | ||
775 | const LLUUID& file_id, | ||
776 | LLAssetType::EType file_type, | ||
777 | void* user_data) | ||
778 | { | ||
779 | LLInvItemRequest *req = (LLInvItemRequest*)user_data; | ||
780 | if(!req) | ||
781 | { | ||
782 | llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" | ||
783 | " without a valid request." << llendl; | ||
784 | return; | ||
785 | } | ||
786 | if (!gAssetStorage) | ||
787 | { | ||
788 | llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl; | ||
789 | return; | ||
790 | } | ||
791 | |||
792 | req->setUUID(file_id); | ||
793 | req->setType(file_type); | ||
794 | if (LL_ERR_NOERR == result) | ||
795 | { | ||
796 | // we might have gotten a zero-size file | ||
797 | LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); | ||
798 | if (vfile.getSize() <= 0) | ||
799 | { | ||
800 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; | ||
801 | |||
802 | result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; | ||
803 | vfile.remove(); | ||
804 | } | ||
805 | } | ||
806 | |||
807 | req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result); | ||
808 | } | ||
809 | |||
810 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
811 | // Store routines | ||
812 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
813 | |||
814 | // virtual | ||
815 | void LLAssetStorage::cancelStoreAsset( | ||
816 | const LLUUID& uuid, | ||
817 | LLAssetType::EType atype) | ||
818 | { | ||
819 | bool do_callback = true; | ||
820 | LLAssetRequest* req = NULL; | ||
821 | |||
822 | if(mPendingUploads.size() > 0) | ||
823 | { | ||
824 | req = mPendingUploads.front(); | ||
825 | if((req->getUUID() == uuid) && (req->getType() == atype)) | ||
826 | { | ||
827 | // This is probably because the request is in progress - do | ||
828 | // not attempt to cancel. | ||
829 | do_callback = false; | ||
830 | } | ||
831 | } | ||
832 | |||
833 | if (mPendingLocalUploads.size() > 0) | ||
834 | { | ||
835 | req = mPendingLocalUploads.front(); | ||
836 | if((req->getUUID() == uuid) && (req->getType() == atype)) | ||
837 | { | ||
838 | // This is probably because the request is in progress - do | ||
839 | // not attempt to cancel. | ||
840 | do_callback = false; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | if (do_callback) | ||
845 | { | ||
846 | // clear it out of the upload queue if it is there. | ||
847 | _callUploadCallbacks(uuid, atype, FALSE); | ||
848 | } | ||
849 | } | ||
850 | |||
851 | // static | ||
852 | void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result) // StoreAssetData callback (fixed) | ||
853 | { | ||
854 | if (!gAssetStorage) | ||
855 | { | ||
856 | llwarns << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << llendl; | ||
857 | return; | ||
858 | } | ||
859 | LLAssetRequest *req = (LLAssetRequest *)user_data; | ||
860 | BOOL success = TRUE; | ||
861 | |||
862 | if (result) | ||
863 | { | ||
864 | llwarns << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << llendl; | ||
865 | success = FALSE; | ||
866 | } | ||
867 | |||
868 | // we're done grabbing the file, tell the client | ||
869 | gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete); | ||
870 | gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock); | ||
871 | gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid); | ||
872 | gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType()); | ||
873 | gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success); | ||
874 | gAssetStorage->mMessageSys->sendReliable(req->mHost); | ||
875 | |||
876 | delete req; | ||
877 | } | ||
878 | |||
879 | void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_data) | ||
880 | { | ||
881 | LLAssetStorage *this_ptr = (LLAssetStorage *)user_data; | ||
882 | LLUUID uuid; | ||
883 | S8 asset_type_s8; | ||
884 | LLAssetType::EType asset_type; | ||
885 | BOOL success = FALSE; | ||
886 | |||
887 | msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid); | ||
888 | msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8); | ||
889 | msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success); | ||
890 | |||
891 | asset_type = (LLAssetType::EType)asset_type_s8; | ||
892 | this_ptr->_callUploadCallbacks(uuid, asset_type, success); | ||
893 | } | ||
894 | |||
895 | void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success) | ||
896 | { | ||
897 | // SJB: We process the callbacks in reverse order, I do not know if this is important, | ||
898 | // but I didn't want to mess with it. | ||
899 | std::list<LLAssetRequest*> requests; | ||
900 | for (std::list<LLAssetRequest*>::iterator iter = mPendingUploads.begin(); | ||
901 | iter != mPendingUploads.end(); ) | ||
902 | { | ||
903 | std::list<LLAssetRequest*>::iterator curiter = iter++; | ||
904 | LLAssetRequest* req = *curiter; | ||
905 | if ((req->getUUID() == uuid) && (req->getType() == asset_type)) | ||
906 | { | ||
907 | requests.push_front(req); | ||
908 | iter = mPendingUploads.erase(curiter); | ||
909 | } | ||
910 | } | ||
911 | for (std::list<LLAssetRequest*>::iterator iter = mPendingLocalUploads.begin(); | ||
912 | iter != mPendingLocalUploads.end(); ) | ||
913 | { | ||
914 | std::list<LLAssetRequest*>::iterator curiter = iter++; | ||
915 | LLAssetRequest* req = *curiter; | ||
916 | if ((req->getUUID() == uuid) && (req->getType() == asset_type)) | ||
917 | { | ||
918 | requests.push_front(req); | ||
919 | iter = mPendingLocalUploads.erase(curiter); | ||
920 | } | ||
921 | } | ||
922 | for (std::list<LLAssetRequest*>::iterator iter = requests.begin(); | ||
923 | iter != requests.end(); ) | ||
924 | { | ||
925 | std::list<LLAssetRequest*>::iterator curiter = iter++; | ||
926 | LLAssetRequest* req = *curiter; | ||
927 | if (req->mUpCallback) | ||
928 | { | ||
929 | req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED )); | ||
930 | } | ||
931 | delete req; | ||
932 | } | ||
933 | } | ||
934 | |||
935 | |||
936 | S32 LLAssetStorage::getNumPendingDownloads() const | ||
937 | { | ||
938 | return mPendingDownloads.size(); | ||
939 | } | ||
940 | |||
941 | S32 LLAssetStorage::getNumPendingUploads() const | ||
942 | { | ||
943 | return mPendingUploads.size(); | ||
944 | } | ||
945 | |||
946 | S32 LLAssetStorage::getNumPendingLocalUploads() | ||
947 | { | ||
948 | return mPendingLocalUploads.size(); | ||
949 | } | ||
950 | |||
951 | LLSD LLAssetStorage::getPendingTypes(const std::list<LLAssetRequest*>& requests) const | ||
952 | { | ||
953 | LLSD type_counts; | ||
954 | std::list<LLAssetRequest*>::const_iterator it = requests.begin(); | ||
955 | std::list<LLAssetRequest*>::const_iterator end = requests.end(); | ||
956 | for ( ; it != end; ++it) | ||
957 | { | ||
958 | LLAssetRequest* req = *it; | ||
959 | |||
960 | const char* type_name = LLAssetType::lookupHumanReadable(req->getType()); | ||
961 | type_counts[type_name] = type_counts[type_name].asInteger() + 1; | ||
962 | } | ||
963 | return type_counts; | ||
964 | } | ||
965 | |||
966 | LLSD LLAssetStorage::getPendingDownloadTypes() const | ||
967 | { | ||
968 | return getPendingTypes(mPendingDownloads); | ||
969 | } | ||
970 | |||
971 | LLSD LLAssetStorage::getPendingUploadTypes() const | ||
972 | { | ||
973 | return getPendingTypes(mPendingUploads); | ||
974 | } | ||
975 | |||
976 | // static | ||
977 | const char* LLAssetStorage::getErrorString(S32 status) | ||
978 | { | ||
979 | switch( status ) | ||
980 | { | ||
981 | case LL_ERR_NOERR: | ||
982 | return "No error"; | ||
983 | |||
984 | case LL_ERR_ASSET_REQUEST_FAILED: | ||
985 | return "Asset request: failed"; | ||
986 | |||
987 | case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE: | ||
988 | return "Asset request: non-existent file"; | ||
989 | |||
990 | case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE: | ||
991 | return "Asset request: asset not found in database"; | ||
992 | |||
993 | case LL_ERR_EOF: | ||
994 | return "End of file"; | ||
995 | |||
996 | case LL_ERR_CANNOT_OPEN_FILE: | ||
997 | return "Cannot open file"; | ||
998 | |||
999 | case LL_ERR_FILE_NOT_FOUND: | ||
1000 | return "File not found"; | ||
1001 | |||
1002 | case LL_ERR_TCP_TIMEOUT: | ||
1003 | return "File transfer timeout"; | ||
1004 | |||
1005 | case LL_ERR_CIRCUIT_GONE: | ||
1006 | return "Circuit gone"; | ||
1007 | |||
1008 | default: | ||
1009 | return "Unknown status"; | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | |||
1014 | |||
1015 | void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32), void *user_data, BOOL is_priority) | ||
1016 | { | ||
1017 | // check for duplicates here, since we're about to fool the normal duplicate checker | ||
1018 | for (std::list<LLAssetRequest*>::iterator iter = mPendingDownloads.begin(); | ||
1019 | iter != mPendingDownloads.end(); ) | ||
1020 | { | ||
1021 | LLAssetRequest* tmp = *iter++; | ||
1022 | if (type == tmp->getType() && | ||
1023 | uuid == tmp->getUUID() && | ||
1024 | legacyGetDataCallback == tmp->mDownCallback && | ||
1025 | callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && | ||
1026 | user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData) | ||
1027 | { | ||
1028 | // this is a duplicate from the same subsystem - throw it away | ||
1029 | llinfos << "Discarding duplicate request for UUID " << uuid << llendl; | ||
1030 | return; | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | |||
1035 | LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; | ||
1036 | |||
1037 | legacy->mDownCallback = callback; | ||
1038 | legacy->mUserData = user_data; | ||
1039 | |||
1040 | getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy, | ||
1041 | is_priority); | ||
1042 | } | ||
1043 | |||
1044 | // static | ||
1045 | void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status) | ||
1046 | { | ||
1047 | LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; | ||
1048 | char filename[LL_MAX_PATH] = ""; /* Flawfinder: ignore */ | ||
1049 | |||
1050 | if (! status) | ||
1051 | { | ||
1052 | LLVFile file(vfs, uuid, type); | ||
1053 | |||
1054 | char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */ | ||
1055 | |||
1056 | uuid.toString(uuid_str); | ||
1057 | snprintf(filename,sizeof(filename),"%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); /* Flawfinder: ignore */ | ||
1058 | |||
1059 | FILE *fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ | ||
1060 | if (fp) | ||
1061 | { | ||
1062 | const S32 buf_size = 65536; | ||
1063 | U8 copy_buf[buf_size]; | ||
1064 | while (file.read(copy_buf, buf_size)) | ||
1065 | { | ||
1066 | if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) | ||
1067 | { | ||
1068 | // return a bad file error if we can't write the whole thing | ||
1069 | status = LL_ERR_CANNOT_OPEN_FILE; | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | fclose(fp); | ||
1074 | } | ||
1075 | else | ||
1076 | { | ||
1077 | status = LL_ERR_CANNOT_OPEN_FILE; | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | legacy->mDownCallback(filename, uuid, legacy->mUserData, status); | ||
1082 | delete legacy; | ||
1083 | } | ||
1084 | |||
1085 | // this is overridden on the viewer and the sim, so it doesn't really do anything | ||
1086 | // virtual | ||
1087 | void LLAssetStorage::storeAssetData( | ||
1088 | const LLTransactionID& tid, | ||
1089 | LLAssetType::EType asset_type, | ||
1090 | LLStoreAssetCallback callback, | ||
1091 | void* user_data, | ||
1092 | bool temp_file, | ||
1093 | bool is_priority, | ||
1094 | bool store_local) | ||
1095 | { | ||
1096 | llwarns << "storeAssetData: wrong version called" << llendl; | ||
1097 | } | ||
1098 | |||
1099 | // virtual | ||
1100 | // this does nothing, viewer and sim both override this. | ||
1101 | void LLAssetStorage::storeAssetData( | ||
1102 | const LLUUID& asset_id, | ||
1103 | LLAssetType::EType asset_type, | ||
1104 | LLStoreAssetCallback callback, | ||
1105 | void* user_data, | ||
1106 | bool temp_file , | ||
1107 | bool is_priority, | ||
1108 | bool store_local, | ||
1109 | const LLUUID& requesting_agent_id) | ||
1110 | { | ||
1111 | llwarns << "storeAssetData: wrong version called" << llendl; | ||
1112 | } | ||
1113 | |||
1114 | // virtual | ||
1115 | // this does nothing, viewer and sim both override this. | ||
1116 | void LLAssetStorage::storeAssetData( | ||
1117 | const char* filename, | ||
1118 | const LLUUID& asset_id, | ||
1119 | LLAssetType::EType asset_type, | ||
1120 | LLStoreAssetCallback callback, | ||
1121 | void* user_data, | ||
1122 | bool temp_file, | ||
1123 | bool is_priority) | ||
1124 | { | ||
1125 | llwarns << "storeAssetData: wrong version called" << llendl; | ||
1126 | } | ||
1127 | |||
1128 | // virtual | ||
1129 | // this does nothing, viewer and sim both override this. | ||
1130 | void LLAssetStorage::storeAssetData( | ||
1131 | const char* filename, | ||
1132 | const LLTransactionID &transactoin_id, | ||
1133 | LLAssetType::EType asset_type, | ||
1134 | LLStoreAssetCallback callback, | ||
1135 | void* user_data, | ||
1136 | bool temp_file, | ||
1137 | bool is_priority) | ||
1138 | { | ||
1139 | llwarns << "storeAssetData: wrong version called" << llendl; | ||
1140 | } | ||
1141 | |||
1142 | // static | ||
1143 | void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status) | ||
1144 | { | ||
1145 | LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; | ||
1146 | if (legacy && legacy->mUpCallback) | ||
1147 | { | ||
1148 | legacy->mUpCallback(uuid, legacy->mUserData, status); | ||
1149 | } | ||
1150 | delete legacy; | ||
1151 | } | ||
1152 | |||
1153 | // virtual | ||
1154 | void LLAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name) | ||
1155 | { } | ||
1156 | |||
1157 | // virtual | ||
1158 | BOOL LLAssetStorage::hasTempAssetData(const LLUUID& texture_id) const | ||
1159 | { return FALSE; } | ||
1160 | |||
1161 | // virtual | ||
1162 | std::string LLAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const | ||
1163 | { return std::string(); } | ||
1164 | |||
1165 | // virtual | ||
1166 | LLUUID LLAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const | ||
1167 | { return LLUUID::null; } | ||
1168 | |||
1169 | // virtual | ||
1170 | void LLAssetStorage::removeTempAssetData(const LLUUID& asset_id) | ||
1171 | { } | ||
1172 | |||
1173 | // virtual | ||
1174 | void LLAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id) | ||
1175 | { } | ||
1176 | |||
1177 | // virtual | ||
1178 | void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const | ||
1179 | { } | ||
1180 | |||
1181 | // virtual | ||
1182 | void LLAssetStorage::clearTempAssetData() | ||
1183 | { } | ||