00001
00032 #include "linden_common.h"
00033
00034 #include "llsys.h"
00035
00036 #include <iostream>
00037 #ifdef LL_STANDALONE
00038 # include <zlib.h>
00039 #else
00040 # include "zlib/zlib.h"
00041 #endif
00042
00043 #include "llprocessor.h"
00044
00045 #if LL_WINDOWS
00046 # define WIN32_LEAN_AND_MEAN
00047 # include <winsock2.h>
00048 # include <windows.h>
00049 #elif LL_DARWIN
00050 # include <errno.h>
00051 # include <sys/sysctl.h>
00052 # include <sys/utsname.h>
00053 # include <stdint.h>
00054 #elif LL_LINUX
00055 # include <errno.h>
00056 # include <sys/utsname.h>
00057 # include <unistd.h>
00058 # include <sys/sysinfo.h>
00059 const char MEMINFO_FILE[] = "/proc/meminfo";
00060 const char CPUINFO_FILE[] = "/proc/cpuinfo";
00061 #endif
00062
00063
00064 static const S32 CPUINFO_BUFFER_SIZE = 16383;
00065 LLCPUInfo gSysCPU;
00066
00067 LLOSInfo::LLOSInfo() :
00068 mMajorVer(0), mMinorVer(0), mBuild(0)
00069 {
00070
00071 #if LL_WINDOWS
00072 OSVERSIONINFOEX osvi;
00073 BOOL bOsVersionInfoEx;
00074
00075
00076 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
00077 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
00078 if(!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi)))
00079 {
00080
00081 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
00082 if(!GetVersionEx( (OSVERSIONINFO *) &osvi))
00083 return;
00084 }
00085 mMajorVer = osvi.dwMajorVersion;
00086 mMinorVer = osvi.dwMinorVersion;
00087 mBuild = osvi.dwBuildNumber;
00088
00089 switch(osvi.dwPlatformId)
00090 {
00091 case VER_PLATFORM_WIN32_NT:
00092 {
00093
00094 if(osvi.dwMajorVersion <= 4)
00095 {
00096 mOSStringSimple = "Microsoft Windows NT ";
00097 }
00098 else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
00099 {
00100 mOSStringSimple = "Microsoft Windows 2000 ";
00101 }
00102 else if(osvi.dwMajorVersion ==5 && osvi.dwMinorVersion == 1)
00103 {
00104 mOSStringSimple = "Microsoft Windows XP ";
00105 }
00106 else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
00107 {
00108 if(osvi.wProductType == VER_NT_WORKSTATION)
00109 mOSStringSimple = "Microsoft Windows XP x64 Edition ";
00110 else
00111 mOSStringSimple = "Microsoft Windows Server 2003 ";
00112 }
00113 else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
00114 {
00115 if(osvi.wProductType == VER_NT_WORKSTATION)
00116 mOSStringSimple = "Microsoft Windows Vista ";
00117 else mOSStringSimple = "Microsoft Windows Vista Server ";
00118 }
00119 else
00120 {
00121 HKEY hKey;
00122 WCHAR szProductType[80];
00123 DWORD dwBufLen;
00124 RegOpenKeyEx( HKEY_LOCAL_MACHINE,
00125 L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
00126 0, KEY_QUERY_VALUE, &hKey );
00127 RegQueryValueEx( hKey, L"ProductType", NULL, NULL,
00128 (LPBYTE) szProductType, &dwBufLen);
00129 RegCloseKey( hKey );
00130 if ( lstrcmpi( L"WINNT", szProductType) == 0 )
00131 {
00132 mOSStringSimple += "Professional ";
00133 }
00134 else if ( lstrcmpi( L"LANMANNT", szProductType) == 0 )
00135 {
00136 mOSStringSimple += "Server ";
00137 }
00138 else if ( lstrcmpi( L"SERVERNT", szProductType) == 0 )
00139 {
00140 mOSStringSimple += "Advanced Server ";
00141 }
00142 }
00143
00144 std::string csdversion = utf16str_to_utf8str(osvi.szCSDVersion);
00145
00146 char tmp[MAX_STRING];
00147 if(osvi.dwMajorVersion <= 4)
00148 {
00149 snprintf(
00150 tmp,
00151 sizeof(tmp),
00152 "version %d.%d %s (Build %d)",
00153 osvi.dwMajorVersion,
00154 osvi.dwMinorVersion,
00155 csdversion.c_str(),
00156 (osvi.dwBuildNumber & 0xffff));
00157 }
00158 else
00159 {
00160 snprintf(
00161 tmp,
00162 sizeof(tmp),
00163 "%s (Build %d)",
00164 csdversion.c_str(),
00165 (osvi.dwBuildNumber & 0xffff));
00166 }
00167 mOSString = mOSStringSimple + tmp;
00168 }
00169 break;
00170
00171 case VER_PLATFORM_WIN32_WINDOWS:
00172
00173 if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
00174 {
00175 mOSStringSimple = "Microsoft Windows 95 ";
00176 if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
00177 {
00178 mOSStringSimple += "OSR2 ";
00179 }
00180 }
00181 if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
00182 {
00183 mOSStringSimple = "Microsoft Windows 98 ";
00184 if ( osvi.szCSDVersion[1] == 'A' )
00185 {
00186 mOSStringSimple += "SE ";
00187 }
00188 }
00189 if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
00190 {
00191 mOSStringSimple = "Microsoft Windows Millennium Edition ";
00192 }
00193 mOSString = mOSStringSimple;
00194 break;
00195 }
00196 #else
00197 struct utsname un;
00198 if(uname(&un) != -1)
00199 {
00200 mOSStringSimple.append(un.sysname);
00201 mOSStringSimple.append(" ");
00202 mOSStringSimple.append(un.release);
00203
00204 mOSString = mOSStringSimple;
00205 mOSString.append(" ");
00206 mOSString.append(un.version);
00207 mOSString.append(" ");
00208 mOSString.append(un.machine);
00209
00210
00211 std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0));
00212 if (ostype == "Darwin")
00213 {
00214
00215 S32 idx1 = mOSStringSimple.find_first_of(".", 0);
00216 std::string simple = mOSStringSimple.substr(0, idx1);
00217 if (simple.length() > 0)
00218 mOSStringSimple = simple;
00219 }
00220 else if (ostype == "Linux")
00221 {
00222
00223 S32 idx1 = mOSStringSimple.find_first_of(".", 0);
00224 S32 idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos;
00225 std::string simple = mOSStringSimple.substr(0, idx2);
00226 if (simple.length() > 0)
00227 mOSStringSimple = simple;
00228 }
00229 }
00230 else
00231 {
00232 mOSStringSimple.append("Unable to collect OS info");
00233 mOSString = mOSStringSimple;
00234 }
00235 #endif
00236
00237 }
00238
00239 #ifndef LL_WINDOWS
00240
00241 S32 LLOSInfo::getMaxOpenFiles()
00242 {
00243 const S32 OPEN_MAX_GUESS = 256;
00244
00245 #ifdef OPEN_MAX
00246 static S32 open_max = OPEN_MAX;
00247 #else
00248 static S32 open_max = 0;
00249 #endif
00250
00251 if (0 == open_max)
00252 {
00253
00254 errno = 0;
00255 if ( (open_max = sysconf(_SC_OPEN_MAX)) < 0)
00256 {
00257 if (0 == errno)
00258 {
00259
00260 open_max = OPEN_MAX_GUESS;
00261 }
00262 else
00263 {
00264 llerrs << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << llendl;
00265 }
00266 }
00267 }
00268 return open_max;
00269 }
00270 #endif
00271
00272 void LLOSInfo::stream(std::ostream& s) const
00273 {
00274 s << mOSString;
00275 }
00276
00277 const std::string& LLOSInfo::getOSString() const
00278 {
00279 return mOSString;
00280 }
00281
00282 const std::string& LLOSInfo::getOSStringSimple() const
00283 {
00284 return mOSStringSimple;
00285 }
00286
00287 const S32 STATUS_SIZE = 8192;
00288
00289
00290 U32 LLOSInfo::getProcessVirtualSizeKB()
00291 {
00292 U32 virtual_size = 0;
00293 #if LL_WINDOWS
00294 #endif
00295 #if LL_LINUX
00296 LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
00297 S32 numRead = 0;
00298 char buff[STATUS_SIZE];
00299
00300 size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep);
00301 buff[nbytes] = '\0';
00302
00303
00304 char *memp = strstr(buff, "VmSize:");
00305 if (memp)
00306 {
00307 numRead += sscanf(memp, "%*s %u", &virtual_size);
00308 }
00309 fclose(status_filep);
00310 #elif LL_SOLARIS
00311 char proc_ps[LL_MAX_PATH];
00312 sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid());
00313 int proc_fd = -1;
00314 if((proc_fd = open(proc_ps, O_RDONLY)) == -1){
00315 llwarns << "unable to open " << proc_ps << llendl;
00316 return 0;
00317 }
00318 psinfo_t proc_psinfo;
00319 if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){
00320 llwarns << "Unable to read " << proc_ps << llendl;
00321 close(proc_fd);
00322 return 0;
00323 }
00324
00325 close(proc_fd);
00326
00327 virtual_size = proc_psinfo.pr_size;
00328 #endif
00329 return virtual_size;
00330 }
00331
00332
00333 U32 LLOSInfo::getProcessResidentSizeKB()
00334 {
00335 U32 resident_size = 0;
00336 #if LL_WINDOWS
00337 #endif
00338 #if LL_LINUX
00339 LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
00340 if (status_filep != NULL)
00341 {
00342 S32 numRead = 0;
00343 char buff[STATUS_SIZE];
00344
00345 size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep);
00346 buff[nbytes] = '\0';
00347
00348
00349 char *memp = strstr(buff, "VmRSS:");
00350 if (memp)
00351 {
00352 numRead += sscanf(memp, "%*s %u", &resident_size);
00353 }
00354 fclose(status_filep);
00355 }
00356 #elif LL_SOLARIS
00357 char proc_ps[LL_MAX_PATH];
00358 sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid());
00359 int proc_fd = -1;
00360 if((proc_fd = open(proc_ps, O_RDONLY)) == -1){
00361 llwarns << "unable to open " << proc_ps << llendl;
00362 return 0;
00363 }
00364 psinfo_t proc_psinfo;
00365 if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){
00366 llwarns << "Unable to read " << proc_ps << llendl;
00367 close(proc_fd);
00368 return 0;
00369 }
00370
00371 close(proc_fd);
00372
00373 resident_size = proc_psinfo.pr_rssize;
00374 #endif
00375 return resident_size;
00376 }
00377
00378 LLCPUInfo::LLCPUInfo()
00379 {
00380 std::ostringstream out;
00381 CProcessor proc;
00382 const ProcessorInfo* info = proc.GetCPUInfo();
00383
00384 mHasSSE = info->_Ext.SSE_StreamingSIMD_Extensions;
00385 mHasSSE2 = info->_Ext.SSE2_StreamingSIMD2_Extensions;
00386 mHasAltivec = info->_Ext.Altivec_Extensions;
00387 mCPUMhz = (S32)(proc.GetCPUFrequency(50)/1000000.0);
00388 mFamily.assign( info->strFamily );
00389 mCPUString = "Unknown";
00390
00391 #if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
00392 out << proc.strCPUName;
00393 if (200 < mCPUMhz && mCPUMhz < 10000)
00394 {
00395 out << " (" << mCPUMhz << " MHz)";
00396 }
00397 mCPUString = out.str();
00398
00399 #elif LL_LINUX
00400 std::map< LLString, LLString > cpuinfo;
00401 LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
00402 if(cpuinfo_fp)
00403 {
00404 char line[MAX_STRING];
00405 memset(line, 0, MAX_STRING);
00406 while(fgets(line, MAX_STRING, cpuinfo_fp))
00407 {
00408
00409
00410 char* tabspot = strchr( line, '\t' );
00411 if (tabspot == NULL)
00412 continue;
00413 char* colspot = strchr( tabspot, ':' );
00414 if (colspot == NULL)
00415 continue;
00416 char* spacespot = strchr( colspot, ' ' );
00417 if (spacespot == NULL)
00418 continue;
00419 char* nlspot = strchr( line, '\n' );
00420 if (nlspot == NULL)
00421 nlspot = line + strlen( line );
00422 std::string linename( line, tabspot );
00423 LLString llinename(linename);
00424 LLString::toLower(llinename);
00425 std::string lineval( spacespot + 1, nlspot );
00426 cpuinfo[ llinename ] = lineval;
00427 }
00428 fclose(cpuinfo_fp);
00429 }
00430 # if LL_X86
00431 LLString flags = " " + cpuinfo["flags"] + " ";
00432 LLString::toLower(flags);
00433 mHasSSE = ( flags.find( " sse " ) != std::string::npos );
00434 mHasSSE2 = ( flags.find( " sse2 " ) != std::string::npos );
00435
00436 F64 mhz;
00437 if (LLString::convertToF64(cpuinfo["cpu mhz"], mhz)
00438 && 200.0 < mhz && mhz < 10000.0)
00439 {
00440 mCPUMhz = (S32)llrint(mhz);
00441 }
00442 if (!cpuinfo["model name"].empty())
00443 mCPUString = cpuinfo["model name"];
00444 # endif // LL_X86
00445 #endif // LL_LINUX
00446 }
00447
00448 bool LLCPUInfo::hasAltivec() const
00449 {
00450 return mHasAltivec;
00451 }
00452
00453 bool LLCPUInfo::hasSSE() const
00454 {
00455 return mHasSSE;
00456 }
00457
00458 bool LLCPUInfo::hasSSE2() const
00459 {
00460 return mHasSSE2;
00461 }
00462
00463 S32 LLCPUInfo::getMhz() const
00464 {
00465 return mCPUMhz;
00466 }
00467
00468 std::string LLCPUInfo::getCPUString() const
00469 {
00470 return mCPUString;
00471 }
00472
00473 void LLCPUInfo::stream(std::ostream& s) const
00474 {
00475 #if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
00476
00477 char proc_buf[CPUINFO_BUFFER_SIZE];
00478 CProcessor proc;
00479 if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE))
00480 {
00481 s << proc_buf;
00482 }
00483 else
00484 {
00485 s << "Unable to collect processor information" << std::endl;
00486 }
00487 #else
00488
00489 LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
00490 if(cpuinfo)
00491 {
00492 char line[MAX_STRING];
00493 memset(line, 0, MAX_STRING);
00494 while(fgets(line, MAX_STRING, cpuinfo))
00495 {
00496 line[strlen(line)-1] = ' ';
00497 s << line;
00498 }
00499 fclose(cpuinfo);
00500 s << std::endl;
00501 }
00502 else
00503 {
00504 s << "Unable to collect processor information" << std::endl;
00505 }
00506 #endif
00507
00508
00509 s << "->mHasSSE: " << (U32)mHasSSE << std::endl;
00510 s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl;
00511 s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl;
00512 s << "->mCPUMhz: " << mCPUMhz << std::endl;
00513 s << "->mCPUString: " << mCPUString << std::endl;
00514 }
00515
00516 LLMemoryInfo::LLMemoryInfo()
00517 {
00518 }
00519
00520 #if LL_WINDOWS
00521 static U32 LLMemoryAdjustKBResult(U32 inKB)
00522 {
00523
00524
00526
00527
00528
00529
00530
00531
00532 inKB += 1024;
00533
00534 return inKB;
00535 }
00536 #endif
00537
00538 U32 LLMemoryInfo::getPhysicalMemoryKB() const
00539 {
00540 #if LL_WINDOWS
00541 MEMORYSTATUSEX state;
00542 state.dwLength = sizeof(state);
00543 GlobalMemoryStatusEx(&state);
00544
00545 return LLMemoryAdjustKBResult((U32)(state.ullTotalPhys >> 10));
00546
00547 #elif LL_DARWIN
00548
00549 uint64_t phys = 0;
00550 int mib[2] = { CTL_HW, HW_MEMSIZE };
00551
00552 size_t len = sizeof(phys);
00553 sysctl(mib, 2, &phys, &len, NULL, 0);
00554
00555 return (U32)(phys >> 10);
00556
00557 #elif LL_LINUX
00558 U64 phys = 0;
00559 phys = (U64)(getpagesize()) * (U64)(get_phys_pages());
00560 return (U32)(phys >> 10);
00561
00562 #elif LL_SOLARIS
00563 U64 phys = 0;
00564 phys = (U64)(getpagesize()) * (U64)(sysconf(_SC_PHYS_PAGES));
00565 return (U32)(phys >> 10);
00566
00567 #else
00568 return 0;
00569
00570 #endif
00571 }
00572
00573 U32 LLMemoryInfo::getPhysicalMemoryClamped() const
00574 {
00575
00576
00577
00578 U32 phys_kb = getPhysicalMemoryKB();
00579 if (phys_kb >= 4194304 )
00580 {
00581 return U32_MAX;
00582 }
00583 else
00584 {
00585 return phys_kb << 10;
00586 }
00587 }
00588
00589 void LLMemoryInfo::stream(std::ostream& s) const
00590 {
00591 #if LL_WINDOWS
00592 MEMORYSTATUSEX state;
00593 state.dwLength = sizeof(state);
00594 GlobalMemoryStatusEx(&state);
00595
00596 s << "Percent Memory use: " << (U32)state.dwMemoryLoad << '%' << std::endl;
00597 s << "Total Physical KB: " << (U32)(state.ullTotalPhys/1024) << std::endl;
00598 s << "Avail Physical KB: " << (U32)(state.ullAvailPhys/1024) << std::endl;
00599 s << "Total page KB: " << (U32)(state.ullTotalPageFile/1024) << std::endl;
00600 s << "Avail page KB: " << (U32)(state.ullAvailPageFile/1024) << std::endl;
00601 s << "Total Virtual KB: " << (U32)(state.ullTotalVirtual/1024) << std::endl;
00602 s << "Avail Virtual KB: " << (U32)(state.ullAvailVirtual/1024) << std::endl;
00603 #elif LL_DARWIN
00604 uint64_t phys = 0;
00605
00606 size_t len = sizeof(phys);
00607
00608 if(sysctlbyname("hw.memsize", &phys, &len, NULL, 0) == 0)
00609 {
00610 s << "Total Physical KB: " << phys/1024 << std::endl;
00611 }
00612 else
00613 {
00614 s << "Unable to collect memory information";
00615 }
00616 #elif LL_SOLARIS
00617 U64 phys = 0;
00618
00619 phys = (U64)(sysconf(_SC_PHYS_PAGES)) * (U64)(sysconf(_SC_PAGESIZE)/1024);
00620
00621 s << "Total Physical KB: " << phys << std::endl;
00622 #else
00623
00624 LLFILE* meminfo = LLFile::fopen(MEMINFO_FILE,"rb");
00625 if(meminfo)
00626 {
00627 char line[MAX_STRING];
00628 memset(line, 0, MAX_STRING);
00629 while(fgets(line, MAX_STRING, meminfo))
00630 {
00631 line[strlen(line)-1] = ' ';
00632 s << line;
00633 }
00634 fclose(meminfo);
00635 }
00636 else
00637 {
00638 s << "Unable to collect memory information";
00639 }
00640 #endif
00641 }
00642
00643 std::ostream& operator<<(std::ostream& s, const LLOSInfo& info)
00644 {
00645 info.stream(s);
00646 return s;
00647 }
00648
00649 std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info)
00650 {
00651 info.stream(s);
00652 return s;
00653 }
00654
00655 std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info)
00656 {
00657 info.stream(s);
00658 return s;
00659 }
00660
00661 BOOL gunzip_file(const char *srcfile, const char *dstfile)
00662 {
00663 char tmpfile[LL_MAX_PATH];
00664 const S32 UNCOMPRESS_BUFFER_SIZE = 32768;
00665 BOOL retval = FALSE;
00666 gzFile src = NULL;
00667 U8 buffer[UNCOMPRESS_BUFFER_SIZE];
00668 LLFILE *dst = NULL;
00669 S32 bytes = 0;
00670 (void *) strcpy(tmpfile, dstfile);
00671 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1);
00672 src = gzopen(srcfile, "rb");
00673 if (! src) goto err;
00674 dst = LLFile::fopen(tmpfile, "wb");
00675 if (! dst) goto err;
00676 do
00677 {
00678 bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE);
00679 size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst);
00680 if (nwrit < (size_t) bytes)
00681 {
00682 llwarns << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << llendl;
00683 goto err;
00684 }
00685 } while(gzeof(src) == 0);
00686 fclose(dst);
00687 dst = NULL;
00688 if (LLFile::rename(tmpfile, dstfile) == -1) goto err;
00689 retval = TRUE;
00690 err:
00691 if (src != NULL) gzclose(src);
00692 if (dst != NULL) fclose(dst);
00693 return retval;
00694 }
00695
00696 BOOL gzip_file(const char *srcfile, const char *dstfile)
00697 {
00698 const S32 COMPRESS_BUFFER_SIZE = 32768;
00699 char tmpfile[LL_MAX_PATH];
00700 BOOL retval = FALSE;
00701 U8 buffer[COMPRESS_BUFFER_SIZE];
00702 gzFile dst = NULL;
00703 LLFILE *src = NULL;
00704 S32 bytes = 0;
00705 (void *) strcpy(tmpfile, dstfile);
00706 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1);
00707 dst = gzopen(tmpfile, "wb");
00708 if (! dst) goto err;
00709 src = LLFile::fopen(srcfile, "rb");
00710 if (! src) goto err;
00711
00712 do
00713 {
00714 bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE,src);
00715 gzwrite(dst, buffer, bytes);
00716 } while(feof(src) == 0);
00717 gzclose(dst);
00718 dst = NULL;
00719 #if LL_WINDOWS
00720
00721 LLFile::remove(dstfile);
00722 #endif
00723 if (LLFile::rename(tmpfile, dstfile) == -1) goto err;
00724 retval = TRUE;
00725 err:
00726 if (src != NULL) fclose(src);
00727 if (dst != NULL) gzclose(dst);
00728 return retval;
00729 }