http_cache_cleaner.cpp
00001 /* 00002 This file is part of KDE 00003 00004 Copyright (C) 1999-2000 Waldo Bastian (bastian@kde.org) 00005 00006 Permission is hereby granted, free of charge, to any person obtaining a copy 00007 of this software and associated documentation files (the "Software"), to deal 00008 in the Software without restriction, including without limitation the rights 00009 to use, copy, modify, merge, publish, distribute, and/or sell 00010 copies of the Software, and to permit persons to whom the Software is 00011 furnished to do so, subject to the following conditions: 00012 00013 The above copyright notice and this permission notice shall be included in 00014 all copies or substantial portions of the Software. 00015 00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00019 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00022 */ 00023 //---------------------------------------------------------------------------- 00024 // 00025 // KDE Http Cache cleanup tool 00026 // $Id$ 00027 00028 #include <time.h> 00029 #include <stdlib.h> 00030 00031 #include <tqdir.h> 00032 #include <tqstring.h> 00033 #include <tqptrlist.h> 00034 00035 #include <kinstance.h> 00036 #include <klocale.h> 00037 #include <kcmdlineargs.h> 00038 #include <kglobal.h> 00039 #include <kstandarddirs.h> 00040 #include <dcopclient.h> 00041 #include <kprotocolmanager.h> 00042 00043 #include <unistd.h> 00044 00045 #include <kdebug.h> 00046 00047 time_t currentDate; 00048 int m_maxCacheAge; 00049 int m_maxCacheSize; 00050 00051 static const char appName[] = "kio_http_cache_cleaner"; 00052 00053 static const char description[] = I18N_NOOP("KDE HTTP cache maintenance tool"); 00054 00055 static const char version[] = "1.0.0"; 00056 00057 static const KCmdLineOptions options[] = 00058 { 00059 {"clear-all", I18N_NOOP("Empty the cache"), 0}, 00060 KCmdLineLastOption 00061 }; 00062 00063 struct FileInfo { 00064 TQString name; 00065 int size; // Size in Kb. 00066 int age; 00067 }; 00068 00069 template class TQPtrList<FileInfo>; 00070 00071 class FileInfoList : public TQPtrList<FileInfo> 00072 { 00073 public: 00074 FileInfoList() : TQPtrList<FileInfo>() { } 00075 int compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2) 00076 { return ((FileInfo *)item1)->age - ((FileInfo *)item2)->age; } 00077 }; 00078 00079 // !START OF SYNC! 00080 // Keep the following in sync with the cache code in http.cc 00081 #define CACHE_REVISION "7\n" 00082 00083 FileInfo *readEntry( const TQString &filename) 00084 { 00085 TQCString CEF = TQFile::encodeName(filename); 00086 FILE *fs = fopen( CEF.data(), "r"); 00087 if (!fs) 00088 return 0; 00089 00090 char buffer[401]; 00091 bool ok = true; 00092 00093 // CacheRevision 00094 if (ok && (!fgets(buffer, 400, fs))) 00095 ok = false; 00096 if (ok && (strcmp(buffer, CACHE_REVISION) != 0)) 00097 ok = false; 00098 00099 // Full URL 00100 if (ok && (!fgets(buffer, 400, fs))) 00101 ok = false; 00102 00103 time_t creationDate; 00104 int age =0; 00105 00106 // Creation Date 00107 if (ok && (!fgets(buffer, 400, fs))) 00108 ok = false; 00109 if (ok) 00110 { 00111 creationDate = (time_t) strtoul(buffer, 0, 10); 00112 age = (int) difftime(currentDate, creationDate); 00113 if ( m_maxCacheAge && ( age > m_maxCacheAge)) 00114 { 00115 ok = false; // Expired 00116 } 00117 } 00118 00119 // Expiration Date 00120 if (ok && (!fgets(buffer, 400, fs))) 00121 ok = false; 00122 if (ok) 00123 { 00124 //WABA: It seems I slightly misunderstood the meaning of "Expire:" header. 00125 #if 0 00126 time_t expireDate; 00127 expireDate = (time_t) strtoul(buffer, 0, 10); 00128 if (expireDate && (expireDate < currentDate)) 00129 ok = false; // Expired 00130 #endif 00131 } 00132 00133 // ETag 00134 if (ok && (!fgets(buffer, 400, fs))) 00135 ok = false; 00136 if (ok) 00137 { 00138 // Ignore ETag 00139 } 00140 00141 // Last-Modified 00142 if (ok && (!fgets(buffer, 400, fs))) 00143 ok = false; 00144 if (ok) 00145 { 00146 // Ignore Last-Modified 00147 } 00148 00149 00150 fclose(fs); 00151 if (ok) 00152 { 00153 FileInfo *info = new FileInfo; 00154 info->age = age; 00155 return info; 00156 } 00157 00158 unlink( CEF.data()); 00159 return 0; 00160 } 00161 // Keep the above in sync with the cache code in http.cc 00162 // !END OF SYNC! 00163 00164 void scanDirectory(FileInfoList &fileEntries, const TQString &name, const TQString &strDir) 00165 { 00166 TQDir dir(strDir); 00167 if (!dir.exists()) return; 00168 00169 TQFileInfoList *newEntries = (TQFileInfoList *) dir.entryInfoList(); 00170 00171 if (!newEntries) return; // Directory not accessible ?? 00172 00173 for(TQFileInfo *qFileInfo = newEntries->first(); 00174 qFileInfo; 00175 qFileInfo = newEntries->next()) 00176 { 00177 if (qFileInfo->isFile()) 00178 { 00179 FileInfo *fileInfo = readEntry( strDir + "/" + qFileInfo->fileName()); 00180 if (fileInfo) 00181 { 00182 fileInfo->name = name + "/" + qFileInfo->fileName(); 00183 fileInfo->size = (qFileInfo->size() + 1023) / 1024; 00184 fileEntries.append(fileInfo); 00185 } 00186 } 00187 } 00188 } 00189 00190 extern "C" KDE_EXPORT int kdemain(int argc, char **argv) 00191 { 00192 KLocale::setMainCatalogue("kdelibs"); 00193 KCmdLineArgs::init( argc, argv, appName, 00194 I18N_NOOP("KDE HTTP cache maintenance tool"), 00195 description, version, true); 00196 00197 KCmdLineArgs::addCmdLineOptions( options ); 00198 00199 KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); 00200 00201 bool deleteAll = args->isSet("clear-all"); 00202 00203 KInstance ins( appName ); 00204 00205 if (!deleteAll) 00206 { 00207 DCOPClient *dcop = new DCOPClient(); 00208 TQCString name = dcop->registerAs(appName, false); 00209 if (!name.isEmpty() && (name != appName)) 00210 { 00211 fprintf(stderr, "%s: Already running! (%s)\n", appName, name.data()); 00212 return 0; 00213 } 00214 } 00215 00216 currentDate = time(0); 00217 m_maxCacheAge = KProtocolManager::maxCacheAge(); 00218 m_maxCacheSize = KProtocolManager::maxCacheSize(); 00219 00220 if (deleteAll) 00221 m_maxCacheSize = -1; 00222 00223 TQString strCacheDir = KGlobal::dirs()->saveLocation("cache", "http"); 00224 00225 TQDir cacheDir( strCacheDir ); 00226 if (!cacheDir.exists()) 00227 { 00228 fprintf(stderr, "%s: '%s' does not exist.\n", appName, strCacheDir.ascii()); 00229 return 0; 00230 } 00231 00232 TQStringList dirs = cacheDir.entryList( ); 00233 00234 FileInfoList cachedEntries; 00235 00236 for(TQStringList::Iterator it = dirs.begin(); 00237 it != dirs.end(); 00238 it++) 00239 { 00240 if ((*it)[0] != '.') 00241 { 00242 scanDirectory( cachedEntries, *it, strCacheDir + "/" + *it); 00243 } 00244 } 00245 00246 cachedEntries.sort(); 00247 00248 int maxCachedSize = m_maxCacheSize / 2; 00249 00250 for(FileInfo *fileInfo = cachedEntries.first(); 00251 fileInfo; 00252 fileInfo = cachedEntries.next()) 00253 { 00254 if (fileInfo->size > maxCachedSize) 00255 { 00256 TQCString filename = TQFile::encodeName( strCacheDir + "/" + fileInfo->name); 00257 unlink(filename.data()); 00258 // kdDebug () << appName << ": Object too big, deleting '" << filename.data() << "' (" << result<< ")" << endl; 00259 } 00260 } 00261 00262 int totalSize = 0; 00263 00264 for(FileInfo *fileInfo = cachedEntries.first(); 00265 fileInfo; 00266 fileInfo = cachedEntries.next()) 00267 { 00268 if ((totalSize + fileInfo->size) > m_maxCacheSize) 00269 { 00270 TQCString filename = TQFile::encodeName( strCacheDir + "/" + fileInfo->name); 00271 unlink(filename.data()); 00272 // kdDebug () << appName << ": Cache too big, deleting '" << filename.data() << "' (" << fileInfo->size << ")" << endl; 00273 } 00274 else 00275 { 00276 totalSize += fileInfo->size; 00277 // fprintf(stderr, "Keep in cache: %s %d %d total = %d\n", fileInfo->name.ascii(), fileInfo->size, fileInfo->age, totalSize); 00278 } 00279 } 00280 kdDebug () << appName << ": Current size of cache = " << totalSize << " kB." << endl; 00281 return 0; 00282 } 00283 00284