diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llmessage/llassetstorage.cpp | 59 | ||||
-rw-r--r-- | indra/llmessage/llassetstorage.h | 26 | ||||
-rw-r--r-- | indra/llmessage/llcachename.cpp | 129 | ||||
-rw-r--r-- | indra/llmessage/llcachename.h | 8 | ||||
-rw-r--r-- | indra/llmessage/llhttpassetstorage.cpp | 67 | ||||
-rw-r--r-- | indra/newview/llappviewer.cpp | 15 | ||||
-rw-r--r-- | indra/newview/llviewerassetstorage.cpp | 59 |
7 files changed, 304 insertions, 59 deletions
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index d5e04456c4..e2043144b8 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -53,7 +53,10 @@ #include "lltransfersourceasset.h" #include "lltransfertargetvfile.h" // For debugging +#include "llmetrics.h" + LLAssetStorage *gAssetStorage = NULL; +LLMetrics *LLAssetStorage::metric_recipient = NULL; const LLUUID CATEGORIZE_LOST_AND_FOUND_ID("00000000-0000-0000-0000-000000000010"); @@ -1279,6 +1282,8 @@ void LLAssetStorage::storeAssetData( F64 timeout) { llwarns << "storeAssetData: wrong version called" << llendl; + // LLAssetStorage metric: Virtual base call + reportMetric( LLUUID::null, asset_type, NULL, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 1" ); } // virtual @@ -1296,6 +1301,8 @@ void LLAssetStorage::storeAssetData( F64 timeout) { llwarns << "storeAssetData: wrong version called" << llendl; + // LLAssetStorage metric: Virtual base call + reportMetric( asset_id, asset_type, NULL, requesting_agent_id, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 2" ); } // virtual @@ -1312,6 +1319,8 @@ void LLAssetStorage::storeAssetData( F64 timeout) { llwarns << "storeAssetData: wrong version called" << llendl; + // LLAssetStorage metric: Virtual base call + reportMetric( asset_id, asset_type, NULL, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 3" ); } // virtual @@ -1328,6 +1337,8 @@ void LLAssetStorage::storeAssetData( F64 timeout) { llwarns << "storeAssetData: wrong version called" << llendl; + // LLAssetStorage metric: Virtual base call + reportMetric( LLUUID::null, asset_type, NULL, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 4" ); } // static @@ -1372,3 +1383,51 @@ void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const // virtual void LLAssetStorage::clearTempAssetData() { } + +// static +void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const char *filename, + const LLUUID& agent_id, S32 asset_size, EMetricResult result, + const char *file, const S32 line, const char *message ) +{ + if( !metric_recipient ) + { + llinfos << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << llendl; + return; + } + + filename = filename ? filename : ""; + file = file ? file : ""; + + // Create revised message - message = "message :: file:line" + std::string new_message; //( message ); + new_message = message; // << " " << file << " " << line; + new_message += " :: "; + new_message += filename; + char line_string[16]; + sprintf( line_string, ":%d", line ); + new_message += line_string; + message = new_message.c_str(); + + // Change always_report to true if debugging... do not check it in this way + static bool always_report = false; + const char *metric_name = "LLAssetStorage::Metrics"; + + bool success = result == MR_OKAY; + + if( (!success) || always_report ) + { + LLSD stats; + stats["asset_id"] = asset_id; + stats["asset_type"] = asset_type; + stats["filename"] = filename? filename : ""; + stats["agent_id"] = agent_id; + stats["asset_size"] = (S32)asset_size; + stats["result"] = (S32)result; + + metric_recipient->recordEventDetails( metric_name, message, success, stats); + } + else + { + metric_recipient->recordEvent(metric_name, message, success); + } +} diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index e2ccf2ca91..8da3926c63 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -420,6 +420,32 @@ private: LLXferManager *xfer, LLVFS *vfs, const LLHost &upstream_host); + +protected: + enum EMetricResult + { + // Static valued enums for #dw readability - please copy this + // declaration to them on updates -- source in llassetstorage.h + MR_INVALID = -1, // Makes no sense + MR_OKAY = 0, // Success - no metric normally + MR_ZERO_SIZE = 1, // Zero size asset + MR_BAD_FUNCTION = 2, // Tried to use a virtual base (PROGRAMMER ERROR) + MR_FILE_NONEXIST = 3, // Old format store call - source file does not exist + MR_NO_FILENAME = 4, // Old format store call - source filename is NULL/0-length + MR_NO_UPSTREAM = 5, // Upstream provider is missing + MR_VFS_CORRUPTION = 6 // VFS is corrupt - too-large or mismatched stated/returned sizes + }; + + static class LLMetrics *metric_recipient; + + static void reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const char *filename, + const LLUUID& agent_id, S32 asset_size, EMetricResult result, + const char *file, const S32 line, const char *message ); +public: + static void setMetricRecipient( LLMetrics *recip ) + { + metric_recipient = recip; + } }; //////////////////////////////////////////////////////////////////////// diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index f731c95a14..3472c3eb5d 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -34,12 +34,13 @@ #include "llcachename.h" // linden library includes -#include "message.h" -#include "llrand.h" #include "lldbstrings.h" #include "llframetimer.h" #include "llhost.h" +#include "llrand.h" +#include "llsdserialize.h" #include "lluuid.h" +#include "message.h" // Constants const char* CN_WAITING = "(waiting)"; @@ -48,6 +49,14 @@ const char* CN_NONE = "(none)"; const char* CN_HIPPOS = "(hippos)"; const F32 HIPPO_PROBABILITY = 0.01f; +// llsd serialization constants +static const std::string AGENTS("agents"); +static const std::string GROUPS("groups"); +static const std::string CTIME("ctime"); +static const std::string FIRST("first"); +static const std::string LAST("last"); +static const std::string NAME("name"); + // We track name requests in flight for up to this long. // We won't re-request a name during this time const U32 PENDING_TIMEOUT_SECS = 5 * 60; @@ -392,41 +401,100 @@ void LLCacheName::importFile(FILE* fp) llinfos << "LLCacheName loaded " << count << " names" << llendl; } - -void LLCacheName::exportFile(FILE* fp) +bool LLCacheName::importFile(std::istream& istr) { - fprintf(fp, "version\t%d\n", CN_FILE_VERSION); + LLSD data; + if(LLSDSerialize::fromXML(data, istr) < 1) + return false; - for (Cache::iterator iter = impl.mCache.begin(), - end = impl.mCache.end(); - iter != end; iter++) + // We'll expire entries more than a week old + U32 now = (U32)time(NULL); + const U32 SECS_PER_DAY = 60 * 60 * 24; + U32 delete_before_time = now - (7 * SECS_PER_DAY); + + // iterate over the agents + S32 count = 0; + LLSD agents = data[AGENTS]; + LLSD::map_iterator iter = agents.beginMap(); + LLSD::map_iterator end = agents.endMap(); + for( ; iter != end; ++iter) { - LLCacheNameEntry* entry = iter->second; - // Only write entries for which we have valid data. - // HACK: Only write agent names. This makes the reader easier. - if ( entry->mFirstName[0] - && entry->mLastName[0]) - { - LLUUID id = iter->first; + LLUUID id((*iter).first); + LLSD agent = (*iter).second; + U32 ctime = (U32)agent[CTIME].asInteger(); + if(ctime < delete_before_time) continue; - // Trivial XOR encoding - S32 i; - for (i = 0; i < UUID_BYTES; i++) - { - id.mData[i] ^= 0x33; - } + LLCacheNameEntry* entry = new LLCacheNameEntry(); + entry->mIsGroup = false; + entry->mCreateTime = ctime; + std::string first = agent[FIRST].asString(); + first.copy(entry->mFirstName, DB_FIRST_NAME_BUF_SIZE, 0); + entry->mFirstName[llmin(first.size(),(std::string::size_type)DB_FIRST_NAME_BUF_SIZE-1)] = '\0'; + std::string last = agent[LAST].asString(); + last.copy(entry->mLastName, DB_LAST_NAME_BUF_SIZE, 0); + entry->mLastName[llmin(last.size(),(std::string::size_type)DB_LAST_NAME_BUF_SIZE-1)] = '\0'; + impl.mCache[id] = entry; + ++count; + } + llinfos << "LLCacheName loaded " << count << " agent names" << llendl; + + count = 0; + LLSD groups = data[GROUPS]; + iter = groups.beginMap(); + end = groups.endMap(); + for( ; iter != end; ++iter) + { + LLUUID id((*iter).first); + LLSD group = (*iter).second; + U32 ctime = (U32)group[CTIME].asInteger(); + if(ctime < delete_before_time) continue; - char id_string[UUID_STR_SIZE]; /*Flawfinder:ignore*/ - id.toString(id_string); + LLCacheNameEntry* entry = new LLCacheNameEntry(); + entry->mIsGroup = true; + entry->mCreateTime = ctime; + std::string name = group[NAME].asString(); + name.copy(entry->mGroupName, DB_GROUP_NAME_BUF_SIZE, 0); + entry->mGroupName[llmin(name.size(), (std::string::size_type)DB_GROUP_NAME_BUF_SIZE-1)] = '\0'; + impl.mCache[id] = entry; + ++count; + } + llinfos << "LLCacheName loaded " << count << " group names" << llendl; + return true; +} - // ...not a group name - fprintf(fp, "%s\t%u\t%s\t%s\n", - id_string, - entry->mCreateTime, - entry->mFirstName, - entry->mLastName); +void LLCacheName::exportFile(std::ostream& ostr) +{ + LLSD data; + Cache::iterator iter = impl.mCache.begin(); + Cache::iterator end = impl.mCache.end(); + for( ; iter != end; ++iter) + { + // Only write entries for which we have valid data. + LLCacheNameEntry* entry = iter->second; + if(!entry + || (NULL != strchr(entry->mFirstName, '?')) + || (NULL != strchr(entry->mGroupName, '?'))) + { + continue; + } + + // store it + LLUUID id = iter->first; + std::string id_str = id.asString(); + if(entry->mFirstName[0] && entry->mLastName[0]) + { + data[AGENTS][id_str][FIRST] = entry->mFirstName; + data[AGENTS][id_str][LAST] = entry->mLastName; + data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime; + } + else if(entry->mIsGroup && entry->mGroupName[0]) + { + data[GROUPS][id_str][NAME] = entry->mGroupName; + data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime; } } + + LLSDSerialize::toPrettyXML(data, ostr); } @@ -884,6 +952,3 @@ void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** us ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true); } - - - diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index ab6282966d..4eae6365bc 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -63,9 +63,12 @@ public: void cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data = NULL); - // storing cache on disk; for viewer, in name.cache + // janky old format. Remove after a while. Phoenix. 2008-01-30 void importFile(FILE* fp); - void exportFile(FILE* fp); + + // storing cache on disk; for viewer, in name.cache + bool importFile(std::istream& istr); + void exportFile(std::ostream& ostr); // If available, copies the first and last name into the strings provided. // first must be at least DB_FIRST_NAME_BUF_SIZE characters. @@ -104,6 +107,7 @@ public: static LLString getDefaultName(); private: + class Impl; Impl& impl; }; diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp index c5b897b87b..cf9bde6fec 100644 --- a/indra/llmessage/llhttpassetstorage.cpp +++ b/indra/llmessage/llhttpassetstorage.cpp @@ -451,7 +451,7 @@ void LLHTTPAssetStorage::storeAssetData( bool user_waiting, F64 timeout) { - if (mVFS->getExists(uuid, type)) + if (mVFS->getExists(uuid, type)) // VFS treats nonexistant and zero-length identically { LLAssetRequest *req = new LLAssetRequest(uuid, type); req->mUpCallback = callback; @@ -460,6 +460,19 @@ void LLHTTPAssetStorage::storeAssetData( req->mIsUserWaiting = user_waiting; req->mTimeout = timeout; + // LLAssetStorage metric: Successful Request + S32 size = mVFS->getSize(uuid, type); + const char *message; + if( store_local ) + { + message = "Added to local upload queue"; + } + else + { + message = "Added to upload queue"; + } + reportMetric( uuid, type, NULL, requesting_agent_id, size, MR_OKAY, __FILE__, __LINE__, message ); + // this will get picked up and transmitted in checkForTimeouts if(store_local) { @@ -479,6 +492,8 @@ void LLHTTPAssetStorage::storeAssetData( llwarns << "AssetStorage: attempt to upload non-existent vfile " << uuid << ":" << LLAssetType::lookup(type) << llendl; if (callback) { + // LLAssetStorage metric: Zero size VFS + reportMetric( uuid, type, NULL, requesting_agent_id, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); callback(uuid, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE); } } @@ -504,13 +519,17 @@ void LLHTTPAssetStorage::storeAssetData( legacy->mUserData = user_data; FILE *fp = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + S32 size = 0; if (fp) { - LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE); - fseek(fp, 0, SEEK_END); - S32 size = ftell(fp); + size = ftell(fp); fseek(fp, 0, SEEK_SET); + } + + if( size ) + { + LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE); file.setMaxSize(size); @@ -528,6 +547,7 @@ void LLHTTPAssetStorage::storeAssetData( LLFile::remove(filename); } + // LLAssetStorage metric: Success not needed; handled in the overloaded method here: storeAssetData( asset_id, asset_type, @@ -540,8 +560,19 @@ void LLHTTPAssetStorage::storeAssetData( user_waiting, timeout); } - else + else // !size { + if( fp ) + { + // LLAssetStorage metric: Zero size + reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" ); + fclose( fp ); + } + else + { + // LLAssetStorage metric: Missing File + reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" ); + } if (callback) { callback(LLUUID::null, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE); @@ -827,7 +858,16 @@ void LLHTTPAssetStorage::checkForTimeouts() } else { - llinfos << "Requesting PUT " << new_req->mURLBuffer << llendl; + // Get the uncompressed file size. + LLVFile file(mVFS,new_req->getUUID(),new_req->getType()); + S32 size = file.getSize(); + llinfos << "Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << llendl; + if (size == 0) + { + llwarns << "Rejecting zero size PUT request!" << llendl; + new_req->cleanupCurlHandle(); + deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID()); + } } // Pending upload will have been flagged by the request } @@ -867,8 +907,19 @@ void LLHTTPAssetStorage::checkForTimeouts() } else { + // Get the uncompressed file size. + S32 size = file.getSize(); + llinfos << "TAT: LLHTTPAssetStorage::checkForTimeouts() : pending local!" - << " Requesting PUT " << new_req->mURLBuffer << llendl; + << " Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << llendl; + if (size == 0) + { + + llwarns << "Rejecting zero size PUT request!" << llendl; + new_req->cleanupCurlHandle(); + deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID()); + } + } // Pending upload will have been flagged by the request } @@ -1403,5 +1454,3 @@ void LLHTTPAssetStorage::clearTempAssetData() llinfos << "TAT: Clearing temp asset data map" << llendl; mTempAssets.clear(); } - - diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 97f652d88d..fe9b90ae60 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3190,6 +3190,14 @@ void LLAppViewer::loadNameCache() std::string name_cache; name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); + llifstream cache_file(name_cache.c_str()); + if(cache_file.is_open()) + { + if(gCacheName->importFile(cache_file)) return; + } + + // Try to load from the legacy format. This should go away after a + // while. Phoenix 2008-01-30 FILE* name_cache_fp = LLFile::fopen(name_cache.c_str(), "r"); // Flawfinder: ignore if (name_cache_fp) { @@ -3204,11 +3212,10 @@ void LLAppViewer::saveNameCache() std::string name_cache; name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); - FILE* name_cache_fp = LLFile::fopen(name_cache.c_str(), "w"); // Flawfinder: ignore - if (name_cache_fp) + llofstream cache_file(name_cache.c_str()); + if(cache_file.is_open()) { - gCacheName->exportFile(name_cache_fp); - fclose(name_cache_fp); + gCacheName->exportFile(cache_file); } } diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 1832c4282c..c015004a71 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -87,6 +87,8 @@ void LLViewerAssetStorage::storeAssetData( { // This can happen if there's a bug in our code or if the VFS has been corrupted. llwarns << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << llendl; + // LLAssetStorage metric: Zero size VFS + reportMetric( asset_id, asset_type, NULL, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); delete req; if (callback) @@ -95,13 +97,21 @@ void LLViewerAssetStorage::storeAssetData( } return; } - else if(is_priority) - { - mPendingUploads.push_front(req); - } else { - mPendingUploads.push_back(req); + // LLAssetStorage metric: Successful Request + S32 size = mVFS->getSize(asset_id, asset_type); + const char *message = "Added to upload queue"; + reportMetric( asset_id, asset_type, NULL, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message ); + + if(is_priority) + { + mPendingUploads.push_front(req); + } + else + { + mPendingUploads.push_back(req); + } } // Read the data from the VFS if it'll fit in this packet. @@ -118,6 +128,10 @@ void LLViewerAssetStorage::storeAssetData( else { llwarns << "Probable corruption in VFS file, aborting store asset data" << llendl; + + // LLAssetStorage metric: VFS corrupt - bogus size + reportMetric( asset_id, asset_type, NULL, LLUUID::null, asset_size, MR_VFS_CORRUPTION, __FILE__, __LINE__, "VFS corruption" ); + if (callback) { callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_VFS_CORRUPT); @@ -143,6 +157,8 @@ void LLViewerAssetStorage::storeAssetData( else { llwarns << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << llendl; + // LLAssetStorage metric: Zero size VFS + reportMetric( asset_id, asset_type, NULL, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); if (callback) { callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE); @@ -152,6 +168,8 @@ void LLViewerAssetStorage::storeAssetData( else { llwarns << "Attempt to move asset store request upstream w/o valid upstream provider" << llendl; + // LLAssetStorage metric: Upstream provider dead + reportMetric( asset_id, asset_type, NULL, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" ); if (callback) { callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); @@ -170,8 +188,10 @@ void LLViewerAssetStorage::storeAssetData( bool user_waiting, F64 timeout) { - if(!filename) +if(!filename) { + // LLAssetStorage metric: no filename + reportMetric( LLUUID::null, asset_type, "", LLUUID::null, 0, MR_VFS_CORRUPTION, __FILE__, __LINE__, "Filename missing" ); llerrs << "No filename specified" << llendl; return; } @@ -181,9 +201,16 @@ void LLViewerAssetStorage::storeAssetData( llinfos << "ASSET_ID: " << asset_id << llendl; + S32 size = 0; FILE* fp = LLFile::fopen(filename, "rb"); if (fp) { + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + } + if( size ) + { LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; legacy->mUpCallback = callback; @@ -191,10 +218,6 @@ void LLViewerAssetStorage::storeAssetData( LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE); - fseek(fp, 0, SEEK_END); - S32 size = ftell(fp); - fseek(fp, 0, SEEK_SET); - file.setMaxSize(size); const S32 buf_size = 65536; @@ -210,7 +233,9 @@ void LLViewerAssetStorage::storeAssetData( { LLFile::remove(filename); } - + + // LLAssetStorage metric: Success not needed; handled in the overloaded method here: + LLViewerAssetStorage::storeAssetData( tid, asset_type, @@ -219,8 +244,18 @@ void LLViewerAssetStorage::storeAssetData( temp_file, is_priority); } - else + else // size == 0 (but previous block changes size) { + if( fp ) + { + // LLAssetStorage metric: Zero size + reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" ); + } + else + { + // LLAssetStorage metric: Missing File + reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" ); + } if (callback) { callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE); |