Compare commits

..

107 Commits

Author SHA1 Message Date
hoa.nguyen%intel.com
22c40d96b2 removed the report of db filesize in GetStorageInUse.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55763 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-08 21:54:27 +00:00
hoa.nguyen%intel.com
06a79b2069 fixed a bug in SetStoredContentLength so that it will update m_StorageInUse in nsNetDiskCache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55762 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-08 21:53:57 +00:00
hoa.nguyen%intel.com
ebc4face0d Added SetDiskCacheFolder for filecache test.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55608 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:08:45 +00:00
hoa.nguyen%intel.com
150696bb86 Fixed DB corruption detection and error recovery logic. Removed Preference. Added routine for the special entry in DB.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55606 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:07:56 +00:00
hoa.nguyen%intel.com
683045595b Added a few member according to the new nsIChannel i/f. Converted all the function to use raw file transport instead of nsIOService.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55605 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:07:21 +00:00
hoa.nguyen%intel.com
7f09538b93 Fixed a memory leak on mInfo. Init() now also pass through recordID.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55601 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:06:29 +00:00
hoa.nguyen%intel.com
bb364ef512 member name changed to follow the same convention. Added error recovery routine.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55600 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:05:57 +00:00
hoa.nguyen%intel.com
7c96c92a19 sync now happens once every second. DB filesize is only updated upon sync. A special entry is added to record initial size and entry number of filecache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55597 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:04:56 +00:00
fur%netscape.com
a6defdef4c Merge portability changes and bug fixes from the trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55586 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 17:40:40 +00:00
fur%netscape.com
76159a2caf Updated to NPL 1.1
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55504 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 01:40:45 +00:00
fur%netscape.com
1988cb05b5 Tweak comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55499 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 01:14:55 +00:00
fur%netscape.com
dd8c6b3bed Added nsINetDataCacheManager::SetDiskCacheFolder()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55484 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 00:02:58 +00:00
fur%netscape.com
bc64749366 Account for arg changes in NewChannel() API
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55475 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:30:30 +00:00
fur%netscape.com
2e9287bd58 Match NewChannel() API changes on trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55472 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:23:07 +00:00
fur%netscape.com
0f2274a140 Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55471 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:22:37 +00:00
fur%netscape.com
957fa10cac Retire nsINetDataCache::GetCapacity
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55469 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:16:10 +00:00
fur%netscape.com
e603146886 Track trunk API changes
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55467 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:15:32 +00:00
fur%netscape.com
cb698a0df1 + Retired nsINetDataCache::GetCapacity()
+ Fixed gcc build problem


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55466 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:14:38 +00:00
fur%netscape.com
1b918d9ef0 + Added proxy channel arg to NewChannel()
+ Changed name of setProtocolPrivate/getProtocolPrivate to setAnnotation/getAnnotation\
+ Added inUse attribute
+ Touched up comments


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55465 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:08:08 +00:00
fur%netscape.com
6407144c9f Removed capacity attribute
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55464 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:06:44 +00:00
fur%netscape.com
2ed563a178 Merge with trunk makefile.win
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55462 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:05:39 +00:00
fur%netscape.com
4becc0b508 Add assertion to cache manager to ensure that it is limiting cache occupancy
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54566 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 15:23:34 +00:00
fur%netscape.com
7d5427ea31 Obey the MAX_CONTENT_LENGTH limit
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54565 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 15:22:56 +00:00
fur%netscape.com
99904bcc48 Eliminate libs build target, as Warren has done for the rest of the tree
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54545 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 02:15:04 +00:00
fur%netscape.com
bcb56c9593 Add strong ref to channel
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54544 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 02:14:17 +00:00
fur%netscape.com
f18bc8e6cd Fix ownership issues. Change SetProtocolData/GetProtocolData args
to match new prototype.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54109 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 07:51:56 +00:00
fur%netscape.com
7d14c5669a Handle NULL load group - they're supposed to be optional
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54108 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 07:51:14 +00:00
fur%netscape.com
c0dd3df02e Fix tons of ref-counting ownership issues and other bug fixes
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54107 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 07:50:25 +00:00
fur%netscape.com
e5cc84978f Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54097 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:08:20 +00:00
fur%netscape.com
5694537330 Changed SetProtocolData/GetProtocolData to accept a tag argument so that
multiple cache clients can attach info to the cache database.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54096 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:07:40 +00:00
fur%netscape.com
297c5ceba3 Add/modify APIs to track nsIChannel
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54095 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:05:01 +00:00
fur%netscape.com
e0311312f7 Temporarily disable pref-reading code, since it doesn't work in the browser
and the code that measures the size of the cache db, since it's a performance
hog.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54094 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:04:13 +00:00
fur%netscape.com
cf3dc77b02 Fix unitialized variable
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54093 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:01:03 +00:00
fur%netscape.com
dd2506a737 Quash warnings
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53842 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-18 06:19:51 +00:00
fur%netscape.com
b1bee1f21c Merge with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53831 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-18 05:38:26 +00:00
fur%netscape.com
48ecc5625b Added review comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53674 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 19:46:28 +00:00
fur%netscape.com
1b791685e6 No longer need factory code. Its been moved to netwerk/cache/builds/nsNetDataCacheModule.cpp
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53663 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 18:21:11 +00:00
fur%netscape.com
dc94d1d6e2 Added review comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53647 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 10:08:26 +00:00
hoa.nguyen%intel.com
f5b437ade3 added Unix support
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53574 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:21:05 +00:00
hoa.nguyen%intel.com
8c0b4b3e4a changed NPL to MPL
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53573 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:16:33 +00:00
hoa.nguyen%intel.com
fb640ab144 added Truncate function
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53572 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:07:27 +00:00
hoa.nguyen%intel.com
106e263b33 added support for memory cache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53570 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:00:54 +00:00
fur%netscape.com
85045a8552 Add TestCacheMgr
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53537 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:13:19 +00:00
fur%netscape.com
a2279be132 *** empty log message ***
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53536 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:12:58 +00:00
fur%netscape.com
0ce702d402 Don't call NS_ERROR() when a record ID is not found
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53533 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:12:17 +00:00
fur%netscape.com
f14d03cd67 Fixed CommitFlags()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53531 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:11:14 +00:00
fur%netscape.com
b91343fdf6 Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53520 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 18:30:44 +00:00
fur%netscape.com
2c517489b5 Disable warning, so cache code can run
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53519 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 17:39:35 +00:00
(no author)
ae57da58eb This commit was manufactured by cvs2svn to create branch
'CacheIntegration_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53517 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 17:10:07 +00:00
fur%netscape.com
8d4586dd65 Update components table and macro instantiations to conform to new definitions
in nsIGenericFactory.h


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53499 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 09:06:41 +00:00
fur%netscape.com
9b473ad9be Added starting offset param to interceptAsyncRead() method
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53498 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 08:53:15 +00:00
fur%netscape.com
2ad227a994 Merged with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53496 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 08:01:58 +00:00
fur%netscape.com
94d8da33c1 Replace 1.0 NPL with 1.1 version
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53487 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 06:13:13 +00:00
fur%netscape.com
81c05809fd Remove dead files
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53486 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 06:08:40 +00:00
fur%netscape.com
e30547b2b2 Remove dead files
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53485 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 05:52:29 +00:00
fur%netscape.com
257f9cfaaa Fix Boogs. Replace 1.0 NPL with 1.1 version
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53484 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 05:51:02 +00:00
fur%netscape.com
96e2654e43 Replace 1.0 NPL with 1.1 NPL
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53474 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 20:35:26 +00:00
fur%netscape.com
3b023433be Replace 1.0 NPL with 1.1 version
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53472 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 19:56:44 +00:00
fur%netscape.com
1b89716afe Added more comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53471 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 19:50:30 +00:00
fur%netscape.com
ad02058877 Add comments. Change method names
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53470 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 18:51:57 +00:00
fur%netscape.com
fa8a3196e7 Merge with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53434 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 19:35:49 +00:00
fur%netscape.com
5c2c543e58 Fixed bugs which prevented embedded NUL characters
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53431 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 18:45:28 +00:00
fur%netscape.com
c588721cc0 Added NS_NewStorageStream().
Changed method name, Initialize ==> Init


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53430 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 18:43:20 +00:00
fur%netscape.com
0b049b17ba Fix Boogs
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53429 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 18:41:01 +00:00
fur%netscape.com
854ef4631d Merge from trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53268 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-11 22:29:20 +00:00
fur%netscape.com
051c558653 Detect failure to truncate cache entry
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53214 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-11 18:16:24 +00:00
fur%netscape.com
37a04adb09 Killed build warnings. Added stubs for unimplemented methods
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53072 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-10 06:05:33 +00:00
fur%netscape.com
c823c04b45 Combine cache components into module
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53014 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-09 22:08:49 +00:00
fur%netscape.com
03cbd000eb Sync with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52998 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-09 17:36:48 +00:00
fur%netscape.com
a91e91a1c7 Added Windows makefiles so that the cache manager, file cache and
memory cache components are built as part of netlib and combined into
a single XPCOM module, named "nkcache.dll"


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52970 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:44:04 +00:00
fur%netscape.com
be7a5a48b6 Added call to LimitCacheSize
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52968 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:40:41 +00:00
fur%netscape.com
b2bc7468e8 Add cache manager CID
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52967 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:38:20 +00:00
fur%netscape.com
9692dfd994 Add cache manager ProgID
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52966 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:37:30 +00:00
fur%netscape.com
f3edd4cfb5 Added an owning reference from nsDiskCacheRecordChannel to
its associated nsDiskCacheRecord.  Without this, the channel
may access free'ed memory.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52962 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:28:39 +00:00
fur%netscape.com
33403345c1 Rename class to avoid name collision with similar code in file cache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52961 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:25:28 +00:00
fur%netscape.com
20c850de23 Merge with tip
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52960 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:23:35 +00:00
fur%netscape.com
e8b619cd02 Merge with tip
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52959 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:18:25 +00:00
fur%netscape.com
eed396bb92 Stabilize ref-count during construction
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52946 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 18:46:17 +00:00
fur%netscape.com
41d44c070b Eliminate dead files
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52932 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-07 20:19:55 +00:00
fur%netscape.com
698ba42268 Revamped directory structure
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52922 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-06 19:36:16 +00:00
(no author)
1a0fd23991 This commit was manufactured by cvs2svn to create branch
'CacheIntegration_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52912 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-06 03:43:56 +00:00
fur%netscape.com
67dded330b Add nsDiskCacheRecordChannel.cpp
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52876 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:18:26 +00:00
fur%netscape.com
936ff4777a Fix compilation errors on Win32
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52874 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:18:04 +00:00
fur%netscape.com
96c55e42f7 Accommodate API changes in nsINetDataCache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52873 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:17:42 +00:00
fur%netscape.com
82fa0cf06a Got rid of GetReadOnly(). Added GetFlags()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52872 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:15:05 +00:00
fur%netscape.com
98c8285334 First shot at Win32 makefile
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52869 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:03:02 +00:00
fur%netscape.com
bad4b683f4 Removed SetCapacity() method
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52868 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:01:26 +00:00
fur%netscape.com
cb5269a28a Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52864 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 21:47:25 +00:00
fur%netscape.com
74712f3635 Added binary I/O streams
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52860 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 20:02:06 +00:00
fur%netscape.com
9f8ea739db Correct error comment
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52859 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 20:01:39 +00:00
hoa.nguyen%intel.com
97a10dd7c6 Add offset writing for nsOutputStream
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52789 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-04 18:02:39 +00:00
hoa.nguyen%intel.com
85a132fac0 Add command line switch to test memory and disk cache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52788 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-04 18:01:28 +00:00
hoa.nguyen%intel.com
e594eee877 Add proxy channel interface, and misc bug fixes.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52787 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-04 17:59:42 +00:00
hoa.nguyen%intel.com
9148eee3d6 Initial checkin of disk cache modules
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51580 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-22 22:37:18 +00:00
hoa.nguyen%intel.com
b5989a8382 Initial checkin of disk cache module
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51579 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-22 22:36:07 +00:00
fur%netscape.com
2b861f60d9 Create a new channel for every call to Write()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51335 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-21 01:35:51 +00:00
fur%netscape.com
87db050b37 Added tests for:
nsINetDataCache::GetStorageInUse()
    nsINetDataCacheRecord::SetContentLength()
    nsIOutputStream::Write(), using non-zero starting offsets


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51071 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-18 23:55:44 +00:00
fur%netscape.com
ffe483cf95 Initial cut at memory-cache functionality is complete
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51067 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-18 23:46:08 +00:00
fur%netscape.com
52aa17a1c3 Incorporate nsStorageStream into xpcom.dll
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50814 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:40:42 +00:00
fur%netscape.com
5fdb3aa69e Initial implementation of 'storage stream' - used as the heart of the memory cache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50812 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:39:45 +00:00
fur%netscape.com
8cae473bc0 Add opaque keys to nsHashtable
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50811 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:38:01 +00:00
fur%netscape.com
0719303755 Fix linkage problem
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50810 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:37:21 +00:00
fur%netscape.com
90d3e40858 Fix bugs in Next(). Prev() and IsDone()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50809 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:36:35 +00:00
fur%netscape.com
c792b2d35c Changed IDL to generate identical C++ headers, but with better scriptability
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50808 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:32:04 +00:00
fur%netscape.com
7a4377d840 Initial cut at memory cache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50806 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:24:06 +00:00
fur%netscape.com
a5fa416010 Added TestRawCache.cpp
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50804 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:19:52 +00:00
(no author)
49d00db5e2 This commit was manufactured by cvs2svn to create branch
'CacheIntegration_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50589 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-13 10:24:13 +00:00
105 changed files with 24580 additions and 11656 deletions

File diff suppressed because it is too large Load Diff

38
mozilla/netwerk/cache/Makefile.in vendored Normal file
View File

@@ -0,0 +1,38 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = \
public \
memcache \
filecache \
mgr \
build \
$(NULL)
include $(topsrcdir)/config/rules.mk

33
mozilla/netwerk/cache/Makefile.win vendored Executable file
View File

@@ -0,0 +1,33 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH=..\..
DIRS= \
public \
mgr \
memcache \
filecache \
build \
$(NULL)
include <$(DEPTH)\config\rules.mak>

54
mozilla/netwerk/cache/build/Makefile.in vendored Normal file
View File

@@ -0,0 +1,54 @@
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = nkcacke
LIBRARY_NAME = necko_cache
IS_COMPONENT = 1
CPPSRCS = nsNetDataCacheModule.cpp
SHARED_LIBRARY_LIBS = \
$(DIST)/lib/libnkcachemgr_s.a \
$(DIST)/lib/libnkfilecache_s.a \
$(DIST)/lib/libnkmemcache_s.a \
$(DIST)/lib/libmozdbm_s.a \
$(DIST)/lib/libxpcomio_s.a \
$(NULL)
LOCAL_INCLUDES = \
-I$(DEPTH)/netwerk/cache/memcache \
-I$(DEPTH)/netwerk/cache/filecache \
-I$(DEPTH)/netwerk/cache/mgr \
$(NULL)
EXTRA_DSO_LDOPTS = \
$(MKSHLIB_FORCE_ALL) \
$(SHARED_LIBRARY_LIBS) \
$(MKSHLIB_UNFORCE_ALL) \
$(NULL)
include $(topsrcdir)/config/rules.mk
$(LIBRARY) $(SHARED_LIBRARY): $(SHARED_LIBRARY_LIBS) Makefile

View File

@@ -0,0 +1,51 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
DEPTH=..\..\..
MODULE=nkcache
MAKE_OBJ_TYPE=DLL
DLLNAME=nkcache
DLL=.\$(OBJDIR)\$(DLLNAME).dll
CPP_OBJS= \
.\$(OBJDIR)\nsNetDataCacheModule.obj \
$(NULL)
LLIBS= \
$(DIST)\lib\nkcachemgr_s.lib \
$(DIST)\lib\nkfilecache_s.lib \
$(DIST)\lib\nkmemcache_s.lib \
$(DIST)\lib\dbm32.lib \
$(DIST)\lib\xpcom.lib \
$(LIBNSPR)
INCS = $(INCS) \
-I$(DEPTH)\netwerk\cache\memcache \
-I$(DEPTH)\netwerk\cache\filecache \
-I$(DEPTH)\netwerk\cache\mgr \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib

View File

@@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsCOMPtr.h"
#include "nsIModule.h"
#include "nscore.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIGenericFactory.h"
#include "nsINetDataCache.h"
#include "nsINetDataCacheManager.h"
#include "nsMemCacheCID.h"
#include "nsMemCache.h"
#include "nsNetDiskCache.h"
#include "nsNetDiskCacheCID.h"
#include "nsCacheManager.h"
// Factory method to create a new nsMemCache instance. Used
// by nsNetDataCacheModule
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMemCache, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNetDiskCache, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCacheManager, Init)
static nsModuleComponentInfo components[] = {
{ "Memory Cache", NS_MEM_CACHE_FACTORY_CID, NS_NETWORK_MEMORY_CACHE_PROGID, nsMemCacheConstructor },
{ "File Cache", NS_NETDISKCACHE_CID, NS_NETWORK_FILE_CACHE_PROGID, nsNetDiskCacheConstructor },
{ "Cache Manager",NS_CACHE_MANAGER_CID, NS_NETWORK_CACHE_MANAGER_PROGID,nsCacheManagerConstructor }
};
NS_IMPL_NSGETMODULE("Network Data Cache", components)

View File

@@ -0,0 +1,60 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Mozilla Communicator.
#
# The Initial Developer of the Original Code is Intel Corp.
# Portions created by Intel Corp. are
# Copyright (C) 1999, 1999 Intel Corp. All
# Rights Reserved.
#
# Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
# Carl Wong <carl.wong@intel.com>
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
VPATH = @srcdir@
srcdir = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = nkcache
LIBRARY_NAME = nkfilecache_s
REQUIRES = nspr dbm
EXTRA_DSO_LDOPTS += -L$(DIST)/lib -lmozdbm_s
EXPORTS=nsNetDiskCacheCID.h \
nsNetDiskCache.h \
nsIDBAccessor.h \
nsDBAccessor.h \
$(NULL)
CPPSRCS = \
nsDBAccessor.cpp\
nsDBEnumerator.cpp \
nsNetDiskCache.cpp \
nsDiskCacheRecord.cpp \
nsDiskCacheRecordChannel.cpp \
$(NULL)
EXTRA_LIBS = $(NSPR_LIBS)
# we don't want the shared lib, but we want to force the creation of a
# static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,44 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = nkcache
LIBRARY_NAME = nkfilecache_s
CPP_OBJS= \
.\$(OBJDIR)\nsDBAccessor.obj \
.\$(OBJDIR)\nsDBEnumerator.obj \
.\$(OBJDIR)\nsNetDiskCache.obj \
.\$(OBJDIR)\nsDiskCacheRecord.obj \
.\$(OBJDIR)\nsDiskCacheRecordChannel.obj \
$(NULL)
EXPORTS=nsNetDiskCacheCID.h
include <$(DEPTH)\config\rules.mak>
install:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -rf $(OBJDIR)
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,416 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* nsIDBAccessor is a interface that shields all the direct database access
* method from nsNetDiskCache.
*
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
* uses dbm(Berkely) as the database.
*
* a nsDiskCacheRecord is mapped into two entries in the database,
* key->recordID
* recordID->metadata
*/
#include "nsDBAccessor.h"
#include "nscore.h"
#include "prtypes.h"
#include "plhash.h"
#include "nsCRT.h"
nsDBAccessor::nsDBAccessor() :
mDB(0) ,
mDBFile(0) ,
mSessionID(0) ,
mSessionCntr(0) ,
mDBFilesize(0)
{
mLastSyncTime = PR_IntervalNow() ;
NS_INIT_REFCNT();
}
nsDBAccessor::~nsDBAccessor()
{
Shutdown() ;
}
//
// Implement nsISupports methods
//
NS_IMPL_ISUPPORTS(nsDBAccessor, NS_GET_IID(nsIDBAccessor))
///////////////////////////////////////////////////////////
// nsIDBAccessor methods
NS_IMETHODIMP
nsDBAccessor::Init(nsIFileSpec* dbfile)
{
char* dbname ;
// this should cover all platforms.
dbfile->GetNativePath(&dbname) ;
mDBFile = dbfile ;
// FUR - how is page size chosen ? It's worth putting a comment
// in here about the possible usefulness of tuning these parameters
HASHINFO hash_info = {
16*1024 , /* bucket size */
0 , /* fill factor */
0 , /* number of elements */
0 , /* bytes to cache */
0 , /* hash function */
0} ; /* byte order */
mDB = dbopen(dbname,
O_RDWR | O_CREAT ,
0600 ,
DB_HASH ,
& hash_info) ;
nsCRT::free(dbname) ;
if(!mDB)
return NS_ERROR_FAILURE ;
// set mSessionID
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, SessionKey) ;
db_key.size = PL_strlen(SessionKey) ;
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == -1) {
NS_ERROR("ERROR: failed get session id in database.") ;
return NS_ERROR_FAILURE ;
}
if(status == 0) {
// get the last session id
PRInt16 *old_ID = NS_STATIC_CAST(PRInt16*, db_data.data) ;
if(*old_ID < ini_sessionID) {
NS_ERROR("ERROR: Bad Session ID in database, corrupted db.") ;
return NS_ERROR_FAILURE ;
}
mSessionID = *old_ID + 1 ;
}
else if(status == 1) {
// must be a new db
mSessionID = ini_sessionID ;
}
db_data.data = NS_REINTERPRET_CAST(void*, &mSessionID) ;
db_data.size = sizeof(PRInt16) ;
// store the new session id
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
if(status == 0) {
(*mDB->sync)(mDB, 0) ;
// initialize database filesize
return mDBFile->GetFileSize(&mDBFilesize) ;
}
else {
NS_ERROR("reset session ID failure.") ;
return NS_ERROR_FAILURE ;
}
}
NS_IMETHODIMP
nsDBAccessor::Shutdown(void)
{
if(mDB) {
(*mDB->sync)(mDB, 0) ;
(*mDB->close)(mDB) ;
mDB = nsnull ;
}
return NS_OK ;
}
NS_IMETHODIMP
nsDBAccessor::Get(PRInt32 aID, void** anEntry, PRUint32 *aLength)
{
if(!anEntry)
return NS_ERROR_NULL_POINTER ;
*anEntry = nsnull ;
*aLength = 0 ;
NS_ASSERTION(mDB, "no database") ;
DBT db_key, db_data ;
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
db_key.size = sizeof(PRInt32) ;
int status = 0 ;
status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == 0) {
*anEntry = db_data.data ;
*aLength = db_data.size ;
return NS_OK ;
}
else if(status == 1)
return NS_OK ;
else
return NS_ERROR_FAILURE ;
}
NS_IMETHODIMP
nsDBAccessor::Put(PRInt32 aID, void* anEntry, PRUint32 aLength)
{
NS_ASSERTION(mDB, "no database") ;
DBT db_key, db_data ;
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
db_key.size = sizeof(PRInt32) ;
db_data.data = anEntry ;
db_data.size = aLength ;
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
return Sync() ;
}
else {
return NS_ERROR_FAILURE ;
}
}
/*
* It's more important to remove the id->metadata entry first since
* key->id mapping is just a reference
*/
NS_IMETHODIMP
nsDBAccessor::Del(PRInt32 aID, void* anEntry, PRUint32 aLength)
{
NS_ASSERTION(mDB, "no database") ;
DBT db_key ;
// delete recordID->metadata
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
db_key.size = sizeof(PRInt32) ;
PRInt32 status = -1 ;
status = (*mDB->del)(mDB, &db_key, 0) ;
if(-1 == status) {
return NS_ERROR_FAILURE ;
}
// delete key->recordID
db_key.data = anEntry ;
db_key.size = aLength ;
status = (*mDB->del)(mDB, &db_key, 0) ;
if(-1 == status) {
return NS_ERROR_FAILURE ;
}
return Sync() ;
}
NS_IMETHODIMP
nsDBAccessor::GetID(const char* key, PRUint32 length, PRInt32* aID)
{
NS_ASSERTION(mDB, "no database") ;
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, key) ;
db_key.size = length ;
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == 0) {
// found recordID
*aID = *(NS_REINTERPRET_CAST(PRInt32*, db_data.data)) ;
return NS_OK ;
}
else if(status == 1) {
// create a new one
PRInt32 id = 0 ;
id = mSessionID << 16 | mSessionCntr++ ;
// add new id into mDB
db_data.data = NS_REINTERPRET_CAST(void*, &id) ;
db_data.size = sizeof(PRInt32) ;
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
if(status != 0) {
NS_ERROR("updating db failure.") ;
return NS_ERROR_FAILURE ;
}
*aID = id ;
return Sync() ;
}
else {
NS_ERROR("ERROR: keydb failure.") ;
return NS_ERROR_FAILURE ;
}
}
NS_IMETHODIMP
nsDBAccessor::EnumEntry(void** anEntry, PRUint32* aLength, PRBool bReset)
{
if(!anEntry)
return NS_ERROR_NULL_POINTER ;
*anEntry = nsnull ;
*aLength = 0 ;
NS_ASSERTION(mDB, "no database") ;
PRUint32 flag ;
if(bReset)
flag = R_FIRST ;
else
flag = R_NEXT ;
DBT db_key, db_data ;
PRUint32 len = PL_strlen(SessionKey) ;
int status ;
do {
status = (*mDB->seq)(mDB, &db_key, &db_data, flag) ;
flag = R_NEXT ;
if(status == -1)
return NS_ERROR_FAILURE ;
// get next if it's a key->recordID
if(db_key.size > sizeof(PRInt32) && db_data.size == sizeof(PRInt32))
continue ;
// get next if it's a sessionID entry
if(db_key.size == len && db_data.size == sizeof(PRInt16))
continue ;
// recordID is always 32 bits long
if(db_key.size == sizeof(PRInt32))
break ;
} while(!status) ;
if (0 == status) {
*anEntry = db_data.data ;
*aLength = db_data.size ;
}
return NS_OK ;
}
/*
* returns the cached database file size.
* mDBFilesize will be updated during Sync().
*/
NS_IMETHODIMP
nsDBAccessor::GetDBFilesize(PRUint32* aSize)
{
*aSize = mDBFilesize ;
return NS_OK ;
}
NS_IMETHODIMP
nsDBAccessor::GetSpecialEntry(void** anEntry, PRUint32* aLength)
{
if(!anEntry)
return NS_ERROR_NULL_POINTER ;
*anEntry = nsnull ;
*aLength = 0 ;
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
db_key.size = PL_strlen(SpecialEntry) ;
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == -1) {
NS_ERROR("ERROR: failed get special entry in database.") ;
return NS_ERROR_FAILURE ;
}
if(status == 0) {
*anEntry = db_data.data ;
*aLength = db_data.size ;
}
return NS_OK ;
}
NS_IMETHODIMP
nsDBAccessor::SetSpecialEntry(void* anEntry, PRUint32 aLength)
{
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
db_key.size = PL_strlen(SpecialEntry) ;
db_data.data = anEntry ;
db_data.size = aLength ;
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
(*mDB->sync)(mDB, 0) ;
return NS_OK ;
}
else {
return NS_ERROR_FAILURE ;
}
}
/*
* sync routine is only called when the SyncInterval is reached. Otherwise
* it just returns. If db synced, the filesize will be updated at the
* same time.
*/
nsresult
nsDBAccessor::Sync(void)
{
PRIntervalTime time = PR_IntervalNow() ;
PRIntervalTime duration = time - mLastSyncTime ;
if (PR_IntervalToMilliseconds(duration) > SyncInterval) {
int status = (*mDB->sync)(mDB, 0) ;
if(status == 0) {
// printf("\tsynced\n") ;
mLastSyncTime = time ;
// update db filesize here
return mDBFile->GetFileSize(&mDBFilesize) ;
} else
return NS_ERROR_FAILURE ;
} else {
// printf("\tnot synced\n") ;
return NS_OK ;
}
}

View File

@@ -0,0 +1,93 @@
/*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* nsIDBAccessor is a interface that shields all the direct database access
* method from nsNetDiskCache.
*
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
* uses dbm(Berkely) as the database.
*
*/
#ifndef _NSIDBACCESSOR_H_
#define _NSIDBACCESSOR_H_
#include "nsIDBAccessor.h"
#include "mcom_db.h"
#include "prinrval.h"
#include "nsCOMPtr.h"
// bogus string for the key of session id
static const char * const SessionKey = "SK" ;
// bogus string for the size
static const char * const SpecialEntry = "SE" ;
// initial session id number
static const PRInt16 ini_sessionID = 0xff ;
static const PRUint16 SyncInterval = 1000 ;
class nsDBAccessor : public nsIDBAccessor
{
public:
NS_DECL_ISUPPORTS
nsDBAccessor() ;
virtual ~nsDBAccessor() ;
NS_IMETHOD Init(nsIFileSpec* dbfile) ;
NS_IMETHOD Shutdown(void) ;
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) ;
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) ;
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) ;
NS_IMETHOD GetDBFilesize(PRUint32* aSize) ;
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) ;
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) ;
protected:
nsresult Sync(void) ;
private:
DB * mDB ;
nsCOMPtr<nsIFileSpec> mDBFile ;
PRInt16 mSessionID ;
PRInt16 mSessionCntr ;
PRIntervalTime mLastSyncTime ;
PRUint32 mDBFilesize ; // cached DB filesize,
// updated on every sync for now
} ;
#endif // _NSIDBACCESSOR_H_

View File

@@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* It implements a simple iterator for the database, see nsDBAccessor.
*/
#include "nsDBEnumerator.h"
#include "nsDiskCacheRecord.h"
nsDBEnumerator::nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) :
m_DB(aDB) ,
m_DiskCache(aCache) ,
m_tempEntry(0) ,
m_tempEntry_length(0) ,
m_CacheEntry(0) ,
m_bReset(PR_TRUE)
{
NS_INIT_REFCNT();
}
nsDBEnumerator::~nsDBEnumerator()
{
NS_IF_RELEASE(m_CacheEntry) ;
}
//
// Implement nsISupports methods
//
NS_IMPL_ISUPPORTS(nsDBEnumerator, NS_GET_IID(nsIEnumerator))
/////////////////////////////////////////////////////////////////
// nsISimpleEnumerator methods
NS_IMETHODIMP
nsDBEnumerator::HasMoreElements(PRBool *_retval)
{
*_retval = PR_FALSE ;
nsresult rv = m_DB->EnumEntry(&m_tempEntry, &m_tempEntry_length, m_bReset) ;
if(NS_FAILED(rv)) {
// do some error recovery
m_DiskCache->DBRecovery() ;
return rv ;
}
m_bReset = PR_FALSE ;
if(m_tempEntry && m_tempEntry_length != 0)
*_retval = PR_TRUE ;
return NS_OK ;
}
// this routine does not create a new item by itself
// Rather it reuses the item inside the object. So if you need to use the
// item later, you have to
// create a new item specifically, using copy constructor or some other dup
// function. And don't forget to release it after you're done
//
NS_IMETHODIMP
nsDBEnumerator::GetNext(nsISupports **_retval)
{
if(!m_CacheEntry) {
m_CacheEntry = new nsDiskCacheRecord(m_DB, m_DiskCache) ;
if(m_CacheEntry)
NS_ADDREF(m_CacheEntry) ;
else
return NS_ERROR_OUT_OF_MEMORY ;
}
if(!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
nsresult rv = m_CacheEntry->RetrieveInfo(m_tempEntry, m_tempEntry_length) ;
if(NS_FAILED(rv))
return rv ;
*_retval = NS_STATIC_CAST(nsISupports*, m_CacheEntry) ;
NS_ADDREF(*_retval) ; // all good getter addref
return NS_OK ;
}

View File

@@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* It implements a simple iterator for the database, see nsDBAccessor.
*/
#ifndef _NS_DBENUMERATOR_H_
#define _NS_DBENUMERATOR_H_
#include "nsISimpleEnumerator.h"
#include "nsINetDataCacheRecord.h"
#include "nsIDBAccessor.h"
#include "nsCOMPtr.h"
#include "nsNetDiskCache.h"
#include "nsDiskCacheRecord.h"
class nsCachedDiskData ; /* forward decl */
class nsDBEnumerator : public nsISimpleEnumerator {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISIMPLEENUMERATOR
nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) ;
virtual ~nsDBEnumerator() ;
private:
nsCOMPtr<nsIDBAccessor> m_DB ;
nsCOMPtr<nsNetDiskCache> m_DiskCache ;
void * m_tempEntry ;
PRUint32 m_tempEntry_length ;
nsDiskCacheRecord* m_CacheEntry ;
PRBool m_bReset ;
};
#endif // _NS_DBENUMERATOR_H_

View File

@@ -0,0 +1,456 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#include "nsDiskCacheRecord.h"
#include "nsINetDataDiskCache.h"
#include "nsNetDiskCacheCID.h"
#include "nsDiskCacheRecordChannel.h"
#include "nsFileStream.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIProtocolHandler.h"
#include "nsIIOService.h"
#include "nsIAllocator.h"
#include "plstr.h"
#include "prprf.h"
#include "prmem.h"
#include "prlog.h"
#include "prtypes.h"
#include "netCore.h"
#include "nsDBAccessor.h"
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
ERROR! Must have a byte order
#endif
#ifdef IS_LITTLE_ENDIAN
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
#else
#define COPY_INT32(_a,_b) /* swap */ \
do { \
((char *)(_a))[0] = ((char *)(_b))[3]; \
((char *)(_a))[1] = ((char *)(_b))[2]; \
((char *)(_a))[2] = ((char *)(_b))[1]; \
((char *)(_a))[3] = ((char *)(_b))[0]; \
} while(0)
#endif
nsDiskCacheRecord::nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) :
mKey(0) ,
mKeyLength(0) ,
mRecordID(0) ,
mMetaData(0) ,
mMetaDataLength(0) ,
mDB(db) ,
mInfo(0) ,
mInfoSize(0) ,
mNumChannels(0) ,
mDiskCache(aCache)
{
NS_INIT_REFCNT();
NS_ASSERTION(mDiskCache, "Must have an nsNetDiskCache");
NS_ADDREF(mDiskCache);
}
// mem alloced. so caller should do free() on key.
NS_IMETHODIMP
nsDiskCacheRecord::Init(const char* key, PRUint32 length, PRInt32 ID)
{
NS_NewFileSpec(getter_AddRefs(mFile));
if(!mFile)
return NS_ERROR_OUT_OF_MEMORY ;
// copy key
mKeyLength = length ;
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
if(!mKey)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(mKey, key, length) ;
// get RecordID
mRecordID = ID ;
// setup the file name
nsCOMPtr<nsIFileSpec> dbFolder ;
mDiskCache->GetDiskCacheFolder(getter_AddRefs(dbFolder)) ;
nsresult rv = mFile->FromFileSpec(dbFolder) ;
if(NS_FAILED(rv))
return NS_ERROR_FAILURE ;
// dir is a hash result of mRecordID%32, hope it's enough
char filename[9], dirName[3] ;
PR_snprintf(dirName, 3, "%02x", (((PRUint32)mRecordID) % 32)) ;
mFile->AppendRelativeUnixPath(dirName) ;
PR_snprintf(filename, 9, "%08x", mRecordID) ;
mFile->AppendRelativeUnixPath(filename) ;
return NS_OK ;
}
nsDiskCacheRecord::~nsDiskCacheRecord()
{
if(mKey)
nsAllocator::Free(mKey) ;
if(mMetaData)
nsAllocator::Free(mMetaData) ;
if(mInfo)
nsAllocator::Free(mInfo) ;
NS_IF_RELEASE(mDiskCache);
}
//
// Implement nsISupports methods
//
NS_IMPL_ISUPPORTS(nsDiskCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
///////////////////////////////////////////////////////////////////////
// nsINetDataCacheRecord methods
// yes, mem alloced on *_retval.
NS_IMETHODIMP
nsDiskCacheRecord::GetKey(PRUint32 *length, char** _retval)
{
if(!_retval)
return NS_ERROR_NULL_POINTER ;
*length = mKeyLength ;
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
if(!*_retval)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(*_retval, mKey, mKeyLength) ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::GetRecordID(PRInt32* aRecordID)
{
*aRecordID = mRecordID ;
return NS_OK ;
}
// yes, mem alloced on *_retval.
NS_IMETHODIMP
nsDiskCacheRecord::GetMetaData(PRUint32 *length, char **_retval)
{
if(!_retval)
return NS_ERROR_NULL_POINTER ;
// always null the return value first.
*_retval = nsnull ;
*length = mMetaDataLength ;
if(mMetaDataLength) {
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
if(!*_retval)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(*_retval, mMetaData, mMetaDataLength) ;
}
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::SetMetaData(PRUint32 length, const char* data)
{
// set the mMetaData
mMetaDataLength = length ;
if(mMetaData)
nsAllocator::Free(mMetaData) ;
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
if(!mMetaData) {
return NS_ERROR_OUT_OF_MEMORY ;
}
memcpy(mMetaData, data, length) ;
// Generate mInfo
nsresult rv = GenInfo() ;
if(NS_FAILED(rv))
return rv ;
// write through into mDB
rv = mDB->Put(mRecordID, mInfo, mInfoSize) ;
return rv ;
}
NS_IMETHODIMP
nsDiskCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
{
return mFile->GetFileSize(aStoredContentLength) ;
}
// untill nsIFileSpec::Truncate() is in, we have to do all this ugly stuff
NS_IMETHODIMP
nsDiskCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
{
PRUint32 len = 0 ;
nsresult rv = mFile->GetFileSize(&len) ;
if(NS_FAILED(rv))
return rv ;
if(len < aStoredContentLength)
{
NS_ERROR("Error: can not set filesize to something bigger than itself.\n") ;
return NS_ERROR_FAILURE ;
}
else {
rv = mFile->Truncate(aStoredContentLength) ;
if(NS_FAILED(rv))
return rv ;
mDiskCache->m_StorageInUse -= (len - aStoredContentLength) ;
return NS_OK ;
}
}
NS_IMETHODIMP
nsDiskCacheRecord::Delete(void)
{
if(mNumChannels)
return NS_ERROR_NOT_AVAILABLE ;
PRUint32 len ;
mFile->GetFileSize(&len) ;
nsFileSpec cache_file ;
nsresult rv = mFile->GetFileSpec(&cache_file) ;
if(NS_FAILED(rv))
return NS_ERROR_FAILURE ;
cache_file.Delete(PR_TRUE) ;
// updata the storage size
mDiskCache->m_StorageInUse -= len ;
rv = mDB->Del(mRecordID, mKey, mKeyLength) ;
if(NS_FAILED(rv))
return NS_ERROR_FAILURE ;
else
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::GetFilename(nsIFileSpec * *aFilename)
{
if(!aFilename)
return NS_ERROR_NULL_POINTER ;
*aFilename = mFile ;
NS_ADDREF(*aFilename) ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::NewChannel(nsILoadGroup *loadGroup, nsIChannel **_retval)
{
nsDiskCacheRecordChannel* channel = new nsDiskCacheRecordChannel(this, loadGroup) ;
if(!channel)
return NS_ERROR_OUT_OF_MEMORY ;
nsresult rv = channel->Init() ;
if(NS_FAILED(rv))
return rv ;
NS_ADDREF(channel) ;
*_retval = NS_STATIC_CAST(nsIChannel*, channel) ;
return NS_OK ;
}
//////////////////////////////////////////////////////////////////////////
// nsDiskCacheRecord methods
// file name is represented by a url string. I hope this would be more
// generic
nsresult
nsDiskCacheRecord::GenInfo()
{
if(mInfo)
nsAllocator::Free(mInfo) ;
char* file_url=nsnull ;
PRUint32 name_len ;
mFile->GetURLString(&file_url) ;
name_len = PL_strlen(file_url)+1 ;
mInfoSize = sizeof(PRUint32) ; // checksum for mInfoSize
mInfoSize += sizeof(PRInt32) ; // RecordID
mInfoSize += sizeof(PRUint32) ; // key length
mInfoSize += mKeyLength ; // key
mInfoSize += sizeof(PRUint32) ; // metadata length
mInfoSize += mMetaDataLength ; // metadata
mInfoSize += sizeof(PRUint32) ; // filename length
mInfoSize += name_len ; // filename
void* newInfo = nsAllocator::Alloc(mInfoSize*sizeof(char)) ;
if(!newInfo) {
return NS_ERROR_OUT_OF_MEMORY ;
}
// copy the checksum mInfoSize
char* cur_ptr = NS_STATIC_CAST(char*, newInfo) ;
COPY_INT32(cur_ptr, &mInfoSize) ;
cur_ptr += sizeof(PRUint32) ;
// copy RecordID
COPY_INT32(cur_ptr, &mRecordID) ;
cur_ptr += sizeof(PRInt32) ;
// copy key length
COPY_INT32(cur_ptr, &mKeyLength) ;
cur_ptr += sizeof(PRUint32) ;
// copy key
memcpy(cur_ptr, mKey, mKeyLength) ;
cur_ptr += mKeyLength ;
// copy metadata length
COPY_INT32(cur_ptr, &mMetaDataLength) ;
cur_ptr += sizeof(PRUint32) ;
// copy metadata
memcpy(cur_ptr, mMetaData, mMetaDataLength) ;
cur_ptr += mMetaDataLength ;
// copy file name length
COPY_INT32(cur_ptr, &name_len) ;
cur_ptr += sizeof(PRUint32) ;
// copy file name
memcpy(cur_ptr, file_url, name_len) ;
cur_ptr += name_len ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, newInfo) + mInfoSize);
mInfo = newInfo ;
return NS_OK ;
}
/*
* This Method suppose to get all the info from the db record
* and set them to accroding members. the original values
* will all be overwritten. only minimal error checking is performed.
*/
NS_IMETHODIMP
nsDiskCacheRecord::RetrieveInfo(void* aInfo, PRUint32 aInfoLength)
{
// reset everything
if(mInfo) {
nsAllocator::Free(mInfo) ;
mInfo = nsnull ;
}
if(mKey) {
nsAllocator::Free(mKey) ;
mKey = nsnull ;
}
if(mMetaData) {
nsAllocator::Free(mMetaData) ;
mMetaData = nsnull ;
}
char * cur_ptr = NS_STATIC_CAST(char*, aInfo) ;
char* file_url ;
PRUint32 name_len ;
// set mInfoSize
COPY_INT32(&mInfoSize, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// check this at least
if(mInfoSize != aInfoLength)
return NS_ERROR_FAILURE ;
// set mRecordID
COPY_INT32(&mRecordID, cur_ptr) ;
cur_ptr += sizeof(PRInt32) ;
// set mKeyLength
COPY_INT32(&mKeyLength, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// set mKey
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
if(!mKey)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(mKey, cur_ptr, mKeyLength) ;
cur_ptr += mKeyLength ;
PRInt32 id ;
mDB->GetID(mKey, mKeyLength, &id) ;
NS_ASSERTION(id==mRecordID, "\t ++++++ bad record, somethings wrong\n") ;
// set mMetaDataLength
COPY_INT32(&mMetaDataLength, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// set mMetaData
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
if(!mMetaData)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(mMetaData, cur_ptr, mMetaDataLength) ;
cur_ptr += mMetaDataLength ;
// get mFile name length
COPY_INT32(&name_len, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// get mFile native name
file_url = NS_STATIC_CAST(char*, nsAllocator::Alloc(name_len*sizeof(char))) ;
if(!file_url)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(file_url, cur_ptr, name_len) ;
cur_ptr += name_len ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, aInfo) + mInfoSize);
// create mFile if Init() isn't called
if(!mFile) {
NS_NewFileSpec(getter_AddRefs(mFile));
if(!mFile)
return NS_ERROR_OUT_OF_MEMORY ;
}
// setup mFile
mFile->SetURLString(file_url) ;
return NS_OK ;
}

View File

@@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _NET_CACHEDDISKDATA_H_
#define _NET_CACHEDDISKDATA_H_
#include "nsINetDataCacheRecord.h"
#include "nsCOMPtr.h"
#include "nsIDBAccessor.h"
#include "prtypes.h"
#include "nsILoadGroup.h"
#include "nsIFileChannel.h"
#include "nsNetDiskCache.h"
class nsDiskCacheRecord : public nsINetDataCacheRecord
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSINETDATACACHERECORD
protected:
nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) ;
virtual ~nsDiskCacheRecord() ;
NS_IMETHOD RetrieveInfo(void* aInfo, PRUint32 aInfoLength) ;
NS_IMETHOD Init(const char* key, PRUint32 length, PRInt32 ID) ;
nsresult GenInfo(void) ;
private:
char* mKey ;
PRUint32 mKeyLength ;
PRInt32 mRecordID ;
char* mMetaData ;
PRUint32 mMetaDataLength ;
nsCOMPtr<nsIFileSpec> mFile ;
nsCOMPtr<nsIDBAccessor> mDB ;
void* mInfo ;
PRUint32 mInfoSize ;
PRUint32 mNumChannels ;
nsNetDiskCache* mDiskCache ;
friend class nsDiskCacheRecordChannel ;
friend class nsDBEnumerator ;
friend class nsNetDiskCache ;
} ;
#endif // _NET_CACHEDDISKDATA_H_

View File

@@ -0,0 +1,552 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* Most of the code are taken from nsFileChannel.
*/
#include "nsDiskCacheRecordChannel.h"
#include "nsIFileTransportService.h"
//#include "nsIIOService.h"
#include "nsIServiceManager.h"
#include "nsIURL.h"
#include "nsIOutputStream.h"
#include "netCore.h"
#include "nsIMIMEService.h"
#include "nsISupportsUtils.h"
//static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID);
// This is copied from nsMemCacheChannel, We should consolidate these two.
class WriteStreamWrapper : public nsIOutputStream
{
public:
WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
nsIOutputStream *aBaseStream) ;
virtual ~WriteStreamWrapper() ;
static nsresult
Create(nsDiskCacheRecordChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) ;
NS_DECL_ISUPPORTS
NS_DECL_NSIBASESTREAM
NS_DECL_NSIOUTPUTSTREAM
private:
nsDiskCacheRecordChannel* mChannel;
nsCOMPtr<nsIOutputStream> mBaseStream;
} ;
// implement nsISupports
NS_IMPL_ISUPPORTS(WriteStreamWrapper, NS_GET_IID(nsIOutputStream))
WriteStreamWrapper::WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
nsIOutputStream *aBaseStream)
: mChannel(aChannel), mBaseStream(aBaseStream)
{
NS_INIT_REFCNT();
NS_ADDREF(mChannel);
}
WriteStreamWrapper::~WriteStreamWrapper()
{
NS_RELEASE(mChannel);
}
nsresult
WriteStreamWrapper::Create(nsDiskCacheRecordChannel*aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* * aWrapper)
{
WriteStreamWrapper *wrapper = new WriteStreamWrapper(aChannel, aBaseStream);
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(wrapper);
*aWrapper = wrapper;
return NS_OK;
}
NS_IMETHODIMP
WriteStreamWrapper::Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten)
{
*aNumWritten = 0;
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
mChannel->NotifyStorageInUse(*aNumWritten);
return rv;
}
NS_IMETHODIMP
WriteStreamWrapper::Flush()
{
return mBaseStream->Flush();
}
NS_IMETHODIMP
WriteStreamWrapper::Close()
{
return mBaseStream->Close();
}
nsDiskCacheRecordChannel::nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord,
nsILoadGroup *aLoadGroup)
: mRecord(aRecord) ,
mLoadGroup(aLoadGroup)
{
NS_INIT_REFCNT() ;
NS_ADDREF(mRecord);
mRecord->mNumChannels++ ;
}
nsDiskCacheRecordChannel::~nsDiskCacheRecordChannel()
{
mRecord->mNumChannels-- ;
NS_RELEASE(mRecord);
}
// I know that I gave conflicting advice on the issue of file
// transport versus file protocol handler, but I thought that the
// last word was that we would use the raw transport, when I wrote:
//
// > I just thought of an argument for the other side of the coin, i.e. the
// > benefit of *not* reusing the file protocol handler: On the Mac, it's
// > expensive to convert from a string URL to an nsFileSpec, because the Mac
// > is brain-dead and scans every directory on the path to the file. It's
// > cheaper to create a nsFileSpec for a cache file by combining a single,
// > static nsFileSpec that corresponds to the cache directory with the
// > relative path to the cache file (using nsFileSpec's operator +). This
// > operation is optimized on the Mac to avoid the scanning operation.
//
// The Mac guys will eat us alive if we do path string to nsFileSpec
// conversions for every cache file we open.
nsresult
nsDiskCacheRecordChannel::Init(void)
{
nsresult rv = mRecord->mFile->GetFileSpec(&mSpec) ;
#ifdef XP_MAC
// Don't assume we actually created a good file spec
FSSpec theSpec = mSpec.GetFSSpec();
if (!theSpec.name[0]) {
NS_ERROR("failed to create a file spec");
// Since we didn't actually create the file spec
// we return an error
return NS_ERROR_MALFORMED_URI;
}
#endif
return rv ;
}
nsresult
nsDiskCacheRecordChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
{
return mRecord->mDiskCache->m_StorageInUse += aBytesUsed ;
}
// implement nsISupports
NS_IMPL_ISUPPORTS4(nsDiskCacheRecordChannel,
nsIChannel,
nsIRequest,
nsIStreamListener,
nsIStreamObserver)
// implement nsIRequest
NS_IMETHODIMP
nsDiskCacheRecordChannel::IsPending(PRBool *aIsPending)
{
*aIsPending = PR_FALSE ;
if(!mFileTransport)
return NS_OK ;
return mFileTransport->IsPending(aIsPending) ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::Cancel(void)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->Cancel() ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::Suspend(void)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->Suspend() ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::Resume(void)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->Resume() ;
}
// implement nsIChannel
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetOriginalURI(nsIURI* *aURI)
{
// FUR - might need to implement this - not sure
return NS_ERROR_NOT_IMPLEMENTED ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetURI(nsIURI * *aURI)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->GetURI(aURI) ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OpenInputStream(PRUint32 aStartPosition,
PRInt32 aReadCount,
nsIInputStream* *aResult)
{
nsresult rv ;
if(mFileTransport)
return NS_ERROR_IN_PROGRESS ;
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
if(NS_FAILED(rv)) return rv ;
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
if(NS_FAILED(rv))
return rv ;
// we don't need to worry about notification callbacks
rv = mFileTransport->OpenInputStream(aStartPosition, aReadCount, aResult) ;
if(NS_FAILED(rv))
mFileTransport = nsnull ;
return rv ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OpenOutputStream(PRUint32 startPosition,
nsIOutputStream* *aResult)
{
nsresult rv ;
NS_ENSURE_ARG(aResult) ;
if(mFileTransport)
return NS_ERROR_IN_PROGRESS ;
nsCOMPtr<nsIOutputStream> outputStream ;
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
if(NS_FAILED(rv)) return rv ;
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
if(NS_FAILED(rv))
return rv ;
// we don't need to worry about notification callbacks
rv = mFileTransport->OpenOutputStream(startPosition, getter_AddRefs(outputStream)) ;
if(NS_FAILED(rv)) {
mFileTransport = nsnull ;
return rv ;
}
return WriteStreamWrapper::Create(this, outputStream, aResult) ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::AsyncOpen(nsIStreamObserver *observer,
nsISupports *ctxt)
{
return NS_ERROR_NOT_IMPLEMENTED ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::AsyncRead(PRUint32 aStartPosition,
PRInt32 aReadCount,
nsISupports *aContext,
nsIStreamListener *aListener)
{
nsresult rv ;
if(mFileTransport)
return NS_ERROR_IN_PROGRESS ;
mRealListener = aListener;
nsCOMPtr<nsIStreamListener> tempListener = this;
if (mLoadGroup) {
nsCOMPtr<nsILoadGroupListenerFactory> factory;
//
// Create a load group "proxy" listener...
//
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (factory) {
nsIStreamListener *newListener;
rv = factory->CreateLoadGroupListener(mRealListener, &newListener);
if (NS_SUCCEEDED(rv)) {
mRealListener = newListener;
NS_RELEASE(newListener);
}
}
rv = mLoadGroup->AddChannel(this, nsnull);
if (NS_FAILED(rv)) return rv;
}
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport));
if (NS_FAILED(rv)) return rv;
// no callbacks
rv = mFileTransport->AsyncRead(aStartPosition,
aReadCount,
aContext,
tempListener);
if (NS_FAILED(rv)) {
// release the transport so that we don't think we're in progress
mFileTransport = nsnull;
}
return rv;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::AsyncWrite(nsIInputStream *fromStream,
PRUint32 startPosition,
PRInt32 writeCount,
nsISupports *ctxt,
nsIStreamObserver *observer)
{
/*
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->AsyncWrite(fromStream,
startPosition,
writeCount,
ctxt,
observer) ;
*/
// I can't do this since the write is not monitored, and I won't be
// able to updata the storage.
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
#define DUMMY_TYPE "text/html"
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetContentType(char * *aContentType)
{
nsresult rv ;
if (mSpec.IsDirectory()) {
*aContentType = nsCRT::strdup("application/http-index-format");
return *aContentType ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
else {
// I wish I can make this simplier
char* urlStr ;
mRecord->mFile->GetURLString(&urlStr) ;
// file: URLs (currently) have no additional structure beyond that provided by standard
// URLs, so there is no "outer" given to CreateInstance
nsCOMPtr<nsIURI> url;
rv = nsComponentManager::CreateInstance(kStandardURLCID, nsnull,
NS_GET_IID(nsIURI),
//(void**)&url);
getter_AddRefs(url)) ;
if (NS_FAILED(rv)) return rv;
rv = url->SetSpec((char*)urlStr);
if (NS_FAILED(rv))
return rv;
NS_WITH_SERVICE(nsIMIMEService, MIMEService, kMIMEServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = MIMEService->GetTypeFromURI(url, aContentType);
if (NS_SUCCEEDED(rv)) return rv;
}
// if all else fails treat it as text/html?
*aContentType = nsCRT::strdup(DUMMY_TYPE);
if (!*aContentType) {
return NS_ERROR_OUT_OF_MEMORY;
} else {
return NS_OK;
}
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetContentLength(PRInt32 *aContentLength)
{
nsresult rv;
PRUint32 length;
rv = mRecord->mFile->GetFileSize(&length);
if (NS_SUCCEEDED(rv)) {
*aContentLength = (PRInt32)length;
} else {
*aContentLength = -1;
}
return rv;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetOwner(nsISupports* *aOwner)
{
*aOwner = mOwner.get() ;
NS_IF_ADDREF(*aOwner) ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetOwner(nsISupports* aOwner)
{
mOwner = aOwner ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_OK;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////////
// nsIStreamListener methods:
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsDiskCacheRecordChannel::OnStartRequest(nsIChannel* transportChannel, nsISupports* context)
{
NS_ASSERTION(mRealListener, "No listener...");
return mRealListener->OnStartRequest(this, context);
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OnStopRequest(nsIChannel* transportChannel, nsISupports* context,
nsresult aStatus, const PRUnichar* aMsg)
{
nsresult rv;
rv = mRealListener->OnStopRequest(this, context, aStatus, aMsg);
if (mLoadGroup) {
if (NS_SUCCEEDED(rv)) {
mLoadGroup->RemoveChannel(this, context, aStatus, aMsg);
}
}
// Release the reference to the consumer stream listener...
mRealListener = null_nsCOMPtr();
mFileTransport = null_nsCOMPtr();
return rv;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OnDataAvailable(nsIChannel* transportChannel, nsISupports* context,
nsIInputStream *aIStream, PRUint32 aSourceOffset,
PRUint32 aLength)
{
nsresult rv;
rv = mRealListener->OnDataAvailable(this, context, aIStream,
aSourceOffset, aLength);
//
// If the connection is being aborted cancel the transport. This will
// insure that the transport will go away even if it is blocked waiting
// for the consumer to empty the pipe...
//
if (NS_FAILED(rv)) {
mFileTransport->Cancel();
}
return rv;
}

View File

@@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _ns_DiskCacheRecordChannel_h_
#define _ns_DiskCacheRecordChannel_h_
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsDiskCacheRecord.h"
#include "nsIStreamListener.h"
/*
* This class is plagiarized from nsMemCacheChannel
*/
class nsDiskCacheRecordChannel : public nsIChannel,
public nsIStreamListener
{
public:
nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
virtual ~nsDiskCacheRecordChannel() ;
// Declare nsISupports methods
NS_DECL_ISUPPORTS
// Declare nsIRequest methods
NS_DECL_NSIREQUEST
// Declare nsIChannel methods
NS_DECL_NSICHANNEL
// Declare nsIStreamObserver methods
NS_DECL_NSISTREAMOBSERVER
// Declare nsIStreamListener methods
NS_DECL_NSISTREAMLISTENER
nsresult Init(void) ;
private:
nsresult NotifyStorageInUse(PRInt32 aBytesUsed) ;
nsDiskCacheRecord* mRecord ;
nsCOMPtr<nsILoadGroup> mLoadGroup ;
nsCOMPtr<nsISupports> mOwner ;
nsCOMPtr<nsIChannel> mFileTransport ;
nsFileSpec mSpec ;
nsCOMPtr<nsIStreamListener> mRealListener;
friend class WriteStreamWrapper ;
} ;
#endif // _ns_DiskCacheRecordChannel_h_

View File

@@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _NS_IDBACCESSOR_H_
#define _NS_IDBACCESSOR_H_
#include "nsISupports.h"
#include "nsIFileSpec.h"
// nsIDBAccessorIID {6AADD4D0-7785-11d3-87FE-000629D01344}
#define NS_IDBACCESSOR_IID \
{ 0x6aadd4d0, 0x7785, 0x11d3, \
{0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44}}
// nsDBAccessorCID {6AADD4D1-7785-11d3-87FE-000629D01344}
#define NS_DBACCESSOR_CID \
{ 0x6aadd4d1, 0x7785, 0x11d3, \
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
class nsIDBAccessor : public nsISupports
{
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IDBACCESSOR_IID)
NS_IMETHOD Init(nsIFileSpec* DBFile) = 0 ;
NS_IMETHOD Shutdown(void) = 0 ;
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) = 0 ;
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) = 0 ;
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) = 0 ;
NS_IMETHOD GetDBFilesize(PRUint32* aSize) = 0 ;
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) = 0 ;
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) = 0 ;
} ;
#endif // _NS_IDBACCESSOR_H_

View File

@@ -0,0 +1,704 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#include "nsNetDiskCache.h"
#include "nscore.h"
#include "plstr.h"
#include "prprf.h"
#include "prtypes.h"
#include "prio.h"
#include "prsystem.h" // Directory Seperator
#include "plhash.h"
#include "prclist.h"
#include "prmem.h"
#include "prlog.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIPref.h"
#include "mcom_db.h"
#include "nsDBEnumerator.h"
#include "nsDiskCacheRecord.h"
#include "netCore.h"
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
ERROR! Must have a byte order
#endif
#ifdef IS_LITTLE_ENDIAN
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
#else
#define COPY_INT32(_a,_b) /* swap */ \
do { \
((char *)(_a))[0] = ((char *)(_b))[3]; \
((char *)(_a))[1] = ((char *)(_b))[2]; \
((char *)(_a))[2] = ((char *)(_b))[1]; \
((char *)(_a))[3] = ((char *)(_b))[0]; \
} while(0)
#endif
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID) ;
static NS_DEFINE_CID(kDBAccessorCID, NS_DBACCESSOR_CID) ;
static const PRUint32 DISK_CACHE_SIZE_DEFAULT = 5*1024*1024 ; // 5MB
static const char * const DISK_CACHE_PREF = "browser.cache.disk_cache_size";
static const char * const CACHE_DIR_PREF = "browser.cache.directory";
class nsDiskCacheRecord ;
nsNetDiskCache::nsNetDiskCache() :
m_Enabled(PR_TRUE) ,
m_NumEntries(0) ,
m_pNextCache(0) ,
m_pDiskCacheFolder(0) ,
m_StorageInUse(0) ,
m_DB(0) ,
m_DBCorrupted(PR_FALSE)
{
// set it to INF for now
m_MaxEntries = (PRUint32)-1 ;
NS_INIT_REFCNT();
}
nsNetDiskCache::~nsNetDiskCache()
{
SetSpecialEntry() ;
NS_IF_RELEASE(m_DB) ;
// FUR
// I think that, eventually, we also want a distinguished key in the DB which
// means "clean cache shutdown". You clear this flag when the db is first
// opened and set it just before the db is closed. If the db wasn't shutdown
// cleanly in a prior session, i.e. because the app crashed, on startup you
// scan all the individual files in directories and look for "orphans",
// i.e. cache files which don't have corresponding entries in the db. That's
// also when storage-in-use and number of entries would be recomputed.
//
// We don't necessarily need all this functionality immediately, though.
if(m_DBCorrupted) {
nsFileSpec cacheFolder ;
m_pDiskCacheFolder->GetFileSpec(&cacheFolder) ;
char nameInt[6] ;
for(nsDirectoryIterator di(cacheFolder, PR_FALSE); di.Exists(); di++) {
char* filename = di.Spec().GetLeafName() ;
char* pname = nameInt ;
pname = PL_strncpyz(pname, filename, 6) ;
if(PL_strcmp(pname, "trash") == 0)
RemoveFolder(di.Spec()) ;
nsCRT::free(filename) ;
}
}
}
NS_IMETHODIMP
nsNetDiskCache::Init(void)
{
nsresult rv ;
// don't initialize if no cache folder is set.
if(!m_pDiskCacheFolder) return NS_OK ;
if(!m_DB) {
m_DB = new nsDBAccessor() ;
if(!m_DB)
return NS_ERROR_OUT_OF_MEMORY ;
else
NS_ADDREF(m_DB) ;
}
// create cache sub directories
nsCOMPtr<nsIFileSpec> cacheSubDir;
rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir));
for (int i=0; i < 32; i++) {
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
if(NS_FAILED(rv))
return rv ;
char dirName[3];
PR_snprintf (dirName, 3, "%0.2x", i);
cacheSubDir->AppendRelativeUnixPath (dirName) ;
CreateDir(cacheSubDir);
}
return InitDB() ;
}
NS_IMETHODIMP
nsNetDiskCache::InitDB(void)
{
nsresult rv ;
if(!m_DBFile) {
NS_NewFileSpec(getter_AddRefs(m_DBFile)) ;
if(!m_DBFile)
return NS_ERROR_OUT_OF_MEMORY ;
}
rv = m_DBFile->FromFileSpec(m_pDiskCacheFolder) ;
if(NS_FAILED(rv))
return rv ;
m_DBFile->AppendRelativeUnixPath("cache.db") ;
rv = m_DB->Init(m_DBFile) ;
if(rv == NS_ERROR_FAILURE) {
// try recovery if error
DBRecovery() ;
}
rv = GetSpecialEntry() ;
if(rv == NS_ERROR_FAILURE) {
// try recovery if error
DBRecovery() ;
}
return rv ;
}
//////////////////////////////////////////////////////////////////////////
// nsISupports methods
NS_IMPL_ISUPPORTS3(nsNetDiskCache,
nsINetDataDiskCache,
nsINetDataCache,
nsISupports)
///////////////////////////////////////////////////////////////////////////
// nsINetDataCache Method
NS_IMETHODIMP
nsNetDiskCache::GetDescription(PRUnichar* *aDescription)
{
nsAutoString description("Disk Cache") ;
*aDescription = description.ToNewUnicode() ;
if(!*aDescription)
return NS_ERROR_OUT_OF_MEMORY ;
return NS_OK ;
}
/* don't alloc mem for nsICachedNetData.
* RecordID is generated using the same scheme in nsCacheDiskData,
* see GetCachedNetData() for detail.
*/
NS_IMETHODIMP
nsNetDiskCache::Contains(const char* key, PRUint32 length, PRBool *_retval)
{
*_retval = PR_FALSE ;
NS_ASSERTION(m_DB, "no db.") ;
PRInt32 id = 0 ;
nsresult rv = m_DB->GetID(key, length, &id) ;
if(NS_FAILED(rv)) {
// try recovery if error
DBRecovery() ;
return rv ;
}
void* info = 0 ;
PRUint32 info_size = 0 ;
rv = m_DB->Get(id, &info, &info_size) ;
if(NS_SUCCEEDED(rv) && info)
*_retval = PR_TRUE ;
if(NS_FAILED(rv)) {
// try recovery if error
DBRecovery() ;
}
return rv ;
}
/* regardless if it's cached or not, a copy of nsNetDiskCache would
* always be returned. so release it appropriately.
* if mem alloced, updata m_NumEntries also.
* for now, the new nsCachedNetData is not written into db yet since
* we have nothing to write.
*/
NS_IMETHODIMP
nsNetDiskCache::GetCachedNetData(const char* key, PRUint32 length, nsINetDataCacheRecord **_retval)
{
NS_ASSERTION(m_DB, "no db.") ;
nsresult rv = 0 ;
if (!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
PRInt32 id = 0 ;
rv = m_DB->GetID(key, length, &id) ;
if(NS_FAILED(rv)) {
// try recovery if error
DBRecovery() ;
return rv ;
}
// construct an empty record
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
if(!newRecord)
return NS_ERROR_OUT_OF_MEMORY ;
rv = newRecord->Init(key, length, id) ;
if(NS_FAILED(rv)) {
delete newRecord ;
return rv ;
}
NS_ADDREF(newRecord) ; // addref for _retval
*_retval = (nsINetDataCacheRecord*) newRecord ;
void* info = 0 ;
PRUint32 info_size = 0 ;
rv = m_DB->Get(id, &info, &info_size) ;
if(NS_SUCCEEDED(rv) && info) {
// this is a previously cached record
nsresult r1 ;
r1 = newRecord->RetrieveInfo(info, info_size) ;
if(NS_SUCCEEDED(rv))
return NS_OK ;
else {
// probably a bad one
NS_RELEASE(newRecord) ;
*_retval = nsnull ;
return r1;
}
} else if (NS_SUCCEEDED(rv) && !info) {
// this is a new record.
m_NumEntries ++ ;
return NS_OK ;
} else {
// database error.
DBRecovery() ;
return rv ;
}
}
/* get an nsICachedNetData, mem needs to be de-alloced if not found. */
NS_IMETHODIMP
nsNetDiskCache::GetCachedNetDataByID(PRInt32 RecordID, nsINetDataCacheRecord **_retval)
{
NS_ASSERTION(m_DB, "no db.") ;
if (!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
nsresult rv ;
void* info = 0 ;
PRUint32 info_size = 0 ;
rv = m_DB->Get(RecordID, &info, &info_size) ;
if(NS_SUCCEEDED(rv) && info) {
// construct an empty record if only found in db
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
if(!newRecord)
return NS_ERROR_OUT_OF_MEMORY ;
NS_ADDREF(newRecord) ; // addref for _retval
rv = newRecord->RetrieveInfo(info, info_size) ;
if(NS_SUCCEEDED(rv)) {
*_retval = (nsINetDataCacheRecord*) newRecord ;
return NS_OK ;
}
else {
// bad record, I guess
NS_RELEASE(newRecord) ; // release if bad things happen
return rv ;
}
} else {
NS_ERROR("Error: RecordID not in DB\n") ;
DBRecovery() ;
return rv ;
}
}
NS_IMETHODIMP
nsNetDiskCache::GetEnabled(PRBool *aEnabled)
{
*aEnabled = m_Enabled ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetEnabled(PRBool aEnabled)
{
m_Enabled = aEnabled ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::GetFlags(PRUint32 *aFlags)
{
*aFlags = FILE_PER_URL_CACHE;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::GetNumEntries(PRUint32 *aNumEntries)
{
*aNumEntries = m_NumEntries ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::GetMaxEntries(PRUint32 *aMaxEntries)
{
*aMaxEntries = m_MaxEntries ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::NewCacheEntryIterator(nsISimpleEnumerator **_retval)
{
NS_ASSERTION(m_DB, "no db.") ;
if(!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
nsISimpleEnumerator* enumerator = new nsDBEnumerator(m_DB, this) ;
if(enumerator) {
NS_ADDREF(enumerator) ;
*_retval = enumerator ;
return NS_OK ;
}
else
return NS_ERROR_OUT_OF_MEMORY ;
}
NS_IMETHODIMP
nsNetDiskCache::GetNextCache(nsINetDataCache * *aNextCache)
{
if(!aNextCache)
return NS_ERROR_NULL_POINTER ;
*aNextCache = m_pNextCache ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetNextCache(nsINetDataCache *aNextCache)
{
m_pNextCache = aNextCache ;
return NS_OK ;
}
// db size can always be measured at the last minute. Since it's hard
// to know before hand.
NS_IMETHODIMP
nsNetDiskCache::GetStorageInUse(PRUint32 *aStorageInUse)
{
NS_ASSERTION(m_DB, "no db.") ;
PRUint32 total_size = m_StorageInUse ;
/*
PRUint32 len = 0 ;
// add the size of the db.
m_DB->GetDBFilesize(&len) ;
total_size += len ;
*/
// we need size in kB
total_size = total_size >> 10 ;
*aStorageInUse = total_size ;
return NS_OK ;
}
/*
* The whole cache dirs can be whiped clean since all the cache
* files are resides in seperate hashed dirs. It's safe to do so.
*/
NS_IMETHODIMP
nsNetDiskCache::RemoveAll(void)
{
NS_ASSERTION(m_DB, "no db.") ;
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
// remove all the sub folders
nsFileSpec cacheSubDir;
for (int i=0; i < 32; i++) {
m_pDiskCacheFolder->GetFileSpec(&cacheSubDir) ;
char dirName[3];
PR_snprintf (dirName, 3, "%0.2x", i);
cacheSubDir += dirName ;
RemoveFolder(cacheSubDir) ;
}
// don't forget the db file itself
m_DB->Shutdown() ;
nsFileSpec dbfile ;
m_DBFile->GetFileSpec(&dbfile) ;
dbfile.Delete(PR_TRUE) ;
// reinitilize
return Init() ;
}
//////////////////////////////////////////////////////////////////
// nsINetDataDiskCache methods
NS_IMETHODIMP
nsNetDiskCache::GetDiskCacheFolder(nsIFileSpec * *aDiskCacheFolder)
{
*aDiskCacheFolder = nsnull ;
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
*aDiskCacheFolder = m_pDiskCacheFolder ;
NS_ADDREF(*aDiskCacheFolder) ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetDiskCacheFolder(nsIFileSpec * aDiskCacheFolder)
{
if(!m_pDiskCacheFolder) {
NS_NewFileSpec(getter_AddRefs(m_pDiskCacheFolder));
if(!m_pDiskCacheFolder)
return NS_ERROR_OUT_OF_MEMORY ;
m_pDiskCacheFolder = aDiskCacheFolder ;
return Init() ;
}
else {
char *newfolder, *oldfolder ;
m_pDiskCacheFolder->GetNativePath(&oldfolder) ;
aDiskCacheFolder->GetNativePath(&newfolder) ;
if(PL_strcmp(newfolder, oldfolder) != 0) {
m_pDiskCacheFolder = aDiskCacheFolder ;
// do we need to blow away old cache before building a new one?
// return RemoveAll() ;
m_DB->Shutdown() ;
return Init() ;
} else
return NS_OK ;
}
}
//////////////////////////////////////////////////////////////////
// nsNetDiskCache methods
// create a directory (recursively)
NS_IMETHODIMP
nsNetDiskCache::CreateDir(nsIFileSpec* dir_spec)
{
PRBool does_exist ;
nsCOMPtr<nsIFileSpec> p_spec ;
dir_spec->Exists(&does_exist) ;
if(does_exist)
return NS_OK ;
nsresult rv = dir_spec->GetParent(getter_AddRefs(p_spec)) ;
if(NS_FAILED(rv))
return rv ;
p_spec->Exists(&does_exist) ;
if(!does_exist) {
CreateDir(p_spec) ;
rv = dir_spec->CreateDir() ;
if(NS_FAILED(rv))
return rv ;
}
else {
rv = dir_spec->CreateDir() ;
if(NS_FAILED(rv))
return rv ;
}
return NS_OK ;
}
// We can't afford to make a *separate* pass over the whole db on every
// startup, just to figure out m_NumEntries and m_StorageInUse. (This is a
// several second operation on a large db). We'll likely need to store
// distinguished keys in the db that contain these values and update them
// incrementally, except when failure to shut down the db cleanly is detected.
NS_IMETHODIMP
nsNetDiskCache::GetSpecialEntry(void)
{
void* pInfo ;
PRUint32 InfoSize ;
nsresult rv = m_DB->GetSpecialEntry(&pInfo, &InfoSize) ;
if(NS_FAILED(rv))
return rv ;
if(!pInfo && InfoSize == 0) {
// must be a new DB
m_NumEntries = 0 ;
m_StorageInUse = 0 ;
}
else {
char * cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
// get m_NumEntries
COPY_INT32(&m_NumEntries, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// get m_StorageInUse
COPY_INT32(&m_StorageInUse, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
}
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetSpecialEntry(void)
{
PRUint32 InfoSize ;
InfoSize = sizeof m_NumEntries ;
InfoSize += sizeof m_StorageInUse ;
void* pInfo = nsAllocator::Alloc(InfoSize*sizeof(char)) ;
if(!pInfo)
return NS_ERROR_OUT_OF_MEMORY ;
char* cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
COPY_INT32(cur_ptr, &m_NumEntries) ;
cur_ptr += sizeof(PRUint32) ;
COPY_INT32(cur_ptr, &m_StorageInUse) ;
cur_ptr += sizeof(PRUint32) ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
return m_DB->SetSpecialEntry(pInfo, InfoSize) ;
}
// this routine will be called everytime we have a db corruption.
// m_DB will be re-initialized, m_StorageInUse and m_NumEntries will
// be reset.
NS_IMETHODIMP
nsNetDiskCache::DBRecovery(void)
{
// rename all the sub cache dirs and remove them later during dtor.
nsresult rv = RenameCacheSubDirs() ;
if(NS_FAILED(rv))
return rv ;
// remove corrupted db file, don't care if db->shutdown fails or not.
m_DB->Shutdown() ;
nsFileSpec dbfile ;
m_DBFile->GetFileSpec(&dbfile) ;
dbfile.Delete(PR_TRUE) ;
// make sure it's not there any more
PRBool exists = dbfile.Exists() ;
if(exists) {
NS_ERROR("can't remove old db.") ;
return NS_ERROR_FAILURE ;
}
// reinitilize DB
return InitDB() ;
}
// this routine will add string "trash" to current CacheSubDir names.
// e.g. 00->trash00, 1f->trash1f. and update the m_DBCorrupted.
NS_IMETHODIMP
nsNetDiskCache::RenameCacheSubDirs(void)
{
nsCOMPtr<nsIFileSpec> cacheSubDir;
nsresult rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir)) ;
for (int i=0; i < 32; i++) {
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
if(NS_FAILED(rv))
return rv ;
char oldName[3], newName[8];
PR_snprintf(oldName, 3, "%0.2x", i) ;
cacheSubDir->AppendRelativeUnixPath(oldName) ;
// re-name the directory
PR_snprintf(newName, 8, "trash%0.2x", i) ;
rv = cacheSubDir->Rename(newName) ;
if(NS_FAILED(rv))
// TODO, error checking
return NS_ERROR_FAILURE ;
}
// update m_DBCorrupted
m_DBCorrupted = PR_TRUE ;
return NS_OK ;
}
// this routine is used by dtor and RemoveAll() to clean up dirs.
NS_IMETHODIMP
nsNetDiskCache::RemoveFolder(nsFileSpec aFolder)
{
for(nsDirectoryIterator di(aFolder, PR_FALSE); di.Exists(); di++) {
di.Spec().Delete(PR_TRUE) ;
}
aFolder.Delete(PR_FALSE) ; // recursive delete
return NS_OK ;
}

View File

@@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* nsNetDiskCache is the main disk cache module that will create
* the cache database, and then store and retrieve nsDiskCacheRecord
* objects from it. It also contains some basic error recovery procedure.
*/
#ifndef __gen_nsNetDiskCache_h__
#define __gen_nsNetDiskCache_h__
#include "nsINetDataDiskCache.h"
#include "nsNetDiskCacheCID.h"
#include "nsCOMPtr.h"
#include "nsIPref.h"
#include "nsDBAccessor.h"
class nsIURI; /* forward decl */
class nsICachedNetData; /* forward decl */
class nsISimpleEnumerator; /* forward decl */
class nsIFileSpec; /* forward decl */
/* starting interface: nsNetDiskCache */
class nsNetDiskCache : public nsINetDataDiskCache {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSINETDATACACHE
NS_DECL_NSINETDATADISKCACHE
NS_IMETHOD Init(void) ;
nsNetDiskCache() ;
virtual ~nsNetDiskCache() ;
protected:
NS_IMETHOD InitDB(void) ;
NS_IMETHOD CreateDir(nsIFileSpec* dir_spec) ;
NS_IMETHOD GetSpecialEntry(void) ;
NS_IMETHOD SetSpecialEntry(void) ;
NS_IMETHOD RenameCacheSubDirs(void) ;
NS_IMETHOD DBRecovery(void) ;
NS_IMETHOD RemoveFolder(nsFileSpec aFolder) ;
private:
PRBool m_Enabled ;
PRUint32 m_NumEntries ;
nsCOMPtr<nsINetDataCache> m_pNextCache ;
nsCOMPtr<nsIFileSpec> m_pDiskCacheFolder ;
nsCOMPtr<nsIFileSpec> m_DBFile ;
PRUint32 m_MaxEntries ;
PRUint32 m_StorageInUse ;
nsIDBAccessor* m_DB ;
// this is used to indicate a db corruption
PRBool m_DBCorrupted ;
friend class nsDiskCacheRecord ;
friend class nsDiskCacheRecordChannel ;
friend class nsDBEnumerator ;
} ;
#endif /* __gen_nsNetDiskCache_h__ */

View File

@@ -0,0 +1,32 @@
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _nsNetDiskCacheCID_h_
#define _nsNetDiskCacheCID_h_
#define NS_NETDISKCACHE_CID_STR "ECFEEA00-7201-11d3-87FE-000629D01344"
#define NS_NETDISKCACHE_CID \
{ 0xecfeea00, 0x7201, 0x11d3, \
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
#endif /* _nsNetDiskCacheCID_h_ */

View File

@@ -0,0 +1,50 @@
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
REQUIRES = libreg xpcom
CPPSRCS = \
diskcache.cpp \
$(NULL)
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=)
ifdef NO_LD_ARCHIVE_FLAGS
LOST_SYM_LIBS = -lxpcomds_s -lxptinfo -lmozreg_s
endif
LIBS = \
-lmozjs \
-lxpcom \
-lmozdbm_s \
$(MOZ_NECKO_UTIL_LIBS) \
$(LOST_SYM_LIBS) \
$(NSPR_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = -I$(srcdir)/..
DEFINES += -DUSE_NSREG -DCACHE

View File

@@ -0,0 +1,836 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIStreamListener.h"
#include "nsIStreamObserver.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include <stdio.h>
#include <unistd.h>
#include "nsINetDataCache.h"
#include "nsINetDataCacheRecord.h"
//#include "nsMemCacheCID.h"
#include "nsNetDiskCache.h"
#include "nsIPref.h"
#include "prenv.h"
#include "nsIFileStream.h"
// Number of test entries to be placed in the cache
#define NUM_CACHE_ENTRIES 250
// Cache content stream length will have random length between zero and
// MAX_CONTENT_LENGTH bytes
#define MAX_CONTENT_LENGTH 20000
// Length of random-data cache entry key
#define CACHE_KEY_LENGTH 15
// Length of random-data cache entry meta-data
#define CACHE_METADATA_LENGTH 100
//static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
// Mapping from test case number to RecordID
static PRInt32 recordID[NUM_CACHE_ENTRIES];
static PRInt32
mapRecordIdToTestNum(PRInt32 aRecordID)
{
int i;
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
if (recordID[i] == aRecordID)
return i;
}
return -1;
}
// A supply of stream data to either store or compare with
class nsITestDataStream {
public:
virtual ~nsITestDataStream() {};
virtual PRUint32 Next() = 0;
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
virtual void Skip(PRUint32 aCount) = 0;
};
// A reproducible stream of random data.
class RandomStream : public nsITestDataStream {
public:
RandomStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState = 1103515245 * mState + 12345;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(Next() & 0xff))
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
while (aCount--)
Next();
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
// A stream of data that increments on each byte that is read, modulo 256
class CounterStream : public nsITestDataStream {
public:
CounterStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState += 1;
mState &= 0xff;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)Next())
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
mState += aCount;
mState &= 0xff;
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
static int gNumReaders = 0;
static PRUint32 gTotalBytesRead = 0;
static PRUint32 gTotalDuration = 0;
class nsReader : public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
nsReader()
: mStartTime(0), mBytesRead(0)
{
NS_INIT_REFCNT();
gNumReaders++;
}
virtual ~nsReader() {
delete mTestDataStream;
gNumReaders--;
}
nsresult
Init(nsIChannel *aChannel, nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
mChannel = aChannel;
mTestDataStream = aRandomStream;
mExpectedStreamLength = aExpectedStreamLength;
mRefCnt = 1;
return NS_OK;
}
NS_IMETHOD OnStartRequest(nsIChannel* channel,
nsISupports* context) {
mStartTime = PR_IntervalNow();
return NS_OK;
}
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *aIStream,
PRUint32 aSourceOffset,
PRUint32 aLength) {
char buf[1025];
while (aLength > 0) {
PRUint32 amt;
PRBool match;
aIStream->Read(buf, sizeof buf, &amt);
if (amt == 0) break;
aLength -= amt;
mBytesRead += amt;
match = mTestDataStream->Match(buf, amt);
NS_ASSERTION(match, "Stored data was corrupted on read");
}
return NS_OK;
}
NS_IMETHOD OnStopRequest(nsIChannel* channel,
nsISupports* context,
nsresult aStatus,
const PRUnichar* aMsg) {
PRIntervalTime endTime;
PRIntervalTime duration;
endTime = PR_IntervalNow();
duration = (endTime - mStartTime);
if (NS_FAILED(aStatus)) printf("channel failed.\n");
// printf("read %d bytes\n", mBytesRead);
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
"Stream in cache is wrong length");
gTotalBytesRead += mBytesRead;
gTotalDuration += duration;
// Release channel
mChannel = 0;
return NS_OK;
}
protected:
PRIntervalTime mStartTime;
PRUint32 mBytesRead;
nsITestDataStream* mTestDataStream;
PRUint32 mExpectedStreamLength;
nsCOMPtr<nsIChannel> mChannel;
};
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
static nsIEventQueue* eventQueue;
nsresult
InitQueue() {
nsresult rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
rv = eventQService->CreateThreadEventQueue();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
return NS_OK;
}
// Process events until all streams are OnStopRequest'ed
nsresult
WaitForEvents() {
while (gNumReaders) {
eventQueue->ProcessPendingEvents();
}
return NS_OK;
}
// Read data for a single cache record and compare against testDataStream
nsresult
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
PRUint32 expectedStreamLength)
{
nsCOMPtr<nsIChannel> channel;
nsresult rv;
PRUint32 actualContentLength;
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = record->GetStoredContentLength(&actualContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(actualContentLength == expectedStreamLength,
"nsINetDataCacheRecord::GetContentLength() busted ?");
nsReader *reader = new nsReader;
reader->AddRef();
rv = reader->Init(channel, testDataStream, expectedStreamLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->AsyncRead(0, -1, 0, reader);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
reader->Release();
return NS_OK;
}
// Check that records can be retrieved using their record-ID, in addition
// to using the opaque key.
nsresult
TestRecordID(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
return NS_OK;
}
// Check that all cache entries in the database are enumerated and that
// no duplicates appear.
nsresult
TestEnumeration(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsISupports> tempISupports;
nsCOMPtr<nsISimpleEnumerator> iterator;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
PRInt32 recID;
int numRecords = 0;
// Iterate over all records in the cache
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
PRBool notDone;
while (1) {
// Done iterating ?
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
// Get next record in iteration
rv = iterator->GetNext(getter_AddRefs(tempISupports));
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
record = do_QueryInterface(tempISupports);
numRecords++;
// Get record ID
rv = record->GetRecordID(&recID);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
testNum = mapRecordIdToTestNum(recID);
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
// Erase mapping from table, so that duplicate enumerations are detected
recordID[testNum] = -1;
// Make sure stream matches test data
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
return NS_OK;
}
// Read the test data that was written in FillCache(), checking for
// corruption, truncation.
nsresult
TestRead(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData, *storedCacheKey;
PRUint32 testNum, storedCacheKeyLength;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Ensure that entry is in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// Match against previously stored meta-data
match = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
// Test GetKey() method
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
(storedCacheKeyLength == sizeof cacheKey) &&
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
"nsINetDataCacheRecord::GetKey failed");
nsAllocator::Free(storedCacheKey);
PRUint32 expectedStreamLength = randomStream->Next() & 0xffff;
TestReadStream(record, randomStream, expectedStreamLength);
}
WaitForEvents();
// Compute rate in MB/s
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
rate *= NUM_CACHE_ENTRIES;
rate *= 1000;
rate /= (1024 * 1024);
printf("Read %d bytes at a rate of %5.1f MB per second \n",
gTotalBytesRead, rate);
return NS_OK;
}
// Repeatedly call SetStoredContentLength() on a cache entry and make
// read the stream's data to ensure that it's not corrupted by the effect
nsresult
TestTruncation(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
char cacheKey[CACHE_KEY_LENGTH];
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
randomStream->Skip(CACHE_METADATA_LENGTH);
PRUint32 initialStreamLength = randomStream->Next() & 0xffff;
delete randomStream;
PRUint32 i;
PRUint32 delta = initialStreamLength / 64;
for (i = initialStreamLength; i >= delta; i -= delta) {
PRUint32 expectedStreamLength = i;
// Do the truncation
record->SetStoredContentLength(expectedStreamLength);
randomStream = new RandomStream(0);
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
TestReadStream(record, randomStream, expectedStreamLength);
WaitForEvents();
}
return NS_OK;
}
// Write known data to random offsets in a single cache entry and test
// resulting stream for correctness.
nsresult
TestOffsetWrites(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[512];
char cacheKey[CACHE_KEY_LENGTH];
RandomStream *randomStream;
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
nsCOMPtr<nsIFileSpec> file ;
record->GetFilename(getter_AddRefs(file)) ;
char* name ;
file->GetUnixStyleFilePath(&name) ;
printf(" file name is %s \n", name) ;
// Write buffer-fulls of data at random offsets into the cache entry.
// Data written is (offset % 0xff)
PRUint32 startingOffset;
PRUint32 streamLength = 0;
PRUint32 len = 0 ;
CounterStream *counterStream;
int i = 0;
for (i = 0; i < 257; i++) {
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
truncate(name, startingOffset) ;
counterStream = new CounterStream(startingOffset);
counterStream->Read(buf, sizeof buf);
nsresult status ;
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
if (NS_FAILED(status)) {
// mState = END_WRITE;
return NS_ERROR_FAILURE;
}
PRIntn offset ;
ras->Tell(&offset) ;
// printf(" offset is %d \n", offset) ;
PRUint32 numWritten;
rv = outStream->Write(buf, sizeof buf, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
streamLength = startingOffset + sizeof buf;
rv = outStream->Close();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
delete counterStream;
record->GetStoredContentLength(&len) ;
if(len != streamLength)
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
}
/*
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
startingOffset = 208;
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
counterStream = new CounterStream(startingOffset);
counterStream->Read(buf, sizeof buf);
nsresult status ;
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
if (NS_FAILED(status)) {
// mState = END_WRITE;
return NS_ERROR_FAILURE;
}
PRIntn offset = 0 ;
ras->Tell(&offset) ;
printf(" offset is %d \n", offset) ;
PRUint32 numWritten;
rv = outStream->Write(buf, sizeof buf, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
streamLength = startingOffset + sizeof buf;
rv = outStream->Close();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
delete counterStream;
record->GetStoredContentLength(&len) ;
if(len != streamLength)
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
*/
delete randomStream;
counterStream = new CounterStream(0);
TestReadStream(record, counterStream, streamLength);
WaitForEvents();
return NS_OK;
}
// Create entries in the network data cache, using random data for the
// key, the meta-data and the stored content data.
nsresult
FillCache(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[1000];
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char metaData[CACHE_METADATA_LENGTH];
PRUint32 testNum;
char *data;
RandomStream *randomStream;
PRIntervalTime startTime = PR_IntervalNow();
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// No entry should be in cache until we add it
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
// Test nsINetDataCacheRecord::GetRecordID()
rv = record->GetRecordID(&recordID[testNum]);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
// Test nsINetDataCache::GetNumEntries()
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
// Record meta-data should be initially empty
rv = record->GetMetaData(&metaDataLength, &data);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
if ((metaDataLength != 0) || (data != 0))
return NS_ERROR_FAILURE;
// Store random data as meta-data
randomStream->Read(metaData, sizeof metaData);
record->SetMetaData(sizeof metaData, metaData);
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
PRUint32 beforeOccupancy;
rv = cache->GetStorageInUse(&beforeOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
int streamLength = randomStream->Next() & 0xffff;
int remaining = streamLength;
while (remaining) {
PRUint32 numWritten;
int amount = PR_MIN(sizeof buf, remaining);
randomStream->Read(buf, amount);
rv = outStream->Write(buf, amount, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
remaining -= amount;
}
outStream->Close();
PRUint32 afterOccupancy;
rv = cache->GetStorageInUse(&afterOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 streamLengthInKB = streamLength >> 10;
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
"nsINetDataCache::GetStorageInUse() is busted");
// *Now* there should be an entry in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
delete randomStream;
}
PRIntervalTime endTime = PR_IntervalNow();
return NS_OK;
}
nsresult NS_AutoregisterComponents()
{
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
NULL /* default */);
return rv;
}
PRBool initPref ()
{
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
if (NS_FAILED(rv))
return false;
nsCOMPtr<nsIFileSpec> fileSpec;
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
if (NS_FAILED(rv))
return false;
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
if (defaultPrefFile.Length())
defaultPrefFile += "/";
else
defaultPrefFile = "./";
defaultPrefFile += "default_prefs.js";
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
PRBool exists = false;
fileSpec->Exists(&exists);
if (exists)
prefPtr->ReadUserPrefsFrom(fileSpec);
else
return false;
return true;
}
int
main(int argc, char* argv[])
{
initPref() ;
nsresult rv;
nsCOMPtr<nsINetDataCache> cache;
rv = NS_AutoregisterComponents();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(cache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
InitQueue();
PRUnichar* description;
rv = cache->GetDescription(&description);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
nsCAutoString descStr(description);
printf("Testing: %s\n", descStr.GetBuffer());
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
PRUint32 startOccupancy;
rv = cache->GetStorageInUse(&startOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
rv = FillCache(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
rv = TestRead(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
rv = TestRecordID(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
rv = TestEnumeration(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
rv = TestTruncation(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
rv = TestOffsetWrites(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
PRUint32 endOccupancy;
rv = cache->GetStorageInUse(&endOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
return 0;
}

View File

@@ -0,0 +1,48 @@
# Generated automatically from Makefile.in by configure.
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
VPATH = @srcdir@
srcdir = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = nkcache
LIBRARY_NAME = nkmemcache_s
REQUIRES = nspr dbm
EXPORTS=nsMemCacheCID.h \
nsMemCache.h \
$(NULL)
CPPSRCS = \
nsMemCache.cpp \
nsMemCacheRecord.cpp \
nsMemCacheChannel.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a
# static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,42 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = nkcache
LIBRARY_NAME = nkmemcache_s
CPP_OBJS = \
.\$(OBJDIR)\nsMemCache.obj \
.\$(OBJDIR)\nsMemCacheRecord.obj \
.\$(OBJDIR)\nsMemCacheChannel.obj \
$(NULL)
EXPORTS=nsMemCacheCID.h
include <$(DEPTH)\config\rules.mak>
install:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -rf $(OBJDIR)
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,334 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
/**
* nsMemCache is the implementation of an in-memory network-data
* cache, used to cache the responses to network retrieval commands.
* Each cache entry may contain both content, e.g. GIF image data, and
* associated metadata, e.g. HTTP headers. Each entry is indexed by
* two different keys: a record id number and an opaque key, which is
* created by the cache manager by combining the URI with a "secondary
* key", e.g. HTTP post data.
*/
#include "nsMemCache.h"
#include "nsMemCacheRecord.h"
#include "nsIGenericFactory.h"
#include "nsString.h"
#include "nsHashtable.h"
#include "nsHashtableEnumerator.h"
#include "nsEnumeratorUtils.h"
PRInt32 nsMemCache::gRecordSerialNumber = 0;
nsMemCache::nsMemCache()
: mNumEntries(0), mOccupancy(0), mEnabled(PR_TRUE),
mHashTable(0)
{
NS_INIT_REFCNT();
}
nsMemCache::~nsMemCache()
{
nsresult rv;
rv = RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv) && (mNumEntries == 0),
"Failure to shut down memory cache. "
"Somewhere, someone is holding references to at least one cache record");
delete mHashTable;
}
nsresult
nsMemCache::Init()
{
mHashTable = new nsHashtable(256);
if (!mHashTable)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsMemCache, NS_GET_IID(nsINetDataCache))
NS_IMETHODIMP
nsMemCache::GetDescription(PRUnichar * *aDescription)
{
nsAutoString description("Memory Cache");
*aDescription = description.ToNewUnicode();
if (!*aDescription)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::Contains(const char *aKey, PRUint32 aKeyLength, PRBool *aFound)
{
nsOpaqueKey *opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
if (!opaqueKey)
return NS_ERROR_OUT_OF_MEMORY;
*aFound = mHashTable->Exists(opaqueKey);
delete opaqueKey;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetCachedNetData(const char *aKey, PRUint32 aKeyLength,
nsINetDataCacheRecord* *aRecord)
{
nsresult rv;
nsMemCacheRecord* record = 0;
nsOpaqueKey *opaqueKey2 = 0;
nsOpaqueKey *opaqueKey3 = 0;
nsOpaqueKey *opaqueKey;
opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
if (!opaqueKey)
goto out_of_memory;
record = (nsMemCacheRecord*)mHashTable->Get(opaqueKey);
delete opaqueKey;
// No existing cache database entry was found. Create a new one.
// This requires two mappings in the hash table:
// Record ID ==> record
// Opaque key ==> record
if (!record) {
record = new nsMemCacheRecord;
if (!record)
goto out_of_memory;
rv = record->Init(aKey, aKeyLength, ++gRecordSerialNumber, this);
if (NS_FAILED(rv)) goto out_of_memory;
// Index the record by opaque key
opaqueKey2 = new nsOpaqueKey(record->mKey, record->mKeyLength);
if (!opaqueKey2) goto out_of_memory;
mHashTable->Put(opaqueKey2, record);
// Index the record by it's record ID
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &record->mRecordID);
opaqueKey3 = new nsOpaqueKey(recordIDbytes,
sizeof record->mRecordID);
if (!opaqueKey3) {
// Clean up the first record from the hash table
mHashTable->Remove(opaqueKey);
goto out_of_memory;
}
mHashTable->Put(opaqueKey3, record);
// The hash table holds on to the record
record->AddRef();
delete opaqueKey2;
delete opaqueKey3;
mNumEntries++;
}
record->AddRef();
*aRecord = record;
return NS_OK;
out_of_memory:
delete opaqueKey2;
delete opaqueKey3;
delete record;
return NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP
nsMemCache::GetCachedNetDataByID(PRInt32 RecordID,
nsINetDataCacheRecord* *aRecord)
{
nsOpaqueKey opaqueKey(NS_REINTERPRET_CAST(const char *, &RecordID),
sizeof RecordID);
*aRecord = (nsINetDataCacheRecord*)mHashTable->Get(&opaqueKey);
if (*aRecord) {
NS_ADDREF(*aRecord);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_METHOD
nsMemCache::Delete(nsMemCacheRecord* aRecord)
{
nsMemCacheRecord *removedRecord;
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &aRecord->mRecordID);
nsOpaqueKey opaqueRecordIDKey(recordIDbytes,
sizeof aRecord->mRecordID);
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueRecordIDKey);
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
nsOpaqueKey opaqueKey(aRecord->mKey, aRecord->mKeyLength);
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueKey);
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
aRecord->Release();
mNumEntries--;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetEnabled(PRBool *aEnabled)
{
NS_ENSURE_ARG(aEnabled);
*aEnabled = mEnabled;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::SetEnabled(PRBool aEnabled)
{
mEnabled = aEnabled;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetFlags(PRUint32 *aFlags)
{
NS_ENSURE_ARG(aFlags);
*aFlags = MEMORY_CACHE;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetNumEntries(PRUint32 *aNumEntries)
{
NS_ENSURE_ARG(aNumEntries);
*aNumEntries = mNumEntries;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetMaxEntries(PRUint32 *aMaxEntries)
{
NS_ENSURE_ARG(aMaxEntries);
*aMaxEntries = MEM_CACHE_MAX_ENTRIES;
return NS_OK;
}
static NS_METHOD
HashEntryConverter(nsHashKey *aKey, void *aValue,
void *unused, nsISupports **retval)
{
nsMemCacheRecord *record;
nsOpaqueKey *opaqueKey;
record = (nsMemCacheRecord*)aValue;
opaqueKey = (nsOpaqueKey*)aKey;
// Hash table keys that index cache entries by their record ID
// shouldn't be enumerated.
if ((opaqueKey->GetKeyLength() == sizeof(PRInt32))) {
#ifdef DEBUG
PRInt32 recordID;
record->GetRecordID(&recordID);
NS_ASSERTION(*((PRInt32*)opaqueKey->GetKey()) == recordID,
"Key has incorrect key length");
#endif
return NS_ERROR_FAILURE;
}
NS_IF_ADDREF(record);
*retval = NS_STATIC_CAST(nsISupports*, record);
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::NewCacheEntryIterator(nsISimpleEnumerator* *aIterator)
{
nsCOMPtr<nsIEnumerator> iterator;
NS_ENSURE_ARG(aIterator);
NS_NewHashtableEnumerator(mHashTable, HashEntryConverter,
mHashTable, getter_AddRefs(iterator));
return NS_NewAdapterEnumerator(aIterator, iterator);
}
NS_IMETHODIMP
nsMemCache::GetNextCache(nsINetDataCache* *aNextCache)
{
NS_ENSURE_ARG(aNextCache);
*aNextCache = mNextCache;
NS_ADDREF(*aNextCache);
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::SetNextCache(nsINetDataCache* aNextCache)
{
mNextCache = aNextCache;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetStorageInUse(PRUint32 *aStorageInUse)
{
NS_ENSURE_ARG(aStorageInUse);
// Convert from bytes to KB
*aStorageInUse = (mOccupancy >> 10);
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::RemoveAll(void)
{
PRBool failed;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsISupports> recordSupports;
nsCOMPtr<nsINetDataCacheRecord> record;
nsresult rv;
failed = PR_FALSE;
rv = NewCacheEntryIterator(getter_AddRefs(iterator));
if (NS_FAILED(rv))
return rv;
PRBool notDone;
while (1) {
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
iterator->GetNext(getter_AddRefs(recordSupports));
record = do_QueryInterface(recordSupports);
recordSupports = 0;
PRUint32 bytesUsed;
record->GetStoredContentLength(&bytesUsed);
rv = record->Delete();
if (NS_FAILED(rv)) {
failed = PR_TRUE;
continue;
}
mOccupancy -= bytesUsed;
}
if (failed)
return NS_ERROR_FAILURE;
return NS_OK;
}

View File

@@ -0,0 +1,83 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
/**
* nsMemCache is the implementation of an in-memory network-data
* cache, used to cache the responses to network retrieval commands.
* Each cache entry may contain both content, e.g. GIF image data, and
* associated metadata, e.g. HTTP headers. Each entry is indexed by
* two different keys: a record id number and an opaque key, which is
* created by the cache manager by combining the URI with a "secondary
* key", e.g. HTTP post data.
*/
#ifndef _nsMemCache_h_
#define _nsMemCache_h_
#include "nsINetDataCache.h"
// Maximum number of URIs that may be resident in the cache
#define MEM_CACHE_MAX_ENTRIES 1000
#define MEM_CACHE_SEGMENT_SIZE (1 << 12)
#define MEM_CACHE_MAX_ENTRY_SIZE (1 << 20)
class nsHashtable;
class nsMemCacheRecord;
class nsMemCache : public nsINetDataCache
{
public:
nsMemCache();
virtual ~nsMemCache();
nsresult Init();
// nsISupports methods
NS_DECL_ISUPPORTS
// nsINetDataCache methods
NS_DECL_NSINETDATACACHE
// Factory
static NS_METHOD nsMemCacheConstructor(nsISupports *aOuter, REFNSIID aIID,
void **aResult);
protected:
PRUint32 mNumEntries;
PRUint32 mOccupancy; // Memory used, in bytes
PRBool mEnabled; // If false, bypass mem cache
nsINetDataCache* mNextCache;
// Mapping from either opaque key or record ID to nsMemCacheRecord
nsHashtable* mHashTable;
// Used to assign record ID's
static PRInt32 gRecordSerialNumber;
NS_METHOD Delete(nsMemCacheRecord* aRecord);
friend class nsMemCacheRecord;
friend class nsMemCacheChannel;
};
#endif // _nsMemCache_h_

View File

@@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
// XPCOM Class ID for the network data in-memory cache
#ifndef nsMEMCACHECID_h__
#define nsMEMCACHECID_h__
// {e4710560-7de2-11d3-90cb-0040056a906e}
#define NS_MEM_CACHE_FACTORY_CID \
{ \
0xe4710560, \
0x7de2, \
0x11d3, \
{0x90, 0xcb, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
}
#endif // nsMEMCACHECID_h__

View File

@@ -0,0 +1,462 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsMemCache.h"
#include "nsMemCacheChannel.h"
#include "nsIStreamListener.h"
#include "nsIChannel.h"
#include "nsIStorageStream.h"
#include "nsIOutputStream.h"
#include "nsIServiceManager.h"
#include "nsIEventQueueService.h"
#include "nsNetUtil.h"
#include "nsILoadGroup.h"
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID);
NS_IMPL_ISUPPORTS(nsMemCacheChannel, NS_GET_IID(nsIChannel))
void
nsMemCacheChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
{
mRecord->mCache->mOccupancy += aBytesUsed;
}
/**
* This class acts as an adaptor around a synchronous input stream to add async
* read capabilities. It adds methods for initiating, suspending, resuming and
* cancelling async reads.
*/
class AsyncReadStreamAdaptor : public nsIInputStream {
public:
AsyncReadStreamAdaptor(nsMemCacheChannel* aChannel, nsIInputStream *aSyncStream):
mSyncStream(aSyncStream), mDataAvailCursor(0),
mRemaining(0), mAvailable(0), mChannel(aChannel), mAborted(PR_FALSE), mSuspended(PR_FALSE)
{
NS_INIT_REFCNT();
NS_ADDREF(mChannel);
}
virtual ~AsyncReadStreamAdaptor() {
mChannel->mAsyncReadStream = 0;
NS_RELEASE(mChannel);
}
NS_DECL_ISUPPORTS
nsresult
IsPending(PRBool* aIsPending) {
*aIsPending = (mRemaining != 0) && !mAborted;
return NS_OK;
}
nsresult
Cancel(void) {
mAborted = PR_TRUE;
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_ABORTED, nsnull);
}
nsresult
Suspend(void) { mSuspended = PR_TRUE; return NS_OK; }
nsresult
Resume(void) {
if (!mSuspended)
return NS_ERROR_FAILURE;
mSuspended = PR_FALSE;
return NextListenerEvent();
}
NS_IMETHOD
Available(PRUint32 *aNumBytes) { return mAvailable; }
NS_IMETHOD
Read(char* aBuf, PRUint32 aCount, PRUint32 *aBytesRead) {
if (mAborted)
return NS_ERROR_ABORT;
*aBytesRead = 0;
aCount = PR_MIN(aCount, mAvailable);
nsresult rv = mSyncStream->Read(aBuf, aCount, aBytesRead);
mAvailable -= *aBytesRead;
if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
Fail();
return rv;
}
if (!mSuspended && !mAvailable) {
rv = NextListenerEvent();
if (NS_FAILED(rv)) {
Fail();
return rv;
}
}
return NS_OK;
}
NS_IMETHOD
Close() {
nsresult rv = mSyncStream->Close();
mSyncStream = 0;
mContext = 0;
mStreamListener = 0;
return rv;
}
nsresult
AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports* aContext, nsIStreamListener* aListener) {
nsresult rv;
nsIEventQueue *eventQ;
mContext = aContext;
mStreamListener = aListener;
mRemaining = aReadCount;
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueService, &rv);
if (NS_FAILED(rv)) return rv;
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQ);
if (NS_FAILED(rv)) return rv;
rv = NS_NewAsyncStreamListener(aListener, eventQ,
getter_AddRefs(mStreamListener));
NS_RELEASE(eventQ);
if (NS_FAILED(rv)) return rv;
rv = mStreamListener->OnStartRequest(mChannel, aContext);
if (NS_FAILED(rv)) return rv;
return NextListenerEvent();
}
protected:
nsresult
Fail(void) {
mAborted = PR_TRUE;
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_FAILED, nsnull);
}
nsresult
NextListenerEvent() {
PRUint32 available;
nsresult rv = mSyncStream->Available(&available);
if (NS_FAILED(rv)) return rv;
available -= mAvailable;
available = PR_MIN(available, mRemaining);
if (available) {
PRUint32 size = PR_MIN(available, MEM_CACHE_SEGMENT_SIZE);
rv = mStreamListener->OnDataAvailable(mChannel, mContext, this,
mDataAvailCursor, size);
mDataAvailCursor += size;
mRemaining -= size;
mAvailable += size;
return rv;
} else {
rv = mStreamListener->OnStopRequest(mChannel, mContext, NS_OK, nsnull);
AsyncReadStreamAdaptor* thisAlias = this;
NS_RELEASE(thisAlias);
return rv;
}
}
private:
nsCOMPtr<nsISupports> mContext; // Opaque context passed to AsyncRead()
nsCOMPtr<nsIStreamListener> mStreamListener; // Stream listener that has been proxied
nsCOMPtr<nsIInputStream> mSyncStream; // Underlying synchronous stream that is
// being converted to an async stream
PRUint32 mDataAvailCursor;
PRUint32 mRemaining; // Size of AsyncRead request less bytes for
// consumer OnDataAvailable's that were fired
PRUint32 mAvailable; // Number of bytes for which OnDataAvailable fired
nsMemCacheChannel* mChannel; // Associated memory cache channel, strong link
// but can not use nsCOMPtr
PRBool mAborted; // Abort() has been called
PRBool mSuspended; // Suspend() has been called
};
NS_IMPL_ISUPPORTS(AsyncReadStreamAdaptor, NS_GET_IID(nsIInputStream))
// The only purpose of this output stream wrapper is to adjust the cache's
// overall occupancy as new data flows into the cache entry.
class MemCacheWriteStreamWrapper : public nsIOutputStream {
public:
MemCacheWriteStreamWrapper(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream):
mBaseStream(aBaseStream), mChannel(aChannel)
{
NS_INIT_REFCNT();
NS_ADDREF(mChannel);
}
virtual ~MemCacheWriteStreamWrapper() { NS_RELEASE(mChannel); };
static nsresult
Create(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) {
MemCacheWriteStreamWrapper *wrapper =
new MemCacheWriteStreamWrapper(aChannel, aBaseStream);
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(wrapper);
*aWrapper = wrapper;
return NS_OK;
}
NS_DECL_ISUPPORTS
NS_IMETHOD
Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten) {
*aNumWritten = 0;
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
mChannel->NotifyStorageInUse(*aNumWritten);
return rv;
}
NS_IMETHOD
Flush() { return mBaseStream->Flush(); }
NS_IMETHOD
Close() { return mBaseStream->Close(); }
private:
nsCOMPtr<nsIOutputStream> mBaseStream;
nsMemCacheChannel* mChannel;
};
NS_IMPL_ISUPPORTS(MemCacheWriteStreamWrapper, NS_GET_IID(nsIOutputStream))
nsMemCacheChannel::nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup)
: mRecord(aRecord)
{
NS_INIT_REFCNT();
mRecord->mNumChannels++;
}
nsMemCacheChannel::~nsMemCacheChannel()
{
mRecord->mNumChannels--;
}
NS_IMETHODIMP
nsMemCacheChannel::IsPending(PRBool* aIsPending)
{
*aIsPending = PR_FALSE;
if (!mAsyncReadStream)
return NS_OK;
return mAsyncReadStream->IsPending(aIsPending);
}
NS_IMETHODIMP
nsMemCacheChannel::Cancel(void)
{
if (!mAsyncReadStream)
return NS_ERROR_FAILURE;
return mAsyncReadStream->Cancel();
}
NS_IMETHODIMP
nsMemCacheChannel::Suspend(void)
{
if (!mAsyncReadStream)
return NS_ERROR_FAILURE;
return mAsyncReadStream->Suspend();
}
NS_IMETHODIMP
nsMemCacheChannel::Resume(void)
{
if (!mAsyncReadStream)
return NS_ERROR_FAILURE;
return mAsyncReadStream->Resume();
}
NS_IMETHODIMP
nsMemCacheChannel::GetOriginalURI(nsIURI * *aURI)
{
// Not required
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetURI(nsIURI * *aURI)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
nsIInputStream* *aResult)
{
nsresult rv;
NS_ENSURE_ARG(aResult);
if (mInputStream)
return NS_ERROR_NOT_AVAILABLE;
rv = mRecord->mStorageStream->NewInputStream(aStartPosition, getter_AddRefs(mInputStream));
*aResult = mInputStream;
NS_ADDREF(*aResult);
return rv;
}
NS_IMETHODIMP
nsMemCacheChannel::OpenOutputStream(PRUint32 startPosition, nsIOutputStream* *aResult)
{
nsresult rv;
NS_ENSURE_ARG(aResult);
nsCOMPtr<nsIOutputStream> outputStream;
PRUint32 oldLength;
mRecord->mStorageStream->GetLength(&oldLength);
rv = mRecord->mStorageStream->GetOutputStream(startPosition, getter_AddRefs(outputStream));
if (NS_FAILED(rv)) return rv;
if (startPosition < oldLength)
NotifyStorageInUse(startPosition - oldLength);
return MemCacheWriteStreamWrapper::Create(this, outputStream, aResult);
}
NS_IMETHODIMP
nsMemCacheChannel::AsyncOpen(nsIStreamObserver *observer, nsISupports *ctxt)
{
// Not required
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports *aContext, nsIStreamListener *aListener)
{
nsCOMPtr<nsIInputStream> inputStream;
nsresult rv = OpenInputStream(aStartPosition, aReadCount, getter_AddRefs(inputStream));
if (NS_FAILED(rv)) return rv;
AsyncReadStreamAdaptor *asyncReadStreamAdaptor;
asyncReadStreamAdaptor = new AsyncReadStreamAdaptor(this, inputStream);
if (!asyncReadStreamAdaptor)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(asyncReadStreamAdaptor);
mAsyncReadStream = asyncReadStreamAdaptor;
rv = asyncReadStreamAdaptor->AsyncRead(aStartPosition, aReadCount, aContext, aListener);
if (NS_FAILED(rv))
delete asyncReadStreamAdaptor;
return rv;
}
NS_IMETHODIMP
nsMemCacheChannel::AsyncWrite(nsIInputStream *fromStream, PRUint32 startPosition,
PRInt32 writeCount, nsISupports *ctxt,
nsIStreamObserver *observer)
{
// Not required to be implemented
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetContentType(char* *aContentType)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetContentLength(PRInt32 *aContentLength)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetOwner(nsISupports* *aOwner)
{
*aOwner = mOwner.get();
NS_IF_ADDREF(*aOwner);
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheChannel::SetOwner(nsISupports* aOwner)
{
// Not required to be implemented, since it is implemented by cache manager
mOwner = aOwner;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#ifndef _nsMemCacheChannel_h_
#define _nsMemCacheChannel_h_
#include "nsMemCacheRecord.h"
#include "nsIChannel.h"
#include "nsIInputStream.h"
#include "nsCOMPtr.h"
class AsyncReadStreamAdaptor;
class nsMemCacheChannel : public nsIChannel
{
public:
// Constructors and Destructor
nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
virtual ~nsMemCacheChannel();
// Declare nsISupports methods
NS_DECL_ISUPPORTS
// Declare nsIRequest methods
NS_DECL_NSIREQUEST
// Declare nsIChannel methods
NS_DECL_NSICHANNEL
protected:
void NotifyStorageInUse(PRInt32 aBytesUsed);
nsCOMPtr<nsMemCacheRecord> mRecord;
nsCOMPtr<nsIInputStream> mInputStream;
nsCOMPtr<nsISupports> mOwner;
AsyncReadStreamAdaptor* mAsyncReadStream; // non-owning pointer
friend class MemCacheWriteStreamWrapper;
friend class AsyncReadStreamAdaptor;
};
#endif // _nsMemCacheChannel_h_

View File

@@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsMemCache.h"
#include "nsMemCacheRecord.h"
#include "nsMemCacheChannel.h"
#include "nsIAllocator.h"
#include "nsStorageStream.h"
static NS_DEFINE_IID(kINetDataCacheRecord, NS_INETDATACACHERECORD_IID);
nsMemCacheRecord::nsMemCacheRecord()
: mKey(0), mKeyLength(0), mMetaData(0), mMetaDataLength(0), mNumChannels(0)
{
NS_INIT_REFCNT();
}
nsMemCacheRecord::~nsMemCacheRecord()
{
if (mMetaData)
delete[] mMetaData;
if (mKey)
delete[] mKey;
}
NS_IMPL_ISUPPORTS(nsMemCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
NS_IMETHODIMP
nsMemCacheRecord::GetKey(PRUint32 *aLength, char **aResult)
{
NS_ENSURE_ARG(aResult);
*aResult = (char *)nsAllocator::Alloc(mKeyLength);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(*aResult, mKey, mKeyLength);
*aLength = mKeyLength;
return NS_OK;
}
nsresult
nsMemCacheRecord::Init(const char *aKey, PRUint32 aKeyLength,
PRUint32 aRecordID, nsMemCache *aCache)
{
nsresult rv;
NS_ASSERTION(!mKey, "Memory cache record key set multiple times");
rv = NS_NewStorageStream(MEM_CACHE_SEGMENT_SIZE, MEM_CACHE_MAX_ENTRY_SIZE,
getter_AddRefs(mStorageStream));
if (NS_FAILED(rv)) return rv;
mKey = new char[aKeyLength];
if (!mKey)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(mKey, aKey, aKeyLength);
mKeyLength = aKeyLength;
mRecordID = aRecordID;
mCache = aCache;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::GetRecordID(PRInt32 *aRecordID)
{
NS_ENSURE_ARG(aRecordID);
*aRecordID = mRecordID;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::GetMetaData(PRUint32 *aLength, char **aResult)
{
NS_ENSURE_ARG(aResult);
*aResult = 0;
if (mMetaDataLength) {
*aResult = (char*)nsAllocator::Alloc(mMetaDataLength);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(*aResult, mMetaData, mMetaDataLength);
}
*aLength = mMetaDataLength;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::SetMetaData(PRUint32 aLength, const char *aData)
{
if (mMetaData)
delete[] mMetaData;
mMetaData = new char[aLength];
if (!mMetaData)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(mMetaData, aData, aLength);
mMetaDataLength = aLength;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
{
NS_ENSURE_ARG(aStoredContentLength);
return mStorageStream->GetLength(aStoredContentLength);
}
NS_IMETHODIMP
nsMemCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
{
PRUint32 before, after;
mStorageStream->GetLength(&before);
nsresult rv = mStorageStream->SetLength(aStoredContentLength);
if (NS_FAILED(rv)) return rv;
mStorageStream->GetLength(&after);
mCache->mOccupancy -= (before - after);
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::Delete(void)
{
if (mNumChannels)
return NS_ERROR_NOT_AVAILABLE;
return mCache->Delete(this);
}
NS_IMETHODIMP
nsMemCacheRecord::GetFilename(nsIFileSpec* *aFilename)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheRecord::NewChannel(nsILoadGroup *aLoadGroup, nsIChannel* *aResult)
{
NS_ENSURE_ARG(aResult);
nsMemCacheChannel* channel = new nsMemCacheChannel(this, aLoadGroup);
if (!channel)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(channel);
*aResult = NS_STATIC_CAST(nsIChannel*, channel);
return NS_OK;
}

View File

@@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#ifndef _nsMemCacheRecord_h_
#define _nsMemCacheRecord_h_
#include "nsINetDataCacheRecord.h"
#include "nsIStorageStream.h"
#include "nsCOMPtr.h"
class nsMemCache;
class nsMemCacheRecord : public nsINetDataCacheRecord
{
public:
// Declare interface methods
NS_DECL_ISUPPORTS
NS_DECL_NSINETDATACACHERECORD
protected:
// Constructors and Destructor
nsMemCacheRecord();
virtual ~nsMemCacheRecord();
nsresult Init(const char *aKey, PRUint32 aKeyLength,
PRUint32 aRecordID, nsMemCache *aCache);
char* mKey; // opaque database key for this record
PRUint32 mKeyLength; // length, in bytes, of mKey
PRInt32 mRecordID; // An alternate key for this record
char* mMetaData; // opaque URI metadata
PRUint32 mMetaDataLength; // length, in bytes, of mMetaData
nsMemCache* mCache; // weak pointer to the cache database
// that this record inhabits
nsCOMPtr<nsIStorageStream> mStorageStream;
PRUint32 mNumChannels; // Count un-Release'ed nsIChannels
friend class nsMemCache;
friend class nsMemCacheChannel;
};
#endif // _nsMemCacheRecord_h_

55
mozilla/netwerk/cache/mgr/Makefile.in vendored Normal file
View File

@@ -0,0 +1,55 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = nkcache
LIBRARY_NAME = nkcachemgr_s
REQUIRES = nspr
EXPORTS = \
nsCacheManager.h \
$(NULL)
CPPSRCS = \
nsCacheManager.cpp \
nsCachedNetData.cpp \
nsReplacementPolicy.cpp \
nsCacheEntryChannel.cpp \
$(NULL)
LOCAL_INCLUDES = -I$(srcdir)/../public -I$(srcdir)/../include
EXTRA_LIBS = $(NSPR_LIBS)
# we don't want the shared lib, but we want to force the creation of a
# static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk

45
mozilla/netwerk/cache/mgr/Makefile.win vendored Executable file
View File

@@ -0,0 +1,45 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH=..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = nkcache
LIBRARY_NAME = nkcachemgr_s
CPP_OBJS = \
.\$(OBJDIR)\nsCacheManager.obj \
.\$(OBJDIR)\nsCachedNetData.obj \
.\$(OBJDIR)\nsReplacementPolicy.obj \
.\$(OBJDIR)\nsCacheEntryChannel.obj \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -rf $(OBJDIR)
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,261 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsCacheManager.h"
#include "nsCacheEntryChannel.h"
#include "nsIOutputStream.h"
#include "nsIIOService.h"
#include "nsIServiceManager.h"
#include "nsIStreamListener.h"
nsCacheEntryChannel::nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup):
nsChannelProxy(aChannel), mCacheEntry(aCacheEntry), mLoadGroup(aLoadGroup), mLoadAttributes(0)
{
NS_ASSERTION(aCacheEntry->mChannelCount < 0xFF, "Overflowed channel counter");
mCacheEntry->mChannelCount++;
NS_INIT_REFCNT();
}
nsCacheEntryChannel::~nsCacheEntryChannel()
{
mCacheEntry->mChannelCount--;
}
NS_IMPL_ISUPPORTS3(nsCacheEntryChannel, nsISupports, nsIChannel, nsIRequest)
// A proxy for nsIOutputStream
class CacheOutputStream : public nsIOutputStream {
public:
CacheOutputStream(nsIOutputStream *aOutputStream, nsCachedNetData *aCacheEntry):
mOutputStream(aOutputStream), mCacheEntry(aCacheEntry), mStartTime(PR_Now())
{ NS_INIT_REFCNT(); }
virtual ~CacheOutputStream() {
mCacheEntry->NoteDownloadTime(mStartTime, PR_Now());
mCacheEntry->ClearFlag(nsCachedNetData::UPDATE_IN_PROGRESS);
}
NS_DECL_ISUPPORTS
NS_IMETHOD Close() {
return mOutputStream->Close();
}
NS_IMETHOD Flush() { return mOutputStream->Flush(); }
NS_IMETHOD
Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes) {
nsresult rv;
*aActualBytes = 0;
rv = mOutputStream->Write(aBuf, aCount, aActualBytes);
mCacheEntry->mLogicalLength += *aActualBytes;
if (NS_FAILED(rv)) return rv;
nsCacheManager::LimitCacheSize();
return rv;
}
protected:
nsCOMPtr<nsIOutputStream> mOutputStream;
nsCOMPtr<nsCachedNetData> mCacheEntry;
// Time at which stream was opened
PRTime mStartTime;
};
NS_IMPL_ISUPPORTS(CacheOutputStream, NS_GET_IID(nsIOutputStream))
NS_IMETHODIMP
nsCacheEntryChannel::OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream)
{
nsresult rv;
nsCOMPtr<nsIOutputStream> baseOutputStream;
rv = mChannel->OpenOutputStream(aStartPosition, getter_AddRefs(baseOutputStream));
if (NS_FAILED(rv)) return rv;
mCacheEntry->NoteUpdate();
mCacheEntry->NoteAccess();
mCacheEntry->mLogicalLength = aStartPosition;
*aOutputStream = new CacheOutputStream(baseOutputStream, mCacheEntry);
if (!*aOutputStream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aOutputStream);
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
nsIInputStream* *aInputStream)
{
mCacheEntry->NoteAccess();
return mChannel->OpenInputStream(aStartPosition, aReadCount, aInputStream);
}
class CacheManagerStreamListener: public nsIStreamListener {
public:
CacheManagerStreamListener(nsIStreamListener *aListener,
nsILoadGroup *aLoadGroup, nsIChannel *aChannel):
mListener(aListener), mLoadGroup(aLoadGroup), mChannel(aChannel)
{ NS_INIT_REFCNT(); }
virtual ~CacheManagerStreamListener() {}
private:
NS_DECL_ISUPPORTS
NS_IMETHOD
OnDataAvailable(nsIChannel *channel, nsISupports *aContext,
nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) {
return mListener->OnDataAvailable(mChannel, aContext, inStr, sourceOffset, count);
}
NS_IMETHOD
OnStartRequest(nsIChannel *channel, nsISupports *aContext) {
if (mLoadGroup)
mLoadGroup->AddChannel(mChannel, aContext);
return mListener->OnStartRequest(mChannel, aContext);
}
NS_IMETHOD
OnStopRequest(nsIChannel *channel, nsISupports *aContext,
nsresult status, const PRUnichar *errorMsg) {
nsresult rv;
rv = mListener->OnStopRequest(mChannel, aContext, status, errorMsg);
if (mLoadGroup)
mLoadGroup->RemoveChannel(mChannel, aContext, status, errorMsg);
return rv;
}
private:
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsIChannel> mChannel;
};
NS_IMPL_ISUPPORTS2(CacheManagerStreamListener, nsIStreamListener, nsIStreamObserver)
NS_IMETHODIMP
nsCacheEntryChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports *aContext, nsIStreamListener *aListener)
{
nsresult rv;
mCacheEntry->NoteAccess();
nsCOMPtr<nsIStreamListener> headListener;
if (mLoadGroup) {
mLoadGroup->GetDefaultLoadAttributes(&mLoadAttributes);
// Create a load group "proxy" listener...
nsCOMPtr<nsILoadGroupListenerFactory> factory;
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (NS_SUCCEEDED(rv) && factory) {
rv = factory->CreateLoadGroupListener(aListener,
getter_AddRefs(headListener));
if (NS_FAILED(rv)) return rv;
}
} else {
headListener = aListener;
}
CacheManagerStreamListener* cacheManagerStreamListener;
nsIChannel *channelForListener;
channelForListener = mProxyChannel ? mProxyChannel.get() : NS_STATIC_CAST(nsIChannel*, this);
cacheManagerStreamListener =
new CacheManagerStreamListener(headListener, mLoadGroup, channelForListener);
if (!cacheManagerStreamListener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(cacheManagerStreamListener);
rv = mChannel->AsyncRead(aStartPosition, aReadCount, aContext,
cacheManagerStreamListener);
NS_RELEASE(cacheManagerStreamListener);
return rv;
}
// No async writes allowed to the cache yet
NS_IMETHODIMP
nsCacheEntryChannel::AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
PRInt32 aWriteCount, nsISupports *aContext,
nsIStreamObserver *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCacheEntryChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
*aLoadGroup = mLoadGroup;
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
*aLoadAttributes = mLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
mLoadAttributes = aLoadAttributes;
return NS_OK;
}
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
NS_IMETHODIMP
nsCacheEntryChannel::GetURI(nsIURI * *aURI)
{
char* spec;
nsresult rv;
rv = mCacheEntry->GetUriSpec(&spec);
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = serv->NewURI(spec, 0, aURI);
nsAllocator::Free(spec);
return rv;
}
NS_IMETHODIMP
nsCacheEntryChannel::GetOriginalURI(nsIURI * *aURI)
{
// FIXME - should return original URI passed into NewChannel() ?
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#ifndef _nsCacheEntryChannel_h_
#define _nsCacheEntryChannel_h_
#include "nsCOMPtr.h"
#include "nsIChannel.h"
#include "nsCachedNetData.h"
#include "nsILoadGroup.h"
class nsIStreamListener;
// A proxy for an nsIChannel, useful when only a few nsIChannel
// methods must be overridden
class nsChannelProxy : public nsIChannel {
public:
NS_FORWARD_NSICHANNEL(mChannel->)
NS_FORWARD_NSIREQUEST(mChannel->)
protected:
nsChannelProxy(nsIChannel* aChannel):mChannel(aChannel) {};
virtual ~nsChannelProxy() {};
nsCOMPtr<nsIChannel> mChannel;
};
// Override several nsIChannel methods so that they interact with the cache manager
class nsCacheEntryChannel : public nsChannelProxy {
public:
NS_DECL_ISUPPORTS
NS_IMETHOD OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream);
NS_IMETHOD OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
nsIInputStream* *aInputStream);
NS_IMETHOD AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports *aContext, nsIStreamListener *aListener);
NS_IMETHOD AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
PRInt32 aWriteCount, nsISupports *aContext,
nsIStreamObserver *aObserver);
NS_IMETHOD GetLoadAttributes(nsLoadFlags *aLoadAttributes);
NS_IMETHOD SetLoadAttributes(nsLoadFlags aLoadAttributes);
NS_IMETHOD GetLoadGroup(nsILoadGroup* *aLoadGroup);
NS_IMETHOD GetURI(nsIURI * *aURI);
NS_IMETHOD GetOriginalURI(nsIURI * *aURI);
protected:
nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
virtual ~nsCacheEntryChannel();
friend class nsCachedNetData;
private:
nsCOMPtr<nsCachedNetData> mCacheEntry;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsIChannel> mProxyChannel;
nsLoadFlags mLoadAttributes;
};
#endif // _nsCacheEntryChannel_h_

View File

@@ -0,0 +1,497 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsINetDataCache.h"
#include "nsCacheManager.h"
#include "nsCachedNetData.h"
#include "nsReplacementPolicy.h"
#include "nsString.h"
#include "nsIURI.h"
#include "nsHashtable.h"
#include "nsIComponentManager.h"
#include "nsINetDataDiskCache.h"
// Limit the number of entries in the cache to conserve memory space
// in the nsReplacementPolicy code
#define MAX_MEM_CACHE_ENTRIES 800
#define MAX_DISK_CACHE_ENTRIES 3200
// Cache capacities in MB, overridable via APIs
#define DEFAULT_MEMORY_CACHE_CAPACITY 1024
#define DEFAULT_DISK_CACHE_CAPACITY 10000
#define CACHE_HIGH_WATER_MARK(capacity) ((PRUint32)(0.98 * (capacity)))
#define CACHE_LOW_WATER_MARK(capacity) ((PRUint32)(0.97 * (capacity)))
nsCacheManager* gCacheManager = 0;
NS_IMPL_ISUPPORTS(nsCacheManager, NS_GET_IID(nsINetDataCacheManager))
nsCacheManager::nsCacheManager()
: mActiveCacheRecords(0),
mDiskCacheCapacity(DEFAULT_DISK_CACHE_CAPACITY),
mMemCacheCapacity(DEFAULT_MEMORY_CACHE_CAPACITY)
{
NS_ASSERTION(!gCacheManager, "Multiple cache managers created");
gCacheManager = this;
NS_INIT_REFCNT();
}
nsCacheManager::~nsCacheManager()
{
gCacheManager = 0;
delete mActiveCacheRecords;
delete mMemSpaceManager;
delete mDiskSpaceManager;
}
nsresult
nsCacheManager::Init()
{
nsresult rv;
mActiveCacheRecords = new nsHashtable(64);
if (!mActiveCacheRecords)
return NS_ERROR_OUT_OF_MEMORY;
// Instantiate the memory cache component
rv = nsComponentManager::CreateInstance(NS_NETWORK_MEMORY_CACHE_PROGID,
nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(mMemCache));
if (NS_FAILED(rv))
return rv;
rv = nsComponentManager::CreateInstance(NS_NETWORK_FLAT_CACHE_PROGID,
nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(mFlatCache));
if (NS_FAILED(rv)) {
// For now, we don't require a flat cache module to be present
if (rv != NS_ERROR_FACTORY_NOT_REGISTERED)
return rv;
}
#ifdef FILE_CACHE_IS_READY
// Instantiate the file cache component
rv = nsComponentManager::CreateInstance(NS_NETWORK_FILE_CACHE_PROGID,
nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(mFileCache));
if (NS_FAILED(rv)) {
NS_WARNING("No disk cache present");
}
#endif
// Set up linked list of caches in search order
mCacheSearchChain = mMemCache;
if (mFlatCache) {
mMemCache->SetNextCache(mFlatCache);
mFlatCache->SetNextCache(mFileCache);
} else {
mMemCache->SetNextCache(mFileCache);
}
// TODO - Load any extension caches here
// Initialize replacement policy for memory cache module
mMemSpaceManager = new nsReplacementPolicy;
if (!mMemSpaceManager)
return NS_ERROR_OUT_OF_MEMORY;
rv = mMemSpaceManager->Init(MAX_MEM_CACHE_ENTRIES);
if (NS_FAILED(rv)) return rv;
rv = mMemSpaceManager->AddCache(mMemCache);
// Initialize replacement policy for disk cache modules (file
// cache and flat cache)
mDiskSpaceManager = new nsReplacementPolicy;
if (!mDiskSpaceManager)
return NS_ERROR_OUT_OF_MEMORY;
rv = mDiskSpaceManager->Init(MAX_DISK_CACHE_ENTRIES);
if (NS_FAILED(rv)) return rv;
if (mFileCache) {
rv = mDiskSpaceManager->AddCache(mFileCache);
if (NS_FAILED(rv)) return rv;
}
if (mFlatCache) {
rv = mDiskSpaceManager->AddCache(mFlatCache);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::GetCachedNetData(const char *aUriSpec, const char *aSecondaryKey,
PRUint32 aSecondaryKeyLength,
PRUint32 aFlags, nsICachedNetData* *aResult)
{
nsCachedNetData *cachedData;
nsresult rv;
nsINetDataCache *cache;
nsReplacementPolicy *spaceManager;
if (aFlags & CACHE_AS_FILE) {
cache = mFileCache;
spaceManager = mDiskSpaceManager;
// Ensure that cache is initialized
if (mDiskCacheCapacity == (PRUint32)-1)
return NS_ERROR_NOT_AVAILABLE;
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
cache = mMemCache;
spaceManager = mMemSpaceManager;
} else {
cache = mFlatCache ? mFlatCache : mFileCache;
spaceManager = mDiskSpaceManager;
}
// Construct the cache key by appending the secondary key to the URI spec
nsCAutoString cacheKey(aUriSpec);
// Insert NUL at end of URI spec
cacheKey += '\0';
if (aSecondaryKey)
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
nsStringKey key(cacheKey);
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
// There is no existing instance of nsCachedNetData for this URL.
// Make one from the corresponding record in the cache module.
if (cachedData) {
NS_ASSERTION(cache == cachedData->mCache,
"Cannot yet handle simultaneously active requests for the "
"same URL using different caches");
NS_ADDREF(cachedData);
} else {
rv = spaceManager->GetCachedNetData(cacheKey.GetBuffer(), cacheKey.Length(),
cache, &cachedData);
if (NS_FAILED(rv)) return rv;
mActiveCacheRecords->Put(&key, cachedData);
}
*aResult = cachedData;
return NS_OK;
}
// Remove this cache entry from the list of active ones
nsresult
nsCacheManager::NoteDormant(nsCachedNetData* aEntry)
{
nsresult rv;
PRUint32 keyLength;
char* key;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCachedNetData* deletedEntry;
rv = aEntry->GetRecord(getter_AddRefs(record));
if (NS_FAILED(rv)) return rv;
rv = record->GetKey(&keyLength, &key);
if (NS_FAILED(rv)) return rv;
nsStringKey hashTableKey(nsCString(key, keyLength));
deletedEntry = (nsCachedNetData*)gCacheManager->mActiveCacheRecords->Remove(&hashTableKey);
// NS_ASSERTION(deletedEntry == aEntry, "Hash table inconsistency");
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::Contains(const char *aUriSpec, const char *aSecondaryKey,
PRUint32 aSecondaryKeyLength,
PRUint32 aFlags, PRBool *aResult)
{
nsINetDataCache *cache;
nsReplacementPolicy *spaceManager;
nsCachedNetData *cachedData;
if (aFlags & CACHE_AS_FILE) {
cache = mFileCache;
spaceManager = mDiskSpaceManager;
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
cache = mMemCache;
spaceManager = mMemSpaceManager;
} else {
cache = mFlatCache ? mFlatCache : mFileCache;
spaceManager = mDiskSpaceManager;
}
// Construct the cache key by appending the secondary key to the URI spec
nsCAutoString cacheKey(aUriSpec);
// Insert NUL between URI spec and secondary key
cacheKey += '\0';
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
// Locate the record using (URI + secondary key)
nsStringKey key(cacheKey);
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
if (cachedData && (cache == cachedData->mCache)) {
*aResult = PR_TRUE;
return NS_OK;
} else {
// No active cache entry, see if there is a dormant one
return cache->Contains(cacheKey.GetBuffer(), cacheKey.Length(), aResult);
}
}
NS_IMETHODIMP
nsCacheManager::GetNumEntries(PRUint32 *aNumEntries)
{
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsISupports> cacheSupports;
nsCOMPtr<nsINetDataCache> cache;
PRUint32 totalEntries = 0;
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
if (NS_FAILED(rv)) return rv;
while (1) {
PRBool notDone;
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
iterator->GetNext(getter_AddRefs(cacheSupports));
cache = do_QueryInterface(cacheSupports);
PRUint32 numEntries;
rv = cache->GetNumEntries(&numEntries);
if (NS_FAILED(rv)) return rv;
totalEntries += numEntries;
}
*aNumEntries = totalEntries;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::NewCacheEntryIterator(nsISimpleEnumerator* *aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
class CacheEnumerator : public nsISimpleEnumerator
{
public:
CacheEnumerator(nsINetDataCache* aFirstCache):mCache(aFirstCache)
{ NS_INIT_REFCNT(); }
virtual ~CacheEnumerator() {};
NS_DECL_ISUPPORTS
NS_IMETHODIMP
HasMoreElements(PRBool* aMoreElements) {
*aMoreElements = (mCache != 0);
return NS_OK;
}
NS_IMETHODIMP
GetNext(nsISupports* *aSupports) {
*aSupports = mCache;
if (!mCache)
return NS_ERROR_FAILURE;
NS_ADDREF(*aSupports);
nsCOMPtr<nsINetDataCache> nextCache;
nsresult rv = mCache->GetNextCache(getter_AddRefs(nextCache));
mCache = nextCache;
return rv;
}
private:
nsCOMPtr<nsINetDataCache> mCache;
};
NS_IMPL_ISUPPORTS(CacheEnumerator, NS_GET_IID(nsISimpleEnumerator))
NS_IMETHODIMP
nsCacheManager::NewCacheModuleIterator(nsISimpleEnumerator* *aResult)
{
*aResult = new CacheEnumerator(mCacheSearchChain);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::RemoveAll(void)
{
nsresult rv, result;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsINetDataCache> cache;
nsCOMPtr<nsISupports> iSupports;
result = NS_OK;
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
if (NS_FAILED(rv)) return rv;
while (1) {
PRBool notDone;
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
iterator->GetNext(getter_AddRefs(iSupports));
cache = do_QueryInterface(iSupports);
PRUint32 cacheFlags;
rv = cache->GetFlags(&cacheFlags);
if (NS_FAILED(rv)) return rv;
if ((cacheFlags & nsINetDataCache::READ_ONLY) == 0) {
rv = cache->RemoveAll();
if (NS_FAILED(rv))
result = rv;
}
}
return result;
}
nsresult
nsCacheManager::LimitMemCacheSize()
{
nsresult rv;
nsReplacementPolicy* spaceManager;
NS_ASSERTION(gCacheManager, "No cache manager");
spaceManager = gCacheManager->mMemSpaceManager;
PRUint32 occupancy;
rv = spaceManager->GetStorageInUse(&occupancy);
if (NS_FAILED(rv)) return rv;
PRUint32 memCacheCapacity = gCacheManager->mMemCacheCapacity;
if (occupancy > CACHE_HIGH_WATER_MARK(memCacheCapacity))
return spaceManager->Evict(CACHE_LOW_WATER_MARK(memCacheCapacity));
return NS_OK;
}
nsresult
nsCacheManager::LimitDiskCacheSize()
{
nsresult rv;
nsReplacementPolicy* spaceManager;
NS_ASSERTION(gCacheManager, "No cache manager");
spaceManager = gCacheManager->mDiskSpaceManager;
PRUint32 occupancy;
rv = spaceManager->GetStorageInUse(&occupancy);
if (NS_FAILED(rv)) return rv;
PRUint32 diskCacheCapacity = gCacheManager->mDiskCacheCapacity;
if (occupancy > CACHE_HIGH_WATER_MARK(diskCacheCapacity))
return spaceManager->Evict(CACHE_LOW_WATER_MARK(diskCacheCapacity));
return NS_OK;
}
nsresult
nsCacheManager::LimitCacheSize()
{
nsresult rv;
rv = LimitDiskCacheSize();
if (NS_FAILED(rv)) return rv;
rv = LimitMemCacheSize();
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::SetMemCacheCapacity(PRUint32 aCapacity)
{
mMemCacheCapacity = aCapacity;
LimitCacheSize();
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::GetMemCacheCapacity(PRUint32* aCapacity)
{
NS_ENSURE_ARG_POINTER(aCapacity);
*aCapacity = mMemCacheCapacity;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::SetDiskCacheCapacity(PRUint32 aCapacity)
{
mDiskCacheCapacity = aCapacity;
LimitCacheSize();
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::GetDiskCacheCapacity(PRUint32* aCapacity)
{
NS_ENSURE_ARG_POINTER(aCapacity);
*aCapacity = mDiskCacheCapacity;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::SetDiskCacheFolder(nsIFileSpec* aFolder)
{
NS_ENSURE_ARG(aFolder);
if (!mFileCache)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsINetDataDiskCache> fileCache;
fileCache = do_QueryInterface(mFileCache);
return fileCache->SetDiskCacheFolder(aFolder);
}
NS_IMETHODIMP
nsCacheManager::GetDiskCacheFolder(nsIFileSpec* *aFolder)
{
NS_ENSURE_ARG(aFolder);
if (!mFileCache)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsINetDataDiskCache> fileCache;
fileCache = do_QueryInterface(mFileCache);
return fileCache->GetDiskCacheFolder(aFolder);
}

View File

@@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#ifndef _nsCacheManager_h_
#define _nsCacheManager_h_
// 2030f0b0-9567-11d3-90d3-0040056a906e
#define NS_CACHE_MANAGER_CID \
{ \
0x2030f0b0, \
0x9567, \
0x11d3, \
{0x90, 0xd3, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
}
#include "nsINetDataCacheManager.h"
#include "nsINetDataCache.h"
#include "nsCOMPtr.h"
class nsHashtable;
class nsReplacementPolicy;
class nsCachedNetData;
class nsCacheManager : public nsINetDataCacheManager {
public:
nsCacheManager();
virtual ~nsCacheManager();
NS_METHOD Init();
// nsISupports methods
NS_DECL_ISUPPORTS
// nsINetDataCacheManager methods
NS_DECL_NSINETDATACACHEMANAGER
private:
// Mapping from cache key to nsCachedNetData, but only for those cache
// entries with external references, i.e. those referred to outside the
// cache manager
nsHashtable* mActiveCacheRecords;
// Memory cache
nsCOMPtr<nsINetDataCache> mMemCache;
// Flat-file database cache; All content aggregated into single disk file
nsCOMPtr<nsINetDataCache> mFlatCache;
// stream-as-file cache
nsCOMPtr<nsINetDataCache> mFileCache;
// Unified replacement policy for flat-cache and file-cache
nsReplacementPolicy* mDiskSpaceManager;
// Replacement policy for memory cache
nsReplacementPolicy* mMemSpaceManager;
// List of caches in search order
nsINetDataCache* mCacheSearchChain;
// Combined file/flat cache capacity, in KB
PRUint32 mDiskCacheCapacity;
// Memory cache capacity, in KB
PRUint32 mMemCacheCapacity;
protected:
static nsresult NoteDormant(nsCachedNetData* aEntry);
static nsresult LimitCacheSize();
static nsresult LimitMemCacheSize();
static nsresult LimitDiskCacheSize();
friend class nsCachedNetData;
friend class CacheOutputStream;
};
#endif // _nsCacheManager_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,242 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#ifndef _nsCachedNetData_h_
#define _nsCachedNetData_h_
#include "nsICachedNetData.h"
#include "nsCOMPtr.h"
#include "nsINetDataCacheRecord.h"
class nsINetDataCache;
class nsIStreamAsFileObserver;
class nsIStreamAsFile;
class nsIArena;
class StreamAsFileObserverClosure;
class CacheMetaData;
// Number of recent access times recorded
#define MAX_K 3
/**
* FIXME - add comment. There are a lot of these data structures resident in
* memory, so be careful about adding members unnecessarily.
*/
class nsCachedNetData : public nsICachedNetData {
public:
NS_DECL_ISUPPORTS
// nsICachedNetData methods
NS_DECL_NSICACHEDNETDATA
NS_METHOD Init(nsINetDataCacheRecord *aRecord, nsINetDataCache *aCache);
protected:
// Bits for mFlags, below
typedef enum {
DIRTY = 1 << 0, // Cache entry data needs to be flushed to database
// ==== Flags that can be set by the protocol handler ====
ALLOW_PARTIAL = 1 << 1, // Protocol handler supports partial fetching
UPDATE_IN_PROGRESS = 1 << 2, // Protocol handler now modifying cache data
// ==== Cache-entry state flags. At most one of these flags can be set ====
TRUNCATED_CONTENT = 1 << 4, // Entry contains valid content, but it has
// been truncated by cache manager
// A previously-used cache entry, which has been purged of all cached
// content and protocol-private data. This cache entry can be refilled
// with new content or it may be retained in this vestigial state
// because the usage statistics it contains will be used by the
// replacement policy if the same URI is ever cached again.
VESTIGIAL = 1 << 5,
// ==== Memory usage status bits. At most one of these flags can be set ====
RECYCLED = 1 << 8, // Previously associated database record has
// been deleted; This cache entry is available
// for recycling.
DORMANT = 1 << 9, // No references to this cache entry, except by
// the cache manager itself
// ==== Setter bits ====
LAST_MODIFIED_KNOWN = 1 <<12, // Protocol handler called SetLastModifiedTime()
EXPIRATION_KNOWN = 1 <<13, // Protocol handler called SetExpirationTime()
STALE_TIME_KNOWN = 1 <<14, // Protocol handler called SetStaleTime()
// ==== Useful flag combinations ====
// Cache entry not eligible for eviction
UNEVICTABLE = VESTIGIAL | RECYCLED | UPDATE_IN_PROGRESS,
// State flags that are in-memory only, i.e. not persistent
TRANSIENT_FLAGS = DIRTY | RECYCLED | DORMANT
} Flag;
PRBool GetFlag(Flag aFlag) { return (mFlags & aFlag) != 0; }
nsresult GetFlag(PRBool *aResult, Flag aFlag) { *aResult = GetFlag(aFlag); return NS_OK; }
// Set a boolean flag for the cache entry
nsresult SetFlag(PRBool aValue, Flag aFlag);
nsresult SetFlag(Flag aFlag) { return SetFlag(PR_TRUE, aFlag); }
nsresult ClearFlag(Flag aFlag) { return SetFlag(PR_FALSE, aFlag); }
void ComputeProfit(PRUint32 aCurrentTime);
static int Compare(const void *a, const void *b, void *unused);
void NoteAccess();
void NoteUpdate();
// Get underlying raw cache database record.
nsresult GetRecord(nsINetDataCacheRecord* *aRecord);
nsresult GetRecordID(PRInt32 *aRecordID);
nsresult Evict(PRUint32 aTruncatedContentLength);
nsresult GetFileSpec(nsIFileSpec* *aFileSpec);
void NoteDownloadTime(PRTime start, PRTime end);
// placement new for arena-allocation
void *operator new (size_t aSize, nsIArena *aArena);
friend class nsReplacementPolicy;
friend class nsCacheManager;
friend class StreamAsFile;
friend class nsCacheEntryChannel;
friend class CacheOutputStream;
friend class InterceptStreamListener;
private:
nsCachedNetData() {};
virtual ~nsCachedNetData() {};
// Initialize internal fields of this nsCachedNetData instance from the
// underlying raw cache database record.
nsresult Deserialize(PRBool aDeserializeFlags);
// Notify stream-as-file observers about change in cache entry status
nsresult Notify(PRUint32 aMessage, nsresult aError);
// Add/Remove stream-as-file observers
nsresult AddObserver(nsIStreamAsFile *aStreamAsFile, nsIStreamAsFileObserver* aObserver);
nsresult RemoveObserver(nsIStreamAsFileObserver* aObserver);
// Mark cache entry to indicate a write out to the cache database is required
void SetDirty() { mFlags |= DIRTY; }
nsresult Resurrect(nsINetDataCacheRecord *aRecord);
nsresult CommitFlags();
CacheMetaData* FindTaggedMetaData(const char* aTag, PRBool aCreate);
private:
// List of nsIStreamAsFileObserver's that will receive notification events
// when the cache manager or a client desires to delete/truncate a cache
// entry file.
StreamAsFileObserverClosure* mObservers;
// Protocol-specific meta-data, opaque to the cache manager
CacheMetaData *mMetaData;
// Next in chain for a single bucket in the replacement policy hash table
// that maps from record ID to nsCachedNetData
nsCachedNetData* mNext;
// See flag bits, above
// NOTE: 16 bit member is combined with members below for
// struct packing efficiency. Do not change order of members!
PRUint16 mFlags;
protected:
// Number of nsCacheEntryChannels referring to this record
PRUint8 mChannelCount;
// Below members are statistics kept per cache-entry, used to decide how
// profitable it will be to evict a record from the cache relative to other
// existing records. Note: times are measured in *seconds* since the
// 1/1/70 epoch, same as a unix time_t.
// Number of accesses for this cache record
// NOTE: 8 bit member is combined with members above for
// struct packing efficiency. Do not change order of members!
PRUint8 mNumAccesses;
// A reference to the underlying, raw cache database record, either as a
// pointer to an in-memory object or as a database record identifier
union {
nsINetDataCacheRecord* mRecord;
// Database record ID of associated cache record. See
// nsINetDataCache::GetRecordByID().
PRInt32 mRecordID;
};
// Weak link to parent cache
nsINetDataCache* mCache;
// Length of stored content, which may be less than storage consumed if
// compression is used
PRUint32 mLogicalLength;
// Most recent cache entry access times, used to compute access frequency
PRUint32 mAccessTime[MAX_K];
// We use modification time of the original document for replacement policy
// computations, i.e. to compute a document's age, but if we don't know it,
// we use the time that the document was last written to the cache.
union {
// Document modification time, if known.
PRUint32 mLastModifiedTime;
// Time of last cache update for this doc
PRUint32 mLastUpdateTime;
};
union {
// Time until which document is fresh, i.e. does not have to be validated
// with server and, therefore, data in cache is guaranteed usable
PRUint32 mExpirationTime;
// Heuristic time at which cached document is likely to be out-of-date
// with respect to canonical copy on server. Used for cache replacement
// policy, not for validation.
PRUint32 mStaleTime;
};
// Download time per byte, measure roughly in units of KB/s
float mDownloadRate;
// Heuristic estimate of cache entry future benefits, based on above values
float mProfit;
};
#endif // _nsCachedNetData_h_

View File

@@ -0,0 +1,666 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsReplacementPolicy.h"
#include "nsCachedNetData.h"
#include "nsQuickSort.h"
#include "nsIAllocator.h"
#include "nsIEnumerator.h"
#include "prtime.h"
#include "prbit.h"
#include "nsCOMPtr.h"
#include <math.h>
// Constant used to estimate frequency of access to a document based on size
#define CACHE_CONST_B 1.35
// A cache whose space is managed by this replacement policy
class nsReplacementPolicy::CacheInfo {
public:
CacheInfo(nsINetDataCache* aCache):mCache(aCache),mNext(0) {}
nsINetDataCache* mCache;
CacheInfo* mNext;
};
nsReplacementPolicy::nsReplacementPolicy()
: mRankedEntries(0), mCaches(0), mRecordsRemovedSinceLastRanking(0),
mNumEntries(0), mCapacityRankedEntriesArray(0), mLastRankTime(0) {}
nsReplacementPolicy::~nsReplacementPolicy()
{
if (mRankedEntries)
nsAllocator::Free(mRankedEntries);
if (mMapRecordIdToEntry)
nsAllocator::Free(mMapRecordIdToEntry);
}
nsresult
nsReplacementPolicy::Init(PRUint32 aMaxCacheEntries)
{
nsresult rv;
rv = NS_NewHeapArena(getter_AddRefs(mArena), sizeof(nsCachedNetData) * 32);
if (NS_FAILED(rv)) return rv;
mMaxEntries = aMaxCacheEntries;
mHashArrayLength = PR_CeilingLog2(aMaxCacheEntries) >> 3;
size_t numBytes = mHashArrayLength * sizeof(*mMapRecordIdToEntry);
mMapRecordIdToEntry = (nsCachedNetData**)nsAllocator::Alloc(numBytes);
if (!mMapRecordIdToEntry)
return NS_ERROR_OUT_OF_MEMORY;
nsCRT::zero(mMapRecordIdToEntry, numBytes);
return NS_OK;
}
nsresult
nsReplacementPolicy::AddCache(nsINetDataCache *aCache)
{
CacheInfo *cacheInfo = new CacheInfo(aCache);
if (!cacheInfo)
return NS_ERROR_OUT_OF_MEMORY;
cacheInfo->mNext = mCaches;
mCaches = cacheInfo;
return NS_OK;
}
PRUint32
nsReplacementPolicy::HashRecordID(PRInt32 aRecordID)
{
return ((aRecordID >> 16) ^ aRecordID) & (mHashArrayLength - 1);
}
nsCachedNetData*
nsReplacementPolicy::FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache)
{
nsresult rv;
nsCachedNetData* cacheEntry;
PRUint32 bucket = HashRecordID(aRecordID);
cacheEntry = mMapRecordIdToEntry[bucket];
for (;cacheEntry; cacheEntry = cacheEntry->mNext) {
PRInt32 recordID;
rv = cacheEntry->GetRecordID(&recordID);
if (NS_FAILED(rv))
continue;
if ((recordID == aRecordID) && (cacheEntry->mCache == aCache))
return cacheEntry;
}
return 0;
}
// Add a cache entry to the hash table that maps record ID to entries
void
nsReplacementPolicy::AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID)
{
nsCachedNetData** cacheEntryp;
PRUint32 bucket = HashRecordID(aRecordID);
cacheEntryp = &mMapRecordIdToEntry[bucket];
while (*cacheEntryp)
cacheEntryp = &(*cacheEntryp)->mNext;
*cacheEntryp = aCacheEntry;
aCacheEntry->mNext = 0;
}
// Delete a cache entry from the hash table that maps record ID to entries
nsresult
nsReplacementPolicy::DeleteCacheEntry(nsCachedNetData* aCacheEntry)
{
nsresult rv;
PRInt32 recordID;
rv = aCacheEntry->GetRecordID(&recordID);
if (NS_FAILED(rv)) return rv;
PRUint32 bucket = HashRecordID(recordID);
nsCachedNetData** cacheEntryp;
cacheEntryp = &mMapRecordIdToEntry[bucket];
while (*cacheEntryp) {
if (*cacheEntryp == aCacheEntry) {
*cacheEntryp = aCacheEntry->mNext;
return NS_OK;
}
cacheEntryp = &(*cacheEntryp)->mNext;
}
NS_ASSERTION(0, "hash table inconsistency");
return NS_ERROR_FAILURE;
}
nsresult
nsReplacementPolicy::AddAllRecordsInCache(nsINetDataCache *aCache)
{
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsISupports> iSupports;
nsCOMPtr<nsINetDataCacheRecord> record;
rv = aCache->NewCacheEntryIterator(getter_AddRefs(iterator));
if (!NS_SUCCEEDED(rv)) return rv;
while (1) {
PRBool notDone;
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
rv = iterator->GetNext(getter_AddRefs(iSupports));
if (!NS_SUCCEEDED(rv)) return rv;
record = do_QueryInterface(iSupports);
rv = AssociateCacheEntryWithRecord(record, aCache, 0);
if (!NS_SUCCEEDED(rv)) return rv;
}
return NS_OK;
}
// Get current time and convert to seconds since the epoch
static PRUint32
now32()
{
double nowFP;
PRInt64 now64 = PR_Now();
LL_L2D(nowFP, now64);
PRUint32 now = (PRUint32)(nowFP * 1e-6);
return now;
}
void
nsCachedNetData::NoteDownloadTime(PRTime start, PRTime end)
{
double startFP, endFP, rate, duration;
LL_L2D(startFP, start);
LL_L2D(endFP, end);
duration = endFP - startFP;
// If the data arrives so fast that it can not be timed due to the clock
// granularity, assume a data arrival duration of 10 ms
if (!duration)
duration = 10000;
// Compute download rate in kB/s
rate = mLogicalLength / (duration * (1e-6 * 1024.0));
if (mDownloadRate) {
// Exponentially smooth download rate
const double alpha = 0.5;
mDownloadRate = (float)(mDownloadRate * alpha + rate * (1.0 - alpha));
} else {
mDownloadRate = (float)rate;
}
}
// 1 hour
#define MIN_HALFLIFE (60 * 60)
// 1 week
#define TYPICAL_HALFLIFE (7 * 24 * 60 * 60)
/**
* Estimate the profit that would be lost if the given cache entry was evicted
* from the cache. Profit is defined as the future expected download delay per
* byte of cached content. The profit computation is made based on projected
* frequency of access, prior download performance and a heuristic staleness
* criteria. The technique used is a variation of that described in the
* following paper:
*
* "A Case for Delay-Conscious Caching of Web Documents"
* http://www.bell-labs.com/user/rvingral/www97.html
*
* Briefly, expected profit is:
*
* (projected frequency of access) * (download time per byte) * (probability freshness)
*/
void
nsCachedNetData::ComputeProfit(PRUint32 aNow)
{
PRUint32 K, now;
if (aNow)
now = aNow;
else
now = now32();
K = PR_MIN(MAX_K, mNumAccesses);
if (!K) {
mProfit = 0;
return;
}
// Compute time, in seconds, since k'th most recent access
double timeSinceKthAccess = now - mAccessTime[K - 1];
if (timeSinceKthAccess <= 0.0) // Sanity check
timeSinceKthAccess = 1.0;
// Estimate frequency of future document access based on past
// access frequency
double frequencyAccess = K / timeSinceKthAccess;
// If we don't have much historical data on access frequency
// use a heuristic based on document size as an estimate
if (mLogicalLength) {
if (K == 1) {
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B);
} else if (K == 2) {
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B / 2);
}
}
// Estimate likelihood that data in cache is fresh, i.e.
// that it corresponds to the document on the server
double probabilityFreshness;
PRInt32 halfLife, age, docTime;
PRBool potentiallyStale;
docTime = GetFlag(LAST_MODIFIED_KNOWN) ? mLastModifiedTime : mLastUpdateTime;
age = now - docTime;
probabilityFreshness = 1.0; // Optimistic
if (GetFlag(EXPIRATION_KNOWN)) {
potentiallyStale = now > mExpirationTime;
halfLife = mExpirationTime - mLastModifiedTime;
} else if (GetFlag(STALE_TIME_KNOWN)) {
potentiallyStale = PR_TRUE;
halfLife = mStaleTime - docTime;
} else {
potentiallyStale = PR_TRUE;
halfLife = TYPICAL_HALFLIFE;
}
if (potentiallyStale) {
if (halfLife < MIN_HALFLIFE)
halfLife = MIN_HALFLIFE;
probabilityFreshness = pow(0.5, (double)age / (double)halfLife);
}
mProfit = (float)(frequencyAccess * probabilityFreshness);
if (mDownloadRate)
mProfit /= mDownloadRate;
}
// Number of entries to grow mRankedEntries array when it's full
#define STATS_GROWTH_INCREMENT 256
// Sorting predicate for NS_Quicksort
int
nsCachedNetData::Compare(const void *a, const void *b, void *unused)
{
nsCachedNetData* entryA = *(nsCachedNetData**)a;
nsCachedNetData* entryB = *(nsCachedNetData**)b;
// Percolate deleted or empty entries to the end of the mRankedEntries
// array, so that they can be recycled.
if (!entryA || entryA->GetFlag(RECYCLED)) {
if (!entryB || entryB->GetFlag(RECYCLED))
return 0;
else
return +1;
}
if (!entryB || entryB->GetFlag(RECYCLED))
return -1;
// Evicted entries (those with no content data) and active entries (those
// currently being updated) are collected towards the end of the sorted
// array just prior to the deleted cache entries, since evicted entries
// can't be re-evicted.
if (entryA->GetFlag(UPDATE_IN_PROGRESS)) {
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
return 0;
else
return +1;
}
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
return -1;
PRUint16 Ka = PR_MIN(MAX_K, entryA->mNumAccesses);
PRUint16 Kb = PR_MIN(MAX_K, entryB->mNumAccesses);
// Order cache entries by the number of times they've been accessed
if (Ka < Kb)
return -1;
if (Ka > Kb)
return +1;
/*
* Among records that have been accessed an equal number of times, order
* them by profit.
*/
if (entryA->mProfit > entryB->mProfit)
return +1;
if (entryA->mProfit < entryB->mProfit)
return -1;
return 0;
}
/**
* Rank cache entries in terms of their elegibility for eviction.
*/
nsresult
nsReplacementPolicy::RankRecords()
{
PRUint32 i, now;
// Add all cache records if this is the first ranking
if (!mLastRankTime) {
nsresult rv;
CacheInfo *cacheInfo;
cacheInfo = mCaches;
while (cacheInfo) {
rv = AddAllRecordsInCache(cacheInfo->mCache);
if (NS_FAILED(rv)) return rv;
cacheInfo = cacheInfo->mNext;
}
}
// Get current time and convert to seconds since the epoch
now = now32();
// Recompute profit for every known cache record, except deleted ones
for (i = 0; i < mNumEntries; i++) {
nsCachedNetData* entry = mRankedEntries[i];
if (entry && !entry->GetFlag(nsCachedNetData::RECYCLED))
entry->ComputeProfit(now);
}
NS_QuickSort(mRankedEntries, mNumEntries, sizeof *mRankedEntries,
nsCachedNetData::Compare, 0);
mNumEntries -= mRecordsRemovedSinceLastRanking;
mRecordsRemovedSinceLastRanking = 0;
mLastRankTime = now;
return NS_OK;
}
// A heuristic policy to avoid the cost of re-ranking cache records by
// profitability every single time space must be made available in the cache.
void
nsReplacementPolicy::MaybeRerankRecords()
{
// Rank at most once per minute
PRUint32 now = now32();
if ((now - mLastRankTime) >= 60)
RankRecords();
}
void
nsReplacementPolicy::CompactRankedEntriesArray()
{
if (mRecordsRemovedSinceLastRanking || !mLastRankTime)
RankRecords();
}
nsresult
nsReplacementPolicy::CheckForTooManyCacheEntries()
{
if (mCapacityRankedEntriesArray == mMaxEntries) {
return DeleteOneEntry(0);
} else {
nsresult rv;
CacheInfo *cacheInfo;
cacheInfo = mCaches;
while (cacheInfo) {
PRUint32 numEntries, maxEntries;
rv = cacheInfo->mCache->GetNumEntries(&numEntries);
if (NS_FAILED(rv)) return rv;
rv = cacheInfo->mCache->GetMaxEntries(&maxEntries);
if (NS_FAILED(rv)) return rv;
if (numEntries == maxEntries)
return DeleteOneEntry(cacheInfo->mCache);
cacheInfo = cacheInfo->mNext;
}
}
return NS_OK;
}
/**
* Create a new association between a low-level cache database record and a
* cache entry. Add the entry to the set of entries eligible for eviction from
* the cache. This would typically be done when the cache entry is created.
*/
nsresult
nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
nsINetDataCache* aCache,
nsCachedNetData** aResult)
{
nsCachedNetData* cacheEntry;
nsresult rv;
// First, see if the record is already known to the replacement policy
PRInt32 recordID;
rv = aRecord->GetRecordID(&recordID);
if (NS_FAILED(rv)) return rv;
cacheEntry = FindCacheEntryByRecordID(recordID, aCache);
if (cacheEntry) {
if (aResult) {
if (cacheEntry->GetFlag(nsCachedNetData::DORMANT))
cacheEntry->Resurrect(aRecord);
NS_ADDREF(cacheEntry);
*aResult = cacheEntry;
}
return NS_OK;
}
// Compact the array of cache entry statistics, so that free entries appear
// at the end, for possible reuse.
if (mNumEntries && (mNumEntries == mCapacityRankedEntriesArray))
CompactRankedEntriesArray();
// If compaction doesn't yield available entries in the
// mRankedEntries array, then extend the array.
if (mNumEntries == mCapacityRankedEntriesArray) {
PRUint32 newCapacity;
rv = CheckForTooManyCacheEntries();
if (NS_FAILED(rv)) return rv;
newCapacity = mCapacityRankedEntriesArray + STATS_GROWTH_INCREMENT;
if (newCapacity > mMaxEntries)
newCapacity = mMaxEntries;
nsCachedNetData** newRankedEntriesArray;
PRUint32 numBytes = sizeof(nsCachedNetData*) * newCapacity;
newRankedEntriesArray =
(nsCachedNetData**)nsAllocator::Realloc(mRankedEntries, numBytes);
if (!newRankedEntriesArray)
return NS_ERROR_OUT_OF_MEMORY;
mRankedEntries = newRankedEntriesArray;
mCapacityRankedEntriesArray = newCapacity;
PRUint32 i;
for (i = mNumEntries; i < newCapacity; i++)
mRankedEntries[i] = 0;
}
// Recycle the record after the last in-use record in the array
nsCachedNetData *entry = mRankedEntries[mNumEntries];
NS_ASSERTION(!entry || !entry->GetFlag(nsCachedNetData::RECYCLED),
"Only deleted cache entries should appear at end of array");
if (!entry) {
entry = new(mArena) nsCachedNetData;
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
mRankedEntries[mNumEntries] = entry;
} else {
// Clear out recycled data structure
nsCRT::zero(entry, sizeof(*entry));
}
entry->Init(aRecord, aCache);
AddCacheEntry(entry, recordID);
// Add one reference to the cache entry from the cache manager
NS_ADDREF(entry);
if (aResult) {
// And one reference from our caller
NS_ADDREF(entry);
*aResult = entry;
}
mNumEntries++;
return NS_OK;
}
nsresult
nsReplacementPolicy::GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
nsINetDataCache* aCache,
nsCachedNetData** aResult)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
rv = aCache->GetCachedNetData(cacheKey, cacheKeyLength,
getter_AddRefs(record));
if (NS_FAILED(rv)) return rv;
return AssociateCacheEntryWithRecord(record, aCache, aResult);
}
/**
* Delete the least desirable record from the cache database. This is used
* when the addition of another record would exceed either the cache manager or
* the cache's maximum permitted number of records.
*/
nsresult
nsReplacementPolicy::DeleteOneEntry(nsINetDataCache *aCache)
{
PRUint32 i;
nsresult rv;
nsCachedNetData *entry;
i = 0;
while (1) {
MaybeRerankRecords();
for (; i < mNumEntries; i++) {
entry = mRankedEntries[i];
if (!entry || entry->GetFlag(nsCachedNetData::RECYCLED))
continue;
if (!aCache || (entry->mCache == aCache))
break;
}
// Report error if no record found to delete
if (i == mNumEntries)
return NS_ERROR_FAILURE;
rv = entry->Delete();
if (NS_SUCCEEDED(rv)) {
rv = DeleteCacheEntry(entry);
return rv;
}
}
}
nsresult
nsReplacementPolicy::GetStorageInUse(PRUint32* aStorageInUse)
{
nsresult rv;
CacheInfo *cacheInfo;
*aStorageInUse = 0;
cacheInfo = mCaches;
while (cacheInfo) {
PRUint32 cacheStorage;
rv = cacheInfo->mCache->GetStorageInUse(&cacheStorage);
if (NS_FAILED(rv)) return rv;
*aStorageInUse += cacheStorage;
cacheInfo = cacheInfo->mNext;
}
return NS_OK;
}
/**
* Delete the least desirable records from the cache until the occupancy of the
* cache has been reduced by the given number of KB. This is used when the
* addition of more cache data would exceed the cache's capacity.
*/
nsresult
nsReplacementPolicy::Evict(PRUint32 aTargetOccupancy)
{
PRUint32 i;
nsCachedNetData *entry;
nsresult rv;
PRUint32 occupancy;
PRInt32 truncatedLength;
nsCOMPtr<nsINetDataCacheRecord> record;
MaybeRerankRecords();
for (i = 0; i < mNumEntries; i++) {
rv = GetStorageInUse(&occupancy);
if (!NS_SUCCEEDED(rv)) return rv;
if (occupancy <= aTargetOccupancy)
return NS_OK;
entry = mRankedEntries[i];
// Skip deleted/empty cache entries and ones that have already been evicted
if (!entry || entry->GetFlag(nsCachedNetData::UNEVICTABLE))
continue;
if (entry->GetFlag(nsCachedNetData::ALLOW_PARTIAL)) {
rv = entry->GetRecord(getter_AddRefs(record));
if (NS_FAILED(rv))
continue;
PRUint32 contentLength;
rv = record->GetStoredContentLength(&contentLength);
if (NS_FAILED(rv))
continue;
// Additional cache storage required, in KB
PRUint32 storageToReclaim = (occupancy - aTargetOccupancy) << 10;
truncatedLength = (PRInt32)(contentLength - storageToReclaim);
if (truncatedLength < 0)
truncatedLength = 0;
} else {
truncatedLength = 0;
}
rv = entry->Evict(truncatedLength);
}
return NS_ERROR_FAILURE;
}

View File

@@ -0,0 +1,136 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
/**
* This class manages one or more caches that share a storage resource, e.g. a
* file cache and a flat-database cache might each occupy space on the disk and
* they would share a single instance of nsReplacementPolicy. The replacement
* policy heuristically chooses which cache entries to evict when storage is
* required to accommodate incoming cache data.
*/
#ifndef _nsReplacementPolicy_h_
#define _nsReplacementPolicy_h_
#include "nscore.h"
#include "nsISupportsUtils.h"
#include "nsINetDataCache.h"
#include "nsICachedNetData.h"
#include "nsIArena.h"
#include "nsCOMPtr.h"
#include "nsHashtable.h"
class nsCachedNetData;
struct PL_HashTable;
/**
* This private class is responsible for implementing the network data cache's
* replacement policy, i.e. it decides which cache data should be evicted to
* make room for new incoming data.
*/
class nsReplacementPolicy {
public:
nsReplacementPolicy();
~nsReplacementPolicy();
protected:
nsresult Init(PRUint32 aMaxCacheEntries);
nsresult AddCache(nsINetDataCache *aCache);
nsresult GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
nsINetDataCache* aCache,
nsCachedNetData** aResult);
nsresult GetStorageInUse(PRUint32* aNumKBytes);
friend class nsCacheManager;
private:
nsresult RankRecords();
void MaybeRerankRecords();
void CompactRankedEntriesArray();
nsresult DeleteOneEntry(nsINetDataCache* aCache);
nsresult Evict(PRUint32 aTargetOccupancy);
nsCachedNetData* FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache);
void AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID);
nsresult DeleteCacheEntry(nsCachedNetData* aCacheEntry);
PRUint32 HashRecordID(PRInt32 aRecordID);
nsresult AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
nsINetDataCache* aCache,
nsCachedNetData** aResult);
nsresult AddAllRecordsInCache(nsINetDataCache *aCache);
nsresult CheckForTooManyCacheEntries();
class CacheInfo;
private:
// Growable array of pointers to individual cache entries; It is sorted by
// profitability, such that low-numbered array indices refer to cache
// entries that are the least profitable to retain. New cache entries are
// added to the end of the array. Deleted cache entries are specially
// marked and percolate to the end of the array for recycling whenever
// mRankedEntries is sorted. Evicted cache entries (those with no
// associated content data) are retained for the purpose of improving the
// replacement policy efficacy, and are percolated towards the end of the
// array, just prior to the deleted cache entries.
//
// The array is not in sorted order 100% of the time; For efficiency
// reasons, sorting is only done when heuristically deemed necessary.
nsCachedNetData** mRankedEntries;
// Hash table buckets to map Record ID to cache entry. We use this instead
// of a PL_HashTable to reduce storage requirements
nsCachedNetData** mMapRecordIdToEntry;
// Length of mMapRecordIdToEntry array
PRUint32 mHashArrayLength;
// Linked list of caches that share this replacement policy
CacheInfo* mCaches;
// Allocation area for cache entry (nsCachedNetData) instances
nsCOMPtr<nsIArena> mArena;
// Bookkeeping
PRUint32 mRecordsRemovedSinceLastRanking;
// Maximum permitted length of mRankedEntries array
PRUint32 mMaxEntries;
// Number of occupied slots in mRankedEntries array
PRUint32 mNumEntries;
// Capacity of mRankedEntries array
PRUint32 mCapacityRankedEntriesArray;
// Time at which cache entries were last ranked by profitability
PRUint32 mLastRankTime;
};
#endif // _nsReplacementPolicy_h_

View File

@@ -0,0 +1,43 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
MODULE = nkcache
include $(DEPTH)/config/autoconf.mk
XPIDLSRCS = \
nsICachedNetData.idl \
nsINetDataCacheManager.idl \
nsINetDataCache.idl \
nsINetDataCacheRecord.idl \
nsINetDataDiskCache.idl \
nsIStreamAsFile.idl \
$(NULL)
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
include $(topsrcdir)/config/rules.mk

41
mozilla/netwerk/cache/public/Makefile.win vendored Executable file
View File

@@ -0,0 +1,41 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
MODULE = nkcache
DEPTH = ..\..\..
include <$(DEPTH)/config/config.mak>
EXPORTS = \
$(NULL)
XPIDLSRCS = \
.\nsICachedNetData.idl \
.\nsINetDataCacheManager.idl \
.\nsINetDataCache.idl \
.\nsINetDataCacheRecord.idl \
.\nsINetDataDiskCache.idl \
.\nsIStreamAsFile.idl \
$(NULL)
include <$(DEPTH)/config/rules.mak>

View File

@@ -0,0 +1,229 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsrootidl.idl"
#include "nsISupports.idl"
interface nsIFileSpec;
interface nsIURI;
interface nsIObserver;
interface nsIChannel;
interface nsINetDataCache;
interface nsINetDataCacheRecord;
interface nsILoadGroup;
interface nsIStreamListener;
/**
* The nsICachedNetData interface represents a single entry in a database that
* caches data retrieved from the network. This interface is implemented by the
* cache manager on top of the low-level nsINetDataCacheRecord and
* nsINetDataCache interfaces that are implemented by the database.
*
* Each cache record may contain both content and metadata. The content may
* be, for example, GIF image data or HTML, and it is accessed through
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
* headers among other things, is stored as a byte array. Each entry in the
* cache is indexed by two different keys: a record id number and a key created
* by combining the URI with a "secondary key", e.g. HTTP post data.
*
* @See nsINetDataCacheRecord
* @See nsINetDataCache
* @See nsINetDataDiskCache
* @See nsINetDataCacheManager
*/
[scriptable, uuid(6aeb2a40-6d43-11d3-90c8-000064657374)]
interface nsICachedNetData : nsISupports
{
/**
* String form of the URI provided as an argument to the call to
* nsINetDataCacheManager::GetCachedNetData() that created this record.
*/
readonly attribute string uriSpec;
/**
* Getter for the opaque secondary database key provided as an argument to
* the call to nsINetDataCacheManager::GetCachedNetData() that created this
* record.
*/
void getSecondaryKey(out unsigned long length,
[retval, size_is(length)] out string secondaryKey);
/**
* This flag may be set by a protocol handler to indicate that it supports
* partial fetching of data. In that case, the cache manager is permitted
* to truncate the entry's content to accommodate incoming data for other
* cache entries rather than deleting it wholesale.
*/
attribute boolean allowPartial;
/**
* This flag indicates that the write stream supplying content data for the
* cache did not complete normally and, therefore, the content may be
* truncated.
*/
readonly attribute boolean partialFlag;
/**
* This flag can be set and cleared by a protocol handler as a form of
* self-notification, so as to avoid race conditions in which a protocol
* handler issues two identical network requests to fill the same cache
* entry. The cache manager itself largely ignores this flag.
*/
attribute boolean updateInProgress;
/**
* inUse is set if any existing channels are associated with this cache
* entry or if the updateInProgess flag is set. This can be used to
* prevent writing to a cache entry by a protocol handler if it's being
* read or written elsewhere.
*/
readonly attribute boolean inUse;
/**
* Date/time that the document was last stored on the origin server, as
* supplied by the protocol handler. This value is used as input to the
* cache replacement policy, i.e. it is not used for validation. If the
* protocol can't supply a last-modified time, this attribute should remain
* unset. When unset, the value of this attribute is zero.
*
* FIXME: Should use nsIDateTime interface, once it's created
* instead of PRTime, for improved scriptability ?
*/
attribute PRTime lastModifiedTime;
/**
* Supplied by the protocol handler, the expirationTime attribute specifies
* the time until which the document is guaranteed fresh, i.e. the document
* does not have to be validated with the server and, therefore, any data
* in cache is definitely usable. The value of this attribute serves as a
* hint to the cache replacement policy. Only one of either staleTime or
* expirationTime may be set for a single cache record. When unset, the
* value of this attribute is zero.
*/
attribute PRTime expirationTime;
/**
* Date/time supplied by the protocol handler, at which point the content
* is *likely* to be stale, i.e. the data in the cache may be out-of-date
* with respect to the data on the server. This heuristic date does not
* necessarily correspond to the HTTP Expires header, as it does not
* determine when cached network data must be validated with the origin
* server, but only serves as a hint to the cache replacement policy. Only
* one of either staleTime or expirationTime may be set for a single cache
* record. When unset, the value of this attribute is zero.
*/
attribute PRTime staleTime;
/**
* Date/time of last access of the data in this cache record, as determined
* by the cache manager.
*/
readonly attribute PRTime lastAccessTime;
/**
* Number of times this record has been accessed since it was first stored.
*/
readonly attribute PRUint16 numberAccesses;
/**
* Accessor methods for opaque meta-data which can be read and updated
* independently of the content data.
*
* The aTag argument can be used to accommodate multiple clients of the
* cache API, each of which wants to store its own private meta-data into
* the cache. For example, there could be a "headers" tag that the HTTP
* protocol handler uses to store http response headers and a "image size"
* tag used to store the image dimensions of a GIF file. The aData
* argument refers to an opaque blob of arbitrary bytes.
*
* IMPORTANT: If aData does not contain byte-oriented data, i.e. it's not a
* string, the contents of aData must be byte-swapped by the,
* caller, so as to make the cache files endian-independent.
*/
void getAnnotation(in string aTag,
out PRUint32 aLength, [size_is(aLength), retval] out string aData);
void setAnnotation(in string aTag,
in PRUint32 aLength, [size_is(aLength)] in string aData);
/**
* As a getter, return the number of content bytes stored in the cache,
* i.e. via the nsIChannel streaming APIs. This may be less than the
* complete content length if a partial cache fill occurred. The cached
* content can be truncated by setting the value of this attribute. The
* value of the attribute represents a logical, not a physical, length. If
* compression has been used, the content may consume less storage than
* indicated by this attribute.
*
* When this attribute is set to zero the associated cache disk file, if
* any, should be deleted.
*/
attribute PRUint32 storedContentLength;
/**
* Notify any observers associated with this cache entry of the deletion
* request. If all observers drop their reference to the cache entry,
* proceed to delete the underlying cache database record and associated
* content storage.
*/
void delete();
/**
* Flush any changes in this entry's data to the cache database. This
* method will automatically be called when the last reference to the cache
* is dropped, but it can also be called explicitly for a synchronous
* effect.
*/
void commit();
/**
* Parent container cache for this entry.
*/
readonly attribute nsINetDataCache cache;
/**
* Create a channel for reading or writing a stream of content into the
* entry. It is expected that many of the nsIChannel methods return
* NS_NOT_IMPLEMENTED, including:
*
* + GetURI()
* + GetContentType()
* + GetContentLength()
*
* Though nsIChannel provides for both async and synchronous I/O APIs, both
* may not be implemented. Only AsyncRead() and OpenOutputStream() is
* required. The aProxyChannel argument allows another channel to be
* specified as the proffered argument to nsIStreamListener methods rather
* than the cache's own channel.
*/
nsIChannel newChannel(in nsILoadGroup aLoadGroup,
in nsIChannel aProxyChannel);
/**
* This method can be used by a caching protocol handler to store data in
* the cache by forking an asynchronous read stream so that it is
* simultaneously sent to a requester and written into the cache. This
* method implicitly sets the updateInProgress flag, if it has not already
* been set.
*/
nsIStreamListener interceptAsyncRead(in nsIStreamListener aOriginalListener,
in PRUint32 aStartOffset);
};

View File

@@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
interface nsIURI;
interface nsINetDataCacheRecord;
interface nsISimpleEnumerator;
interface nsIFileSpec;
/**
* The nsINetDataCache defines the low-level API for a network-data
* cache, used to cache the responses to network retrieval commands.
* This interface, along with nsINetDataCacheRecord, is implemented by
* the memory cache, the file cache and, optionally, by some extension
* caches. This interface is essentially a pseudo-private API for the
* cache manager. Other clients should never use this interface.
*
* Each cache entry may contain both content, e.g. GIF image data, and
* associated metadata, e.g. HTTP headers. Each entry is indexed by two
* different keys: a record id number and a key created by combining the URI
* with a "secondary key", e.g. HTTP post data.
*
* The nsINetDataCache interface is agnostic as to where the data is
* stored and whether the storage is volatile or persistent. The
* memory cache, any disk caches and any extension caches must all
* implement this interface.
*
*/
[scriptable, uuid(ccfc58c0-6dde-11d3-90c8-000064657374)]
interface nsINetDataCache : nsISupports
{
/**
* Human-readable description of the cache module, e.g. "Disk Cache"
*/
readonly attribute wstring description;
/**
* Returns true if cached data is available for the given opaque key,
* even if only partial data is stored.
*/
boolean contains([size_is(length)] in string key, in PRUint32 length);
/**
* Fetch the cache entry record for the given opaque key. If one does not
* exist, create a new, empty record.
*/
nsINetDataCacheRecord getCachedNetData([size_is(length)] in string key,
in PRUint32 length);
/**
* Fetch the cache entry record for the given URI using the record ID as a key.
*/
nsINetDataCacheRecord getCachedNetDataByID(in PRInt32 RecordID);
/**
* False indicates that this cache is entirely bypassed.
*/
attribute boolean enabled;
/**
* Constants for flags attribute, below
*/
// Used for extension caches, e.g. a CD-ROM cache
const long READ_ONLY = 1 << 0;
// One of these bits must be set
const long MEMORY_CACHE = 1 << 1;
const long FLAT_FILE_CACHE = 1 << 2;
const long FILE_PER_URL_CACHE = 1 << 3;
/**
* See constants defined above.
*/
readonly attribute PRUint32 flags;
/**
* Total number of URI entries stored in the cache.
*/
readonly attribute PRUint32 numEntries;
/**
* Maximum number of URI entries that may be stored in the cache.
*/
readonly attribute PRUint32 maxEntries;
/**
* Enumerate the URI entries stored in the cache.
*/
nsISimpleEnumerator newCacheEntryIterator();
/**
* Contains a reference to the next cache in search order. For the memory
* cache, this attribute always references the disk cache. For the disk
* cache, it contains a reference to the first extension cache.
*/
attribute nsINetDataCache nextCache;
/**
* An estimate of the amount of storage occupied by the cache, in kB.
* Actual use may be slightly higher than reported due to cache overhead
* and heap fragmentation (in the memory cache) or block quantization (in
* the disk cache).
*/
readonly attribute PRUint32 storageInUse;
/**
* Remove all entries from a writable cache. This could be used, for
* example, after a guest ends a browser session. This is equivalent to
* setting the cache's Capacity to zero, except that all cache entries,
* even those in active use, will be deleted. Also, any global cache
* database files will be deleted.
*/
void removeAll();
};
%{ C++
// ProgID prefix for Components that implement this interface
#define NS_NETWORK_CACHE_PROGID "component://netscape/network/cache"
#define NS_NETWORK_MEMORY_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=memory-cache"
#define NS_NETWORK_FLAT_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=flat-cache"
#define NS_NETWORK_FILE_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=file-cache"
%}

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
interface nsISimpleEnumerator;
interface nsICachedNetData;
interface nsINetDataCache;
interface nsINetDataDiskCache;
interface nsIURI;
interface nsIFileSpec;
/**
* The network-response cache manager is partly responsible for the caching of
* content and associated metadata that has been retrieved via the network.
* (The remaining responsibility for caching lies with individual network
* protocol handlers.)
*
* The cache manager supervises the actions of individual cache components,
* such as the memory cache, the disk cache and any extension caches, e.g. a
* read-only CD-ROM cache.
*
* @See nsINetDataCache
* @See nsICachedNetData
*/
[scriptable, uuid(71c8ab00-6d5c-11d3-90c8-000064657374)]
interface nsINetDataCacheManager : nsISupports
{
/**
* Flag for the GetCachedNetData() method: If set, the memory cache is
* neither searched nor will any data be stored into it. This might be
* appropriate, for example, with images, because they have their own
* cache for storing *decoded* images.
*/
const unsigned long BYPASS_MEMORY_CACHE = 1 << 0;
/**
* Flag for the GetCachedNetData() method: If set, the disk cache
* is neither searched nor will any be data stored into it.
* However, read-only extension caches may be searched. This
* might be used to avoid leaving persistent records of secure
* data.
*/
const unsigned long BYPASS_PERSISTENT_CACHE = 1 << 1;
/**
* Flag for the GetCachedNetData() method: If set, any stream
* content is stored in the cache as a single disk file. Content
* will not be cached in the memory cache nor is it cached in a
* flat-file cache database. This is used to implement the jar
* protocol handler and to provide the stream-as-file semantics
* required by the classic bowser plugin API.
*/
const unsigned long CACHE_AS_FILE = 1 << 2;
/**
* Fetch the cache entry record for the given URI. If one does not exist,
* create a new, empty record. The normal search order for caches is:
* + Memory cache
* + Disk cache
* + File cache (stream-as-file cache)
* + All extension caches
*
* When writing, data is typically stored in both the memory cache and the
* disk cache. Both the search order and this write policy can be modified by
* setting one or more of the flag argument bits, as defined above.
*
* The optionally-NULL secondaryKey argument can be used, e.g. for form
* post data or for HTTP headers in the case of HTTP.
*/
nsICachedNetData getCachedNetData(in string uri,
[size_is(secondaryKeyLength)] in string secondaryKey,
in PRUint32 secondaryKeyLength,
in PRUint32 flags);
/**
* Returns true if cached content is available for the given URI, even if
* only partial data is stored. The flags argument behaves the same as for
* the GetCachedNetData() method, above.
*/
boolean contains(in string uri,
[size_is(secondaryKeyLength)] in string secondaryKey,
in PRUint32 secondaryKeyLength,
in PRUint32 flags);
/**
* Total number of unexpired URI entries stored in all caches. This number
* does not take into account duplicate URIs, e.g. because the memory cache
* and the disk cache might each contain an entry for the same URI.
*/
readonly attribute PRUint32 numEntries;
/**
* Enumerate the unexpired URI entries stored in all caches. Some URIs may
* be enumerated more than once, e.g. because the the memory cache and the
* disk cache might each contain an entry for the same URI.
*/
nsISimpleEnumerator newCacheEntryIterator();
/*
* Enumerate all the loaded nsINetDataCache-implementing cache modules.
* The first module enumerated will be the memory cache, the second will be
* the disk cache, then the file cache, followed by all the extension
* caches, in search order.
*/
nsISimpleEnumerator newCacheModuleIterator();
/**
* Remove all entries from all writable caches. This could be used, for
* example, after a guest ends a browser session. This is equivalent to
* setting the DiskCacheCapacity to zero, except that all cache entries,
* even those in active use, will be deleted. Also, any global cache
* database files will be deleted.
*/
void RemoveAll();
/**
* The disk cache is made up of the file cache (for stream-as-file
* requests) and a (possibly independent) persistent cache that handles all
* other cache requests. This attribute sets/gets the combined capacity of
* these caches, measured in KBytes. Setting the capacity lower than the
* current amount of space currently in use may cause cache entries to be
* evicted from the cache to accomodate the requested capacity.
*/
attribute PRUint32 diskCacheCapacity;
/**
* This attribute sets/gets the capacity of the memory cache, measured in
* KBytes. Setting the capacity lower than the current amount of space
* currently in use may cause cache entries to be evicted from the cache to
* accomodate the requested capacity.
*/
attribute PRUint32 memCacheCapacity;
/**
* This attribute must be set before attempting to store into the disk cache.
*/
attribute nsIFileSpec diskCacheFolder;
};
%{ C++
// ProgID prefix for Components that implement this interface
#define NS_NETWORK_CACHE_MANAGER_PROGID NS_NETWORK_CACHE_PROGID "?name=manager"
%}

View File

@@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
#include "nsrootidl.idl"
interface nsIFileSpec;
interface nsIChannel;
interface nsINetDataCache;
/**
* The nsINetDataCacheRecord represents a single entry in a database that
* caches data retrieved from the network. On top of this low-level interface
* to the raw record data, the cache manager implements a higher-level record
* interface, nsICachedNetData. Each instance of nsINetDataCacheRecord is
* (internally) associated with a parent database, an instance of the
* nsINetDataCache interface. This interface is essentially a pseudo-private
* API for the cache manager. Other clients should never use this interface.
*
* Each cache record may contain both content and metadata. The content may
* be, for example, GIF image data or HTML, and it is accessed through
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
* headers among other things, is accessed as a contiguous byte array. Each
* entry in the cache is indexed by two different keys: a unique record id
* number, generated by the cache, and an opaque string. The latter contains
* the URI and other secondary key information, e.g. HTTP form post key/value
* pairs.
*
* The nsINetDataCacheRecord interface is agnostic as to where the data is
* stored and whether the storage is volatile or persistent. The memory cache,
* the disk cache, a flat-file cache and any read-only extension caches must
* all implement this interface.
*
* @See nsICachedNetData
* @See nsINetDataCache
* @See nsINetDataDiskCache
* @See nsINetDataCacheManager
*/
interface nsILoadGroup;
[scriptable, uuid(fdcdd6a0-7461-11d3-90ca-0040056a906e)]
interface nsINetDataCacheRecord : nsISupports
{
/**
* As far as the nsINetDataCacheRecord implementation is concerned, the
* cache entry database key is an opaque blob, but it's intended to contain
* both the URI and any secondary keys, such as HTTP post data.
*/
void getKey(out unsigned long length, [size_is(length), retval] out string key);
/**
* A persistent record number assigned by the cache which must be unique
* among all entries stored within the same cache. The record ID serves as
* an alternate key to the cache record. Providing that they satisfy the
* afforementioned uniqueness requirement, record IDs can be assigned any
* value by the database except that they may never be zero.
*/
readonly attribute PRInt32 recordID;
/**
* Opaque data which can be updated for each cache entry independently of
* the content data. This data is a combination of protocol-independent
* data provided by the cache manager and protocol-specific meta-data,
* e.g. HTTP headers.
*/
void getMetaData(out PRUint32 length, [size_is(length), retval] out string metaData);
void setMetaData(in PRUint32 length, [size_is(length)] in string data);
/**
* Number of content bytes stored in the cache, i.e. via the nsIChannel
* streaming APIs. This may be less than the complete content length if a
* partial cache fill occurred. Additionally, the cached content can be
* truncated by reducing the value of this attribute. When this attribute
* is set to zero the associated cache disk file, if any, should be
* deleted.
*/
attribute PRUint32 storedContentLength;
/**
* Delete this cache entry and its associated content.
*/
void delete();
/**
* Create a channel for reading or writing a stream of content into the
* entry. However, many of the nsIChannel methods may return
* NS_NOT_IMPLEMENTED, including:
*
* + GetURI()
* + GetContentType()
* + GetContentLength()
*/
nsIChannel newChannel(in nsILoadGroup loadGroup);
/**
* If a cache is implemented such that it stores each URI's content in an
* individual disk file, this method will identify the file corresponding
* to this record. This may be used to implement the "stream-as-file"
* semantics required by some plugins and by the 'jar:' protocol handler.
* However, not all cache implementations are *required* to store the data
* from each URI in an individual file, so it is acceptable for an
* implementation of this method to signal NS_NOT_IMPLEMENTED.
*/
readonly attribute nsIFileSpec filename;
};

View File

@@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsINetDataCache.idl"
interface nsIFileSpec;
/**
/**
* A network-data disk cache is used to persistently cache the responses to
* network retrieval commands. Each cache entry may contain both content,
* e.g. GIF image data, and associated metadata, e.g. HTTP headers.
*/
[scriptable, uuid(6408e390-6f13-11d3-90c8-000064657374)]
interface nsINetDataDiskCache : nsINetDataCache
{
/**
* This attribute must be set before calling any other methods of this
* interface.
*/
attribute nsIFileSpec diskCacheFolder;
};

View File

@@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsrootidl.idl"
#include "nsISupports.idl"
interface nsIFileSpec;
interface nsIStreamAsFileObserver;
/**
* In addition to enhancing effective network response time via caching, the
* cache manager serves a second purpose by providing the stream-as-file
* service required by traditional browser plugins and the jar: protocol
* handler. The interface below provides a means for a client to determine the
* filename associated with a stream and to detect modification/deletion of
* that file.
*/
[scriptable, uuid(0eedbbf0-92d9-11d3-90d3-0040056a906e)]
interface nsIStreamAsFile : nsISupports
{
/**
* Filename containing stream-as-file
*/
readonly attribute nsIFileSpec fileSpec;
/**
* Add an observer for this cache record. When the cache wants to delete
* or truncate a record, so as to make space for another cache entry's
* content data, it will call <code>aObserver</code>'s Observe() method,
* passing the nsIStreamAsFile instance as the <code>aSubject</code>
* argument and an appropriate message. If the observer does not wish to
* inhibit deletion/truncation, it should Release() any references it has to the
* cache record.
*
* @See nsIStreamAsFileObserver
*/
void addObserver(in nsIStreamAsFileObserver aObserver);
/**
* Delete an observer that was added by the AddObserver() method.
*/
void removeObserver(in nsIStreamAsFileObserver aObserver);
};
/**
* This interface can be implemented by a client to receive notifications of
* either modification or deletion of a file created by the cache manager using
* the stream-as-file semantics.
*/
[scriptable, uuid(a26e27c0-92da-11d3-90d3-0040056a906e)]
interface nsIStreamAsFileObserver : nsISupports
{
/**
* Flag bits for argument to Observe() method.
*/
const long NOTIFY_AVAILABLE = 1 << 0; // Stream-as-file now available for reading
const long NOTIFY_ERROR = 1 << 1; // Error while loading stream / creating file
const long REQUEST_DELETION = 1 << 2; // Cache manager wishes to delete/truncate file
const long INVALIDATE = 1 << 3; // File is out-of-date
// Convenience value
const long MAKE_UNAVAILABLE = REQUEST_DELETION | INVALIDATE;
/**
* Receive either a notification or a request concerning a file that has
* been opened using stream-as-file. The aMessage and aError arguments
* have varying values depending on the nature of the notification.
* aMessage is set to NOTIFY_AVAILABLE when a complete stream has been read
* and stored on disk in a file. At that point, and no sooner, may the
* filename attribute of the associated nsIStreamAsFile be accessed via the
* associated nsIStreamAsFile interface. If the aMessage argument is
* NOTIFY_ERROR, the aError argument contains the relevant error code. If
* the aMessage argument is either REQUEST_DELETION or REQUEST_TRUNCATION,
* the callee should immediately Release() all references to the
* nsIStreamAsFile (and any references to its associated nsICachedNetData
* instances), unless it wishes to inhibit the requested file modification.
* If the aMessage argument is INVALIDATE, the cache manager is replacing
* the file with a more recent version. If a client wants to continue
* using the (now out-of-date) file, it must delete it when it has finished,
* as the cache manager will effectively relinquished ownership of the
* file.
*/
void ObserveStreamAsFile(in nsIStreamAsFile aStreamAsFile,
in PRUint32 aMessage,
in nsresult aError);
};

View File

@@ -0,0 +1,39 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH = ..
MODULE = necko
DIRS= \
base \
dns \
build \
protocol \
socket \
util \
mime \
streamconv \
cache \
test \
$(NULL)
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,32 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
interface nsIAtom;
[scriptable, uuid(a3ec67f0-465a-11d3-9a89-0080c7cb1080)]
interface nsIHTTPHeader : nsISupports
{
nsIAtom GetField();
string GetValue();
};

View File

@@ -0,0 +1,603 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIStreamListener.h"
#include "nsIStreamObserver.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsINetDataCache.h"
#include "nsINetDataCacheManager.h"
#include "nsICachedNetData.h"
// Number of test entries to be placed in the cache
// FIXME - temporary
#define NUM_CACHE_ENTRIES 25
// Cache content stream length will have random length between zero and
// MAX_CONTENT_LENGTH bytes
#define MAX_CONTENT_LENGTH 20000
// Limits, converted to KB
#define DISK_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 4) >> 10)
#define MEM_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 3) >> 10)
// Length of random-data cache entry URI key
#define CACHE_KEY_LENGTH 13
// Length of random-data cache entry secondary key
#define CACHE_SECONDARY_KEY_LENGTH 10
// Length of random-data cache entry meta-data
#define CACHE_PROTOCOL_PRIVATE_LENGTH 10
// Mapping from test case number to RecordID
static PRInt32 recordID[NUM_CACHE_ENTRIES];
static PRInt32
mapRecordIdToTestNum(PRInt32 aRecordID)
{
int i;
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
if (recordID[i] == aRecordID)
return i;
}
return -1;
}
// A supply of stream data to either store or compare with
class nsITestDataStream {
public:
virtual ~nsITestDataStream() {};
virtual PRUint32 Next() = 0;
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
virtual void ReadString(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool MatchString(char* aBuf, PRUint32 aCount) = 0;
virtual void Skip(PRUint32 aCount) = 0;
virtual void SkipString(PRUint32 aCount) = 0;
};
// A reproducible stream of random data.
class RandomStream : public nsITestDataStream {
public:
RandomStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState = 1103515245 * mState + 12345 ^ (mState >> 16);
return mState;
}
PRUint8 NextChar() {
PRUint8 c;
do {
c = Next();
} while (!isalnum(c));
return c;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
// Same as Read(), but using only printable chars and
// with a terminating NUL
void ReadString(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = NextChar();
}
*aBuf = 0;
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(Next() & 0xff))
return PR_FALSE;
}
return PR_TRUE;
}
PRBool
MatchString(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(NextChar() & 0xff))
return PR_FALSE;
}
// Check for terminating NUL character
if (*aBuf)
return PR_FALSE;
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
while (aCount--)
Next();
}
void
SkipString(PRUint32 aCount) {
while (aCount--)
NextChar();
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
static int gNumReaders = 0;
static PRUint32 gTotalBytesRead = 0;
static PRUint32 gTotalBytesWritten = 0;
static PRUint32 gTotalDuration = 0;
class nsReader : public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
nsReader()
: mStartTime(0), mBytesRead(0)
{
NS_INIT_REFCNT();
gNumReaders++;
}
virtual ~nsReader() {
delete mTestDataStream;
gNumReaders--;
}
nsresult
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
mTestDataStream = aRandomStream;
mExpectedStreamLength = aExpectedStreamLength;
mRefCnt = 1;
return NS_OK;
}
NS_IMETHOD OnStartRequest(nsIChannel* channel,
nsISupports* context) {
mStartTime = PR_IntervalNow();
return NS_OK;
}
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *aIStream,
PRUint32 aSourceOffset,
PRUint32 aLength) {
char buf[1025];
while (aLength > 0) {
PRUint32 amt;
PRBool match;
aIStream->Read(buf, sizeof buf, &amt);
if (amt == 0) break;
aLength -= amt;
mBytesRead += amt;
match = mTestDataStream->Match(buf, amt);
NS_ASSERTION(match, "Stored data was corrupted on read");
}
return NS_OK;
}
NS_IMETHOD OnStopRequest(nsIChannel* channel,
nsISupports* context,
nsresult aStatus,
const PRUnichar* aMsg) {
PRIntervalTime endTime;
PRIntervalTime duration;
endTime = PR_IntervalNow();
duration = (endTime - mStartTime);
if (NS_FAILED(aStatus)) printf("channel failed.\n");
// printf("read %d bytes\n", mBytesRead);
//FIXME NS_ASSERTION(mBytesRead == mExpectedStreamLength,
// "Stream in cache is wrong length");
gTotalBytesRead += mBytesRead;
gTotalDuration += duration;
return NS_OK;
}
protected:
PRIntervalTime mStartTime;
PRUint32 mBytesRead;
nsITestDataStream* mTestDataStream;
PRUint32 mExpectedStreamLength;
};
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
static nsIEventQueue* eventQueue;
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
nsresult
InitQueue() {
nsresult rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
rv = eventQService->CreateThreadEventQueue();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
return NS_OK;
}
// Process events until all streams are OnStopRequest'ed
nsresult
WaitForEvents() {
while (gNumReaders) {
eventQueue->ProcessPendingEvents();
}
return NS_OK;
}
// Read data for a single cache record and compare against testDataStream
nsresult
TestReadStream(nsICachedNetData *cacheEntry, nsITestDataStream *testDataStream,
PRUint32 expectedStreamLength)
{
nsCOMPtr<nsIChannel> channel;
nsresult rv;
PRUint32 actualContentLength;
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = cacheEntry->GetStoredContentLength(&actualContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// FIXME NS_ASSERTION(actualContentLength == expectedStreamLength,
// "nsICachedNetData::GetContentLength() busted ?");
nsReader *reader = new nsReader;
reader->AddRef();
rv = reader->Init(testDataStream, expectedStreamLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->AsyncRead(0, -1, 0, reader);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
reader->Release();
return NS_OK;
}
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch
static PRUint32
convertPRTimeToSeconds(PRTime aTime64)
{
double fpTime;
LL_L2D(fpTime, aTime64);
return (PRUint32)(fpTime * 1e-6 + 0.5);
}
// Convert unix-style time_t, i.e. seconds since the epoch, to PRTime
static PRTime
convertSecondsToPRTime(PRUint32 aSeconds)
{
PRInt64 t64;
LL_L2I(t64, aSeconds);
LL_MUL(t64, t64, 1000000);
return t64;
}
// Read the test data that was written in FillCache(), checking for
// corruption, truncation.
nsresult
TestRead(nsINetDataCacheManager *aCache, PRUint32 aFlags)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsICachedNetData> cacheEntry;
RandomStream *randomStream;
char uriCacheKey[CACHE_KEY_LENGTH];
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
char *storedUriKey;
PRUint32 testNum;
gTotalBytesRead = 0;
gTotalDuration = 0;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->ReadString(uriCacheKey, sizeof uriCacheKey - 1);
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
// Ensure that entry is in the cache
rv = aCache->Contains(uriCacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
rv = aCache->GetCachedNetData(uriCacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags,
getter_AddRefs(cacheEntry));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// Test GetUriSpec() method
rv = cacheEntry->GetUriSpec(&storedUriKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
!memcmp(storedUriKey, &uriCacheKey[0], sizeof uriCacheKey),
"nsICachedNetData::GetKey failed");
nsAllocator::Free(storedUriKey);
// Test GetSecondaryKey() method
PRUint32 storedSecondaryKeyLength;
char* storedSecondaryKey;
rv = cacheEntry->GetSecondaryKey(&storedSecondaryKeyLength, &storedSecondaryKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
!memcmp(storedSecondaryKey, &secondaryCacheKey[0],
sizeof secondaryCacheKey),
"nsICachedNetData::GetSecondaryKey failed");
// Compare against stored protocol data
char *storedProtocolData;
PRUint32 storedProtocolDataLength;
rv = cacheEntry->GetAnnotation("test data", &storedProtocolDataLength, &storedProtocolData);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
storedProtocolDataLength == CACHE_PROTOCOL_PRIVATE_LENGTH,
"nsICachedNetData::GetAnnotation() failed");
randomStream->Match(storedProtocolData, storedProtocolDataLength);
// Test GetAllowPartial()
PRBool allowPartial;
rv = cacheEntry->GetAllowPartial(&allowPartial);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
(allowPartial == (PRBool)(randomStream->Next() & 1)),
"nsICachedNetData::GetAllowPartial() failed");
// Test GetExpirationTime()
PRTime expirationTime;
PRTime expectedExpirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
rv = cacheEntry->GetExpirationTime(&expirationTime);
NS_ASSERTION(NS_SUCCEEDED(rv) && LL_EQ(expirationTime, expectedExpirationTime),
"nsICachedNetData::GetExpirationTime() failed");
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
TestReadStream(cacheEntry, randomStream, expectedStreamLength);
}
WaitForEvents();
// Compute rate in MB/s
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
rate *= NUM_CACHE_ENTRIES;
rate *= 1000;
rate /= (1024 * 1024);
printf("Read %7d bytes at a rate of %5.1f MB per second \n",
gTotalBytesRead, rate);
return NS_OK;
}
// Create entries in the network data cache, using random data for the
// key, the meta-data and the stored content data.
nsresult
FillCache(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsICachedNetData> cacheEntry;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
nsCOMPtr<nsINetDataCache> containingCache;
char buf[1000];
PRUint32 protocolDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
char protocolData[CACHE_PROTOCOL_PRIVATE_LENGTH];
PRUint32 testNum;
RandomStream *randomStream;
gTotalBytesWritten = 0;
PRIntervalTime startTime = PR_IntervalNow();
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->ReadString(cacheKey, sizeof cacheKey - 1);
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
// No entry should be in cache until we add it
rv = aCache->Contains(cacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(!inCache, "nsINetDataCacheManager::Contains error");
rv = aCache->GetCachedNetData(cacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags,
getter_AddRefs(cacheEntry));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access cacheEntry via cache key");
// Test nsINetDataCacheManager::GetNumEntries()
PRUint32 numEntries = (PRUint32)-1;
rv = aCache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
// Record meta-data should be initially empty
char *protocolDatap;
rv = cacheEntry->GetAnnotation("test data", &protocolDataLength, &protocolDatap);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
if ((protocolDataLength != 0) || (protocolDatap != 0))
return NS_ERROR_FAILURE;
// Store random data as meta-data
randomStream->Read(protocolData, sizeof protocolData);
cacheEntry->SetAnnotation("test data", sizeof protocolData, protocolData);
// Store random data as allow-partial flag
PRBool allowPartial = randomStream->Next() & 1;
rv = cacheEntry->SetAllowPartial(allowPartial);
NS_ASSERTION(NS_SUCCEEDED(rv),
"nsICachedNetData::SetAllowPartial() failed");
// Store random data as expiration time
PRTime expirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
rv = cacheEntry->SetExpirationTime(expirationTime);
NS_ASSERTION(NS_SUCCEEDED(rv),
"nsICachedNetData::SetExpirationTime() failed");
// Cache manager complains if expiration set without setting last-modified time
rv = cacheEntry->SetLastModifiedTime(expirationTime);
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = cacheEntry->GetCache(getter_AddRefs(containingCache));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
int remaining = streamLength;
while (remaining) {
PRUint32 numWritten;
int amount = PR_MIN(sizeof buf, remaining);
randomStream->Read(buf, amount);
rv = outStream->Write(buf, amount, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
remaining -= amount;
PRUint32 storageInUse;
rv = containingCache->GetStorageInUse(&storageInUse);
NS_ASSERTION(NS_SUCCEEDED(rv) && (storageInUse <= aCacheCapacity),
"Cache manager failed to limit cache growth");
}
outStream->Close();
gTotalBytesWritten += streamLength;
// *Now* there should be an entry in the cache
rv = aCache->Contains(cacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
delete randomStream;
}
PRIntervalTime endTime = PR_IntervalNow();
// Compute rate in MB/s
double rate = gTotalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
rate *= 1000;
rate /= (1024 * 1024);
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
gTotalBytesWritten, rate);
return NS_OK;
}
nsresult NS_AutoregisterComponents()
{
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
NULL /* default */);
return rv;
}
nsresult
Test(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
{
nsresult rv;
rv = aCache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
PRUint32 numEntries = (PRUint32)-1;
rv = aCache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
rv = FillCache(aCache, aFlags, aCacheCapacity);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
rv = TestRead(aCache, aFlags);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
rv = aCache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
rv = aCache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
return 0;
}
int
main(int argc, char* argv[])
{
nsresult rv;
nsCOMPtr<nsINetDataCacheManager> cache;
rv = NS_AutoregisterComponents();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
rv = nsComponentManager::CreateInstance(NS_NETWORK_CACHE_MANAGER_PROGID,
nsnull,
NS_GET_IID(nsINetDataCacheManager),
getter_AddRefs(cache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create cache manager factory") ;
cache->SetDiskCacheCapacity(DISK_CACHE_CAPACITY);
cache->SetMemCacheCapacity(MEM_CACHE_CAPACITY);
InitQueue();
Test(cache, nsINetDataCacheManager::BYPASS_PERSISTENT_CACHE, MEM_CACHE_CAPACITY);
Test(cache, nsINetDataCacheManager::BYPASS_MEMORY_CACHE, DISK_CACHE_CAPACITY);
return 0;
}

View File

@@ -0,0 +1,820 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIStreamListener.h"
#include "nsIStreamObserver.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include <stdio.h>
#include "nsINetDataCache.h"
#include "nsINetDataDiskCache.h"
#include "nsINetDataCacheRecord.h"
#include "nsMemCacheCID.h"
// file cache include
#include "nsNetDiskCacheCID.h"
#include "nsIPref.h"
#include "prenv.h"
#include "nsIFileStream.h"
// Number of test entries to be placed in the cache
#define NUM_CACHE_ENTRIES 250
// Cache content stream length will have random length between zero and
// MAX_CONTENT_LENGTH bytes
#define MAX_CONTENT_LENGTH 20000
// Length of random-data cache entry key
#define CACHE_KEY_LENGTH 15
// Length of random-data cache entry meta-data
#define CACHE_METADATA_LENGTH 100
static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
// file cache cid
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
// Mapping from test case number to RecordID
static PRInt32 recordID[NUM_CACHE_ENTRIES];
static PRInt32
mapRecordIdToTestNum(PRInt32 aRecordID)
{
int i;
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
if (recordID[i] == aRecordID)
return i;
}
return -1;
}
// A supply of stream data to either store or compare with
class nsITestDataStream {
public:
virtual ~nsITestDataStream() {};
virtual PRUint32 Next() = 0;
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
virtual void Skip(PRUint32 aCount) = 0;
};
// A reproducible stream of random data.
class RandomStream : public nsITestDataStream {
public:
RandomStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState = 1103515245 * mState + 12345;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(Next() & 0xff))
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
while (aCount--)
Next();
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
// A stream of data that increments on each byte that is read, modulo 256
class CounterStream : public nsITestDataStream {
public:
CounterStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState += 1;
mState &= 0xff;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)Next())
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
mState += aCount;
mState &= 0xff;
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
static int gNumReaders = 0;
static PRUint32 gTotalBytesRead = 0;
static PRUint32 gTotalDuration = 0;
class nsReader : public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
nsReader()
: mStartTime(0), mBytesRead(0)
{
NS_INIT_REFCNT();
gNumReaders++;
}
virtual ~nsReader() {
delete mTestDataStream;
gNumReaders--;
}
nsresult
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
mTestDataStream = aRandomStream;
mExpectedStreamLength = aExpectedStreamLength;
mRefCnt = 1;
return NS_OK;
}
NS_IMETHOD OnStartRequest(nsIChannel* channel,
nsISupports* context) {
mStartTime = PR_IntervalNow();
return NS_OK;
}
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *aIStream,
PRUint32 aSourceOffset,
PRUint32 aLength) {
char buf[1025];
while (aLength > 0) {
PRUint32 amt;
PRBool match;
aIStream->Read(buf, sizeof buf, &amt);
if (amt == 0) break;
aLength -= amt;
mBytesRead += amt;
match = mTestDataStream->Match(buf, amt);
NS_ASSERTION(match, "Stored data was corrupted on read");
}
return NS_OK;
}
NS_IMETHOD OnStopRequest(nsIChannel* channel,
nsISupports* context,
nsresult aStatus,
const PRUnichar* aMsg) {
PRIntervalTime endTime;
PRIntervalTime duration;
endTime = PR_IntervalNow();
duration = (endTime - mStartTime);
if (NS_FAILED(aStatus)) printf("channel failed.\n");
// printf("read %d bytes\n", mBytesRead);
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
"Stream in cache is wrong length");
gTotalBytesRead += mBytesRead;
gTotalDuration += duration;
return NS_OK;
}
protected:
PRIntervalTime mStartTime;
PRUint32 mBytesRead;
nsITestDataStream* mTestDataStream;
PRUint32 mExpectedStreamLength;
};
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
static nsIEventQueue* eventQueue;
nsresult
InitQueue() {
nsresult rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
rv = eventQService->CreateThreadEventQueue();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
return NS_OK;
}
// Process events until all streams are OnStopRequest'ed
nsresult
WaitForEvents() {
while (gNumReaders) {
eventQueue->ProcessPendingEvents();
}
return NS_OK;
}
// Read data for a single cache record and compare against testDataStream
nsresult
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
PRUint32 expectedStreamLength)
{
nsCOMPtr<nsIChannel> channel;
nsresult rv;
PRUint32 actualContentLength;
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = record->GetStoredContentLength(&actualContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(actualContentLength == expectedStreamLength,
"nsINetDataCacheRecord::GetContentLength() busted ?");
nsReader *reader = new nsReader;
rv = reader->Init(testDataStream, expectedStreamLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->AsyncRead(0, -1, 0, reader);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
reader->Release();
return NS_OK;
}
// Check that records can be retrieved using their record-ID, in addition
// to using the opaque key.
nsresult
TestRecordID(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
return NS_OK;
}
// Check that all cache entries in the database are enumerated and that
// no duplicates appear.
nsresult
TestEnumeration(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsISupports> tempISupports;
nsCOMPtr<nsISimpleEnumerator> iterator;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
PRInt32 recID;
int numRecords = 0;
// Iterate over all records in the cache
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
PRBool notDone;
while (1) {
// Done iterating ?
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
// Get next record in iteration
rv = iterator->GetNext(getter_AddRefs(tempISupports));
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
record = do_QueryInterface(tempISupports);
numRecords++;
// Get record ID
rv = record->GetRecordID(&recID);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
testNum = mapRecordIdToTestNum(recID);
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
// Erase mapping from table, so that duplicate enumerations are detected
recordID[testNum] = -1;
// Make sure stream matches test data
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
return NS_OK;
}
// Read the test data that was written in FillCache(), checking for
// corruption, truncation.
nsresult
TestRead(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData, *storedCacheKey;
PRUint32 testNum, storedCacheKeyLength;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Ensure that entry is in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// Match against previously stored meta-data
match = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
// Test GetKey() method
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
(storedCacheKeyLength == sizeof cacheKey) &&
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
"nsINetDataCacheRecord::GetKey failed");
nsAllocator::Free(storedCacheKey);
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
TestReadStream(record, randomStream, expectedStreamLength);
}
WaitForEvents();
// Compute rate in MB/s
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
rate *= NUM_CACHE_ENTRIES;
rate *= 1000;
rate /= (1024 * 1024);
printf("Read %d bytes at a rate of %5.1f MB per second \n",
gTotalBytesRead, rate);
return NS_OK;
}
// Repeatedly call SetStoredContentLength() on a cache entry and make
// read the stream's data to ensure that it's not corrupted by the effect
nsresult
TestTruncation(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
char cacheKey[CACHE_KEY_LENGTH];
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
randomStream->Skip(CACHE_METADATA_LENGTH);
PRUint32 initialStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
delete randomStream;
PRUint32 i;
PRUint32 delta = initialStreamLength / 64;
for (i = initialStreamLength; i >= delta; i -= delta) {
PRUint32 expectedStreamLength = i;
// Do the truncation
record->SetStoredContentLength(expectedStreamLength);
randomStream = new RandomStream(0);
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
PRUint32 afterContentLength;
rv = record->GetStoredContentLength(&afterContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(afterContentLength == expectedStreamLength,
"nsINetDataCacheRecord::SetContentLength() failed to truncate record");
TestReadStream(record, randomStream, expectedStreamLength);
WaitForEvents();
}
return NS_OK;
}
// Write known data to random offsets in a single cache entry and test
// resulting stream for correctness.
nsresult
TestOffsetWrites(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[512];
char cacheKey[CACHE_KEY_LENGTH];
RandomStream *randomStream;
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
// Write buffer-fulls of data at random offsets into the cache entry.
// Data written is (offset % 0xff)
PRUint32 startingOffset;
PRUint32 streamLength = 0;
CounterStream *counterStream;
int i;
for (i = 0; i < 100; i++) {
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
counterStream = new CounterStream(startingOffset);
counterStream->Read(buf, sizeof buf);
PRUint32 numWritten;
rv = outStream->Write(buf, sizeof buf, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
streamLength = startingOffset + sizeof buf;
rv = outStream->Close();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
delete counterStream;
}
delete randomStream;
counterStream = new CounterStream(0);
TestReadStream(record, counterStream, streamLength);
WaitForEvents();
return NS_OK;
}
// Create entries in the network data cache, using random data for the
// key, the meta-data and the stored content data.
nsresult
FillCache(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[1000];
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char metaData[CACHE_METADATA_LENGTH];
PRUint32 testNum;
char *data;
RandomStream *randomStream;
PRUint32 totalBytesWritten = 0;
PRIntervalTime startTime = PR_IntervalNow();
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// No entry should be in cache until we add it
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
// Test nsINetDataCacheRecord::GetRecordID()
rv = record->GetRecordID(&recordID[testNum]);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
// Test nsINetDataCache::GetNumEntries()
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
// Record meta-data should be initially empty
rv = record->GetMetaData(&metaDataLength, &data);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
if ((metaDataLength != 0) || (data != 0))
return NS_ERROR_FAILURE;
// Store random data as meta-data
randomStream->Read(metaData, sizeof metaData);
record->SetMetaData(sizeof metaData, metaData);
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
PRUint32 beforeOccupancy;
rv = cache->GetStorageInUse(&beforeOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
int remaining = streamLength;
while (remaining) {
PRUint32 numWritten;
int amount = PR_MIN(sizeof buf, remaining);
randomStream->Read(buf, amount);
rv = outStream->Write(buf, amount, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
remaining -= amount;
}
outStream->Close();
totalBytesWritten += streamLength;
PRUint32 afterOccupancy;
rv = cache->GetStorageInUse(&afterOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 streamLengthInKB = streamLength >> 10;
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
"nsINetDataCache::GetStorageInUse() is busted");
// *Now* there should be an entry in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
delete randomStream;
}
PRIntervalTime endTime = PR_IntervalNow();
// Compute rate in MB/s
double rate = totalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
rate *= 1000;
rate /= (1024 * 1024);
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
totalBytesWritten, rate);
return NS_OK;
}
nsresult NS_AutoregisterComponents()
{
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
NULL /* default */);
return rv;
}
PRBool initPref ()
{
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
if (NS_FAILED(rv))
return false;
nsCOMPtr<nsIFileSpec> fileSpec;
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
if (NS_FAILED(rv))
return false;
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
if (defaultPrefFile.Length())
defaultPrefFile += "/";
else
defaultPrefFile = "./";
defaultPrefFile += "default_prefs.js";
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
PRBool exists = false;
fileSpec->Exists(&exists);
if (exists)
prefPtr->ReadUserPrefsFrom(fileSpec);
else
return false;
return true;
}
int
main(int argc, char* argv[])
{
nsresult rv;
if(argc <2) {
printf(" %s -f to test filecache\n", argv[0]) ;
printf(" %s -m to test memcache\n", argv[0]) ;
return -1 ;
}
rv = NS_AutoregisterComponents();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
nsCOMPtr<nsINetDataCache> cache;
if (PL_strcasecmp(argv[1], "-m") == 0) {
rv = nsComponentManager::CreateInstance(kMemCacheCID, nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(cache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
} else if (PL_strcasecmp(argv[1], "-f") == 0) {
nsCOMPtr<nsINetDataDiskCache> diskcache ;
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
NS_GET_IID(nsINetDataDiskCache),
getter_AddRefs(diskcache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create disk cache factory") ;
nsCOMPtr<nsIFileSpec> folder ;
NS_NewFileSpec(getter_AddRefs(folder)) ;
folder->SetUnixStyleFilePath("/tmp") ;
diskcache->SetDiskCacheFolder(folder) ;
cache = diskcache ;
} else {
printf(" %s -f to test filecache\n", argv[0]) ;
printf(" %s -m to test memcache\n", argv[0]) ;
return -1 ;
}
InitQueue();
PRUnichar* description;
rv = cache->GetDescription(&description);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
nsCAutoString descStr(description);
printf("Testing: %s\n", descStr.GetBuffer());
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
PRUint32 startOccupancy;
rv = cache->GetStorageInUse(&startOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
rv = FillCache(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
rv = TestRead(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
rv = TestRecordID(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
rv = TestEnumeration(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
rv = TestTruncation(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
rv = TestOffsetWrites(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
PRUint32 endOccupancy;
rv = cache->GetStorageInUse(&endOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
return 0;
}

View File

@@ -0,0 +1,82 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH=..\..
MAKE_OBJ_TYPE = EXE
PROG1 = .\$(OBJDIR)\TestFileInput.exe
PROG2 = .\$(OBJDIR)\TestSocketInput.exe
PROG3 = .\$(OBJDIR)\TestSocketIO.exe
PROG4 = .\$(OBJDIR)\TestProtocols.exe
PROG5 = .\$(OBJDIR)\TestSocketTransport.exe
PROG6 = .\$(OBJDIR)\urltest.exe
PROG7 = .\$(OBJDIR)\TestFileInput2.exe
PROG8 = .\$(OBJDIR)\TestFileTransport.exe
PROG9 = .\$(OBJDIR)\TestRes.exe
PROGA = .\$(OBJDIR)\TestRawCache.exe
PROGB = .\$(OBJDIR)\TestCacheMgr.exe
PROGRAMS = \
#$(PROG1) $(PROG2) $(PROG3) $(PROG4) $(PROG5) $(PROG6) $(PROG7) $(PROG8) $(PROG9)\
$(PROGA) $(PROGB)
LCFLAGS=-DUSE_NSREG -GX
REQUIRES=libreg
INCS = $(INCS) \
-I$(DEPTH)\dist\include \
$(NULL)
LLIBS= \
$(DIST)\lib\xpcom.lib \
$(LIBNSPR) \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(PROGRAMS)
-for %p in ($(PROGRAMS)) do $(MAKE_INSTALL) %p $(DIST)\bin
clobber::
-for %p in ($(PROGRAMS)) do $(RM) %p $(DIST)\bin\%p
$(PROG1): $(OBJDIR) TestFileInput.cpp
$(PROG2): $(OBJDIR) TestSocketInput.cpp
$(PROG3): $(OBJDIR) TestSocketIO.cpp
$(PROG4): $(OBJDIR) TestProtocols.cpp
$(PROG5): $(OBJDIR) TestSocketTransport.cpp
$(PROG6): $(OBJDIR) urltest.cpp
$(PROG7): $(OBJDIR) TestFileInput2.cpp
$(PROG8): $(OBJDIR) TestFileTransport.cpp
$(PROG9): $(OBJDIR) TestRes.cpp
$(PROGA): $(OBJDIR) TestRawCache.cpp
$(PROGB): $(OBJDIR) TestCacheMgr.cpp

File diff suppressed because it is too large Load Diff

View File

@@ -1,135 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<!-- Coding standards for this document
* Other than the GFDL, please use the "section" tag instead of "sect1",
"sect2", etc.
* Use Entities to include files for new chapters in Bugzilla-Guide.xml.
* Try to use Entities for frequently-used passages of text as well.
* Ensure all documents compile cleanly to HTML after modification.
The warning, "DTDDECL catalog types not supported" is normal.
* Try to index important terms wherever possible.
* Use "glossterm" whenever you introduce a new term.
* Follow coding standards at http://www.tldp.org, and
check out the KDE guidelines (they are nice, too)
http://i18n.kde.org/doc/markup.html
* All tags should be lowercase.
* Please use sensible spacing. The comments at the very end of each
file define reasonable defaults for PSGML mode in EMACS.
* Double-indent tags, use double spacing whenever possible, and
try to avoid clutter and feel free to waste space in the code to make it
more readable.
-->
<book id="index">
<!-- Header -->
<bookinfo>
<title>The Bugzilla Guide - &bz-ver;
<!-- BZ-DEVEL -->Development <!-- /BZ-DEVEL -->
Release</title>
<authorgroup>
<corpauthor>The Bugzilla Team</corpauthor>
</authorgroup>
<pubdate>&bz-date;</pubdate>
<abstract>
<para>
This is the documentation for Bugzilla, a
bug-tracking system from mozilla.org.
Bugzilla is an enterprise-class piece of software
that tracks millions of bugs and issues for hundreds of
organizations around the world.
</para>
<para>
The most current version of this document can always be found on the
<ulink url="http://www.bugzilla.org/docs/">Bugzilla
Documentation Page</ulink>.
</para>
</abstract>
<keywordset>
<keyword>Bugzilla</keyword>
<keyword>Guide</keyword>
<keyword>installation</keyword>
<keyword>FAQ</keyword>
<keyword>administration</keyword>
<keyword>integration</keyword>
<keyword>MySQL</keyword>
<keyword>Mozilla</keyword>
<keyword>webtools</keyword>
</keywordset>
</bookinfo>
<!-- About This Guide -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="about.xml" />
<!-- Installing Bugzilla -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="installation.xml" />
<!-- Administering Bugzilla -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="administration.xml" />
<!-- Securing Bugzilla -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="security.xml" />
<!-- Customizing Bugzilla -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="customization.xml" />
<!-- Using Bugzilla -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="using.xml" />
<!-- Appendix: Troubleshooting -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="troubleshooting.xml" />
<!-- Appendix: Custom Patches -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="patches.xml" />
<!-- Appendix: Manually Installing Perl Modules -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="modules.xml" />
<!-- Appendix: GNU Free Documentation License -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="gfdl.xml" />
<!-- Glossary -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="glossary.xml" />
<!-- Index -->
<!--xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="index.xml" /-->
</book>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,246 +0,0 @@
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<!-- $Id: about.xml,v 1.26.4.1 2008-07-13 16:44:28 mozilla%colinogilvie.co.uk Exp $ -->
<chapter id="about">
<title>About This Guide</title>
<section id="copyright">
<title>Copyright Information</title>
<para>This document is copyright (c) 2000-&current-year; by the various
Bugzilla contributors who wrote it.</para>
<blockquote>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation
License, Version 1.1 or any later version published by the
Free Software Foundation; with no Invariant Sections, no
Front-Cover Texts, and with no Back-Cover Texts. A copy of
the license is included in <xref linkend="gfdl"/>.
</para>
</blockquote>
<para>
If you have any questions regarding this document, its
copyright, or publishing this document in non-electronic form,
please contact the Bugzilla Team.
</para>
</section>
<section id="disclaimer">
<title>Disclaimer</title>
<para>
No liability for the contents of this document can be accepted.
Follow the instructions herein at your own risk.
This document may contain errors
and inaccuracies that may damage your system, cause your partner
to leave you, your boss to fire you, your cats to
pee on your furniture and clothing, and global thermonuclear
war. Proceed with caution.
</para>
<para>
Naming of particular products or brands should not be seen as
endorsements, with the exception of the term "GNU/Linux". We
wholeheartedly endorse the use of GNU/Linux; it is an extremely
versatile, stable,
and robust operating system that offers an ideal operating
environment for Bugzilla.
</para>
<para>
Although the Bugzilla development team has taken great care to
ensure that all exploitable bugs have been fixed, security holes surely
exist in any piece of code. Great care should be taken both in
the installation and usage of this software. The Bugzilla development
team members assume no liability for your use of Bugzilla. You have
the source code, and are responsible for auditing it yourself to ensure
your security needs are met.
</para>
</section>
<!-- Section 2: New Versions -->
<section id="newversions">
<title>New Versions</title>
<para>
This is the &bz-ver; version of The Bugzilla Guide. It is so named
to match the current version of Bugzilla.
<!-- BZ-DEVEL --> This version of the guide, like its associated Bugzilla version, is a
development version.<!-- /BZ-DEVEL -->
</para>
<para>
The latest version of this guide can always be found at <ulink
url="http://www.bugzilla.org"/>, or checked out via CVS by
following the <ulink url="http://www.mozilla.org/cvs.html">Mozilla
CVS</ulink> instructions and check out the
<filename>mozilla/webtools/bugzilla/docs/</filename>
subtree. However, you should read the version
which came with the Bugzilla release you are using.
</para>
<para>
The Bugzilla Guide, or a section of it, is also available in
the following languages:
<ulink url="http://www.traduc.org/docs/guides/lecture/bugzilla/">French</ulink>,
<ulink url="http://bugzilla-de.sourceforge.net/docs/html/">German</ulink>,
<ulink url="http://www.bugzilla.jp/docs/2.18/">Japanese</ulink>.
Note that these may be outdated or not up to date.
</para>
<para>
In addition, there are Bugzilla template localization projects in
the following languages. They may have translated documentation
available:
<ulink url="http://sourceforge.net/projects/bugzilla-ar/">Arabic</ulink>,
<ulink url="http://sourceforge.net/projects/bugzilla-be/">Belarusian</ulink>,
<ulink url="http://openfmi.net/projects/mozilla-bg/">Bulgarian</ulink>,
<ulink url="http://sourceforge.net/projects/bugzilla-br/">Brazilian Portuguese</ulink>,
<ulink url="http://sourceforge.net/projects/bugzilla-cn/">Chinese</ulink>,
<ulink url="http://sourceforge.net/projects/bugzilla-fr/">French</ulink>,
<ulink url="http://germzilla.ganderbay.net/">German</ulink>,
<ulink url="http://sourceforge.net/projects/bugzilla-it/">Italian</ulink>,
<ulink url="http://www.bugzilla.jp/about/jp.html">Japanese</ulink>,
<ulink url="http://sourceforge.net/projects/bugzilla-kr/">Korean</ulink>,
<ulink url="http://sourceforge.net/projects/bugzilla-ru/">Russian</ulink> and
<ulink url="http://sourceforge.net/projects/bugzilla-es/">Spanish</ulink>.
</para>
<para>
If you would like to volunteer to translate the Guide into additional
languages, please contact
<ulink url="mailto:justdave@bugzilla.org">Dave Miller</ulink>.
</para>
</section>
<section id="credits">
<title>Credits</title>
<para>
The people listed below have made enormous contributions to the
creation of this Guide, through their writing, dedicated hacking efforts,
numerous e-mail and IRC support sessions, and overall excellent
contribution to the Bugzilla community:
</para>
<!-- TODO: This is evil... there has to be a valid way to get this look -->
<variablelist>
<varlistentry>
<term>Matthew P. Barnson <email>mbarnson@sisna.com</email></term>
<listitem>
<para>for the Herculean task of pulling together the Bugzilla Guide
and shepherding it to 2.14.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Terry Weissman <email>terry@mozilla.org</email></term>
<listitem>
<para>for initially writing Bugzilla and creating the README upon
which the UNIX installation documentation is largely based.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Tara Hernandez <email>tara@tequilarists.org</email></term>
<listitem>
<para>for keeping Bugzilla development going strong after Terry left
mozilla.org and for running landfill.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Dave Lawrence <email>dkl@redhat.com</email></term>
<listitem>
<para>for providing insight into the key differences between Red
Hat's customized Bugzilla.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Dawn Endico <email>endico@mozilla.org</email></term>
<listitem>
<para>for being a hacker extraordinaire and putting up with Matthew's
incessant questions and arguments on irc.mozilla.org in #mozwebtools
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Jacob Steenhagen <email>jake@bugzilla.org</email></term>
<listitem>
<para>for taking over documentation during the 2.17 development
period.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Dave Miller <email>justdave@bugzilla.org</email></term>
<listitem>
<para>for taking over as project lead when Tara stepped down and
continually pushing for the documentation to be the best it can be.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Thanks also go to the following people for significant contributions
to this documentation:
<simplelist type="inline">
<member>Kevin Brannen</member>
<member>Vlad Dascalu</member>
<member>Ben FrantzDale</member>
<member>Eric Hanson</member>
<member>Zach Lipton</member>
<member>Gervase Markham</member>
<member>Andrew Pearson</member>
<member>Joe Robins</member>
<member>Spencer Smith</member>
<member>Ron Teitelbaum</member>
<member>Shane Travis</member>
<member>Martin Wulffeld</member>
</simplelist>.
</para>
<para>
Also, thanks are due to the members of the
<ulink url="news://news.mozilla.org/mozilla.support.bugzilla">
mozilla.support.bugzilla</ulink>
newsgroup (and its predecessor, netscape.public.mozilla.webtools).
Without your discussions, insight, suggestions, and patches,
this could never have happened.
</para>
</section>
<!-- conventions used here (didn't want to give it a chapter of its own) -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="conventions.xml" />
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End: -->

File diff suppressed because it is too large Load Diff

View File

@@ -1,168 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<section id="conventions">
<title>Document Conventions</title>
<indexterm zone="conventions">
<primary>conventions</primary>
</indexterm>
<para>This document uses the following conventions:</para>
<informaltable frame="none">
<tgroup cols="2">
<thead>
<row>
<entry>Descriptions</entry>
<entry>Appearance</entry>
</row>
</thead>
<tbody>
<row>
<entry>Caution</entry>
<entry>
<caution>
<para>Don't run with scissors!</para>
</caution>
</entry>
</row>
<row>
<entry>Hint or Tip</entry>
<entry>
<tip>
<para>For best results... </para>
</tip>
</entry>
</row>
<row>
<entry>Note</entry>
<entry>
<note>
<para>Dear John...</para>
</note>
</entry>
</row>
<row>
<entry>Warning</entry>
<entry>
<warning>
<para>Read this or the cat gets it.</para>
</warning>
</entry>
</row>
<row>
<entry>File or directory name</entry>
<entry>
<filename>filename</filename>
</entry>
</row>
<row>
<entry>Command to be typed</entry>
<entry>
<command>command</command>
</entry>
</row>
<row>
<entry>Application name</entry>
<entry>
<application>application</application>
</entry>
</row>
<row>
<entry>
Normal user's prompt under bash shell</entry>
<entry>bash$</entry>
</row>
<row>
<entry>
Root user's prompt under bash shell</entry>
<entry>bash#</entry>
</row>
<row>
<entry>
Normal user's prompt under tcsh shell</entry>
<entry>tcsh$</entry>
</row>
<row>
<entry>Environment variables</entry>
<entry>
<envar>VARIABLE</envar>
</entry>
</row>
<row>
<entry>Term found in the glossary</entry>
<entry>
<glossterm linkend="gloss-bugzilla">Bugzilla</glossterm>
</entry>
</row>
<row>
<entry>Code example</entry>
<entry>
<programlisting><sgmltag class="starttag">para</sgmltag>
Beginning and end of paragraph
<sgmltag class="endtag">para</sgmltag></programlisting>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
This documentation is maintained in DocBook 4.1.2 XML format.
Changes are best submitted as plain text or XML diffs, attached
to a bug filed in the &bzg-bugs; component.
</para>
</section>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,821 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<chapter id="customization">
<title>Customizing Bugzilla</title>
<section id="cust-skins">
<title>Custom Skins</title>
<para>
Bugzilla allows you to have multiple skins. These are custom CSS and possibly
also custom images for Bugzilla. To create a new custom skin, you have two
choices:
<itemizedlist>
<listitem>
<para>
Make a single CSS file, and put it in the
<filename>skins/contrib</filename> directory.
</para>
</listitem>
<listitem>
<para>
Make a directory that contains all the same CSS file
names as <filename>skins/standard/</filename>, and put
your directory in <filename>skins/contrib/</filename>.
</para>
</listitem>
</itemizedlist>
</para>
<para>
After you put the file or the directory there, make sure to run checksetup.pl
so that it can reset the file permissions correctly.
</para>
<para>
After you have installed the new skin, it will show up as an option in the
user's General Preferences. If you would like to force a particular skin on all
users, just select it in the Default Preferences and then uncheck "Enabled" on
the preference.
</para>
</section>
<section id="cust-templates">
<title>Template Customization</title>
<para>
Administrators can configure the look and feel of Bugzilla without
having to edit Perl files or face the nightmare of massive merge
conflicts when they upgrade to a newer version in the future.
</para>
<para>
Templatization also makes localized versions of Bugzilla possible,
for the first time. It's possible to have Bugzilla's UI language
determined by the user's browser. More information is available in
<xref linkend="template-http-accept"/>.
</para>
<section id="template-directory">
<title>Template Directory Structure</title>
<para>
The template directory structure starts with top level directory
named <filename>template</filename>, which contains a directory
for each installed localization. The next level defines the
language used in the templates. Bugzilla comes with English
templates, so the directory name is <filename>en</filename>,
and we will discuss <filename>template/en</filename> throughout
the documentation. Below <filename>template/en</filename> is the
<filename>default</filename> directory, which contains all the
standard templates shipped with Bugzilla.
</para>
<warning>
<para>
A directory <filename>data/templates</filename> also exists;
this is where Template Toolkit puts the compiled versions of
the templates from either the default or custom directories.
<emphasis>Do not</emphasis> directly edit the files in this
directory, or all your changes will be lost the next time
Template Toolkit recompiles the templates.
</para>
</warning>
</section>
<section id="template-method">
<title>Choosing a Customization Method</title>
<para>
If you want to edit Bugzilla's templates, the first decision
you must make is how you want to go about doing so. There are two
choices, and which you use depends mainly on the scope of your
modifications, and the method you plan to use to upgrade Bugzilla.
</para>
<para>
The first method of making customizations is to directly edit the
templates found in <filename>template/en/default</filename>.
This is probably the best way to go about it if you are going to
be upgrading Bugzilla through CVS, because if you then execute
a <command>cvs update</command>, any changes you have made will
be merged automagically with the updated versions.
</para>
<note>
<para>
If you use this method, and CVS conflicts occur during an
update, the conflicted templates (and possibly other parts
of your installation) will not work until they are resolved.
</para>
</note>
<para>
The second method is to copy the templates to be modified
into a mirrored directory structure under
<filename>template/en/custom</filename>. Templates in this
directory structure automatically override any identically-named
and identically-located templates in the
<filename>default</filename> directory.
</para>
<note>
<para>
The <filename>custom</filename> directory does not exist
at first and must be created if you want to use it.
</para>
</note>
<para>
The second method of customization should be used if you
use the overwriting method of upgrade, because otherwise
your changes will be lost. This method may also be better if
you are using the CVS method of upgrading and are going to make major
changes, because it is guaranteed that the contents of this directory
will not be touched during an upgrade, and you can then decide whether
to continue using your own templates, or make the effort to merge your
changes into the new versions by hand.
</para>
<para>
Using this method, your installation may break if incompatible
changes are made to the template interface. Such changes should
be documented in the release notes, provided you are using a
stable release of Bugzilla. If you use using unstable code, you will
need to deal with this one yourself, although if possible the changes
will be mentioned before they occur in the deprecations section of the
previous stable release's release notes.
</para>
<note>
<para>
Regardless of which method you choose, it is recommended that
you run <command>./checksetup.pl</command> after creating or
editing any templates in the <filename>template/en/default</filename>
directory, and after editing any templates in the
<filename>custom</filename> directory.
</para>
</note>
<warning>
<para>
It is <emphasis>required</emphasis> that you run
<command>./checksetup.pl</command> after creating a new
template in the <filename>custom</filename> directory. Failure
to do so will raise an incomprehensible error message.
</para>
</warning>
</section>
<section id="template-edit">
<title>How To Edit Templates</title>
<note>
<para>
If you are making template changes that you intend on submitting back
for inclusion in standard Bugzilla, you should read the relevant
sections of the
<ulink url="http://www.bugzilla.org/docs/developer.html">Developers'
Guide</ulink>.
</para>
</note>
<para>
The syntax of the Template Toolkit language is beyond the scope of
this guide. It's reasonably easy to pick up by looking at the current
templates; or, you can read the manual, available on the
<ulink url="http://www.template-toolkit.org">Template Toolkit home
page</ulink>.
</para>
<para>
One thing you should take particular care about is the need
to properly HTML filter data that has been passed into the template.
This means that if the data can possibly contain special HTML characters
such as &lt;, and the data was not intended to be HTML, they need to be
converted to entity form, i.e. &amp;lt;. You use the 'html' filter in the
Template Toolkit to do this. If you forget, you may open up
your installation to cross-site scripting attacks.
</para>
<para>
Also note that Bugzilla adds a few filters of its own, that are not
in standard Template Toolkit. In particular, the 'url_quote' filter
can convert characters that are illegal or have special meaning in URLs,
such as &amp;, to the encoded form, i.e. %26. This actually encodes most
characters (but not the common ones such as letters and numbers and so
on), including the HTML-special characters, so there's never a need to
HTML filter afterwards.
</para>
<para>
Editing templates is a good way of doing a <quote>poor man's custom
fields</quote>.
For example, if you don't use the Status Whiteboard, but want to have
a free-form text entry box for <quote>Build Identifier</quote>,
then you can just
edit the templates to change the field labels. It's still be called
status_whiteboard internally, but your users don't need to know that.
</para>
</section>
<section id="template-formats">
<title>Template Formats and Types</title>
<para>
Some CGI's have the ability to use more than one template. For example,
<filename>buglist.cgi</filename> can output itself as RDF, or as two
formats of HTML (complex and simple). The mechanism that provides this
feature is extensible.
</para>
<para>
Bugzilla can support different types of output, which again can have
multiple formats. In order to request a certain type, you can append
the &amp;ctype=&lt;contenttype&gt; (such as rdf or html) to the
<filename>&lt;cginame&gt;.cgi</filename> URL. If you would like to
retrieve a certain format, you can use the &amp;format=&lt;format&gt;
(such as simple or complex) in the URL.
</para>
<para>
To see if a CGI supports multiple output formats and types, grep the
CGI for <quote>get_format</quote>. If it's not present, adding
multiple format/type support isn't too hard - see how it's done in
other CGIs, e.g. config.cgi.
</para>
<para>
To make a new format template for a CGI which supports this,
open a current template for
that CGI and take note of the INTERFACE comment (if present.) This
comment defines what variables are passed into this template. If
there isn't one, I'm afraid you'll have to read the template and
the code to find out what information you get.
</para>
<para>
Write your template in whatever markup or text style is appropriate.
</para>
<para>
You now need to decide what content type you want your template
served as. The content types are defined in the
<filename>Bugzilla/Constants.pm</filename> file in the
<filename>contenttypes</filename>
constant. If your content type is not there, add it. Remember
the three- or four-letter tag assigned to your content type.
This tag will be part of the template filename.
</para>
<note>
<para>
After adding or changing a content type, it's suitable to edit
<filename>Bugzilla/Constants.pm</filename> in order to reflect
the changes. Also, the file should be kept up to date after an
upgrade if content types have been customized in the past.
</para>
</note>
<para>
Save the template as <filename>&lt;stubname&gt;-&lt;formatname&gt;.&lt;contenttypetag&gt;.tmpl</filename>.
Try out the template by calling the CGI as
<filename>&lt;cginame&gt;.cgi?format=&lt;formatname&gt;&amp;ctype=&lt;type&gt;</filename> .
</para>
</section>
<section id="template-specific">
<title>Particular Templates</title>
<para>
There are a few templates you may be particularly interested in
customizing for your installation.
</para>
<para>
<command>index.html.tmpl</command>:
This is the Bugzilla front page.
</para>
<para>
<command>global/header.html.tmpl</command>:
This defines the header that goes on all Bugzilla pages.
The header includes the banner, which is what appears to users
and is probably what you want to edit instead. However the
header also includes the HTML HEAD section, so you could for
example add a stylesheet or META tag by editing the header.
</para>
<para>
<command>global/banner.html.tmpl</command>:
This contains the <quote>banner</quote>, the part of the header
that appears
at the top of all Bugzilla pages. The default banner is reasonably
barren, so you'll probably want to customize this to give your
installation a distinctive look and feel. It is recommended you
preserve the Bugzilla version number in some form so the version
you are running can be determined, and users know what docs to read.
</para>
<para>
<command>global/footer.html.tmpl</command>:
This defines the footer that goes on all Bugzilla pages. Editing
this is another way to quickly get a distinctive look and feel for
your Bugzilla installation.
</para>
<para>
<command>global/variables.none.tmpl</command>:
This defines a list of terms that may be changed in order to
<quote>brand</quote> the Bugzilla instance In this way, terms
like <quote>bugs</quote> can be replaced with <quote>issues</quote>
across the whole Bugzilla installation. The name
<quote>Bugzilla</quote> and other words can be customized as well.
</para>
<para>
<command>list/table.html.tmpl</command>:
This template controls the appearance of the bug lists created
by Bugzilla. Editing this template allows per-column control of
the width and title of a column, the maximum display length of
each entry, and the wrap behaviour of long entries.
For long bug lists, Bugzilla inserts a 'break' every 100 bugs by
default; this behaviour is also controlled by this template, and
that value can be modified here.
</para>
<para>
<command>bug/create/user-message.html.tmpl</command>:
This is a message that appears near the top of the bug reporting page.
By modifying this, you can tell your users how they should report
bugs.
</para>
<para>
<command>bug/process/midair.html.tmpl</command>:
This is the page used if two people submit simultaneous changes to the
same bug. The second person to submit their changes will get this page
to tell them what the first person did, and ask if they wish to
overwrite those changes or go back and revisit the bug. The default
title and header on this page read "Mid-air collision detected!" If
you work in the aviation industry, or other environment where this
might be found offensive (yes, we have true stories of this happening)
you'll want to change this to something more appropriate for your
environment.
</para>
<para>
<command>bug/create/create.html.tmpl</command> and
<command>bug/create/comment.txt.tmpl</command>:
You may not wish to go to the effort of creating custom fields in
Bugzilla, yet you want to make sure that each bug report contains
a number of pieces of important information for which there is not
a special field. The bug entry system has been designed in an
extensible fashion to enable you to add arbitrary HTML widgets,
such as drop-down lists or textboxes, to the bug entry page
and have their values appear formatted in the initial comment.
A hidden field that indicates the format should be added inside
the form in order to make the template functional. Its value should
be the suffix of the template filename. For example, if the file
is called <filename>create-cust.html.tmpl</filename>, then
<programlisting>&lt;input type="hidden" name="format" value="cust"&gt;</programlisting>
should be used inside the form.
</para>
<para>
An example of this is the mozilla.org
<ulink url="http://landfill.bugzilla.org/bugzilla-tip/enter_bug.cgi?product=WorldControl&amp;format=guided">guided
bug submission form</ulink>. The code for this comes with the Bugzilla
distribution as an example for you to copy. It can be found in the
files
<filename>create-guided.html.tmpl</filename> and
<filename>comment-guided.html.tmpl</filename>.
</para>
<para>
So to use this feature, create a custom template for
<filename>enter_bug.cgi</filename>. The default template, on which you
could base it, is
<filename>custom/bug/create/create.html.tmpl</filename>.
Call it <filename>create-&lt;formatname&gt;.html.tmpl</filename>, and
in it, add widgets for each piece of information you'd like
collected - such as a build number, or set of steps to reproduce.
</para>
<para>
Then, create a template like
<filename>custom/bug/create/comment.txt.tmpl</filename>, and call it
<filename>comment-&lt;formatname&gt;.txt.tmpl</filename>. This
template should reference the form fields you have created using
the syntax <filename>[% form.&lt;fieldname&gt; %]</filename>. When a
bug report is
submitted, the initial comment attached to the bug report will be
formatted according to the layout of this template.
</para>
<para>
For example, if your custom enter_bug template had a field
<programlisting>&lt;input type="text" name="buildid" size="30"&gt;</programlisting>
and then your comment.txt.tmpl had
<programlisting>BuildID: [% form.buildid %]</programlisting>
then something like
<programlisting>BuildID: 20020303</programlisting>
would appear in the initial comment.
</para>
</section>
<section id="template-http-accept">
<title>Configuring Bugzilla to Detect the User's Language</title>
<para>Bugzilla honours the user's Accept: HTTP header. You can install
templates in other languages, and Bugzilla will pick the most appropriate
according to a priority order defined by you. Many
language templates can be obtained from <ulink
url="http://www.bugzilla.org/download.html#localizations"/>. Instructions
for submitting new languages are also available from that location.
</para>
</section>
</section>
<section id="cust-hooks">
<title>The Bugzilla Extension Mechanism</title>
<warning>
<para>
Note that the below paths are inconsistent and confusing. They will
likely be changed in Bugzilla 4.0.
</para>
</warning>
<para>
Extensions are a way for extensions to Bugzilla to insert code
into the standard Bugzilla templates and source files
without modifying these files themselves. The extension mechanism
defines a consistent API for extending the standard templates and source files
in a way that cleanly separates standard code from extension code.
Hooks reduce merge conflicts and make it easier to write extensions that work
across multiple versions of Bugzilla, making upgrading a Bugzilla installation
with installed extensions easier. Furthermore, they make it easy to install
and remove extensions as each extension is nothing more than a
simple directory structure.
</para>
<para>
There are two main types of hooks: code hooks and template hooks. Code
hooks allow extensions to invoke code at specific points in various
source files, while template hooks allow extensions to add elements to
the Bugzilla user interface.
</para>
<para>
A hook is just a named place in a standard source or template file
where extension source code or template files for that hook get processed.
Each extension has a corresponding directory in the Bugzilla directory
tree (<filename>BUGZILLA_ROOT/extensions/extension_name</filename>). Hooking
an extension source file or template to a hook is as simple as putting
the extension file into extension's template or code directory.
When Bugzilla processes the source file or template and reaches the hook,
it will process all extension files in the hook's directory.
The hooks themselves can be added into any source file or standard template
upon request by extension authors.
</para>
<para>
To use hooks to extend Bugzilla, first make sure there is
a hook at the appropriate place within the source file or template you
want to extend. The exact appearance of a hook depends on if the hook
is a code hook or a template hook.
</para>
<para>
Code hooks appear in Bugzilla source files as a single method call
in the format <literal role="code">Bugzilla::Hook->process("<varname>name</varname>");</literal>.
For instance, <filename>enter_bug.cgi</filename> may invoke the hook
"<varname>enter_bug-entrydefaultvars</varname>". Thus, a source file at
<filename>BUGZILLA_ROOT/extensions/EXTENSION_NAME/code/enter_bug-entrydefaultvars.pl</filename>
will be automatically invoked when the code hook is reached.
</para>
<para>
Template hooks appear in the standard Bugzilla templates as a
single directive in the format
<literal role="code">[% Hook.process("<varname>name</varname>") %]</literal>,
where <varname>name</varname> is the unique name of the hook.
</para>
<para>
If you aren't sure what you want to extend or just want to browse the
available hooks, either use your favorite multi-file search
tool (e.g. <command>grep</command>) to search the standard templates
for occurrences of <methodname>Hook.process</methodname> or the source
files for occurrences of <methodname>Bugzilla::Hook::process</methodname>.
</para>
<para>
If there is no hook at the appropriate place within the Bugzilla
source file or template you want to extend,
<ulink url="http://bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&amp;component=User%20Interface">file
a bug requesting one</ulink>, specifying:
</para>
<simplelist>
<member>the source or template file for which you are
requesting a hook;</member>
<member>
where in the file you would like the hook to be placed
(line number/position for latest version of the file in CVS
or description of location);
</member>
<member>the purpose of the hook;</member>
<member>a link to information about your extension, if any.</member>
</simplelist>
<para>
The Bugzilla reviewers will promptly review each hook request,
name the hook, add it to the template or source file, and check
the new version of the template into CVS.
</para>
<para>
You may optionally attach a patch to the bug which implements the hook
and check it in yourself after receiving approval from a Bugzilla
reviewer. The developers may suggest changes to the location of the
hook based on their analysis of your needs or so the hook can satisfy
the needs of multiple extensions, but the process of getting hooks
approved and checked in is not as stringent as the process for general
changes to Bugzilla, and any extension, whether released or still in
development, can have hooks added to meet their needs.
</para>
<para>
After making sure the hook you need exists (or getting it added if not),
add your extension to the directory within the Bugzilla
extensions tree corresponding to the hook.
</para>
<para>
That's it! Now, when the source file or template containing the hook
is processed, your extension file will be processed at the point
where the hook appears.
</para>
<para>
For example, let's say you have an extension named Projman that adds
project management capabilities to Bugzilla. Projman has an
administration interface <filename>edit-projects.cgi</filename>,
and you want to add a link to it into the navigation bar at the bottom
of every Bugzilla page for those users who are authorized
to administer projects.
</para>
<para>
The navigation bar is generated by the template file
<filename>useful-links.html.tmpl</filename>, which is located in
the <filename>global/</filename> subdirectory on the standard Bugzilla
template path
<filename>BUGZILLA_ROOT/template/en/default/</filename>.
Looking in <filename>useful-links.html.tmpl</filename>, you find
the following hook at the end of the list of standard Bugzilla
administration links:
</para>
<programlisting><![CDATA[...
[% ', <a href="editkeywords.cgi">keywords</a>'
IF user.groups.editkeywords %]
[% Hook.process("edit") %]
...]]></programlisting>
<para>
The corresponding extension file for this hook is
<filename>BUGZILLA_ROOT/extensions/projman/template/en/global/useful-links-edit.html.tmpl</filename>.
You then create that template file and add the following constant:
</para>
<programlisting><![CDATA[...[% ', <a href="edit-projects.cgi">projects</a>' IF user.groups.projman_admins %]]]></programlisting>
<para>
Voila! The link now appears after the other administration links in the
navigation bar for users in the <literal>projman_admins</literal> group.
</para>
<para>
Now, let us say your extension adds a custom "project_manager" field
to enter_bug.cgi. You want to modify the CGI script to set the default
project manager to be productname@company.com. Looking at
<filename>enter_bug.cgi</filename>, you see the enter_bug-entrydefaultvars
hook near the bottom of the file before the default form values are set.
The corresponding extension source file for this hook is located at
<filename>BUGZILLA_ROOT/extensions/projman/code/enter_bug-entrydefaultvars.pl</filename>.
You then create that file and add the following:
</para>
<programlisting>$default{'project_manager'} = $product.'@company.com';</programlisting>
<para>
This code will be invoked whenever enter_bug.cgi is executed.
Assuming that the rest of the customization was completed (e.g. the
custom field was added to the enter_bug template and the required hooks
were used in process_bug.cgi), the new field will now have this
default value.
</para>
<para>
Notes:
</para>
<itemizedlist>
<listitem>
<para>
If your extension includes entirely new templates in addition to
extensions of standard templates, it should store those new
templates in its
<filename>BUGZILLA_ROOT/extensions/template/en/</filename>
directory. Extension template directories, like the
<filename>default/</filename> and <filename>custom/</filename>
directories, are part of the template search path, so putting templates
there enables them to be found by the template processor.
</para>
<para>
The template processor looks for templates first in the
<filename>custom/</filename> directory (i.e. templates added by the
specific installation), then in the <filename>extensions/</filename>
directory (i.e. templates added by extensions), and finally in the
<filename>default/</filename> directory (i.e. the standard Bugzilla
templates). Thus, installation-specific templates override both
default and extension templates.
</para>
</listitem>
<listitem>
<para>
If you are looking to customize Bugzilla, you can also take advantage
of template hooks. To do so, create a directory in
<filename>BUGZILLA_ROOT/template/en/custom/hook/</filename>
that corresponds to the hook you wish to use, then place your
customization templates into those directories. For example,
if you wanted to use the hook "end" in
<filename>global/useful-links.html.tmpl</filename>, you would
create the directory <filename>BUGZILLA_ROOT/template/en/custom/hook/
global/useful-links.html.tmpl/end/</filename> and add your customization
template to this directory.
</para>
<para>
Obviously this method of customizing Bugzilla only lets you add code
to the standard source files and templates; you cannot change the
existing code. Nevertheless, for those customizations that only add
code, this method can reduce conflicts when merging changes,
making upgrading your customized Bugzilla installation easier.
</para>
</listitem>
</itemizedlist>
</section>
<section id="cust-change-permissions">
<title>Customizing Who Can Change What</title>
<warning>
<para>
This feature should be considered experimental; the Bugzilla code you
will be changing is not stable, and could change or move between
versions. Be aware that if you make modifications as outlined here,
you may have
to re-make them or port them if Bugzilla changes internally between
versions, and you upgrade.
</para>
</warning>
<para>
Companies often have rules about which employees, or classes of employees,
are allowed to change certain things in the bug system. For example,
only the bug's designated QA Contact may be allowed to VERIFY the bug.
Bugzilla has been
designed to make it easy for you to write your own custom rules to define
who is allowed to make what sorts of value transition.
</para>
<para>
By default, assignees, QA owners and users
with <emphasis>editbugs</emphasis> privileges can edit all fields of bugs,
except group restrictions (unless they are members of the groups they
are trying to change). Bug reporters also have the ability to edit some
fields, but in a more restrictive manner. Other users, without
<emphasis>editbugs</emphasis> privileges, can not edit
bugs, except to comment and add themselves to the CC list.
</para>
<para>
For maximum flexibility, customizing this means editing Bugzilla's Perl
code. This gives the administrator complete control over exactly who is
allowed to do what. The relevant method is called
<filename>check_can_change_field()</filename>,
and is found in <filename>Bug.pm</filename> in your
Bugzilla/ directory. If you open that file and search for
<quote>sub check_can_change_field</quote>, you'll find it.
</para>
<para>
This function has been carefully commented to allow you to see exactly
how it works, and give you an idea of how to make changes to it.
Certain marked sections should not be changed - these are
the <quote>plumbing</quote> which makes the rest of the function work.
In between those sections, you'll find snippets of code like:
<programlisting> # Allow the assignee to change anything.
if ($ownerid eq $whoid) {
return 1;
}</programlisting>
It's fairly obvious what this piece of code does.
</para>
<para>
So, how does one go about changing this function? Well, simple changes
can be made just by removing pieces - for example, if you wanted to
prevent any user adding a comment to a bug, just remove the lines marked
<quote>Allow anyone to change comments.</quote> If you don't want the
Reporter to have any special rights on bugs they have filed, just
remove the entire section that deals with the Reporter.
</para>
<para>
More complex customizations are not much harder. Basically, you add
a check in the right place in the function, i.e. after all the variables
you are using have been set up. So, don't look at $ownerid before
$ownerid has been obtained from the database. You can either add a
positive check, which returns 1 (allow) if certain conditions are true,
or a negative check, which returns 0 (deny.) E.g.:
<programlisting> if ($field eq "qacontact") {
if (Bugzilla->user->groups("quality_assurance")) {
return 1;
}
else {
return 0;
}
}</programlisting>
This says that only users in the group "quality_assurance" can change
the QA Contact field of a bug.
</para>
<para>
Getting more weird:
<programlisting><![CDATA[ if (($field eq "priority") &&
(Bugzilla->user->email =~ /.*\@example\.com$/))
{
if ($oldvalue eq "P1") {
return 1;
}
else {
return 0;
}
}]]></programlisting>
This says that if the user is trying to change the priority field,
and their email address is @example.com, they can only do so if the
old value of the field was "P1". Not very useful, but illustrative.
</para>
<warning>
<para>
If you are modifying <filename>process_bug.cgi</filename> in any
way, do not change the code that is bounded by DO_NOT_CHANGE blocks.
Doing so could compromise security, or cause your installation to
stop working entirely.
</para>
</warning>
<para>
For a list of possible field names, look at the bugs table in the
database. If you need help writing custom rules for your organization,
ask in the newsgroup.
</para>
</section>
<!-- Integrating Bugzilla with Third-Party Tools -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="integration.xml" />
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,449 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<appendix id="gfdl">
<title>GNU Free Documentation License</title>
<!-- - GNU Project - Free Software Foundation (FSF) -->
<!-- LINK REV="made" HREF="mailto:webmasters@gnu.org" -->
<!-- section>
<title>GNU Free Documentation License</title -->
<para>Version 1.1, March 2000</para>
<blockquote>
<para>Copyright (C) 2000 Free Software Foundation, Inc. 59 Temple Place,
Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and
distribute verbatim copies of this license document, but changing it is
not allowed.</para>
</blockquote>
<section label="0" id="gfdl-0">
<title>Preamble</title>
<para>The purpose of this License is to make a manual, textbook, or other
written document "free" in the sense of freedom: to assure everyone the
effective freedom to copy and redistribute it, with or without modifying
it, either commercially or noncommercially. Secondarily, this License
preserves for the author and publisher a way to get credit for their
work, while not being considered responsible for modifications made by
others.</para>
<para>This License is a kind of "copyleft", which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft license
designed for free software.</para>
<para>We have designed this License in order to use it for manuals for
free software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals; it
can be used for any textual work, regardless of subject matter or whether
it is published as a printed book. We recommend this License principally
for works whose purpose is instruction or reference.</para>
</section>
<section label="1" id="gfdl-1">
<title>Applicability and Definition</title>
<para>This License applies to any manual or other work that contains a
notice placed by the copyright holder saying it can be distributed under
the terms of this License. The "Document", below, refers to any such
manual or work. Any member of the public is a licensee, and is addressed
as "you".</para>
<para>A "Modified Version" of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.</para>
<para>A "Secondary Section" is a named appendix or a front-matter section
of the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall subject
(or to related matters) and contains nothing that could fall directly
within that overall subject. (For example, if the Document is in part a
textbook of mathematics, a Secondary Section may not explain any
mathematics.) The relationship could be a matter of historical connection
with the subject or with related matters, or of legal, commercial,
philosophical, ethical or political position regarding them.</para>
<para>The "Invariant Sections" are certain Secondary Sections whose
titles are designated, as being those of Invariant Sections, in the
notice that says that the Document is released under this License.</para>
<para>The "Cover Texts" are certain short passages of text that are
listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says
that the Document is released under this License.</para>
<para>A "Transparent" copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the general
public, whose contents can be viewed and edited directly and
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or for
automatic translation to a variety of formats suitable for input to text
formatters. A copy made in an otherwise Transparent file format whose
markup has been designed to thwart or discourage subsequent modification
by readers is not Transparent. A copy that is not "Transparent" is called
"Opaque".</para>
<para>Examples of suitable formats for Transparent copies include plain
ASCII without markup, Texinfo input format, LaTeX input format, SGML or
XML using a publicly available DTD, and standard-conforming simple HTML
designed for human modification. Opaque formats include PostScript, PDF,
proprietary formats that can be read and edited only by proprietary word
processors, SGML or XML for which the DTD and/or processing tools are not
generally available, and the machine-generated HTML produced by some word
processors for output purposes only.</para>
<para>The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in formats
which do not have any title page as such, "Title Page" means the text
near the most prominent appearance of the work's title, preceding the
beginning of the body of the text.</para>
</section>
<section label="2" id="gfdl-2">
<title>Verbatim Copying</title>
<para>You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies to
the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use technical
measures to obstruct or control the reading or further copying of the
copies you make or distribute. However, you may accept compensation in
exchange for copies. If you distribute a large enough number of copies
you must also follow the conditions in section 3.</para>
<para>You may also lend copies, under the same conditions stated above,
and you may publicly display copies.</para>
</section>
<section label="3" id="gfdl-3">
<title>Copying in Quantity</title>
<para>If you publish printed copies of the Document numbering more than
100, and the Document's license notice requires Cover Texts, you must
enclose the copies in covers that carry, clearly and legibly, all these
Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts
on the back cover. Both covers must also clearly and legibly identify you
as the publisher of these copies. The front cover must present the full
title with all words of the title equally prominent and visible. You may
add other material on the covers in addition. Copying with changes
limited to the covers, as long as they preserve the title of the Document
and satisfy these conditions, can be treated as verbatim copying in other
respects.</para>
<para>If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit reasonably)
on the actual cover, and continue the rest onto adjacent pages.</para>
<para>If you publish or distribute Opaque copies of the Document
numbering more than 100, you must either include a machine-readable
Transparent copy along with each Opaque copy, or state in or with each
Opaque copy a publicly-accessible computer-network location containing a
complete Transparent copy of the Document, free of added material, which
the general network-using public has access to download anonymously at no
charge using public-standard network protocols. If you use the latter
option, you must take reasonably prudent steps, when you begin
distribution of Opaque copies in quantity, to ensure that this
Transparent copy will remain thus accessible at the stated location until
at least one year after the last time you distribute an Opaque copy
(directly or through your agents or retailers) of that edition to the
public.</para>
<para>It is requested, but not required, that you contact the authors of
the Document well before redistributing any large number of copies, to
give them a chance to provide you with an updated version of the
Document.</para>
</section>
<section label="4" id="gfdl-4">
<title>Modifications</title>
<para>You may copy and distribute a Modified Version of the Document
under the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution and
modification of the Modified Version to whoever possesses a copy of it.
In addition, you must do these things in the Modified Version:</para>
<orderedlist numeration="upperalpha">
<listitem>
<para>Use in the Title Page (and on the covers, if any) a title
distinct from that of the Document, and from those of previous
versions (which should, if there were any, be listed in the History
section of the Document). You may use the same title as a previous
version if the original publisher of that version gives
permission.</para>
</listitem>
<listitem>
<para>List on the Title Page, as authors, one or more persons or
entities responsible for authorship of the modifications in the
Modified Version, together with at least five of the principal
authors of the Document (all of its principal authors, if it has less
than five).</para>
</listitem>
<listitem>
<para>State on the Title page the name of the publisher of the
Modified Version, as the publisher.</para>
</listitem>
<listitem>
<para>Preserve all the copyright notices of the Document.</para>
</listitem>
<listitem>
<para>Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.</para>
</listitem>
<listitem>
<para>Include, immediately after the copyright notices, a license
notice giving the public permission to use the Modified Version under
the terms of this License, in the form shown in the Addendum
below.</para>
</listitem>
<listitem>
<para>Preserve in that license notice the full lists of Invariant
Sections and required Cover Texts given in the Document's license
notice.</para>
</listitem>
<listitem>
<para>Include an unaltered copy of this License.</para>
</listitem>
<listitem>
<para>Preserve the section entitled "History", and its title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.</para>
</listitem>
<listitem>
<para>Preserve the network location, if any, given in the Document
for public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions it
was based on. These may be placed in the "History" section. You may
omit a network location for a work that was published at least four
years before the Document itself, or if the original publisher of the
version it refers to gives permission.</para>
</listitem>
<listitem>
<para>In any section entitled "Acknowledgements" or "Dedications",
preserve the section's title, and preserve in the section all the
substance and tone of each of the contributor acknowledgements and/or
dedications given therein.</para>
</listitem>
<listitem>
<para>Preserve all the Invariant Sections of the Document, unaltered
in their text and in their titles. Section numbers or the equivalent
are not considered part of the section titles.</para>
</listitem>
<listitem>
<para>Delete any section entitled "Endorsements". Such a section may
not be included in the Modified Version.</para>
</listitem>
<listitem>
<para>Do not retitle any existing section as "Endorsements" or to
conflict in title with any Invariant Section.</para>
</listitem>
</orderedlist>
<para>If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all of
these sections as invariant. To do this, add their titles to the list of
Invariant Sections in the Modified Version's license notice. These titles
must be distinct from any other section titles.</para>
<para>You may add a section entitled "Endorsements", provided it contains
nothing but endorsements of your Modified Version by various parties--for
example, statements of peer review or that the text has been approved by
an organization as the authoritative definition of a standard.</para>
<para>You may add a passage of up to five words as a Front-Cover Text,
and a passage of up to 25 words as a Back-Cover Text, to the end of the
list of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or through
arrangements made by) any one entity. If the Document already includes a
cover text for the same cover, previously added by you or by arrangement
made by the same entity you are acting on behalf of, you may not add
another; but you may replace the old one, on explicit permission from the
previous publisher that added the old one.</para>
<para>The author(s) and publisher(s) of the Document do not by this
License give permission to use their names for publicity for or to assert
or imply endorsement of any Modified Version.</para>
</section>
<section label="5" id="gfdl-5">
<title>Combining Documents</title>
<para>You may combine the Document with other documents released under
this License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and list
them all as Invariant Sections of your combined work in its license
notice.</para>
<para>The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single copy.
If there are multiple Invariant Sections with the same name but different
contents, make the title of each such section unique by adding at the end
of it, in parentheses, the name of the original author or publisher of
that section if known, or else a unique number. Make the same adjustment
to the section titles in the list of Invariant Sections in the license
notice of the combined work.</para>
<para>In the combination, you must combine any sections entitled
"History" in the various original documents, forming one section entitled
"History"; likewise combine any sections entitled "Acknowledgements", and
any sections entitled "Dedications". You must delete all sections
entitled "Endorsements."</para>
</section>
<section label="6" id="gfdl-6">
<title>Collections of Documents</title>
<para>You may make a collection consisting of the Document and other
documents released under this License, and replace the individual copies
of this License in the various documents with a single copy that is
included in the collection, provided that you follow the rules of this
License for verbatim copying of each of the documents in all other
respects.</para>
<para>You may extract a single document from such a collection, and
distribute it individually under this License, provided you insert a copy
of this License into the extracted document, and follow this License in
all other respects regarding verbatim copying of that document.</para>
</section>
<section label="7" id="gfdl-7">
<title>Aggregation with Independent Works</title>
<para>A compilation of the Document or its derivatives with other
separate and independent documents or works, in or on a volume of a
storage or distribution medium, does not as a whole count as a Modified
Version of the Document, provided no compilation copyright is claimed for
the compilation. Such a compilation is called an "aggregate", and this
License does not apply to the other self-contained works thus compiled
with the Document, on account of their being thus compiled, if they are
not themselves derivative works of the Document.</para>
<para>If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one quarter of
the entire aggregate, the Document's Cover Texts may be placed on covers
that surround only the Document within the aggregate. Otherwise they must
appear on covers around the whole aggregate.</para>
</section>
<section label="8" id="gfdl-8">
<title>Translation</title>
<para>Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include translations
of some or all Invariant Sections in addition to the original versions of
these Invariant Sections. You may include a translation of this License
provided that you also include the original English version of this
License. In case of a disagreement between the translation and the
original English version of this License, the original English version
will prevail.</para>
</section>
<section label="9" id="gfdl-9">
<title>Termination</title>
<para>You may not copy, modify, sublicense, or distribute the Document
except as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document is void, and will
automatically terminate your rights under this License. However, parties
who have received copies, or rights, from you under this License will not
have their licenses terminated so long as such parties remain in full
compliance.</para>
</section>
<section label="10" id="gfdl-10">
<title>Future Revisions of this License</title>
<para>The Free Software Foundation may publish new, revised versions of
the GNU Free Documentation License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in
detail to address new problems or concerns. See
<ulink url="http://www.gnu.org/copyleft/"/>.</para>
<para>Each version of the License is given a distinguishing version
number. If the Document specifies that a particular numbered version of
this License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or of
any later version that has been published (not as a draft) by the Free
Software Foundation. If the Document does not specify a version number of
this License, you may choose any version ever published (not as a draft)
by the Free Software Foundation.</para>
</section>
<section label="" id="gfdl-howto">
<title>How to use this License for your documents</title>
<para>To use this License in a document you have written, include a copy
of the License in the document and put the following copyright and
license notices just after the title page:</para>
<blockquote>
<para>Copyright (c) YEAR YOUR NAME. Permission is granted to copy,
distribute and/or modify this document under the terms of the GNU Free
Documentation License, Version 1.1 or any later version published by
the Free Software Foundation; with the Invariant Sections being LIST
THEIR TITLES, with the Front-Cover Texts being LIST, and with the
Back-Cover Texts being LIST. A copy of the license is included in the
section entitled "GNU Free Documentation License".</para>
</blockquote>
<para>If you have no Invariant Sections, write "with no Invariant
Sections" instead of saying which ones are invariant. If you have no
Front-Cover Texts, write "no Front-Cover Texts" instead of "Front-Cover
Texts being LIST"; likewise for Back-Cover Texts.</para>
<para>If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of free
software license, such as the GNU General Public License, to permit their
use in free software.</para>
</section>
</appendix>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,555 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<glossary id="glossary">
<glossdiv>
<title>0-9, high ascii</title>
<glossentry id="gloss-htaccess">
<glossterm>.htaccess</glossterm>
<glossdef>
<para>Apache web server, and other NCSA-compliant web servers,
observe the convention of using files in directories called
<filename>.htaccess</filename>
to restrict access to certain files. In Bugzilla, they are used
to keep secret files which would otherwise
compromise your installation - e.g. the
<filename>localconfig</filename>
file contains the password to your database.
curious.</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-a">
<title>A</title>
<glossentry id="gloss-apache">
<glossterm>Apache</glossterm>
<glossdef>
<para>In this context, Apache is the web server most commonly used
for serving up Bugzilla
pages. Contrary to popular belief, the apache web server has nothing
to do with the ancient and noble Native American tribe, but instead
derived its name from the fact that it was
<quote>a patchy</quote>
version of the original
<acronym>NCSA</acronym>
world-wide-web server.</para>
<variablelist>
<title>Useful Directives when configuring Bugzilla</title>
<varlistentry>
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#addhandler">AddHandler</ulink></computeroutput></term>
<listitem>
<para>Tell Apache that it's OK to run CGI scripts.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#allowoverride">AllowOverride</ulink></computeroutput></term>
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#options">Options</ulink></computeroutput></term>
<listitem>
<para>These directives are used to tell Apache many things about
the directory they apply to. For Bugzilla's purposes, we need
them to allow script execution and <filename>.htaccess</filename>
overrides.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/mod_dir.html#directoryindex">DirectoryIndex</ulink></computeroutput></term>
<listitem>
<para>Used to tell Apache what files are indexes. If you can
not add <filename>index.cgi</filename> to the list of valid files,
you'll need to set <computeroutput>$index_html</computeroutput> to
1 in <filename>localconfig</filename> so
<command>./checksetup.pl</command> will create an
<filename>index.html</filename> that redirects to
<filename>index.cgi</filename>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#scriptinterpretersource">ScriptInterpreterSource</ulink></computeroutput></term>
<listitem>
<para>Used when running Apache on windows so the shebang line
doesn't have to be changed in every Bugzilla script.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>For more information about how to configure Apache for Bugzilla,
see <xref linkend="http-apache"/>.
</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-b">
<title>B</title>
<glossentry>
<glossterm>Bug</glossterm>
<glossdef>
<para>A
<quote>bug</quote>
in Bugzilla refers to an issue entered into the database which has an
associated number, assignments, comments, etc. Some also refer to a
<quote>tickets</quote>
or
<quote>issues</quote>;
in the context of Bugzilla, they are synonymous.</para>
</glossdef>
</glossentry>
<glossentry>
<glossterm>Bug Number</glossterm>
<glossdef>
<para>Each Bugzilla bug is assigned a number that uniquely identifies
that bug. The bug associated with a bug number can be pulled up via a
query, or easily from the very front page by typing the number in the
"Find" box.</para>
</glossdef>
</glossentry>
<glossentry id="gloss-bugzilla">
<glossterm>Bugzilla</glossterm>
<glossdef>
<para>Bugzilla is the world-leading free software bug tracking system.
</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-c">
<title>C</title>
<glossentry id="gloss-cgi">
<glossterm>Common Gateway Interface</glossterm>
<acronym>CGI</acronym>
<glossdef>
<para><acronym>CGI</acronym> is an acronym for Common Gateway Interface. This is
a standard for interfacing an external application with a web server. Bugzilla
is an example of a <acronym>CGI</acronym> application.
</para>
</glossdef>
</glossentry>
<glossentry id="gloss-component">
<glossterm>Component</glossterm>
<glossdef>
<para>A Component is a subsection of a Product. It should be a narrow
category, tailored to your organization. All Products must contain at
least one Component (and, as a matter of fact, creating a Product
with no Components will create an error in Bugzilla).</para>
</glossdef>
</glossentry>
<glossentry id="gloss-cpan">
<glossterm>Comprehensive Perl Archive Network</glossterm>
<acronym>CPAN</acronym>
<!-- TODO: Rewrite def for CPAN -->
<glossdef>
<para>
<acronym>CPAN</acronym>
stands for the
<quote>Comprehensive Perl Archive Network</quote>.
CPAN maintains a large number of extremely useful
<glossterm>Perl</glossterm>
modules - encapsulated chunks of code for performing a
particular task.</para>
</glossdef>
</glossentry>
<glossentry id="gloss-contrib">
<glossterm><filename class="directory">contrib</filename></glossterm>
<glossdef>
<para>The <filename class="directory">contrib</filename> directory is
a location to put scripts that have been contributed to Bugzilla but
are not a part of the official distribution. These scripts are written
by third parties and may be in languages other than perl. For those
that are in perl, there may be additional modules or other requirements
than those of the official distribution.
<note>
<para>Scripts in the <filename class="directory">contrib</filename>
directory are not officially supported by the Bugzilla team and may
break in between versions.
</para>
</note>
</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-d">
<title>D</title>
<glossentry id="gloss-daemon">
<glossterm>daemon</glossterm>
<glossdef>
<para>A daemon is a computer program which runs in the background. In
general, most daemons are started at boot time via System V init
scripts, or through RC scripts on BSD-based systems.
<glossterm>mysqld</glossterm>,
the MySQL server, and
<glossterm>apache</glossterm>,
a web server, are generally run as daemons.</para>
</glossdef>
</glossentry>
<glossentry id="gloss-dos">
<glossterm>DOS Attack</glossterm>
<glossdef>
<para>A DOS, or Denial of Service attack, is when a user attempts to
deny access to a web server by repeatedly accessing a page or sending
malformed requests to a webserver. A D-DOS, or
Distributed Denial of Service attack, is when these requests come
from multiple sources at the same time. Unfortunately, these are much
more difficult to defend against.
</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-g">
<title>G</title>
<glossentry id="gloss-groups">
<glossterm>Groups</glossterm>
<glossdef>
<para>The word
<quote>Groups</quote>
has a very special meaning to Bugzilla. Bugzilla's main security
mechanism comes by placing users in groups, and assigning those
groups certain privileges to view bugs in particular
<glossterm>Products</glossterm>
in the
<glossterm>Bugzilla</glossterm>
database.</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-j">
<title>J</title>
<glossentry id="gloss-javascript">
<glossterm>JavaScript</glossterm>
<glossdef>
<para>JavaScript is cool, we should talk about it.
</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-m">
<title>M</title>
<glossentry id="gloss-mta">
<glossterm>Message Transport Agent</glossterm>
<acronym>MTA</acronym>
<glossdef>
<para>A Message Transport Agent is used to control the flow of email on a system.
The <ulink url="http://search.cpan.org/dist/Email-Send/lib/Email/Send.pm">Email::Send</ulink>
Perl module, which Bugzilla uses to send email, can be configured to
use many different underlying implementations for actually sending the
mail using the <option>mail_delivery_method</option> parameter.
Implementations other than <literal>sendmail</literal> require that the
<option>sendmailnow</option> param be set to <literal>on</literal>.
</para>
</glossdef>
</glossentry>
<glossentry id="gloss-mysql">
<glossterm>MySQL</glossterm>
<glossdef>
<para>MySQL is currently the required
<glossterm linkend="gloss-rdbms">RDBMS</glossterm> for Bugzilla. MySQL
can be downloaded from <ulink url="http://www.mysql.com"/>. While you
should familiarize yourself with all of the documentation, some high
points are:
</para>
<variablelist>
<varlistentry>
<term><ulink url="http://www.mysql.com/doc/en/Backup.html">Backup</ulink></term>
<listitem>
<para>Methods for backing up your Bugzilla database.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><ulink url="http://www.mysql.com/doc/en/Option_files.html">Option Files</ulink></term>
<listitem>
<para>Information about how to configure MySQL using
<filename>my.cnf</filename>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><ulink url="http://www.mysql.com/doc/en/Privilege_system.html">Privilege System</ulink></term>
<listitem>
<para>Much more detailed information about the suggestions in
<xref linkend="security-mysql"/>.
</para>
</listitem>
</varlistentry>
</variablelist>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-p">
<title>P</title>
<glossentry id="gloss-ppm">
<glossterm>Perl Package Manager</glossterm>
<acronym>PPM</acronym>
<glossdef>
<para><ulink url="http://aspn.activestate.com/ASPN/Downloads/ActivePerl/PPM/"/>
</para>
</glossdef>
</glossentry>
<glossentry>
<glossterm id="gloss-product">Product</glossterm>
<glossdef>
<para>A Product is a broad category of types of bugs, normally
representing a single piece of software or entity. In general,
there are several Components to a Product. A Product may define a
group (used for security) for all bugs entered into
its Components.</para>
</glossdef>
</glossentry>
<glossentry>
<glossterm>Perl</glossterm>
<glossdef>
<para>First written by Larry Wall, Perl is a remarkable program
language. It has the benefits of the flexibility of an interpreted
scripting language (such as shell script), combined with the speed
and power of a compiled language, such as C.
<glossterm>Bugzilla</glossterm>
is maintained in Perl.</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-q">
<title>Q</title>
<glossentry>
<glossterm>QA</glossterm>
<glossdef>
<para>
<quote>QA</quote>,
<quote>Q/A</quote>, and
<quote>Q.A.</quote>
are short for
<quote>Quality Assurance</quote>.
In most large software development organizations, there is a team
devoted to ensuring the product meets minimum standards before
shipping. This team will also generally want to track the progress of
bugs over their life cycle, thus the need for the
<quote>QA Contact</quote>
field in a bug.</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-r">
<title>R</title>
<glossentry id="gloss-rdbms">
<glossterm>Relational DataBase Management System</glossterm>
<acronym>RDBMS</acronym>
<glossdef>
<para>A relational database management system is a database system
that stores information in tables that are related to each other.
</para>
</glossdef>
</glossentry>
<glossentry id="gloss-regexp">
<glossterm>Regular Expression</glossterm>
<acronym>regexp</acronym>
<glossdef>
<para>A regular expression is an expression used for pattern matching.
<ulink url="http://perldoc.com/perl5.6/pod/perlre.html#Regular-Expressions">Documentation</ulink>
</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-s">
<title>S</title>
<glossentry id="gloss-service">
<glossterm>Service</glossterm>
<glossdef>
<para>In Windows NT environment, a boot-time background application
is referred to as a service. These are generally managed through the
control panel while logged in as an account with
<quote>Administrator</quote> level capabilities. For more
information, consult your Windows manual or the MSKB.
</para>
</glossdef>
</glossentry>
<glossentry>
<glossterm>
<acronym>SGML</acronym>
</glossterm>
<glossdef>
<para>
<acronym>SGML</acronym>
stands for
<quote>Standard Generalized Markup Language</quote>.
Created in the 1980's to provide an extensible means to maintain
documentation based upon content instead of presentation,
<acronym>SGML</acronym>
has withstood the test of time as a robust, powerful language.
<glossterm>
<acronym>XML</acronym>
</glossterm>
is the
<quote>baby brother</quote>
of SGML; any valid
<acronym>XML</acronym>
document it, by definition, a valid
<acronym>SGML</acronym>
document. The document you are reading is written and maintained in
<acronym>SGML</acronym>,
and is also valid
<acronym>XML</acronym>
if you modify the Document Type Definition.</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-t">
<title>T</title>
<glossentry id="gloss-target-milestone" xreflabel="Target Milestone">
<glossterm>Target Milestone</glossterm>
<glossdef>
<para>Target Milestones are Product goals. They are configurable on a
per-Product basis. Most software development houses have a concept of
<quote>milestones</quote>
where the people funding a project expect certain functionality on
certain dates. Bugzilla facilitates meeting these milestones by
giving you the ability to declare by which milestone a bug will be
fixed, or an enhancement will be implemented.</para>
</glossdef>
</glossentry>
<glossentry id="gloss-tcl">
<glossterm>Tool Command Language</glossterm>
<acronym>TCL</acronym>
<glossdef>
<para>TCL is an open source scripting language available for Windows,
Macintosh, and Unix based systems. Bugzilla 1.0 was written in TCL but
never released. The first release of Bugzilla was 2.0, which was when
it was ported to perl.
</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv id="gloss-z">
<title>Z</title>
<glossentry id="gloss-zarro">
<glossterm>Zarro Boogs Found</glossterm>
<glossdef>
<para>This is just a goofy way of saying that there were no bugs
found matching your query. When asked to explain this message,
Terry had the following to say:
</para>
<blockquote>
<attribution>Terry Weissman</attribution>
<para>I've been asked to explain this ... way back when, when
Netscape released version 4.0 of its browser, we had a release
party. Naturally, there had been a big push to try and fix every
known bug before the release. Naturally, that hadn't actually
happened. (This is not unique to Netscape or to 4.0; the same thing
has happened with every software project I've ever seen.) Anyway,
at the release party, T-shirts were handed out that said something
like "Netscape 4.0: Zarro Boogs". Just like the software, the
T-shirt had no known bugs. Uh-huh.
</para>
<para>So, when you query for a list of bugs, and it gets no results,
you can think of this as a friendly reminder. Of *course* there are
bugs matching your query, they just aren't in the bugsystem yet...
</para>
</blockquote>
</glossdef>
</glossentry>
</glossdiv>
</glossary>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,21 +0,0 @@
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

File diff suppressed because it is too large Load Diff

View File

@@ -1,124 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<!-- Keep these tools listings in alphabetical order please. -MPB -->
<section id="integration">
<title>Integrating Bugzilla with Third-Party Tools</title>
<section id="bonsai"
xreflabel="Bonsai, the Mozilla automated CVS management system">
<title>Bonsai</title>
<para>Bonsai is a web-based tool for managing
<xref linkend="cvs" />
. Using Bonsai, administrators can control open/closed status of trees,
query a fast relational database back-end for change, branch, and comment
information, and view changes made since the last time the tree was
closed. Bonsai
also integrates with
<xref linkend="tinderbox" />.
</para>
</section>
<section id="cvs" xreflabel="CVS, the Concurrent Versioning System">
<title>CVS</title>
<para>CVS integration is best accomplished, at this point, using the
Bugzilla Email Gateway.</para>
<para>Follow the instructions in this Guide for enabling Bugzilla e-mail
integration. Ensure that your check-in script sends an email to your
Bugzilla e-mail gateway with the subject of
<quote>[Bug XXXX]</quote>,
and you can have CVS check-in comments append to your Bugzilla bug. If
you want to have the bug be closed automatically, you'll have to modify
the <filename>contrib/bugzilla_email_append.pl</filename> script.
</para>
<para>There is also a CVSZilla project, based upon somewhat dated
Bugzilla code, to integrate CVS and Bugzilla through CVS' ability to
email. Check it out at: <ulink url="http://www.cvszilla.org/"/>.
</para>
<para>Another system capable of CVS integration with Bugzilla is
Scmbug. This system provides generic integration of Source code
Configuration Management with Bugtracking. Check it out at: <ulink
url="http://freshmeat.net/projects/scmbug/"/>.
</para>
</section>
<section id="scm"
xreflabel="Perforce SCM (Fast Software Configuration Management System, a powerful commercial alternative to CVS">
<title>Perforce SCM</title>
<para>You can find the project page for Bugzilla and Teamtrack Perforce
integration (p4dti) at:
<ulink url="http://www.ravenbrook.com/project/p4dti/"/>
.
<quote>p4dti</quote>
is now an officially supported product from Perforce, and you can find
the "Perforce Public Depot" p4dti page at
<ulink url="http://public.perforce.com/public/perforce/p4dti/index.html"/>
.</para>
<para>Integration of Perforce with Bugzilla, once patches are applied, is
seamless. Perforce replication information will appear below the comments
of each bug. Be certain you have a matching set of patches for the
Bugzilla version you are installing. p4dti is designed to support
multiple defect trackers, and maintains its own documentation for it.
Please consult the pages linked above for further information.</para>
</section>
<section id="svn"
xreflabel="Subversion, a compelling replacement for CVS">
<title>Subversion</title>
<para>Subversion is a free/open-source version control system,
designed to overcome various limitations of CVS. Integration of
Subversion with Bugzilla is possible using Scmbug, a system
providing generic integration of Source Code Configuration
Management with Bugtracking. Scmbug is available at <ulink
url="http://freshmeat.net/projects/scmbug/"/>.</para>
</section>
<section id="tinderbox"
xreflabel="Tinderbox, the Mozilla automated build management system">
<title>Tinderbox/Tinderbox2</title>
<para>Tinderbox is a continuous-build system which can integrate with
Bugzilla - see
<ulink url="http://www.mozilla.org/projects/tinderbox"/> for details
of Tinderbox, and
<ulink url="http://tinderbox.mozilla.org/showbuilds.cgi"/> to see it
in action.</para>
</section>
</section>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,121 +0,0 @@
<chapter id="introduction">
<title>Introduction</title>
<section id="what-is-bugzilla">
<title>What is Bugzilla?</title>
<para>
Bugzilla is a bug- or issue-tracking system. Bug-tracking
systems allow individual or groups of developers effectively to keep track
of outstanding problems with their products.
</para>
<para><emphasis>Do we need more here?</emphasis></para>
</section>
<section id="why-tracking">
<title>Why use a bug-tracking system?</title>
<para>Those who do not use a bug-tracking system tend to rely on
shared lists, email, spreadsheets and/or Post-It notes to monitor the
status of defects. This procedure
is usually error-prone and tends to cause those bugs judged least
significant by developers to be dropped or ignored.</para>
<para>Integrated defect-tracking systems make sure that nothing gets
swept under the carpet; they provide a method of creating, storing,
arranging and processing defect reports and enhancement requests.</para>
</section>
<section id="why-bugzilla">
<title>Why use Bugzilla?</title>
<para>Bugzilla is the leading open-source/free software bug tracking
system. It boasts many advanced features, including:
<itemizedlist>
<listitem>
<para>Powerful searching</para>
</listitem>
<listitem>
<para>User-configurable email notifications of bug changes</para>
</listitem>
<listitem>
<para>Full change history</para>
</listitem>
<listitem>
<para>Inter-bug dependency tracking and graphing</para>
</listitem>
<listitem>
<para>Excellent attachment management</para>
</listitem>
<listitem>
<para>Integrated, product-based, granular security schema</para>
</listitem>
<listitem>
<para>Fully security-audited, and runs under Perl's taint mode</para>
</listitem>
<listitem>
<para>A robust, stable RDBMS back-end</para>
</listitem>
<listitem>
<para>Completely customizable and/or localizable web user
interface</para>
</listitem>
<listitem>
<para>Additional XML, email and console interfaces</para>
</listitem>
<listitem>
<para>Extensive configurability</para>
</listitem>
<listitem>
<para>Smooth upgrade pathway between versions</para>
</listitem>
</itemizedlist>
</para>
<para>Bugzilla is very adaptable to various situations. Known uses
currently include IT support queues, Systems Administration deployment
management, chip design and development problem tracking (both
pre-and-post fabrication), and software and hardware bug tracking for
luminaries such as Redhat, NASA, Linux-Mandrake, and VA Systems.
Combined with systems such as
<ulink url="http://www.cvshome.org">CVS</ulink>,
<ulink url="http://www.mozilla.org/bonsai.html">Bonsai</ulink>, or
<ulink url="http://www.perforce.com">Perforce SCM</ulink>, Bugzilla
provides a powerful, easy-to-use configuration management solution.</para>
</section>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,197 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<appendix id="install-perlmodules-manual">
<title>Manual Installation of Perl Modules</title>
<section id="modules-manual-instructions">
<title>Instructions</title>
<para>
If you need to install Perl modules manually, here's how it's done.
Download the module using the link given in the next section, and then
apply this magic incantation, as root:
</para>
<para>
<screen><prompt>bash#</prompt> tar -xzvf &lt;module&gt;.tar.gz
<prompt>bash#</prompt> cd &lt;module&gt;
<prompt>bash#</prompt> perl Makefile.PL
<prompt>bash#</prompt> make
<prompt>bash#</prompt> make test
<prompt>bash#</prompt> make install</screen>
</para>
<note>
<para>
In order to compile source code under Windows you will need to obtain
a 'make' utility. The <command>nmake</command> utility provided with
Microsoft Visual C++ may be used. As an alternative, there is a
utility called <command>dmake</command> available from CPAN which is
written entirely in Perl.
</para>
<para>
As described in <xref linkend="modules-manual-download" />, however, most
packages already exist and are available from ActiveState or theory58S.
We highly recommend that you install them using the ppm GUI available with
ActiveState and to add the theory58S repository to your list of repositories.
</para>
</note>
</section>
<section id="modules-manual-download">
<title>Download Locations</title>
<note>
<para>
Running Bugzilla on Windows requires the use of ActiveState
Perl 5.8.1 or higher. Many modules already exist in the core
distribution of ActiveState Perl. Additional modules can be downloaded
from <ulink url="http://theoryx5.uwinnipeg.ca/ppms/" /> if you use
Perl 5.8.x or from <ulink url="http://cpan.uwinnipeg.ca/PPMPackages/10xx/" />
if you use Perl 5.10.x.
</para>
</note>
<para>
CGI:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/CGI.pm/"/>
Documentation: <ulink url="http://perldoc.perl.org/CGI.html"/>
</literallayout>
</para>
<para>
Data-Dumper:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Data-Dumper/"/>
Documentation: <ulink url="http://search.cpan.org/dist/Data-Dumper/Dumper.pm"/>
</literallayout>
</para>
<para>
Date::Format (part of TimeDate):
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/TimeDate/"/>
Documentation: <ulink url="http://search.cpan.org/dist/TimeDate/lib/Date/Format.pm"/>
</literallayout>
</para>
<para>
DBI:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/DBI/"/>
Documentation: <ulink url="http://dbi.perl.org/docs/"/>
</literallayout>
</para>
<para>
DBD::mysql:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/DBD-mysql/"/>
Documentation: <ulink url="http://search.cpan.org/dist/DBD-mysql/lib/DBD/mysql.pm"/>
</literallayout>
</para>
<para>
DBD::Pg:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/DBD-Pg/"/>
Documentation: <ulink url="http://search.cpan.org/dist/DBD-Pg/Pg.pm"/>
</literallayout>
</para>
<para>
File::Spec:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/File-Spec/"/>
Documentation: <ulink url="http://perldoc.perl.org/File/Spec.html"/>
</literallayout>
</para>
<para>
Template-Toolkit:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Template-Toolkit/"/>
Documentation: <ulink url="http://www.template-toolkit.org/docs.html"/>
</literallayout>
</para>
<para>
GD:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/GD/"/>
Documentation: <ulink url="http://search.cpan.org/dist/GD/GD.pm"/>
</literallayout>
</para>
<para>
Template::Plugin::GD:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Template-GD/" />
Documentation: <ulink url="http://www.template-toolkit.org/docs/aqua/Modules/index.html" />
</literallayout>
</para>
<para>
MIME::Parser (part of MIME-tools):
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/MIME-tools/"/>
Documentation: <ulink url="http://search.cpan.org/dist/MIME-tools/lib/MIME/Parser.pm"/>
</literallayout>
</para>
</section>
<section id="modules-manual-optional">
<title>Optional Modules</title>
<para>
Chart::Base:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Chart/"/>
Documentation: <ulink url="http://search.cpan.org/dist/Chart/Chart.pod"/>
</literallayout>
</para>
<para>
GD::Graph:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/GDGraph/"/>
Documentation: <ulink url="http://search.cpan.org/dist/GDGraph/Graph.pm"/>
</literallayout>
</para>
<para>
GD::Text::Align (part of GD::Text::Util):
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/GDTextUtil/"/>
Documentation: <ulink url="http://search.cpan.org/dist/GDTextUtil/Text/Align.pm"/>
</literallayout>
</para>
<para>
XML::Twig:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/XML-Twig/"/>
Documentation: <ulink url="http://standards.ieee.org/resources/spasystem/twig/twig_stable.html"/>
</literallayout>
</para>
<para>
PatchReader:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/author/JKEISER/PatchReader/"/>
Documentation: <ulink url="http://www.johnkeiser.com/mozilla/Patch_Viewer.html"/>
</literallayout>
</para>
<para>
Image::Magick:
<literallayout>
CPAN Download Page: <ulink url="http://search.cpan.org/dist/PerlMagick/"/>
Documentation: <ulink url="http://www.imagemagick.org/script/resources.php"/>
</literallayout>
</para>
</section>
</appendix>

View File

@@ -1,135 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<appendix id="patches" xreflabel="Useful Patches and Utilities for Bugzilla">
<title>Contrib</title>
<para>
There are a number of unofficial Bugzilla add-ons in the
<filename class="directory">$BUGZILLA_ROOT/contrib/</filename>
directory. This section documents them.
</para>
<section id="cmdline">
<title>Command-line Search Interface</title>
<para>
There are a suite of Unix utilities for searching Bugzilla from the
command line. They live in the
<filename class="directory">contrib/cmdline</filename> directory.
There are three files - <filename>query.conf</filename>,
<filename>buglist</filename> and <filename>bugs</filename>.
</para>
<warning>
<para>
These files pre-date the templatization work done as part of the
2.16 release, and have not been updated.
</para>
</warning>
<para>
<filename>query.conf</filename> contains the mapping from
options to field names and comparison types. Quoted option names
are <quote>grepped</quote> for, so it should be easy to edit this
file. Comments (#) have no effect; you must make sure these lines
do not contain any quoted <quote>option</quote>.
</para>
<para>
<filename>buglist</filename> is a shell script that submits a
Bugzilla query and writes the resulting HTML page to stdout.
It supports both short options, (such as <quote>-Afoo</quote>
or <quote>-Rbar</quote>) and long options (such
as <quote>--assignedto=foo</quote> or <quote>--reporter=bar</quote>).
If the first character of an option is not <quote>-</quote>, it is
treated as if it were prefixed with <quote>--default=</quote>.
</para>
<para>
The column list is taken from the COLUMNLIST environment variable.
This is equivalent to the <quote>Change Columns</quote> option
that is available when you list bugs in buglist.cgi. If you have
already used Bugzilla, grep for COLUMNLIST in your cookies file
to see your current COLUMNLIST setting.
</para>
<para>
<filename>bugs</filename> is a simple shell script which calls
<filename>buglist</filename> and extracts the
bug numbers from the output. Adding the prefix
<quote>http://bugzilla.mozilla.org/buglist.cgi?bug_id=</quote>
turns the bug list into a working link if any bugs are found.
Counting bugs is easy. Pipe the results through
<command>sed -e 's/,/ /g' | wc | awk '{printf $2 "\n"}'</command>
</para>
<para>
Akkana Peck says she has good results piping
<filename>buglist</filename> output through
<command>w3m -T text/html -dump</command>
</para>
</section>
<section id="cmdline-bugmail">
<title>Command-line 'Send Unsent Bug-mail' tool</title>
<para>
Within the <filename class="directory">contrib</filename> directory
exists a utility with the descriptive (if compact) name
of <filename>sendunsentbugmail.pl</filename>. The purpose of this
script is, simply, to send out any bug-related mail that should
have been sent by now, but for one reason or another has not.
</para>
<para>
To accomplish this task, <filename>sendunsentbugmail.pl</filename> uses
the same mechanism as the <filename>sanitycheck.cgi</filename> script;
it scans through the entire database looking for bugs with changes that
were made more than 30 minutes ago, but where there is no record of
anyone related to that bug having been sent mail. Having compiled a list,
it then uses the standard rules to determine who gets mail, and sends it
out.
</para>
<para>
As the script runs, it indicates the bug for which it is currently
sending mail; when it has finished, it gives a numerical count of how
many mails were sent and how many people were excluded. (Individual
user names are not recorded or displayed.) If the script produces
no output, that means no unsent mail was detected.
</para>
<para>
<emphasis>Usage</emphasis>: move the sendunsentbugmail.pl script
up into the main directory, ensure it has execute permission, and run it
from the command line (or from a cron job) with no parameters.
</para>
</section>
</appendix>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,77 +0,0 @@
<!-- <!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> -->
<appendix id="downloadlinks">
<title>Software Download Links</title>
<para>All of these sites are current as of April, 2001. Hopefully they'll
stay current for a while.</para>
<para>Apache Web Server:
<ulink url="http://www.apache.org/"/>
Optional web server for Bugzilla, but recommended because of broad user
base and support.</para>
<para>Bugzilla:
<ulink url="http://www.bugzilla.org/"/>
</para>
<para>MySQL:
<ulink url="http://www.mysql.com/"/>
</para>
<para>Perl:
<ulink url="http://www.perl.org/"/>
</para>
<para>CPAN:
<ulink url="http://www.cpan.org/"/>
</para>
<para>DBI Perl module:
<ulink url="http://www.cpan.org/modules/by-module/DBI/"/>
</para>
<para>MySQL related Perl modules:
<ulink url="http://www.cpan.org/modules/by-module/Mysql/"/>
</para>
<para>TimeDate Perl module collection:
<ulink url="http://www.cpan.org/modules/by-module/Date/"/>
</para>
<para>GD Perl module:
<ulink url="http://www.cpan.org/modules/by-module/GD/"/>
Alternately, you should be able to find the latest version of GD at
<ulink url="http://www.boutell.com/gd/"/>
</para>
<para>Chart::Base module:
<ulink url="http://www.cpan.org/modules/by-module/Chart/"/>
</para>
<para>(But remember, Bundle::Bugzilla will install all the modules for you.)
</para>
</appendix>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End:
-->

View File

@@ -1,364 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<!-- $Id: security.xml,v 1.19.2.1 2008-07-13 16:44:28 mozilla%colinogilvie.co.uk Exp $ -->
<chapter id="security">
<title>Bugzilla Security</title>
<para>While some of the items in this chapter are related to the operating
system Bugzilla is running on or some of the support software required to
run Bugzilla, it is all related to protecting your data. This is not
intended to be a comprehensive guide to securing Linux, Apache, MySQL, or
any other piece of software mentioned. There is no substitute for active
administration and monitoring of a machine. The key to good security is
actually right in the middle of the word: <emphasis>U R It</emphasis>.
</para>
<para>While programmers in general always strive to write secure code,
accidents can and do happen. The best approach to security is to always
assume that the program you are working with isn't 100% secure and restrict
its access to other parts of your machine as much as possible.
</para>
<section id="security-os">
<title>Operating System</title>
<section id="security-os-ports">
<title>TCP/IP Ports</title>
<!-- TODO: Get exact number of ports -->
<para>The TCP/IP standard defines more than 65,000 ports for sending
and receiving traffic. Of those, Bugzilla needs exactly one to operate
(different configurations and options may require up to 3). You should
audit your server and make sure that you aren't listening on any ports
you don't need to be. It's also highly recommended that the server
Bugzilla resides on, along with any other machines you administer, be
placed behind some kind of firewall.
</para>
</section>
<section id="security-os-accounts">
<title>System User Accounts</title>
<para>Many <glossterm linkend="gloss-daemon">daemons</glossterm>, such
as Apache's <filename>httpd</filename> or MySQL's
<filename>mysqld</filename>, run as either <quote>root</quote> or
<quote>nobody</quote>. This is even worse on Windows machines where the
majority of <glossterm linkend="gloss-service">services</glossterm>
run as <quote>SYSTEM</quote>. While running as <quote>root</quote> or
<quote>SYSTEM</quote> introduces obvious security concerns, the
problems introduced by running everything as <quote>nobody</quote> may
not be so obvious. Basically, if you run every daemon as
<quote>nobody</quote> and one of them gets compromised it can
compromise every other daemon running as <quote>nobody</quote> on your
machine. For this reason, it is recommended that you create a user
account for each daemon.
</para>
<note>
<para>You will need to set the <option>webservergroup</option> option
in <filename>localconfig</filename> to the group your web server runs
as. This will allow <filename>./checksetup.pl</filename> to set file
permissions on Unix systems so that nothing is world-writable.
</para>
</note>
</section>
<section id="security-os-chroot">
<title>The <filename>chroot</filename> Jail</title>
<para>
If your system supports it, you may wish to consider running
Bugzilla inside of a <filename>chroot</filename> jail. This option
provides unprecedented security by restricting anything running
inside the jail from accessing any information outside of it. If you
wish to use this option, please consult the documentation that came
with your system.
</para>
</section>
</section>
<section id="security-mysql">
<title>MySQL</title>
<section id="security-mysql-account">
<title>The MySQL System Account</title>
<para>As mentioned in <xref linkend="security-os-accounts"/>, the MySQL
daemon should run as a non-privileged, unique user. Be sure to consult
the MySQL documentation or the documentation that came with your system
for instructions.
</para>
</section>
<section id="security-mysql-root">
<title>The MySQL <quote>root</quote> and <quote>anonymous</quote> Users</title>
<para>By default, MySQL comes with a <quote>root</quote> user with a
blank password and an <quote>anonymous</quote> user, also with a blank
password. In order to protect your data, the <quote>root</quote> user
should be given a password and the anonymous user should be disabled.
</para>
<example id="security-mysql-account-root">
<title>Assigning the MySQL <quote>root</quote> User a Password</title>
<screen>
<prompt>bash$</prompt> mysql mysql
<prompt>mysql&gt;</prompt> UPDATE user SET password = password('<replaceable>new_password</replaceable>') WHERE user = 'root';
<prompt>mysql&gt;</prompt> FLUSH PRIVILEGES;
</screen>
</example>
<example id="security-mysql-account-anonymous">
<title>Disabling the MySQL <quote>anonymous</quote> User</title>
<screen>
<prompt>bash$</prompt> mysql -u root -p mysql <co id="security-mysql-account-anonymous-mysql"/>
<prompt>Enter Password:</prompt> <replaceable>new_password</replaceable>
<prompt>mysql&gt;</prompt> DELETE FROM user WHERE user = '';
<prompt>mysql&gt;</prompt> FLUSH PRIVILEGES;
</screen>
<calloutlist>
<callout arearefs="security-mysql-account-anonymous-mysql">
<para>This command assumes that you have already completed
<xref linkend="security-mysql-account-root"/>.
</para>
</callout>
</calloutlist>
</example>
</section>
<section id="security-mysql-network">
<title>Network Access</title>
<para>If MySQL and your web server both run on the same machine and you
have no other reason to access MySQL remotely, then you should disable
the network access. This, along with the suggestion in
<xref linkend="security-os-ports"/>, will help protect your system from
any remote vulnerabilities in MySQL.
</para>
<example id="security-mysql-network-ex">
<title>Disabling Networking in MySQL</title>
<para>Simply enter the following in <filename>/etc/my.cnf</filename>:
<screen>
[mysqld]
# Prevent network access to MySQL.
skip-networking
</screen>
</para>
</example>
</section>
<!-- For possible addition in the future: How to better control the bugs user
<section id="security-mysql-bugs">
<title>The bugs User</title>
</section>
-->
</section>
<section id="security-webserver">
<title>Web server</title>
<section id="security-webserver-access">
<title>Disabling Remote Access to Bugzilla Configuration Files</title>
<para>
There are many files that are placed in the Bugzilla directory
area that should not be accessible from the web server. Because of the way
Bugzilla is currently layed out, the list of what should and should not
be accessible is rather complicated. A quick way is to run
<filename>testserver.pl</filename> to check if your web server serves
Bugzilla files as expected. If not, you may want to follow the few
steps below.
</para>
<tip>
<para>Bugzilla ships with the ability to create
<glossterm linkend="gloss-htaccess"><filename>.htaccess</filename></glossterm>
files that enforce these rules. Instructions for enabling these
directives in Apache can be found in <xref linkend="http-apache"/>
</para>
</tip>
<itemizedlist spacing="compact">
<listitem>
<para>In the main Bugzilla directory, you should:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Block:
<simplelist type="inline">
<member><filename>*.pl</filename></member>
<member><filename>*localconfig*</filename></member>
</simplelist>
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>In <filename class="directory">data</filename>:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Block everything</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>In <filename class="directory">data/webdot</filename>:</para>
<itemizedlist spacing="compact">
<listitem>
<para>If you use a remote webdot server:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Block everything</para>
</listitem>
<listitem>
<para>But allow
<simplelist type="inline">
<member><filename>*.dot</filename></member>
</simplelist>
only for the remote webdot server</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>Otherwise, if you use a local GraphViz:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Block everything</para>
</listitem>
<listitem>
<para>But allow:
<simplelist type="inline">
<member><filename>*.png</filename></member>
<member><filename>*.gif</filename></member>
<member><filename>*.jpg</filename></member>
<member><filename>*.map</filename></member>
</simplelist>
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>And if you don't use any dot:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Block everything</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>In <filename class="directory">Bugzilla</filename>:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Block everything</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>In <filename class="directory">template</filename>:</para>
<itemizedlist spacing="compact">
<listitem>
<para>Block everything</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>Be sure to test that data that should not be accessed remotely is
properly blocked. Of particular interest is the localconfig file which
contains your database password. Also, be aware that many editors
create temporary and backup files in the working directory and that
those should also not be accessible. For more information, see
<ulink url="http://bugzilla.mozilla.org/show_bug.cgi?id=186383">bug 186383</ulink>
or
<ulink url="http://online.securityfocus.com/bid/6501">Bugtraq ID 6501</ulink>.
To test, simply run <filename>testserver.pl</filename>, as said above.
</para>
<tip>
<para>Be sure to check <xref linkend="http"/> for instructions
specific to the web server you use.
</para>
</tip>
</section>
</section>
<section id="security-bugzilla">
<title>Bugzilla</title>
<section id="security-bugzilla-charset">
<title>Prevent users injecting malicious Javascript</title>
<para>If you installed Bugzilla version 2.22 or later from scratch,
then the <emphasis>utf8</emphasis> parameter is switched on by default.
This makes Bugzilla explicitly set the character encoding, following
<ulink
url="http://www.cert.org/tech_tips/malicious_code_mitigation.html#3">a
CERT advisory</ulink> recommending exactly this.
The following therefore does not apply to you; just keep
<emphasis>utf8</emphasis> turned on.
</para>
<para>If you've upgraded from an older version, then it may be possible
for a Bugzilla user to take advantage of character set encoding
ambiguities to inject HTML into Bugzilla comments.
This could include malicious scripts.
This is because due to internationalization concerns, we are unable to
turn the <emphasis>utf8</emphasis> parameter on by default for upgraded
installations.
Turning it on manually will prevent this problem.
</para>
</section>
</section>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End: -->

View File

@@ -1,311 +0,0 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % myents SYSTEM "bugzilla.ent">
%myents;
]>
<!-- $Id: troubleshooting.xml,v 1.13.4.1 2008-07-13 16:44:28 mozilla%colinogilvie.co.uk Exp $ -->
<appendix id="troubleshooting">
<title>Troubleshooting</title>
<para>This section gives solutions to common Bugzilla installation
problems. If none of the section headings seems to match your
problem, read the general advice.
</para>
<section id="general-advice">
<title>General Advice</title>
<para>If you can't get <filename>checksetup.pl</filename> to run to
completion, it normally explains what's wrong and how to fix it.
If you can't work it out, or if it's being uncommunicative, post
the errors in the
<ulink url="news://news.mozilla.org/mozilla.support.bugzilla">mozilla.support.bugzilla</ulink>
newsgroup.
</para>
<para>If you have made it all the way through
<xref linkend="installation"/> (Installation) and
<xref linkend="configuration"/> (Configuration) but accessing the Bugzilla
URL doesn't work, the first thing to do is to check your web server error
log. For Apache, this is often located at
<filename>/etc/logs/httpd/error_log</filename>. The error messages
you see may be self-explanatory enough to enable you to diagnose and
fix the problem. If not, see below for some commonly-encountered
errors. If that doesn't help, post the errors to the newsgroup.
</para>
<para>
Bugzilla can also log all user-based errors (and many code-based errors)
that occur, without polluting the web server's error log. To enable
Bugzilla error logging, create a file that Bugzilla can write to, named
<filename>errorlog</filename>, in the Bugzilla <filename>data</filename>
directory. Errors will be logged as they occur, and will include the type
of the error, the IP address and username (if available) of the user who
triggered the error, and the values of all environment variables; if a
form was being submitted, the data in the form will also be included.
To disable error logging, delete or rename the
<filename>errorlog</filename> file.
</para>
</section>
<section id="trbl-testserver">
<title>The Apache web server is not serving Bugzilla pages</title>
<para>After you have run <command>checksetup.pl</command> twice,
run <command>testserver.pl http://yoursite.yourdomain/yoururl</command>
to confirm that your web server is configured properly for
Bugzilla.
</para>
<programlisting>
<prompt>bash$</prompt> ./testserver.pl http://landfill.bugzilla.org/bugzilla-tip
TEST-OK Webserver is running under group id in $webservergroup.
TEST-OK Got ant picture.
TEST-OK Webserver is executing CGIs.
TEST-OK Webserver is preventing fetch of http://landfill.bugzilla.org/bugzilla-tip/localconfig.
</programlisting>
</section>
<section id="trbl-perlmodule">
<title>I installed a Perl module, but
<filename>checksetup.pl</filename> claims it's not installed!</title>
<para>This could be caused by one of two things:</para>
<orderedlist>
<listitem>
<para>You have two versions of Perl on your machine. You are installing
modules into one, and Bugzilla is using the other. Rerun the CPAN
commands (or manual compile) using the full path to Perl from the
top of <filename>checksetup.pl</filename>. This will make sure you
are installing the modules in the right place.
</para>
</listitem>
<listitem>
<para>The permissions on your library directories are set incorrectly.
They must, at the very least, be readable by the web server user or
group. It is recommended that they be world readable.
</para>
</listitem>
</orderedlist>
</section>
<section id="trbl-dbdSponge">
<title>DBD::Sponge::db prepare failed</title>
<para>The following error message may appear due to a bug in DBD::mysql
(over which the Bugzilla team have no control):
</para>
<programlisting><![CDATA[ DBD::Sponge::db prepare failed: Cannot determine NUM_OF_FIELDS at D:/Perl/site/lib/DBD/mysql.pm line 248.
SV = NULL(0x0) at 0x20fc444
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
]]></programlisting>
<para>To fix this, go to
<filename>&lt;path-to-perl&gt;/lib/DBD/sponge.pm</filename>
in your Perl installation and replace
</para>
<programlisting><![CDATA[ my $numFields;
if ($attribs->{'NUM_OF_FIELDS'}) {
$numFields = $attribs->{'NUM_OF_FIELDS'};
} elsif ($attribs->{'NAME'}) {
$numFields = @{$attribs->{NAME}};
]]></programlisting>
<para>with</para>
<programlisting><![CDATA[ my $numFields;
if ($attribs->{'NUM_OF_FIELDS'}) {
$numFields = $attribs->{'NUM_OF_FIELDS'};
} elsif ($attribs->{'NAMES'}) {
$numFields = @{$attribs->{NAMES}};
]]></programlisting>
<para>(note the S added to NAME.)</para>
</section>
<section id="paranoid-security">
<title>cannot chdir(/var/spool/mqueue)</title>
<para>If you are installing Bugzilla on SuSE Linux, or some other
distributions with <quote>paranoid</quote> security options, it is
possible that the checksetup.pl script may fail with the error:
<programlisting><![CDATA[cannot chdir(/var/spool/mqueue): Permission denied
]]></programlisting>
</para>
<para>This is because your <filename>/var/spool/mqueue</filename>
directory has a mode of <computeroutput>drwx------</computeroutput>.
Type <command>chmod 755 <filename>/var/spool/mqueue</filename></command>
as root to fix this problem. This will allow any process running on your
machine the ability to <emphasis>read</emphasis> the
<filename>/var/spool/mqueue</filename> directory.
</para>
</section>
<section id="trbl-relogin-everyone">
<title>Everybody is constantly being forced to relogin</title>
<para>The most-likely cause is that the <quote>cookiepath</quote> parameter
is not set correctly in the Bugzilla configuration. You can change this (if
you're a Bugzilla administrator) from the editparams.cgi page via the web interface.
</para>
<para>The value of the cookiepath parameter should be the actual directory
containing your Bugzilla installation, <emphasis>as seen by the end-user's
web browser</emphasis>. Leading and trailing slashes are mandatory. You can
also set the cookiepath to any directory which is a parent of the Bugzilla
directory (such as '/', the root directory). But you can't put something
that isn't at least a partial match or it won't work. What you're actually
doing is restricting the end-user's browser to sending the cookies back only
to that directory.
</para>
<para>How do you know if you want your specific Bugzilla directory or the
whole site?
</para>
<para>If you have only one Bugzilla running on the server, and you don't
mind having other applications on the same server with it being able to see
the cookies (you might be doing this on purpose if you have other things on
your site that share authentication with Bugzilla), then you'll want to have
the cookiepath set to "/", or to a sufficiently-high enough directory that
all of the involved apps can see the cookies.
</para>
<example id="trbl-relogin-everyone-share">
<title>Examples of urlbase/cookiepath pairs for sharing login cookies</title>
<blockquote>
<literallayout>
urlbase is <ulink url="http://bugzilla.mozilla.org/"/>
cookiepath is /
urlbase is <ulink url="http://tools.mysite.tld/bugzilla/"/>
but you have http://tools.mysite.tld/someotherapp/ which shares
authentication with your Bugzilla
cookiepath is /
</literallayout>
</blockquote>
</example>
<para>On the other hand, if you have more than one Bugzilla running on the
server (some people do - we do on landfill) then you need to have the
cookiepath restricted enough so that the different Bugzillas don't
confuse their cookies with one another.
</para>
<example id="trbl-relogin-everyone-restrict">
<title>Examples of urlbase/cookiepath pairs to restrict the login cookie</title>
<blockquote>
<literallayout>
urlbase is <ulink url="http://landfill.bugzilla.org/bugzilla-tip/"/>
cookiepath is /bugzilla-tip/
urlbase is <ulink url="http://landfill.bugzilla.org/bugzilla-2.16-branch/"/>
cookiepath is /bugzilla-2.16-branch/
</literallayout>
</blockquote>
</example>
<para>If you had cookiepath set to <quote>/</quote> at any point in the
past and need to set it to something more restrictive
(i.e. <quote>/bugzilla/</quote>), you can safely do this without
requiring users to delete their Bugzilla-related cookies in their
browser (this is true starting with Bugzilla 2.18 and Bugzilla 2.16.5).
</para>
</section>
<section id="trbl-relogin-some">
<title>Some users are constantly being forced to relogin</title>
<para>First, make sure cookies are enabled in the user's browser.
</para>
<para>If that doesn't fix the problem, it may be that the user's ISP
implements a rotating proxy server. This causes the user's effective IP
address (the address which the Bugzilla server perceives him coming from)
to change periodically. Since Bugzilla cookies are tied to a specific IP
address, each time the effective address changes, the user will have to
log in again.
</para>
<para>If you are using 2.18 (or later), there is a
parameter called <quote>loginnetmask</quote>, which you can use to set
the number of bits of the user's IP address to require to be matched when
authenticating the cookies. If you set this to something less than 32,
then the user will be given a checkbox for <quote>Restrict this login to
my IP address</quote> on the login screen, which defaults to checked. If
they leave the box checked, Bugzilla will behave the same as it did
before, requiring an exact match on their IP address to remain logged in.
If they uncheck the box, then only the left side of their IP address (up
to the number of bits you specified in the parameter) has to match to
remain logged in.
</para>
</section>
<section id="trbl-index">
<title><filename>index.cgi</filename> doesn't show up unless specified in the URL</title>
<para>
You probably need to set up your web server in such a way that it
will serve the index.cgi page as an index page.
</para>
<para>
If you are using Apache, you can do this by adding
<filename>index.cgi</filename> to the end of the
<computeroutput>DirectoryIndex</computeroutput> line
as mentioned in <xref linkend="http-apache"/>.
</para>
</section>
<section id="trbl-passwd-encryption">
<title>
checksetup.pl reports "Client does not support authentication protocol
requested by server..."
</title>
<para>
This error is occurring because you are using the new password
encryption that comes with MySQL 4.1, while your
<filename>DBD::mysql</filename> module was compiled against an
older version of MySQL. If you recompile <filename>DBD::mysql</filename>
against the current MySQL libraries (or just obtain a newer version
of this module) then the error may go away.
</para>
<para>
If that does not fix the problem, or if you cannot recompile the
existing module (e.g. you're running Windows) and/or don't want to
replace it (e.g. you want to keep using a packaged version), then a
workaround is available from the MySQL docs:
<ulink url="http://dev.mysql.com/doc/mysql/en/Old_client.html"/>
</para>
</section>
</appendix>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-always-quote-attributes:t
sgml-auto-insert-required-elements:t
sgml-balanced-tag-edit:t
sgml-exposed-tags:nil
sgml-general-insert-case:lower
sgml-indent-data:t
sgml-indent-step:2
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
sgml-minimize-attributes:nil
sgml-namecase-general:t
sgml-omittag:t
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
sgml-shorttag:t
sgml-tag-region-if-active:t
End: -->

File diff suppressed because it is too large Load Diff

View File

@@ -1,217 +0,0 @@
#!/usr/bin/perl -w
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Matthew Tuck <matty@chariot.net.au>
# Jacob Steenhagen <jake@bugzilla.org>
# Colin Ogilvie <colin.ogilvie@gmail.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
# This script compiles all the documentation.
use strict;
use Cwd;
# We need to be in this directory to use our libraries.
BEGIN {
require File::Basename;
import File::Basename qw(dirname);
chdir dirname($0);
}
use lib qw(.. ../lib lib);
# We only compile our POD if Pod::Simple is installed. We do the checks
# this way so that if there's a compile error in Pod::Simple::HTML::Bugzilla,
# makedocs doesn't just silently fail, but instead actually tells us there's
# a compile error.
my $pod_simple;
if (eval { require Pod::Simple }) {
require Pod::Simple::HTMLBatch::Bugzilla;
require Pod::Simple::HTML::Bugzilla;
$pod_simple = 1;
};
use Bugzilla::Install::Requirements
qw(REQUIRED_MODULES OPTIONAL_MODULES);
use Bugzilla::Constants qw(DB_MODULE BUGZILLA_VERSION);
###############################################################################
# Generate minimum version list
###############################################################################
my $modules = REQUIRED_MODULES;
my $opt_modules = OPTIONAL_MODULES;
open(ENTITIES, '>', 'bugzilla.ent') or die('Could not open bugzilla.ent: ' . $!);
print ENTITIES <<END_ENTITIES;
<?xml version="1.0" encoding="UTF-8" ?>
<!ENTITY bz-ver "3.3">
<!ENTITY bz-nextver "4.0">
<!ENTITY bz-date "2008-05-20">
<!ENTITY current-year "2008">
<!ENTITY landfillbase "http://landfill.bugzilla.org/bugzilla-tip/">
<!ENTITY bz "http://www.bugzilla.org/">
<!ENTITY bzg-bugs "<ulink url='https://bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&amp;component=Documentation'>Bugzilla Documentation</ulink>">
<!ENTITY mysql "http://www.mysql.com/">
<!ENTITY min-perl-ver "5.8.1">
<!-- Module Versions -->
END_ENTITIES
foreach my $module (@$modules, @$opt_modules)
{
my $name = $module->{'module'};
$name =~ s/::/-/g;
$name = lc($name);
#This needs to be a string comparison, due to the modules having
#version numbers like 0.9.4
my $version = $module->{'version'} eq 0 ? 'any' : $module->{'version'};
print ENTITIES '<!ENTITY min-' . $name . '-ver "'.$version.'">' . "\n";
}
# CGI is a special case, because for Perl versions below 5.10, it has an
# optional version *and* a required version.
# We check @opt_modules first, then @modules, and pick the first we get.
# We'll get the optional one then, if it is given, otherwise the required one.
my ($cgi_opt) = grep($_->{module} eq 'CGI', @$opt_modules, @$modules);
print ENTITIES '<!ENTITY min-mp-cgi-ver "' . $cgi_opt->{version} . '">' . "\n";
print ENTITIES "\n <!-- Database Versions --> \n";
my $db_modules = DB_MODULE;
foreach my $db (keys %$db_modules) {
my $dbd = $db_modules->{$db}->{dbd};
my $name = $dbd->{module};
$name =~ s/::/-/g;
$name = lc($name);
my $version = $dbd->{version} || 'any';
my $db_version = $db_modules->{$db}->{'db_version'};
print ENTITIES '<!ENTITY min-' . $name . '-ver "'.$version.'">' . "\n";
print ENTITIES '<!ENTITY min-' . lc($db) . '-ver "'.$db_version.'">' . "\n";
}
close(ENTITIES);
###############################################################################
# Subs
###############################################################################
sub MakeDocs {
my ($name, $cmdline) = @_;
print "Creating $name documentation ...\n" if defined $name;
print "$cmdline\n\n";
system $cmdline;
print "\n";
}
sub make_pod {
print "Creating API documentation...\n";
my $converter = Pod::Simple::HTMLBatch::Bugzilla->new;
# Don't output progress information.
$converter->verbose(0);
$converter->html_render_class('Pod::Simple::HTML::Bugzilla');
my $doctype = Pod::Simple::HTML::Bugzilla->DOCTYPE;
my $content_type = Pod::Simple::HTML::Bugzilla->META_CT;
my $bz_version = BUGZILLA_VERSION;
my $contents_start = <<END_HTML;
$doctype
<html>
<head>
$content_type
<title>Bugzilla $bz_version API Documentation</title>
</head>
<body class="contentspage">
<h1>Bugzilla $bz_version API Documentation</h1>
END_HTML
$converter->contents_page_start($contents_start);
$converter->contents_page_end("</body></html>");
$converter->add_css('./../../../style.css');
$converter->javascript_flurry(0);
$converter->css_flurry(0);
$converter->batch_convert(['../../'], 'html/api/');
print "\n";
}
###############################################################################
# Make the docs ...
###############################################################################
my @langs;
# search for sub directories which have a 'xml' sub-directory
opendir(LANGS, './');
foreach my $dir (readdir(LANGS)) {
next if (($dir eq '.') || ($dir eq '..') || (! -d $dir));
if (-d "$dir/xml") {
push(@langs, $dir);
}
}
closedir(LANGS);
my $docparent = getcwd();
foreach my $lang (@langs) {
chdir "$docparent/$lang";
MakeDocs(undef, 'cp ../bugzilla.ent ./xml/');
if (!-d 'txt') {
unlink 'txt';
mkdir 'txt', 0755;
}
if (!-d 'pdf') {
unlink 'pdf';
mkdir 'pdf', 0755;
}
if (!-d 'html') {
unlink 'html';
mkdir 'html', 0755;
}
if (!-d 'html/api') {
unlink 'html/api';
mkdir 'html/api', 0755;
}
MakeDocs(undef, 'cp ../style.css html/api/');
make_pod() if $pod_simple;
MakeDocs('separate HTML', 'xmlto -m ../xsl/chunks.xsl -o html html ' .
'xml/Bugzilla-Guide.xml');
MakeDocs('big HTML', 'xmlto -m ../xsl/nochunks.xsl -o html html-nochunks ' .
'xml/Bugzilla-Guide.xml');
MakeDocs('big text', "lynx -dump -justify=off -nolist html/Bugzilla-Guide.html " .
"> txt/Bugzilla-Guide.txt");
if (! grep($_ eq "--with-pdf", @ARGV)) {
next;
}
MakeDocs('PDF', 'xmlto -m ../xsl/pdf.xsl -o pdf pdf xml/Bugzilla-Guide.xml');
}

View File

@@ -1,112 +0,0 @@
/* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Bugzilla Bug Tracking System.
*
* The Initial Developer of the Original Code is Everything Solved.
* Portions created by Everything Solved are Copyright (C) 2006
* Everything Solved. All Rights Reserved.
*
* Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
*/
body {
background: white;
color: #111;
padding: 0 1em;
margin: 0;
font-family: Verdana, Arial, sans-serif;
font-size: small;
}
td, th {
font-family: Verdana, Arial, sans-serif;
font-size: small;
}
a:link, a:active { color: #36415c; }
a:visited { color: #666; }
a:hover { color: #888; }
h1 {
font-size: 150%;
font-weight: bold;
border-bottom: 2px solid #ccc;
}
h2 {
font-size: 125%;
font-weight: bold;
border-bottom: 1px solid #ccc;
margin-bottom: 8px;
}
h3 {
font-size: 115%;
font-weight: bold;
margin-bottom: 0;
padding-bottom: 0;
}
/* This makes Description/Params/Returns look nice. */
dd { margin-top: .2em; }
dd p { margin-top: 0; }
dl { margin-bottom: 1em; }
/* This makes the names of functions slightly larger, in Gecko. */
body > dl > dt code { font-size: 1.35em; }
#pod h1 a, #pod h2 a, #pod h3 a {
color: #36415c;
text-decoration: none;
}
pre, code, tt, kbd, samp {
/* Unfortunately, the default monospace fonts on most browsers
look odd with relative sizing. */
font-size: 12px;
}
.code {
background: #eed;
border: 1px solid #ccc;
}
pre.code {
margin-left: 10px;
width: 90%;
padding: 10px;
}
/* Special styles for the Contents page */
.contentspage dt {
font-size: large;
font-weight: bold;
}
.pod_desc_table {
border-collapse: collapse;
table-layout: auto;
border: 1px solid #ccc;
}
.pod_desc_table th {
text-align: left;
}
.pod_desc_table td, .pod_desc_table th {
padding: .25em;
border-top: 1px solid #ccc;
}
.pod_desc_table .odd th, .pod_desc_table .odd td {
background-color: #eee;
}
.pod_desc_table

View File

@@ -1,102 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Nicer Filenames -->
<xsl:param name="use.id.as.filename" select="1"/>
<!-- Label sections if they aren't automatically labeled -->
<xsl:param name="section.autolabel" select="1"/>
<!-- Table of Contents Depth -->
<xsl:param name="toc.section.depth">1</xsl:param>
<!-- Set chunk parameters -->
<xsl:param name="chunk.section.depth" select="1"/>
<xsl:param name="chunk.first.sections" select="1"/>
<xsl:param name="chunker.output.encoding" select="UTF-8"/>
<!-- Show titles of next/previous page -->
<xsl:param name="navig.showtitles">1</xsl:param>
<!-- Tidy up the HTML a bit... -->
<xsl:param name="html.cleanup" select="1"/>
<xsl:param name="make.valid.html" select="1"/>
<xsl:param name="html.stylesheet">api/style.css</xsl:param>
<!-- make links nicer... -->
<xsl:param name="refentry.generate.title" select="1"/>
<xsl:param name="refentry.generate.name" select="0"/>
<!-- Use Graphics, specify their Path and Extension -->
<xsl:param name="admon.graphics" select="1"/>
<xsl:param name="admon.graphics.path">../images/</xsl:param>
<xsl:param name="admon.graphics.extension">.gif</xsl:param>
<xsl:param name="qanda.inherit.numeration" select="0" />
<!--
****
CODE BELOW HERE IS EXTRACTED AND EDITED FROM THE DOCBOOK XSL SOURCES
****
-->
<xsl:template match="simplelist[@type='inline']/member">
<xsl:apply-templates/>
</xsl:template>
<!--
To generate valid HTML, we need to redefine this section... Code extracted from
http://cvs.sourceforge.net/viewcvs.py/docbook/xsl/html/qandaset.xsl?rev=1.19&view=log
and modified below. Basic change: Remove the colspan attribute of the tr tags - no
other changes have been made to the document.
-->
<xsl:template match="qandadiv">
<xsl:variable name="preamble" select="*[name(.) != 'title'
and name(.) != 'titleabbrev'
and name(.) != 'qandadiv'
and name(.) != 'qandaentry']"/>
<xsl:if test="blockinfo/title|title">
<tr class="qandadiv">
<td align="left" valign="top" colspan="2">
<xsl:call-template name="anchor">
<xsl:with-param name="conditional" select="0"/>
</xsl:call-template>
<xsl:apply-templates select="(blockinfo/title|title)[1]"/>
</td>
</tr>
</xsl:if>
<xsl:variable name="toc">
<xsl:call-template name="dbhtml-attribute">
<xsl:with-param name="pis"
select="processing-instruction('dbhtml')"/>
<xsl:with-param name="attribute" select="'toc'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="toc.params">
<xsl:call-template name="find.path.params">
<xsl:with-param name="table" select="normalize-space($generate.toc)"/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="(contains($toc.params, 'toc') and $toc != '0') or $toc = '1'">
<tr class="toc">
<td align="left" valign="top" colspan="2">
<xsl:call-template name="process.qanda.toc"/>
</td>
</tr>
</xsl:if>
<xsl:if test="$preamble">
<tr class="toc" >
<td align="left" valign="top" colspan="2">
<xsl:apply-templates select="$preamble"/>
</td>
</tr>
</xsl:if>
<xsl:apply-templates select="qandadiv|qandaentry"/>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Include default bugzilla XSL -->
<xsl:include href="bugzilla-docs.xsl"/>
<!-- Set Chunk Specific XSL Params -->
<xsl:param name="chunker.output.doctype-public">-//W3C//DTD HTML 4.01 Transitional//EN</xsl:param>
<xsl:param name="chunker.output.doctype-system">http://www.w3.org/TR/html4/loose.dtd</xsl:param>
<xsl:param name="chunk.section.depth" select="1"/>
<xsl:param name="chunk.first.sections" select="1"/>
<!-- Don't output filename list - mimic old behaviour-->
<xsl:param name="chunk.quietly" select="0" />
</xsl:stylesheet>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Include default bugzilla XSL -->
<xsl:include href="bugzilla-docs.xsl"/>
<!-- No other params necessary -->
</xsl:stylesheet>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
<!-- Enable passivetex extensions -->
<xsl:param name="passivetex.extensions" select="1"/>
<xsl:param name="tablecolumns.extensions" select="1"/>
<!-- Show <ulink>s as footnotes -->
<xsl:param name="ulink.footnotes" select="1" />
<xsl:param name="ulink.show" select="1" />
<!-- Don't use Graphics -->
<xsl:param name="admon.graphics" select="0"/>
<xsl:param name="callout.graphics" select="'0'"/>
<xsl:template match="simplelist[@type='inline']/member">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,226 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsError_h
#define nsError_h
#ifndef prtypes_h___
#include "prtypes.h"
#endif
/**
* Generic result data type
*/
typedef PRUint32 nsresult;
/*
* To add error code to your module, you need to do the following:
*
* 1) Add a module offset code. Add yours to the bottom of the list
* right below this comment, adding 1.
*
* 2) In your module, define a header file which uses one of the
* NE_ERROR_GENERATExxxxxx macros. Some examples below:
*
* #define NS_ERROR_MYMODULE_MYERROR1 NS_ERROR_GENERATE(NS_ERROR_SEVERITY_ERROR,NS_ERROR_MODULE_MYMODULE,1)
* #define NS_ERROR_MYMODULE_MYERROR2 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_MYMODULE,2)
* #define NS_ERROR_MYMODULE_MYERROR3 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_MYMODULE,3)
*
*/
/**
* @name Standard Module Offset Code. Each Module should identify a unique number
* and then all errors associated with that module become offsets from the
* base associated with that module id. There are 16 bits of code bits for
* each module.
*/
#define NS_ERROR_MODULE_XPCOM 1
#define NS_ERROR_MODULE_BASE 2
#define NS_ERROR_MODULE_GFX 3
#define NS_ERROR_MODULE_WIDGET 4
#define NS_ERROR_MODULE_CALENDAR 5
#define NS_ERROR_MODULE_NETWORK 6
#define NS_ERROR_MODULE_PLUGINS 7
#define NS_ERROR_MODULE_LAYOUT 8
#define NS_ERROR_MODULE_HTMLPARSER 9
#define NS_ERROR_MODULE_RDF 10
#define NS_ERROR_MODULE_UCONV 11
#define NS_ERROR_MODULE_REG 12
#define NS_ERROR_MODULE_FILES 13
#define NS_ERROR_MODULE_DOM 14
#define NS_ERROR_MODULE_IMGLIB 15
#define NS_ERROR_MODULE_MAILNEWS 16
#define NS_ERROR_MODULE_EDITOR 17
#define NS_ERROR_MODULE_XPCONNECT 18
/**
* @name Standard Error Handling Macros
*/
#define NS_FAILED(_nsresult) ((_nsresult) & 0x80000000)
#define NS_SUCCEEDED(_nsresult) (!((_nsresult) & 0x80000000))
/**
* @name Severity Code. This flag identifies the level of warning
*/
#define NS_ERROR_SEVERITY_SUCCESS 0
#define NS_ERROR_SEVERITY_ERROR 1
/**
* @name Mozilla Code. This flag separates consumers of mozilla code
* from the native platform
*/
#define NS_ERROR_MODULE_BASE_OFFSET 0x45
/**
* @name Standard Error Generating Macros
*/
#define NS_ERROR_GENERATE(sev,module,code) \
((nsresult) (((PRUint32)(sev)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
#define NS_ERROR_GENERATE_SUCCESS(module,code) \
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_SUCCESS)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
#define NS_ERROR_GENERATE_FAILURE(module,code) \
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_ERROR)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
/**
* @name Standard Macros for retrieving error bits
*/
#define NS_ERROR_GET_CODE(err) ((err) & 0xffff)
#define NS_ERROR_GET_MODULE(err) (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff))
#define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1)
/**
* @name Standard return values
*/
/*@{*/
/* Standard "it worked" return value */
#define NS_OK 0
/* The backwards COM false */
#define NS_COMFALSE 1
#define NS_ERROR_BASE ((nsresult) 0xC1F30000)
/* Returned when an instance is not initialized */
#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1)
/* Returned when an instance is already initialized */
#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2)
/* Returned by a not implemented function */
#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L)
/* Returned when a given interface is not supported. */
#define NS_NOINTERFACE ((nsresult) 0x80004002L)
#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE
#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L)
#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER
/* Returned when a function aborts */
#define NS_ERROR_ABORT ((nsresult) 0x80004004L)
/* Returned when a function fails */
#define NS_ERROR_FAILURE ((nsresult) 0x80004005L)
/* Returned when an unexpected error occurs */
#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL)
/* Returned when a memory allocation failes */
#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL)
/* Returned when an illegal value is passed */
#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L)
#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE
/* Returned when a class doesn't allow aggregation */
#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L)
/* Returned when an operation can't complete due to an unavailable resource */
#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L)
/* Returned when a class is not registered */
#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L)
/* Returned when a class cannot be registered, but may be tried again later */
#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L)
/* Returned when a dynamically loaded factory couldn't be found */
#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L)
/* Returned when a factory doesn't support signatures */
#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \
(NS_ERROR_BASE + 0x101)
/* Returned when a factory already is registered */
#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100)
/* For COM compatibility reasons, we want to use exact error code numbers
for NS_ERROR_PROXY_INVALID_IN_PARAMETER and NS_ERROR_PROXY_INVALID_OUT_PARAMETER.
The first matches:
#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L)
Errors returning this mean that the xpcom proxy code could not create a proxy for
one of the in paramaters.
Because of this, we are ignoring the convention if using a base and offset for
error numbers.
*/
/* Returned when a proxy could not be create a proxy for one of the IN parameters
This is returned only when the "real" meathod has NOT been invoked.
*/
#define NS_ERROR_PROXY_INVALID_IN_PARAMETER ((nsresult) 0x80010010L)
/* Returned when a proxy could not be create a proxy for one of the OUT parameters
This is returned only when the "real" meathod has ALREADY been invoked.
*/
#define NS_ERROR_PROXY_INVALID_OUT_PARAMETER ((nsresult) 0x80010011L)
/*@}*/
////////////////////////////////////////////////////////////////////////////////
#ifdef XP_PC
#pragma warning(disable: 4251) // 'nsCOMPtr<class nsIInputStream>' needs to have dll-interface to be used by clients of class 'nsInputStream'
#pragma warning(disable: 4275) // non dll-interface class 'nsISupports' used as base for dll-interface class 'nsIRDFNode'
#endif
#endif

View File

@@ -0,0 +1,126 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
// Force references to all of the symbols that we want exported from
// the dll that are located in the .lib files we link with
#include "nsVoidArray.h"
#include "nsIAtom.h"
#include "nsFileSpec.h"
//#include "nsIBuffer.h"
//#include "nsIByteBufferInputStream.h"
#include "nsFileStream.h"
#include "nsFileSpecStreaming.h"
#include "nsSpecialSystemDirectory.h"
#include "nsIThread.h"
#include "nsDeque.h"
#include "nsObserver.h"
#include "nsTraceRefcnt.h"
#include "nsXPIDLString.h"
#include "nsIEnumerator.h"
#include "nsEnumeratorUtils.h"
#include "nsQuickSort.h"
#include "nsString2.h"
#include "nsProxyEventPrivate.h"
#include "xpt_xdr.h"
#include "nsInterfaceInfo.h"
#include "xptcall.h"
#include "nsIFileSpec.h"
#include "nsIGenericFactory.h"
#include "nsAVLTree.h"
#include "nsHashtableEnumerator.h"
#include "nsPipe2.h"
#include "nsCWeakReference.h"
#include "nsWeakReference.h"
#include "nsISizeOfHandler.h"
#include "nsTextFormater.h"
#include "nsStorageStream.h"
#include "nsIBinaryInputStream.h"
#ifdef DEBUG
#include "pure.h"
#endif
class dummyComparitor: public nsAVLNodeComparitor {
public:
virtual PRInt32 operator()(void* anItem1,void* anItem2)
{
return 0;
}
};
#ifdef DEBUG
extern NS_COM void
TestSegmentedBuffer();
#endif
void XXXNeverCalled()
{
nsTextFormater::snprintf(nsnull,0,nsnull);
dummyComparitor dummy;
nsVoidArray();
nsAVLTree(dummy, nsnull);
NS_GetNumberOfAtoms();
nsFileURL(NULL);
// NS_NewPipe(NULL, NULL, 0, 0, 0, NULL);
NS_NewPipe(NULL, NULL, NULL, 0, 0);
nsFileSpec s;
NS_NewIOFileStream(NULL, s, 0, 0);
nsInputFileStream(s, 0, 0);
nsPersistentFileDescriptor d;
ReadDescriptor(NULL, d);
new nsSpecialSystemDirectory(nsSpecialSystemDirectory::OS_DriveDirectory);
nsIThread::GetCurrent(NULL);
nsDeque(NULL);
NS_NewObserver(NULL, NULL);
nsTraceRefcnt::DumpStatistics();
nsXPIDLCString::Copy(NULL);
NS_NewEmptyEnumerator(NULL);
nsArrayEnumerator(NULL);
NS_NewIntersectionEnumerator(NULL, NULL, NULL);
NS_QuickSort(NULL, 0, 0, NULL, NULL);
nsString2();
nsProxyObject(NULL, 0, NULL);
XPT_DoString(NULL, NULL);
XPT_DoHeader(NULL, NULL);
nsInterfaceInfo* info = NULL;
info->GetName(NULL);
#ifdef DEBUG
info->print(NULL);
PurePrintf(0);
#endif
XPTC_InvokeByIndex(NULL, 0, 0, NULL);
NS_NewFileSpec(NULL);
xptc_dummy();
xptc_dummy2();
XPTI_GetInterfaceInfoManager();
NS_NewGenericFactory(NULL, NULL, NULL);
NS_NewHashtableEnumerator(NULL, NULL, NULL, NULL);
nsCWeakProxy(0, 0);
nsCWeakReferent(0);
NS_GetWeakReference(NULL);
#ifdef DEBUG
TestSegmentedBuffer();
#endif
NS_NewSizeOfHandler(0);
nsStorageStream();
NS_NewBinaryInputStream(0, 0);
}

View File

@@ -0,0 +1,170 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsIGenericFactory_h___
#define nsIGenericFactory_h___
#include "nsIFactory.h"
// {3bc97f01-ccdf-11d2-bab8-b548654461fc}
#define NS_GENERICFACTORY_CID \
{ 0x3bc97f01, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
// {3bc97f00-ccdf-11d2-bab8-b548654461fc}
#define NS_IGENERICFACTORY_IID \
{ 0x3bc97f00, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
#define NS_GENERICFACTORY_PROGID "component:/netscape/generic-factory"
#define NS_GENERICFACTORY_CLASSNAME "Generic Factory"
/**
* Provides a Generic nsIFactory implementation that can be used by
* DLLs with very simple factory needs.
*/
class nsIGenericFactory : public nsIFactory {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }
typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);
typedef NS_CALLBACK(DestructorProcPtr) (void);
/**
* Establishes the generic factory's constructor function, which will be called
* by CreateInstance.
*/
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
/**
* Establishes the generic factory's destructor function, which will be called
* whe the generic factory is deleted. This is used to notify the DLL that
* an instance of one of its generic factories is going away.
*/
NS_IMETHOD SetDestructor(DestructorProcPtr destructor) = 0;
};
extern NS_COM nsresult
NS_NewGenericFactory(nsIGenericFactory* *result,
nsIGenericFactory::ConstructorProcPtr constructor,
nsIGenericFactory::DestructorProcPtr destructor = NULL);
////////////////////////////////////////////////////////////////////////////////
// Generic Modules
//
// (See xpcom/sample/nsSampleModule.cpp to see how to use this.)
#include "nsIModule.h"
/**
* Use this type to define a list of module component info to pass to
* NS_NewGenericModule. E.g.:
* static nsModuleComponentInfo components[] = { ... };
* See xpcom/sample/nsSampleModule.cpp for more info.
*/
struct nsModuleComponentInfo {
const char* mDescription;
nsCID mCID;
const char* mProgID;
nsIGenericFactory::ConstructorProcPtr mConstructor;
};
extern NS_COM nsresult
NS_NewGenericModule(const char* moduleName,
PRUint32 componentCount,
nsModuleComponentInfo* components,
nsIModule* *result);
#define NS_IMPL_NSGETMODULE(_name, _components) \
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, \
nsIFileSpec* location, \
nsIModule** result) \
{ \
return NS_NewGenericModule((_name), \
sizeof(_components) / sizeof(_components[0]), \
(_components), result); \
}
////////////////////////////////////////////////////////////////////////////////
#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
static NS_IMETHODIMP \
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
{ \
nsresult rv; \
\
_InstanceClass * inst; \
\
if (NULL == aResult) { \
rv = NS_ERROR_NULL_POINTER; \
return rv; \
} \
*aResult = NULL; \
if (NULL != aOuter) { \
rv = NS_ERROR_NO_AGGREGATION; \
return rv; \
} \
\
NS_NEWXPCOM(inst, _InstanceClass); \
if (NULL == inst) { \
rv = NS_ERROR_OUT_OF_MEMORY; \
return rv; \
} \
NS_ADDREF(inst); \
rv = inst->QueryInterface(aIID, aResult); \
NS_RELEASE(inst); \
\
return rv; \
} \
#define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \
static NS_IMETHODIMP \
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
{ \
nsresult rv; \
\
_InstanceClass * inst; \
\
if (NULL == aResult) { \
rv = NS_ERROR_NULL_POINTER; \
return rv; \
} \
*aResult = NULL; \
if (NULL != aOuter) { \
rv = NS_ERROR_NO_AGGREGATION; \
return rv; \
} \
\
NS_NEWXPCOM(inst, _InstanceClass); \
if (NULL == inst) { \
rv = NS_ERROR_OUT_OF_MEMORY; \
return rv; \
} \
NS_ADDREF(inst); \
rv = inst->_InitMethod(); \
if(NS_SUCCEEDED(rv)) { \
rv = inst->QueryInterface(aIID, aResult); \
} \
NS_RELEASE(inst); \
\
return rv; \
} \
#endif /* nsIGenericFactory_h___ */

View File

@@ -0,0 +1,521 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "prmem.h"
#include "prlog.h"
#include "nsHashtable.h"
//
// Key operations
//
static PR_CALLBACK PLHashNumber _hashValue(const void *key)
{
return ((const nsHashKey *) key)->HashValue();
}
static PR_CALLBACK PRIntn _hashKeyCompare(const void *key1, const void *key2) {
return ((const nsHashKey *) key1)->Equals((const nsHashKey *) key2);
}
static PR_CALLBACK PRIntn _hashValueCompare(const void *value1,
const void *value2) {
// We're not going to make any assumptions about value equality
return 0;
}
//
// Memory callbacks
//
static PR_CALLBACK void *_hashAllocTable(void *pool, PRSize size) {
return PR_MALLOC(size);
}
static PR_CALLBACK void _hashFreeTable(void *pool, void *item) {
PR_DELETE(item);
}
static PR_CALLBACK PLHashEntry *_hashAllocEntry(void *pool, const void *key) {
return PR_NEW(PLHashEntry);
}
static PR_CALLBACK void _hashFreeEntry(void *pool, PLHashEntry *entry,
PRUintn flag) {
if (flag == HT_FREE_ENTRY) {
delete (nsHashKey *) (entry->key);
PR_DELETE(entry);
}
}
static PLHashAllocOps _hashAllocOps = {
_hashAllocTable, _hashFreeTable,
_hashAllocEntry, _hashFreeEntry
};
//
// Enumerator callback
//
struct _HashEnumerateArgs {
nsHashtableEnumFunc fn;
void* arg;
};
static PR_CALLBACK PRIntn _hashEnumerate(PLHashEntry *he, PRIntn i, void *arg)
{
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
? HT_ENUMERATE_NEXT
: HT_ENUMERATE_STOP;
}
//
// HashKey
//
nsHashKey::nsHashKey(void)
{
}
nsHashKey::~nsHashKey(void)
{
}
nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe)
: mLock(NULL)
{
hashtable = PL_NewHashTable(aInitSize,
_hashValue,
_hashKeyCompare,
_hashValueCompare,
&_hashAllocOps,
NULL);
if (threadSafe == PR_TRUE)
{
mLock = PR_NewLock();
if (mLock == NULL)
{
// Cannot create a lock. If running on a multiprocessing system
// we are sure to die.
PR_ASSERT(mLock != NULL);
}
}
}
nsHashtable::~nsHashtable() {
PL_HashTableDestroy(hashtable);
if (mLock) PR_DestroyLock(mLock);
}
PRBool nsHashtable::Exists(nsHashKey *aKey)
{
PLHashNumber hash = aKey->HashValue();
if (mLock) PR_Lock(mLock);
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
if (mLock) PR_Unlock(mLock);
return *hep != NULL;
}
void *nsHashtable::Put(nsHashKey *aKey, void *aData) {
void *res = NULL;
PLHashNumber hash = aKey->HashValue();
PLHashEntry *he;
if (mLock) PR_Lock(mLock);
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
if ((he = *hep) != NULL) {
res = he->value;
he->value = aData;
} else {
PL_HashTableRawAdd(hashtable, hep, hash,
(void *) aKey->Clone(), aData);
}
if (mLock) PR_Unlock(mLock);
return res;
}
void *nsHashtable::Get(nsHashKey *aKey) {
if (mLock) PR_Lock(mLock);
void *ret = PL_HashTableLookup(hashtable, (void *) aKey);
if (mLock) PR_Unlock(mLock);
return ret;
}
void *nsHashtable::Remove(nsHashKey *aKey) {
PLHashNumber hash = aKey->HashValue();
PLHashEntry *he;
if (mLock) PR_Lock(mLock);
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
void *res = NULL;
if ((he = *hep) != NULL) {
res = he->value;
PL_HashTableRawRemove(hashtable, hep, he);
}
if (mLock) PR_Unlock(mLock);
return res;
}
// XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
// I don't know how this was supposed to work since the elements are neither copied
// nor refcounted.
static PR_CALLBACK PRIntn _hashEnumerateShare(PLHashEntry *he, PRIntn i, void *arg)
{
nsHashtable *newHashtable = (nsHashtable *)arg;
newHashtable->Put((nsHashKey *) he->key, he->value);
return HT_ENUMERATE_NEXT;
}
nsHashtable * nsHashtable::Clone() {
PRBool threadSafe = PR_FALSE;
if (mLock)
threadSafe = PR_TRUE;
nsHashtable *newHashTable = new nsHashtable(hashtable->nentries, threadSafe);
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateShare, newHashTable);
return newHashTable;
}
void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure) {
_HashEnumerateArgs thunk;
thunk.fn = aEnumFunc;
thunk.arg = closure;
PL_HashTableEnumerateEntries(hashtable, _hashEnumerate, &thunk);
}
static PR_CALLBACK PRIntn _hashEnumerateRemove(PLHashEntry *he, PRIntn i, void *arg)
{
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
if (thunk)
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
? HT_ENUMERATE_REMOVE
: HT_ENUMERATE_STOP;
else
return HT_ENUMERATE_REMOVE;
}
void nsHashtable::Reset() {
Reset(NULL);
}
void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* closure)
{
if (destroyFunc != NULL)
{
_HashEnumerateArgs thunk;
thunk.fn = destroyFunc;
thunk.arg = closure;
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, &thunk);
}
else
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, NULL);
}
////////////////////////////////////////////////////////////////////////////////
nsStringKey::nsStringKey(const char* str)
{
mStr.Assign(str);
}
nsStringKey::nsStringKey(const PRUnichar* str)
{
mStr.Assign(str);
}
nsStringKey::nsStringKey(const nsStr& str)
{
mStr.Assign(str);
}
nsStringKey::~nsStringKey(void)
{
}
PRUint32 nsStringKey::HashValue(void) const
{
if(mStr.IsUnicode())
{
PRUint32 h;
PRUint32 n;
PRUint32 m;
const PRUnichar* c;
h = 0;
n = mStr.Length();
c = mStr.GetUnicode();
if(n < 16)
{ /* Hash every char in a short string. */
for(; n; c++, n--)
h = (h >> 28) ^ (h << 4) ^ *c;
}
else
{ /* Sample a la jave.lang.String.hash(). */
for(m = n / 8; n >= m; c += m, n -= m)
h = (h >> 28) ^ (h << 4) ^ *c;
}
return h;
}
return (PRUint32)PL_HashString((const void*) mStr.GetBuffer());
}
PRBool nsStringKey::Equals(const nsHashKey* aKey) const
{
return ((nsStringKey*)aKey)->mStr == mStr;
}
nsHashKey* nsStringKey::Clone() const
{
return new nsStringKey(mStr);
}
const nsString& nsStringKey::GetString() const
{
return mStr;
}
////////////////////////////////////////////////////////////////////////////////
// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
// deleted
nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
void* cloneElementClosure,
nsHashtableEnumFunc destroyElementFun,
void* destroyElementClosure,
PRUint32 aSize, PRBool threadSafe)
: nsHashtable(aSize, threadSafe),
mCloneElementFun(cloneElementFun),
mCloneElementClosure(cloneElementClosure),
mDestroyElementFun(destroyElementFun),
mDestroyElementClosure(destroyElementClosure)
{
}
nsObjectHashtable::~nsObjectHashtable()
{
Reset();
}
PR_CALLBACK PRIntn
nsObjectHashtable::CopyElement(PLHashEntry *he, PRIntn i, void *arg)
{
nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
void* newElement =
newHashtable->mCloneElementFun((nsHashKey*)he->key, he->value,
newHashtable->mCloneElementClosure);
if (newElement == nsnull)
return HT_ENUMERATE_STOP;
newHashtable->Put((nsHashKey*)he->key, newElement);
return HT_ENUMERATE_NEXT;
}
nsHashtable*
nsObjectHashtable::Clone()
{
PRBool threadSafe = PR_FALSE;
if (mLock)
threadSafe = PR_TRUE;
nsObjectHashtable* newHashTable =
new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
mDestroyElementFun, mDestroyElementClosure,
hashtable->nentries, threadSafe);
PL_HashTableEnumerateEntries(hashtable, CopyElement, newHashTable);
return newHashTable;
}
void
nsObjectHashtable::Reset()
{
nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
}
PRBool
nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
{
void *value = Remove(aKey);
if (value && mDestroyElementFun)
{
return (*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
}
else
return PR_FALSE;
}
////////////////////////////////////////////////////////////////////////////////
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
static PR_CALLBACK PRBool
_ReleaseElement(nsHashKey *aKey, void *aData, void* closure)
{
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
NS_IF_RELEASE(element);
return PR_TRUE;
}
nsSupportsHashtable::~nsSupportsHashtable()
{
Enumerate(_ReleaseElement, nsnull);
}
void*
nsSupportsHashtable::Put(nsHashKey *aKey, void *aData)
{
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
NS_IF_ADDREF(element);
return nsHashtable::Put(aKey, aData);
}
void*
nsSupportsHashtable::Get(nsHashKey *aKey)
{
void* data = nsHashtable::Get(aKey);
if (!data)
return nsnull;
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
NS_IF_ADDREF(element);
return data;
}
void*
nsSupportsHashtable::Remove(nsHashKey *aKey)
{
void* data = nsHashtable::Remove(aKey);
if (!data)
return nsnull;
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
NS_IF_RELEASE(element);
return data;
}
static PR_CALLBACK PRIntn
_hashEnumerateCopy(PLHashEntry *he, PRIntn i, void *arg)
{
nsHashtable *newHashtable = (nsHashtable *)arg;
nsISupports* element = NS_STATIC_CAST(nsISupports*, he->value);
NS_IF_ADDREF(element);
newHashtable->Put((nsHashKey*)he->key, he->value);
return HT_ENUMERATE_NEXT;
}
nsHashtable*
nsSupportsHashtable::Clone()
{
PRBool threadSafe = PR_FALSE;
if (mLock)
threadSafe = PR_TRUE;
nsSupportsHashtable* newHashTable =
new nsSupportsHashtable(hashtable->nentries, threadSafe);
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateCopy, newHashTable);
return newHashTable;
}
void
nsSupportsHashtable::Reset()
{
Enumerate(_ReleaseElement, nsnull);
nsHashtable::Reset();
}
////////////////////////////////////////////////////////////////////////////////
// nsOpaqueKey: Where keys are opaque byte array blobs
//
// Note opaque keys are not copied by this constructor. If you want a private
// copy in each hash key, you must create one and pass it in to this function.
nsOpaqueKey::nsOpaqueKey(const char *aOpaqueKey, PRUint32 aKeyLength)
{
mOpaqueKey = aOpaqueKey;
mKeyLength = aKeyLength;
}
nsOpaqueKey::~nsOpaqueKey(void)
{
}
PRUint32
nsOpaqueKey::HashValue(void) const
{
PRUint32 h, i, k;
h = 0;
// Same hashing technique as for java.lang.String.hashCode()
if (mKeyLength <= 15) {
// A short key; Use a dense sampling to compute the hash code
for (i = 0; i < mKeyLength; i++)
h += 37 * mOpaqueKey[i];
} else {
// A long key; Use a sparse sampling to compute the hash code
k = mKeyLength >> 3;
for (i = 0; i < mKeyLength; i += k)
h += 39 * mOpaqueKey[i];
}
return h;
}
PRBool
nsOpaqueKey::Equals(const nsHashKey* aKey) const
{
nsOpaqueKey *otherKey = (nsOpaqueKey*)aKey;
if (mKeyLength != otherKey->mKeyLength)
return PR_FALSE;
return !(PRBool)memcmp(otherKey->mOpaqueKey, mOpaqueKey, mKeyLength);
}
nsHashKey*
nsOpaqueKey::Clone() const
{
return new nsOpaqueKey(mOpaqueKey, mKeyLength);
}
PRUint32
nsOpaqueKey::GetKeyLength() const
{
return mKeyLength;
}
const char*
nsOpaqueKey::GetKey() const
{
return mOpaqueKey;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,248 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsHashtable_h__
#define nsHashtable_h__
#include "plhash.h"
#include "prlock.h"
#include "nsCom.h"
class NS_COM nsHashKey {
protected:
nsHashKey(void);
public:
virtual ~nsHashKey(void);
virtual PRUint32 HashValue(void) const = 0;
virtual PRBool Equals(const nsHashKey *aKey) const = 0;
virtual nsHashKey *Clone(void) const = 0;
};
// Enumerator callback function. Use
typedef PRBool (*nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* closure);
class NS_COM nsHashtable {
protected:
// members
PLHashTable *hashtable;
PRLock *mLock;
public:
nsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
~nsHashtable();
PRInt32 Count(void) { return hashtable->nentries; }
PRBool Exists(nsHashKey *aKey);
void *Put(nsHashKey *aKey, void *aData);
void *Get(nsHashKey *aKey);
void *Remove(nsHashKey *aKey);
nsHashtable *Clone();
void Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure = NULL);
void Reset();
void Reset(nsHashtableEnumFunc destroyFunc, void* closure = NULL);
};
////////////////////////////////////////////////////////////////////////////////
// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
// deleted
typedef void* (*nsHashtableCloneElementFunc)(nsHashKey *aKey, void *aData, void* closure);
class NS_COM nsObjectHashtable : public nsHashtable {
public:
nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
void* cloneElementClosure,
nsHashtableEnumFunc destroyElementFun,
void* destroyElementClosure,
PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
~nsObjectHashtable();
nsHashtable *Clone();
void Reset();
PRBool RemoveAndDelete(nsHashKey *aKey);
protected:
static PR_CALLBACK PRIntn CopyElement(PLHashEntry *he, PRIntn i, void *arg);
nsHashtableCloneElementFunc mCloneElementFun;
void* mCloneElementClosure;
nsHashtableEnumFunc mDestroyElementFun;
void* mDestroyElementClosure;
};
////////////////////////////////////////////////////////////////////////////////
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
class NS_COM nsSupportsHashtable : public nsHashtable {
public:
nsSupportsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE)
: nsHashtable(aSize, threadSafe) {}
~nsSupportsHashtable();
void *Put(nsHashKey *aKey, void *aData);
void *Get(nsHashKey *aKey);
void *Remove(nsHashKey *aKey);
nsHashtable *Clone();
void Reset();
};
////////////////////////////////////////////////////////////////////////////////
// nsISupportsKey: Where keys are nsISupports objects that get refcounted.
#include "nsISupports.h"
class nsISupportsKey : public nsHashKey {
protected:
nsISupports* mKey;
public:
nsISupportsKey(nsISupports* key) {
mKey = key;
NS_IF_ADDREF(mKey);
}
~nsISupportsKey(void) {
NS_IF_RELEASE(mKey);
}
PRUint32 HashValue(void) const {
return (PRUint32)mKey;
}
PRBool Equals(const nsHashKey *aKey) const {
return (mKey == ((nsISupportsKey *) aKey)->mKey);
}
nsHashKey *Clone(void) const {
return new nsISupportsKey(mKey);
}
};
////////////////////////////////////////////////////////////////////////////////
// nsVoidKey: Where keys are void* objects that don't get refcounted.
class nsVoidKey : public nsHashKey {
protected:
const void* mKey;
public:
nsVoidKey(const void* key) {
mKey = key;
}
PRUint32 HashValue(void) const {
return (PRUint32)mKey;
}
PRBool Equals(const nsHashKey *aKey) const {
return (mKey == ((const nsVoidKey *) aKey)->mKey);
}
nsHashKey *Clone(void) const {
return new nsVoidKey(mKey);
}
};
////////////////////////////////////////////////////////////////////////////////
// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID).
#include "nsID.h"
class nsIDKey : public nsHashKey {
protected:
nsID mID;
public:
nsIDKey(const nsID &aID) {
mID = aID;
}
PRUint32 HashValue(void) const {
return mID.m0;
}
PRBool Equals(const nsHashKey *aKey) const {
return (mID.Equals(((const nsIDKey *) aKey)->mID));
}
nsHashKey *Clone(void) const {
return new nsIDKey(mID);
}
};
////////////////////////////////////////////////////////////////////////////////
// nsStringKey: Where keys are PRUnichar* or char*
// Some uses: hashing ProgIDs, filenames, URIs
#include "nsString.h"
class NS_COM nsStringKey : public nsHashKey {
protected:
nsAutoString mStr;
public:
nsStringKey(const char* str);
nsStringKey(const PRUnichar* str);
nsStringKey(const nsStr& str);
~nsStringKey(void);
PRUint32 HashValue(void) const;
PRBool Equals(const nsHashKey* aKey) const;
nsHashKey* Clone() const;
// For when the owner of the hashtable wants to peek at the actual
// string in the key. No copy is made, so be careful.
const nsString& GetString() const;
};
////////////////////////////////////////////////////////////////////////////////
// nsOpaqueKey: Where keys are opaque byte-array blobs
#include "nsString.h"
class NS_COM nsOpaqueKey : public nsHashKey {
protected:
const char* mOpaqueKey; // Byte array of opaque data
PRUint32 mKeyLength; // Length, in bytes, of mOpaqueKey
public:
// Note opaque keys are not copied by this constructor. If you want a private
// copy in each hash key, you must create one and pass it in to this function.
nsOpaqueKey(const char* aOpaqueKey, PRUint32 aKeyLength);
~nsOpaqueKey(void);
PRUint32 HashValue(void) const;
PRBool Equals(const nsHashKey* aKey) const;
nsHashKey* Clone() const;
// For when the owner of the hashtable wants to peek at the actual
// opaque array in the key. No copy is made, so be careful.
const char* GetKey() const;
PRUint32 GetKeyLength() const;
};
#endif

View File

@@ -0,0 +1,247 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
* Implementation of nsHashEnumerator.
* Use it to expose nsIEnumerator interfaces around nsHashtable objects.
* Contributed by Rob Ginda, rginda@ix.netcom.com
*/
#include "nscore.h"
#include "nsHashtableEnumerator.h"
class nsHashtableEnumerator : public nsIBidirectionalEnumerator
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIENUMERATOR
NS_DECL_NSIBIDIRECTIONALENUMERATOR
public:
virtual ~nsHashtableEnumerator ();
nsHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData);
nsHashtableEnumerator (); /* no implementation */
private:
NS_IMETHOD Reset(nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData);
NS_IMETHOD ReleaseElements();
nsISupports **mElements;
PRInt16 mCount, mCurrent;
PRBool mDoneFlag;
};
struct nsHashEnumClosure
{
NS_HASH_ENUMERATOR_CONVERTER Converter;
nsISupports **Elements;
PRInt16 Current;
void *Data;
};
extern "C" NS_COM nsresult
NS_NewHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData, nsIEnumerator **retval)
{
NS_PRECONDITION (retval, "null ptr");
*retval = nsnull;
nsHashtableEnumerator *hte = new nsHashtableEnumerator (aHash, aConverter,
aData);
if (!hte)
return NS_ERROR_OUT_OF_MEMORY;
return hte->QueryInterface (nsCOMTypeInfo<nsIEnumerator>::GetIID(),
(void **)retval);
}
nsHashtableEnumerator::nsHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData)
: mElements(nsnull), mCount(0), mDoneFlag(PR_TRUE)
{
NS_INIT_REFCNT();
Reset (aHash, aConverter, aData);
}
PRBool
hash_enumerator (nsHashKey *aKey, void *aObject, void *closure)
{
nsresult rv;
nsHashEnumClosure *c = (nsHashEnumClosure *)closure;
rv = c->Converter (aKey, (void *)aObject, (void *)c->Data,
&c->Elements[c->Current]);
if (!NS_FAILED(rv))
c->Current++;
return PR_TRUE;
}
NS_IMETHODIMP
nsHashtableEnumerator::Reset (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData)
{
nsHashEnumClosure c;
ReleaseElements();
mCurrent = c.Current = 0;
mCount = aHash->Count();
if (mCount == 0)
return NS_ERROR_FAILURE;
mElements = c.Elements = new nsISupports*[mCount];
c.Data = aData;
c.Converter = aConverter;
aHash->Enumerate (&hash_enumerator, &c);
mCount = c.Current; /* some items may not have converted correctly */
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::ReleaseElements()
{
for (; mCount > 0; mCount--)
if (mElements[mCount - 1])
NS_RELEASE(mElements[mCount - 1]);
delete[] mElements;
mElements = nsnull;
return NS_OK;
}
NS_IMPL_ISUPPORTS2(nsHashtableEnumerator, nsIBidirectionalEnumerator, nsIEnumerator)
nsHashtableEnumerator::~nsHashtableEnumerator()
{
ReleaseElements();
}
NS_IMETHODIMP
nsHashtableEnumerator::First ()
{
if (!mElements || (mCount == 0))
return NS_ERROR_FAILURE;
mCurrent = 0;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::Last ()
{
if (!mElements || (mCount == 0))
return NS_ERROR_FAILURE;
mCurrent = mCount - 1;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::Prev ()
{
if (!mElements || (mCount == 0) || (mCurrent == 0)) {
mDoneFlag = PR_TRUE;
return NS_ERROR_FAILURE;
}
mCurrent--;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::Next ()
{
if (!mElements || (mCount == 0) || (mCurrent == mCount - 1)) {
mDoneFlag = PR_TRUE;
return NS_ERROR_FAILURE;
}
mCurrent++;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::CurrentItem (nsISupports **retval)
{
NS_PRECONDITION (retval, "null ptr");
NS_PRECONDITION (mElements, "invalid state");
NS_ASSERTION (mCurrent >= 0, "mCurrent less than zero");
if (mCount == 0)
{
*retval = nsnull;
return NS_ERROR_FAILURE;
}
NS_ASSERTION (mCurrent <= mCount - 1, "mCurrent too high");
*retval = mElements[mCurrent];
/* who says the item can't be null? */
if (*retval)
NS_ADDREF(*retval);
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::IsDone ()
{
if ((!mElements) || (mCount == 0) || (mDoneFlag))
return NS_OK;
return NS_COMFALSE;
}

View File

@@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
* This class can be used to expose nsI(BiDirectional)Enumerator interfaces
* around nsHashtable objects.
* Contributed by Rob Ginda, rginda@ix.netcom.com
*/
#ifndef nsHashtableEnumerator_h___
#define nsHashtableEnumerator_h___
#include "nscore.h"
#include "nsIEnumerator.h"
#include "nsHashtable.h"
typedef NS_CALLBACK(NS_HASH_ENUMERATOR_CONVERTER) (nsHashKey *key, void *data,
void *convert_data,
nsISupports **retval);
extern "C" NS_COM nsresult
NS_NewHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData, nsIEnumerator **retval);
#endif /* nsHashtableEnumerator_h___ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,170 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsIGenericFactory_h___
#define nsIGenericFactory_h___
#include "nsIFactory.h"
// {3bc97f01-ccdf-11d2-bab8-b548654461fc}
#define NS_GENERICFACTORY_CID \
{ 0x3bc97f01, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
// {3bc97f00-ccdf-11d2-bab8-b548654461fc}
#define NS_IGENERICFACTORY_IID \
{ 0x3bc97f00, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
#define NS_GENERICFACTORY_PROGID "component:/netscape/generic-factory"
#define NS_GENERICFACTORY_CLASSNAME "Generic Factory"
/**
* Provides a Generic nsIFactory implementation that can be used by
* DLLs with very simple factory needs.
*/
class nsIGenericFactory : public nsIFactory {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }
typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);
typedef NS_CALLBACK(DestructorProcPtr) (void);
/**
* Establishes the generic factory's constructor function, which will be called
* by CreateInstance.
*/
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
/**
* Establishes the generic factory's destructor function, which will be called
* whe the generic factory is deleted. This is used to notify the DLL that
* an instance of one of its generic factories is going away.
*/
NS_IMETHOD SetDestructor(DestructorProcPtr destructor) = 0;
};
extern NS_COM nsresult
NS_NewGenericFactory(nsIGenericFactory* *result,
nsIGenericFactory::ConstructorProcPtr constructor,
nsIGenericFactory::DestructorProcPtr destructor = NULL);
////////////////////////////////////////////////////////////////////////////////
// Generic Modules
//
// (See xpcom/sample/nsSampleModule.cpp to see how to use this.)
#include "nsIModule.h"
/**
* Use this type to define a list of module component info to pass to
* NS_NewGenericModule. E.g.:
* static nsModuleComponentInfo components[] = { ... };
* See xpcom/sample/nsSampleModule.cpp for more info.
*/
struct nsModuleComponentInfo {
const char* mDescription;
nsCID mCID;
const char* mProgID;
nsIGenericFactory::ConstructorProcPtr mConstructor;
};
extern NS_COM nsresult
NS_NewGenericModule(const char* moduleName,
PRUint32 componentCount,
nsModuleComponentInfo* components,
nsIModule* *result);
#define NS_IMPL_NSGETMODULE(_name, _components) \
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, \
nsIFileSpec* location, \
nsIModule** result) \
{ \
return NS_NewGenericModule((_name), \
sizeof(_components) / sizeof(_components[0]), \
(_components), result); \
}
////////////////////////////////////////////////////////////////////////////////
#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
static NS_IMETHODIMP \
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
{ \
nsresult rv; \
\
_InstanceClass * inst; \
\
if (NULL == aResult) { \
rv = NS_ERROR_NULL_POINTER; \
return rv; \
} \
*aResult = NULL; \
if (NULL != aOuter) { \
rv = NS_ERROR_NO_AGGREGATION; \
return rv; \
} \
\
NS_NEWXPCOM(inst, _InstanceClass); \
if (NULL == inst) { \
rv = NS_ERROR_OUT_OF_MEMORY; \
return rv; \
} \
NS_ADDREF(inst); \
rv = inst->QueryInterface(aIID, aResult); \
NS_RELEASE(inst); \
\
return rv; \
} \
#define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \
static NS_IMETHODIMP \
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
{ \
nsresult rv; \
\
_InstanceClass * inst; \
\
if (NULL == aResult) { \
rv = NS_ERROR_NULL_POINTER; \
return rv; \
} \
*aResult = NULL; \
if (NULL != aOuter) { \
rv = NS_ERROR_NO_AGGREGATION; \
return rv; \
} \
\
NS_NEWXPCOM(inst, _InstanceClass); \
if (NULL == inst) { \
rv = NS_ERROR_OUT_OF_MEMORY; \
return rv; \
} \
NS_ADDREF(inst); \
rv = inst->_InitMethod(); \
if(NS_SUCCEEDED(rv)) { \
rv = inst->QueryInterface(aIID, aResult); \
} \
NS_RELEASE(inst); \
\
return rv; \
} \
#endif /* nsIGenericFactory_h___ */

View File

@@ -0,0 +1,84 @@
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = xpcom
XPIDL_MODULE = xpcom_io
LIBRARY_NAME = xpcomio_s
REQUIRES = xpcom uconv unicharutil
CPPSRCS = \
nsEscape.cpp \
nsFileSpec.cpp \
nsFileSpecStreaming.cpp \
nsFileStream.cpp \
nsFileSpecImpl.cpp \
nsIFileStream.cpp \
nsIStringStream.cpp \
nsSegmentedBuffer.cpp \
nsPipe2.cpp \
nsSpecialSystemDirectory.cpp \
nsUnicharInputStream.cpp \
nsBinaryStream.cpp \
nsStorageStream.cpp \
$(NULL)
EXPORTS = \
nsEscape.h \
nsFileSpec.h \
nsFileSpecStreaming.h \
nsFileStream.h \
nsIFileStream.h \
nsIStringStream.h \
nsIUnicharInputStream.h \
nsSpecialSystemDirectory.h \
$(NULL)
XPIDLSRCS = \
nsIPipe.idl \
nsIFileSpec.idl \
nsIBaseStream.idl \
nsIInputStream.idl \
nsIOutputStream.idl \
nsIBufferInputStream.idl \
nsIBufferOutputStream.idl \
nsIBinaryInputStream.idl \
nsIBinaryOutputStream.idl \
nsIStorageStream.idl \
$(NULL)
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
# we don't want the shared lib, but we want to force the creation of a static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk
DEFINES += -D_IMPL_NS_COM -D_IMPL_NS_BASE
ifeq ($(OS_ARCH), Linux)
DEFINES += -D_BSD_SOURCE
endif

View File

@@ -0,0 +1,91 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=..\..
MODULE = xpcom
################################################################################
## exports
EXPORTS = \
nsEscape.h \
nsFileSpec.h \
nsFileSpecStreaming.h \
nsFileStream.h \
nsIFileStream.h \
nsIStringStream.h \
nsIUnicharInputStream.h \
nsSpecialSystemDirectory.h \
nsStorageStream.h \
$(NULL)
NO_XPT_GEN=1
XPIDL_MODULE = xpcom_io
XPIDLSRCS = \
.\nsIPipe.idl \
.\nsIFileSpec.idl \
.\nsIBaseStream.idl \
.\nsIBinaryInputStream.idl \
.\nsIBinaryOutputStream.idl \
.\nsIInputStream.idl \
.\nsIOutputStream.idl \
.\nsIBufferInputStream.idl \
.\nsIBufferOutputStream.idl \
.\nsIStorageStream.idl \
$(NULL)
################################################################################
## library
LIBRARY_NAME=xpcomio_s
LINCS = \
-I$(PUBLIC)\xpcom \
-I$(PUBLIC)\uconv \
-I$(PUBLIC)\unicharutil \
$(NULL)
LINCS = $(LINCS) -I$(PUBLIC)\raptor # until we sort out the filespec/widgets dependency
LCFLAGS = -D_IMPL_NS_COM -D_IMPL_NS_BASE -DWIN32_LEAN_AND_MEAN
CPP_OBJS = \
.\$(OBJDIR)\nsBinaryStream.obj \
.\$(OBJDIR)\nsEscape.obj \
.\$(OBJDIR)\nsFileSpec.obj \
.\$(OBJDIR)\nsFileSpecImpl.obj \
.\$(OBJDIR)\nsFileSpecStreaming.obj \
.\$(OBJDIR)\nsFileStream.obj \
.\$(OBJDIR)\nsIFileStream.obj \
.\$(OBJDIR)\nsIStringStream.obj \
.\$(OBJDIR)\nsSegmentedBuffer.obj \
.\$(OBJDIR)\nsPipe2.obj \
.\$(OBJDIR)\nsSpecialSystemDirectory.obj \
.\$(OBJDIR)\nsStorageStream.obj \
.\$(OBJDIR)\nsUnicharInputStream.obj \
$(NULL)
include <$(DEPTH)\config\rules.mak>
libs:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,361 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
/**
* This file contains implementations of the nsIBinaryInputStream and
* nsIBinaryOutputStream interfaces. Together, these interfaces allows reading
* and writing of primitive data types (integers, floating-point values,
* booleans, etc.) to a stream in a binary, untagged, fixed-endianness format.
* This might be used, for example, to implement network protocols or to
* produce architecture-neutral binary disk files, i.e. ones that can be read
* and written by both big-endian and little-endian platforms. Output is
* written in big-endian order (high-order byte first), as this is traditional
* network order.
*
* @See nsIBinaryInputStream
* @See nsIBinaryOutputStream
*/
#include "nsBinaryStream.h"
#include "nsIAllocator.h"
// Swap macros, used to convert to/from canonical (big-endian) format
#ifdef IS_LITTLE_ENDIAN
# define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
# define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16)))
#else
# ifndef IS_BIG_ENDIAN
# error "Unknown endianness"
# endif
# define SWAP16(x) (x)
# define SWAP32(x) (x)
#endif
nsBinaryOutputStream::nsBinaryOutputStream(nsIOutputStream* aStream): mOutputStream(aStream)
{
NS_INIT_REFCNT();
}
NS_IMPL_ISUPPORTS(nsBinaryOutputStream, NS_GET_IID(nsIBinaryOutputStream))
NS_IMETHODIMP
nsBinaryOutputStream::Flush() { return mOutputStream->Flush(); }
NS_IMETHODIMP
nsBinaryOutputStream::Close() { return mOutputStream->Close(); }
NS_IMETHODIMP
nsBinaryOutputStream::Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes)
{
return mOutputStream->Write(aBuf, aCount, aActualBytes);
}
NS_IMETHODIMP
nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream)
{
NS_ENSURE_ARG_POINTER(aOutputStream);
mOutputStream = aOutputStream;
return NS_OK;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteBoolean(PRBool aBoolean)
{
return Write8(aBoolean);
}
NS_IMETHODIMP
nsBinaryOutputStream::Write8(PRUint8 aByte)
{
nsresult rv;
PRUint32 bytesWritten;
rv = Write((const char*)&aByte, sizeof aByte, &bytesWritten);
if (bytesWritten != sizeof aByte)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::Write16(PRUint16 a16)
{
nsresult rv;
PRUint32 bytesWritten;
a16 = SWAP16(a16);
rv = Write((const char*)&a16, sizeof a16, &bytesWritten);
if (bytesWritten != sizeof a16)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::Write32(PRUint32 a32)
{
nsresult rv;
PRUint32 bytesWritten;
a32 = SWAP32(a32);
rv = Write((const char*)&a32, sizeof a32, &bytesWritten);
if (bytesWritten != sizeof a32)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::Write64(PRUint64 a64)
{
nsresult rv;
PRUint32* raw32 = (PRUint32*)&a64;
#ifdef IS_BIG_ENDIAN
rv = Write32(raw32[0]);
if (NS_FAILED(rv)) return rv;
return Write32(raw32[1]);
#else
rv = Write32(raw32[1]);
if (NS_FAILED(rv)) return rv;
return Write32(raw32[0]);
#endif
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteFloat(float aFloat)
{
NS_ASSERTION(sizeof(float) == sizeof (PRUint32),
"False assumption about sizeof(float)");
return Write32(*NS_REINTERPRET_CAST(PRUint32*, &aFloat));
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteDouble(double aDouble)
{
NS_ASSERTION(sizeof(double) == sizeof(PRUint64),
"False assumption about sizeof(double)");
return Write64(*NS_REINTERPRET_CAST(PRUint64*,&aDouble));
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteStringZ(const char *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteWStringZ(const PRUnichar* aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteUtf8Z(const PRUnichar* aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteBytes(const char *aString, PRUint32 aLength)
{
nsresult rv;
PRUint32 bytesWritten;
rv = Write(aString, aLength, &bytesWritten);
if (bytesWritten != aLength)
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryOutputStream::WriteString(nsString* aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsBinaryInputStream::nsBinaryInputStream(nsIInputStream* aStream): mInputStream(aStream) { NS_INIT_REFCNT(); }
NS_IMPL_ISUPPORTS(nsBinaryInputStream, NS_GET_IID(nsIBinaryInputStream))
NS_IMETHODIMP
nsBinaryInputStream::Available(PRUint32* aResult) { return mInputStream->Available(aResult); }
NS_IMETHODIMP
nsBinaryInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead)
{
return mInputStream->Read(aBuffer, aCount, aNumRead);
}
NS_IMETHODIMP
nsBinaryInputStream::Close() { return mInputStream->Close(); }
NS_IMETHODIMP
nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream)
{
NS_ENSURE_ARG_POINTER(aInputStream);
mInputStream = aInputStream;
return NS_OK;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadBoolean(PRBool* aBoolean)
{
PRUint8 byteResult;
nsresult rv = Read8(&byteResult);
*aBoolean = byteResult;
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read8(PRUint8* aByte)
{
nsresult rv;
PRUint32 bytesRead;
rv = Read((char*)aByte, sizeof(*aByte), &bytesRead);
if (bytesRead != sizeof (*aByte))
return NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read16(PRUint16* a16)
{
nsresult rv;
PRUint32 bytesRead;
rv = Read((char*)a16, sizeof *a16, &bytesRead);
if (bytesRead != sizeof *a16)
return NS_ERROR_FAILURE;
*a16 = SWAP16(*a16);
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read32(PRUint32* a32)
{
nsresult rv;
PRUint32 bytesRead;
rv = Read((char*)a32, sizeof *a32, &bytesRead);
if (bytesRead != sizeof *a32)
return NS_ERROR_FAILURE;
*a32 = SWAP32(*a32);
return rv;
}
NS_IMETHODIMP
nsBinaryInputStream::Read64(PRUint64* a64)
{
nsresult rv;
PRUint32* raw32 = (PRUint32*)a64;
#ifdef IS_BIG_ENDIAN
rv = Read32(&raw32[0]);
if (NS_FAILED(rv)) return rv;
return Read32(&raw32[1]);
#else
rv = Read32(&raw32[1]);
if (NS_FAILED(rv)) return rv;
return Read32(&raw32[0]);
#endif
}
NS_IMETHODIMP
nsBinaryInputStream::ReadFloat(float* aFloat)
{
NS_ASSERTION(sizeof(float) == sizeof (PRUint32),
"False assumption about sizeof(float)");
return Read32(NS_REINTERPRET_CAST(PRUint32*, aFloat));
}
NS_IMETHODIMP
nsBinaryInputStream::ReadDouble(double* aDouble)
{
NS_ASSERTION(sizeof(double) == sizeof(PRUint64),
"False assumption about sizeof(double)");
return Read64(NS_REINTERPRET_CAST(PRUint64*, aDouble));
}
NS_IMETHODIMP
nsBinaryInputStream::ReadStringZ(char* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadWStringZ(PRUnichar* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadUtf8Z(PRUnichar* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadBytes(char* *aString, PRUint32 aLength)
{
nsresult rv;
PRUint32 bytesRead;
char* s;
s = (char*)nsAllocator::Alloc(aLength);
if (!s)
return NS_ERROR_OUT_OF_MEMORY;
rv = Read(s, aLength, &bytesRead);
if (NS_FAILED(rv)) return rv;
if (bytesRead != aLength)
return NS_ERROR_FAILURE;
*aString = s;
return NS_OK;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadString(nsString* *aString)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_COM nsresult
NS_NewBinaryOutputStream(nsIBinaryOutputStream* *aResult, nsIOutputStream* aDestStream)
{
NS_ENSURE_ARG_POINTER(aResult);
nsIBinaryOutputStream *stream = new nsBinaryOutputStream(aDestStream);
if (!stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aResult = stream;
return NS_OK;
}
NS_COM nsresult
NS_NewBinaryInputStream(nsIBinaryInputStream* *aResult, nsIInputStream* aSrcStream)
{
NS_ENSURE_ARG_POINTER(aResult);
nsIBinaryInputStream *stream = new nsBinaryInputStream(aSrcStream);
if (!stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aResult = stream;
return NS_OK;
}

View File

@@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsIBinaryInputStream.h"
#include "nsIBinaryOutputStream.h"
#include "nsCOMPtr.h"
class nsBinaryOutputStream : public nsIBinaryOutputStream
{
public:
nsBinaryOutputStream(nsIOutputStream *aStream);
virtual ~nsBinaryOutputStream() {};
private:
// nsISupports methods
NS_DECL_ISUPPORTS
// nsIBaseStream methods
NS_DECL_NSIBASESTREAM
// nsIOutputStream methods
NS_DECL_NSIOUTPUTSTREAM
// nsIBinaryOutputStream methods
NS_DECL_NSIBINARYOUTPUTSTREAM
protected:
nsCOMPtr<nsIOutputStream> mOutputStream;
};
class nsBinaryInputStream : public nsIBinaryInputStream
{
public:
nsBinaryInputStream(nsIInputStream *aStream);
virtual ~nsBinaryInputStream() {};
private:
// nsISupports methods
NS_DECL_ISUPPORTS
// nsIBaseStream methods
NS_DECL_NSIBASESTREAM
// nsIInputStream methods
NS_DECL_NSIINPUTSTREAM
// nsIBinaryInputStream methods
NS_DECL_NSIBINARYINPUTSTREAM
protected:
nsCOMPtr<nsIInputStream> mInputStream;
};

View File

@@ -0,0 +1,806 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// First checked in on 98/11/20 by John R. McMullen in the wrong directory.
// Checked in again 98/12/04.
// Polished version 98/12/08.
//========================================================================================
//
// Classes defined:
//
// nsFilePath, nsFileURL, nsFileSpec, nsPersistentFileDescriptor
// nsDirectoryIterator. Oh, and a convenience class nsAutoCString.
//
// Q. How should I represent files at run time?
// A. Use nsFileSpec. Using char* will lose information on some platforms.
//
// Q. Then what are nsFilePath and nsFileURL for?
// A. Only when you need a char* parameter for legacy code.
//
// Q. How should I represent files in a persistent way (eg, in a disk file)?
// A. Use nsPersistentFileDescriptor. Convert to and from nsFileSpec at run time.
//
// This suite provides the following services:
//
// 1. Encapsulates all platform-specific file details, so that files can be
// described correctly without any platform #ifdefs
//
// 2. Type safety. This will fix the problems that used to occur because people
// confused file paths. They used to use const char*, which could mean three
// or four different things. Bugs were introduced as people coded, right up
// to the moment Communicator 4.5 shipped.
//
// 3. Used in conjunction with nsFileStream.h (q.v.), this supports all the power
// and readability of the ansi stream syntax.
//
// Basic example:
//
// nsFilePath myPath("/Development/iotest.txt");
//
// nsOutputFileStream testStream(nsFileSpec(myPath));
// testStream << "Hello World" << nsEndl;
//
// 4. Handy methods for manipulating file specifiers safely, e.g. MakeUnique(),
// SetLeafName(), Exists().
//
// 5. Easy cross-conversion.
//
// Examples:
//
// Initialize a URL from a string
//
// nsFileURL fileURL("file:///Development/MPW/MPW%20Shell");
//
// Initialize a Unix-style path from a URL
//
// nsFilePath filePath(fileURL);
//
// Initialize a file spec from a URL
//
// nsFileSpec fileSpec(fileURL);
//
// Make the spec unique.
//
// fileSpec.MakeUnique();
//
// Assign the spec to a URL (causing conversion)
//
// fileURL = fileSpec;
//
// Assign a unix path using a string
//
// filePath = "/Development/MPW/SysErrs.err";
//
// Assign to a file spec using a unix path (causing conversion).
//
// fileSpec = filePath;
//
// Make this unique.
//
// fileSpec.MakeUnique();
//
// 6. Fixes a bug that have been there for a long time, and
// is inevitable if you use NSPR alone, where files are described as paths.
//
// The problem affects platforms (Macintosh) in which a path does not fully
// specify a file, because two volumes can have the same name. This
// is solved by holding a "private" native file spec inside the
// nsFilePath and nsFileURL classes, which is used when appropriate.
//
//========================================================================================
#ifndef _FILESPEC_H_
#define _FILESPEC_H_
#include "nscore.h"
#include "nsError.h"
#include "nsString.h"
#include "nsCRT.h"
#include "prtypes.h"
//========================================================================================
// Compiler-specific macros, as needed
//========================================================================================
#if !defined(NS_USING_NAMESPACE) && (defined(__MWERKS__) || defined(XP_PC))
#define NS_USING_NAMESPACE
#endif
#ifdef NS_USING_NAMESPACE
#define NS_NAMESPACE_PROTOTYPE
#define NS_NAMESPACE namespace
#define NS_NAMESPACE_END
#define NS_EXPLICIT explicit
#else
#define NS_NAMESPACE_PROTOTYPE static
#define NS_NAMESPACE struct
#define NS_NAMESPACE_END ;
#define NS_EXPLICIT
#endif
//=========================== End Compiler-specific macros ===============================
#ifdef XP_MAC
#include <Files.h>
#elif defined(XP_UNIX) || defined (XP_OS2) || defined(XP_BEOS)
#include <dirent.h>
#elif defined(XP_PC)
// This clashes with some of the Win32 system headers (specifically,
// winbase.h). Hopefully they'll have been included first; else we may
// have problems. We could include winbase.h before doing this;
// unfortunately, it's bring in too much crap and'd slow stuff down
// more than it's worth doing.
#ifdef CreateDirectory
#undef CreateDirectory
#endif
#include "prio.h"
#endif
//========================================================================================
// Here are the allowable ways to describe a file.
//========================================================================================
class nsFileSpec; // Preferred. For i/o use nsInputFileStream, nsOutputFileStream
class nsFilePath;
class nsFileURL;
class nsNSPRPath; // This can be passed to NSPR file I/O routines, if you must.
class nsPersistentFileDescriptor; // Used for storage across program launches.
#define kFileURLPrefix "file://"
#define kFileURLPrefixLength (7)
class nsOutputStream;
class nsInputStream;
class nsIOutputStream;
class nsIInputStream;
class nsOutputFileStream;
class nsInputFileStream;
class nsOutputConsoleStream;
class nsString;
//========================================================================================
// Conversion of native file errors to nsresult values. These are really only for use
// in the file module, clients of this interface shouldn't really need them.
// Error results returned from this interface have, in the low-order 16 bits,
// native errors that are masked to 16 bits. Assumption: a native error of 0 is success
// on all platforms. Note the way we define this using an inline function. This
// avoids multiple evaluation if people go NS_FILE_RESULT(function_call()).
#define NS_FILE_RESULT(x) ns_file_convert_result((PRInt32)x)
nsresult ns_file_convert_result(PRInt32 nativeErr);
#define NS_FILE_FAILURE NS_FILE_RESULT(-1)
//========================================================================================
class NS_COM nsAutoCString
//
// This should be in nsString.h, but the owner would not reply to my proposal. After four
// weeks, I decided to put it in here.
//
// This is a quiet little class that acts as a sort of autoptr for
// a const char*. If you used to call nsString::ToNewCString(), just
// to pass the result a parameter list, it was a nuisance having to
// call delete [] on the result after the call. Now you can say
// nsString myStr;
// ...
// f(nsAutoCString(myStr));
// where f is declared as void f(const char*); This call will
// make a temporary char* pointer on the stack and delete[] it
// when the function returns.
//========================================================================================
{
public:
NS_EXPLICIT nsAutoCString(const nsString& other) : mCString(other.ToNewCString()) {}
virtual ~nsAutoCString();
operator const char*() const { return mCString; }
// operator const char*() { return mCString; }
// don't need this, since |operator const char*() const| can
// serve for both |const| and non-|const| callers
protected:
const char* mCString;
}; // class nsAutoCString
//========================================================================================
class NS_COM nsSimpleCharString
// An envelope for char*: reference counted. Used internally by all the nsFileSpec
// classes below.
//========================================================================================
{
public:
nsSimpleCharString();
nsSimpleCharString(const char*);
nsSimpleCharString(const nsString&);
nsSimpleCharString(const nsSimpleCharString&);
nsSimpleCharString(const char* inData, PRUint32 inLength);
~nsSimpleCharString();
void operator = (const char*);
void operator = (const nsString&);
void operator = (const nsSimpleCharString&);
operator const char*() const { return mData ? mData->mString : 0; }
operator char* ()
{
ReallocData(Length()); // requires detaching if shared...
return mData ? mData->mString : 0;
}
PRBool operator == (const char*);
PRBool operator == (const nsString&);
PRBool operator == (const nsSimpleCharString&);
void operator += (const char* inString);
nsSimpleCharString operator + (const char* inString) const;
char operator [](int i) const { return mData ? mData->mString[i] : 0; }
char& operator [](int i)
{
if (i >= (int)Length())
ReallocData((PRUint32)i + 1);
return mData->mString[i]; // caveat appelator
}
char& operator [](unsigned int i) { return (*this)[(int)i]; }
void Catenate(const char* inString1, const char* inString2);
void SetToEmpty();
PRBool IsEmpty() const { return Length() == 0; }
PRUint32 Length() const { return mData ? mData->mLength : 0; }
void SetLength(PRUint32 inLength) { ReallocData(inLength); }
void CopyFrom(const char* inData, PRUint32 inLength);
void LeafReplace(char inSeparator, const char* inLeafName);
char* GetLeaf(char inSeparator) const; // use PR_Free()
void Unescape();
protected:
void AddRefData();
void ReleaseData();
void ReallocData(PRUint32 inLength);
//--------------------------------------------------
// Data
//--------------------------------------------------
protected:
struct Data {
int mRefCount;
PRUint32 mLength;
char mString[1];
};
Data* mData;
}; // class nsSimpleCharString
//========================================================================================
class NS_COM nsFileSpec
// This is whatever each platform really prefers to describe files as. Declared first
// because the other two types have an embedded nsFileSpec object.
//========================================================================================
{
public:
nsFileSpec();
// These two meathods take *native* file paths.
NS_EXPLICIT nsFileSpec(const char* inNativePath, PRBool inCreateDirs = PR_FALSE);
NS_EXPLICIT nsFileSpec(const nsString& inNativePath, PRBool inCreateDirs = PR_FALSE);
NS_EXPLICIT nsFileSpec(const nsFilePath& inPath);
NS_EXPLICIT nsFileSpec(const nsFileURL& inURL);
NS_EXPLICIT nsFileSpec(const nsPersistentFileDescriptor& inURL);
nsFileSpec(const nsFileSpec& inPath);
virtual ~nsFileSpec();
// These two operands take *native* file paths.
void operator = (const char* inNativePath);
void operator = (const nsString& inNativePath)
{
const nsAutoCString path(inNativePath);
*this = path;
}
void operator = (const nsFilePath& inPath);
void operator = (const nsFileURL& inURL);
void operator = (const nsFileSpec& inOther);
void operator = (const nsPersistentFileDescriptor& inOther);
PRBool operator ==(const nsFileSpec& inOther) const;
PRBool operator !=(const nsFileSpec& inOther) const;
// Returns a native path, and allows the
// path to be "passed" to legacy code. This practice
// is VERY EVIL and should only be used to support legacy
// code. Using it guarantees bugs on Macintosh.
// The path is cached and freed by the nsFileSpec destructor
// so do not delete (or free) it. See also nsNSPRPath below,
// if you really must pass a string to PR_OpenFile().
// Doing so will introduce two automatic bugs.
const char* GetCString() const;
// Same as GetCString (please read the comments).
// Do not try to free this!
operator const char* () const { return GetCString(); }
// Same as GetCString (please read the comments).
// Do not try to free this!
const char* GetNativePathCString() const { return GetCString(); }
PRBool IsChildOf(nsFileSpec &possibleParent);
#ifdef XP_MAC
// For Macintosh people, this is meant to be useful in its own right as a C++ version
// of the FSSpec struct.
nsFileSpec(
short vRefNum,
long parID,
ConstStr255Param name,
PRBool resolveAlias = PR_TRUE);
nsFileSpec(const FSSpec& inSpec, PRBool resolveAlias = PR_TRUE);
void operator = (const FSSpec& inSpec);
operator FSSpec* () { return &mSpec; }
operator const FSSpec* const () { return &mSpec; }
operator FSSpec& () { return mSpec; }
operator const FSSpec& () const { return mSpec; }
const FSSpec& GetFSSpec() const { return mSpec; }
FSSpec& GetFSSpec() { return mSpec; }
ConstFSSpecPtr GetFSSpecPtr() const { return &mSpec; }
FSSpecPtr GetFSSpecPtr() { return &mSpec; }
void MakeAliasSafe();
void MakeUnique(ConstStr255Param inSuggestedLeafName);
StringPtr GetLeafPName() { return mSpec.name; }
ConstStr255Param GetLeafPName() const { return mSpec.name; }
OSErr GetCatInfo(CInfoPBRec& outInfo) const;
OSErr SetFileTypeAndCreator(OSType type, OSType creator);
OSErr GetFileTypeAndCreator(OSType* type, OSType* creator);
#endif // end of Macintosh utility methods.
PRBool Valid() const { return NS_SUCCEEDED(Error()); }
nsresult Error() const
{
#ifndef XP_MAC
if (mPath.IsEmpty() && NS_SUCCEEDED(mError))
((nsFileSpec*)this)->mError = NS_ERROR_NOT_INITIALIZED;
#endif
return mError;
}
PRBool Failed() const { return (PRBool)NS_FAILED(Error()); }
//--------------------------------------------------
// Queries and path algebra. These do not modify the disk.
//--------------------------------------------------
char* GetLeafName() const; // Allocated. Use nsCRT::free().
#if 0
// needs implementing
// copy the leaf name into the supplied buffer, thus
// getting a copy without allocation. Buffer should be
// 64 chars big.
void GetLeafNameCopy(char* destBuffer, PRInt32 bufferSize) const;
#endif
// inLeafName can be a relative path, so this allows
// one kind of concatenation of "paths".
void SetLeafName(const char* inLeafName);
void SetLeafName(const nsString& inLeafName)
{
const nsAutoCString leafName(inLeafName);
SetLeafName(leafName);
}
// Return the filespec of the parent directory. Used
// in conjunction with GetLeafName(), this lets you
// parse a path into a list of node names. Beware,
// however, that the top node is still not a name,
// but a spec. Volumes on Macintosh can have identical
// names. Perhaps could be used for an operator --() ?
void GetParent(nsFileSpec& outSpec) const;
// ie nsFileSpec::TimeStamp. This is 32 bits now,
// but might change, eg, to a 64-bit class. So use the
// typedef, and use a streaming operator to convert
// to a string, so that your code won't break. It's
// none of your business what the number means. Don't
// rely on the implementation.
typedef PRUint32 TimeStamp;
// This will return different values on different
// platforms, even for the same file (eg, on a server).
// But if the platform is constant, it will increase after
// every file modification.
void GetModDate(TimeStamp& outStamp) const;
PRBool ModDateChanged(const TimeStamp& oldStamp) const
{
TimeStamp newStamp;
GetModDate(newStamp);
return newStamp != oldStamp;
}
PRUint32 GetFileSize() const;
PRInt64 GetDiskSpaceAvailable() const;
nsFileSpec operator + (const char* inRelativeUnixPath) const;
nsFileSpec operator + (const nsString& inRelativeUnixPath) const
{
const nsAutoCString
relativePath(inRelativeUnixPath);
return *this + relativePath;
}
// Concatenate the relative path to this directory.
// Used for constructing the filespec of a descendant.
// This must be a directory for this to work. This differs
// from SetLeafName(), since the latter will work
// starting with a sibling of the directory and throws
// away its leaf information, whereas this one assumes
// this is a directory, and the relative path starts
// "below" this.
void operator += (const char* inRelativeUnixPath);
void operator += (const nsString& inRelativeUnixPath)
{
const nsAutoCString relativePath(inRelativeUnixPath);
*this += relativePath;
}
void MakeUnique();
void MakeUnique(const char* inSuggestedLeafName);
void MakeUnique(const nsString& inSuggestedLeafName)
{
const nsAutoCString suggestedLeafName(inSuggestedLeafName);
MakeUnique(suggestedLeafName);
}
PRBool IsDirectory() const; // More stringent than Exists()
PRBool IsFile() const; // More stringent than Exists()
PRBool Exists() const;
PRBool IsHidden() const;
PRBool IsSymlink() const;
//--------------------------------------------------
// Creation and deletion of objects. These can modify the disk.
//--------------------------------------------------
// Called for the spec of an alias. Modifies the spec to
// point to the original. Sets mError.
nsresult ResolveSymlink(PRBool& wasSymlink);
void CreateDirectory(int mode = 0700 /* for unix */);
void CreateDir(int mode = 0700) { CreateDirectory(mode); }
// workaround for yet another VC++ bug with long identifiers.
void Delete(PRBool inRecursive) const;
void RecursiveCopy(nsFileSpec newDir) const;
nsresult Truncate(const PRInt32 offset) const;
nsresult Rename(const char* inNewName); // not const: gets updated
nsresult Rename(const nsString& inNewName)
{
const nsAutoCString newName(inNewName);
return Rename(newName);
}
nsresult CopyToDir(const nsFileSpec& inNewParentDirectory) const;
nsresult MoveToDir(const nsFileSpec& inNewParentDirectory);
nsresult Execute(const char* args) const;
nsresult Execute(const nsString& args) const
{
const nsAutoCString argsString(args);
return Execute(argsString);
}
//--------------------------------------------------
// Data
//--------------------------------------------------
protected:
// Clear the nsFileSpec contents, resetting it
// to the uninitialized state;
void Clear();
friend class nsFilePath;
friend class nsFileURL;
friend class nsDirectoryIterator;
#ifdef XP_MAC
FSSpec mSpec;
#endif
nsSimpleCharString mPath;
nsresult mError;
}; // class nsFileSpec
// FOR HISTORICAL REASONS:
typedef nsFileSpec nsNativeFileSpec;
//========================================================================================
class NS_COM nsFileURL
// This is an escaped string that looks like "file:///foo/bar/mumble%20fish". Since URLs
// are the standard way of doing things in mozilla, this allows a string constructor,
// which just stashes the string with no conversion.
//========================================================================================
{
public:
nsFileURL(const nsFileURL& inURL);
NS_EXPLICIT nsFileURL(const char* inURLString, PRBool inCreateDirs = PR_FALSE);
NS_EXPLICIT nsFileURL(const nsString& inURLString, PRBool inCreateDirs = PR_FALSE);
NS_EXPLICIT nsFileURL(const nsFilePath& inPath);
NS_EXPLICIT nsFileURL(const nsFileSpec& inPath);
virtual ~nsFileURL();
// nsString GetString() const { return mPath; }
// may be needed for implementation reasons,
// but should not provide a conversion constructor.
void operator = (const nsFileURL& inURL);
void operator = (const char* inURLString);
void operator = (const nsString& inURLString)
{
const nsAutoCString string(inURLString);
*this = string;
}
void operator = (const nsFilePath& inOther);
void operator = (const nsFileSpec& inOther);
void operator +=(const char* inRelativeUnixPath);
nsFileURL operator +(const char* inRelativeUnixPath) const;
operator const char* () const { return (const char*)mURL; } // deprecated.
const char* GetURLString() const { return (const char*)mURL; }
// Not allocated, so don't free it.
const char* GetAsString() const { return (const char*)mURL; }
// Not allocated, so don't free it.
#ifdef XP_MAC
// Accessor to allow quick assignment to a mFileSpec
const nsFileSpec& GetFileSpec() const { return mFileSpec; }
#endif
//--------------------------------------------------
// Data
//--------------------------------------------------
protected:
friend class nsFilePath; // to allow construction of nsFilePath
nsSimpleCharString mURL;
#ifdef XP_MAC
// Since the path on the macintosh does not uniquely specify a file (volumes
// can have the same name), stash the secret nsFileSpec, too.
nsFileSpec mFileSpec;
#endif
}; // class nsFileURL
//========================================================================================
class NS_COM nsFilePath
// This is a string that looks like "/foo/bar/mumble fish". Same as nsFileURL, but
// without the "file:// prefix", and NOT %20 ENCODED! Strings passed in must be
// valid unix-style paths in this format.
//========================================================================================
{
public:
nsFilePath(const nsFilePath& inPath);
NS_EXPLICIT nsFilePath(const char* inUnixPathString, PRBool inCreateDirs = PR_FALSE);
NS_EXPLICIT nsFilePath(const nsString& inUnixPathString, PRBool inCreateDirs = PR_FALSE);
NS_EXPLICIT nsFilePath(const nsFileURL& inURL);
NS_EXPLICIT nsFilePath(const nsFileSpec& inPath);
virtual ~nsFilePath();
operator const char* () const { return mPath; }
// This will return a UNIX string. If you
// need a string that can be passed into
// NSPR, take a look at the nsNSPRPath class.
void operator = (const nsFilePath& inPath);
void operator = (const char* inUnixPathString);
void operator = (const nsString& inUnixPathString)
{
const nsAutoCString string(inUnixPathString);
*this = string;
}
void operator = (const nsFileURL& inURL);
void operator = (const nsFileSpec& inOther);
void operator +=(const char* inRelativeUnixPath);
nsFilePath operator +(const char* inRelativeUnixPath) const;
#ifdef XP_MAC
public:
// Accessor to allow quick assignment to a mFileSpec
const nsFileSpec& GetFileSpec() const { return mFileSpec; }
#endif
//--------------------------------------------------
// Data
//--------------------------------------------------
private:
nsSimpleCharString mPath;
#ifdef XP_MAC
// Since the path on the macintosh does not uniquely specify a file (volumes
// can have the same name), stash the secret nsFileSpec, too.
nsFileSpec mFileSpec;
#endif
}; // class nsFilePath
//========================================================================================
class NS_COM nsPersistentFileDescriptor
// To save information about a file's location in another file, initialize
// one of these from your nsFileSpec, and then write this out to your output stream.
// To retrieve the info, create one of these, read its value from an input stream.
// and then make an nsFileSpec from it.
//========================================================================================
{
public:
nsPersistentFileDescriptor() {}
// For use prior to reading in from a stream
nsPersistentFileDescriptor(const nsPersistentFileDescriptor& inEncodedData);
virtual ~nsPersistentFileDescriptor();
void operator = (const nsPersistentFileDescriptor& inEncodedData);
// Conversions
NS_EXPLICIT nsPersistentFileDescriptor(const nsFileSpec& inSpec);
void operator = (const nsFileSpec& inSpec);
// The following four functions are declared here (as friends). Their implementations
// are in mozilla/base/src/nsFileSpecStreaming.cpp.
friend nsresult Read(nsIInputStream* aStream, nsPersistentFileDescriptor&);
friend nsresult Write(nsIOutputStream* aStream, const nsPersistentFileDescriptor&);
// writes the data to a file
friend NS_COM nsInputStream& operator >> (nsInputStream&, nsPersistentFileDescriptor&);
// reads the data from a file
friend NS_COM nsOutputStream& operator << (nsOutputStream&, const nsPersistentFileDescriptor&);
// writes the data to a file
friend class nsFileSpec;
void GetData(nsSimpleCharString& outData) const;
void SetData(const nsSimpleCharString& inData);
void GetData(nsSimpleCharString& outData, PRInt32& outSize) const;
void SetData(const nsSimpleCharString& inData, PRInt32 inSize);
void SetData(const char* inData, PRInt32 inSize);
//--------------------------------------------------
// Data
//--------------------------------------------------
protected:
nsSimpleCharString mDescriptorString;
}; // class nsPersistentFileDescriptor
//========================================================================================
class NS_COM nsDirectoryIterator
// Example:
//
// nsFileSpec parentDir(...); // directory over whose children we shall iterate
// for (nsDirectoryIterator i(parentDir, PR_FALSE); i.Exists(); i++)
// {
// // do something with i.Spec()
// }
//
// - or -
//
// for (nsDirectoryIterator i(parentDir, PR_TRUE); i.Exists(); i--)
// {
// // do something with i.Spec()
// }
// This one passed the PR_TRUE flag which will resolve any symlink encountered.
//========================================================================================
{
public:
nsDirectoryIterator( const nsFileSpec& parent,
PRBool resoveSymLinks);
#ifndef XP_MAC
// Macintosh currently doesn't allocate, so needn't clean up.
virtual ~nsDirectoryIterator();
#endif
PRBool Exists() const { return mExists; }
nsDirectoryIterator& operator ++(); // moves to the next item, if any.
nsDirectoryIterator& operator ++(int) { return ++(*this); } // post-increment.
nsDirectoryIterator& operator --(); // moves to the previous item, if any.
nsDirectoryIterator& operator --(int) { return --(*this); } // post-decrement.
operator nsFileSpec&() { return mCurrent; }
nsFileSpec& Spec() { return mCurrent; }
private:
#if defined(XP_MAC)
OSErr SetToIndex();
#endif
//--------------------------------------------------
// Data
//--------------------------------------------------
private:
nsFileSpec mCurrent;
PRBool mExists;
PRBool mResoveSymLinks;
#if defined(XP_UNIX) || defined(XP_BEOS) || defined (XP_PC)
nsFileSpec mStarting;
#endif
#if defined(XP_UNIX) || defined(XP_BEOS)
DIR* mDir;
#elif defined(XP_PC)
PRDir* mDir; // XXX why not use PRDir for Unix too?
#elif defined(XP_MAC)
short mVRefNum;
long mParID;
short mIndex;
short mMaxIndex;
#endif
}; // class nsDirectoryIterator
//========================================================================================
class NS_COM nsNSPRPath
// This class will allow you to pass any one of the nsFile* classes directly into NSPR
// without the need to worry about whether you have the right kind of filepath or not.
// It will also take care of cleaning up any allocated memory.
//========================================================================================
{
public:
NS_EXPLICIT nsNSPRPath(const nsFileSpec& inSpec)
: mFilePath(inSpec), modifiedNSPRPath(nsnull) {}
NS_EXPLICIT nsNSPRPath(const nsFileURL& inURL)
: mFilePath(inURL), modifiedNSPRPath(nsnull) {}
NS_EXPLICIT nsNSPRPath(const nsFilePath& inUnixPath)
: mFilePath(inUnixPath), modifiedNSPRPath(nsnull) {}
virtual ~nsNSPRPath();
operator const char*() const;
// Returns the path
// that NSPR file routines expect on each platform.
// Concerning constness, this can modify
// modifiedNSPRPath, but it's really just "mutable".
//--------------------------------------------------
// Data
//--------------------------------------------------
private:
nsFilePath mFilePath;
char* modifiedNSPRPath; // Currently used only on XP_PC
}; // class nsNSPRPath
#endif // _FILESPEC_H_

View File

@@ -0,0 +1,781 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsFileSpecImpl.h"// Always first, to ensure that it compiles alone.
#include "nsIFileStream.h"
#include "nsFileStream.h"
#include "prmem.h"
NS_IMPL_ISUPPORTS1(nsFileSpecImpl, nsIFileSpec)
#ifdef NS_DEBUG
#define TEST_OUT_PTR(p) \
if (!(p)) \
return NS_ERROR_NULL_POINTER;
#else
#define TEST_OUT_PTR(p)
#endif
//----------------------------------------------------------------------------------------
nsFileSpecImpl::nsFileSpecImpl()
//----------------------------------------------------------------------------------------
: mInputStream(nsnull)
, mOutputStream(nsnull)
{
NS_INIT_ISUPPORTS();
}
//----------------------------------------------------------------------------------------
nsFileSpecImpl::nsFileSpecImpl(const nsFileSpec& inSpec)
//----------------------------------------------------------------------------------------
: mFileSpec(inSpec)
, mInputStream(nsnull)
, mOutputStream(nsnull)
{
NS_INIT_ISUPPORTS();
}
//----------------------------------------------------------------------------------------
nsFileSpecImpl::~nsFileSpecImpl()
//----------------------------------------------------------------------------------------
{
CloseStream();
}
//----------------------------------------------------------------------------------------
/* static */
nsresult nsFileSpecImpl::MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** result)
//----------------------------------------------------------------------------------------
{
nsFileSpecImpl* it = new nsFileSpecImpl(inSpec);
if (!it)
return NS_ERROR_OUT_OF_MEMORY;
return it->QueryInterface(nsIFileSpec::GetIID(), (void **) result);
} // nsFileSpecImpl::MakeInterface
#define FILESPEC(ifilespec) ((nsFileSpecImpl*)ifilespec)->mFileSpec
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::FromFileSpec(const nsIFileSpec *original)
//----------------------------------------------------------------------------------------
{
mFileSpec = FILESPEC(original);
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::IsChildOf(nsIFileSpec *possibleParent,
PRBool *_retval)
{
*_retval = mFileSpec.IsChildOf(FILESPEC(possibleParent));
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetURLString(char * *aURLString)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aURLString)
if (mFileSpec.Failed())
return mFileSpec.Error();
nsFileURL url(mFileSpec);
*aURLString = nsCRT::strdup(url.GetURLString());
if (!*aURLString)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
} // nsFileSpecImpl::GetURLString
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::SetURLString(const char * aURLString)
//----------------------------------------------------------------------------------------
{
mFileSpec = nsFileURL(aURLString);
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetUnixStyleFilePath(char * *aUnixStyleFilePath)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aUnixStyleFilePath)
if (mFileSpec.Failed())
return mFileSpec.Error();
nsFilePath path(mFileSpec);
*aUnixStyleFilePath = nsCRT::strdup((const char*) path);
if (!*aUnixStyleFilePath)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::SetUnixStyleFilePath(const char * aUnixStyleFilePath)
//----------------------------------------------------------------------------------------
{
mFileSpec = nsFilePath(aUnixStyleFilePath);
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetPersistentDescriptorString(char * *aPersistentDescriptorString)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aPersistentDescriptorString)
if (mFileSpec.Failed())
return mFileSpec.Error();
nsPersistentFileDescriptor desc(mFileSpec);
nsSimpleCharString data;
desc.GetData(data);
*aPersistentDescriptorString = nsCRT::strdup((const char*) data);
if (!*aPersistentDescriptorString)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::SetPersistentDescriptorString(const char * aPersistentDescriptorString)
//----------------------------------------------------------------------------------------
{
nsPersistentFileDescriptor desc(mFileSpec);
desc.SetData(aPersistentDescriptorString);
mFileSpec = desc;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetNativePath(char * *aNativePath)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aNativePath)
if (mFileSpec.Failed())
return mFileSpec.Error();
*aNativePath = nsCRT::strdup(mFileSpec.GetNativePathCString());
if (!*aNativePath)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::SetNativePath(const char * aNativePath)
//----------------------------------------------------------------------------------------
{
mFileSpec = aNativePath;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetNSPRPath(char * *aNSPRPath)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aNSPRPath)
if (mFileSpec.Failed())
return mFileSpec.Error();
nsNSPRPath path(mFileSpec);
*aNSPRPath = nsCRT::strdup((const char*) path);
if (!*aNSPRPath)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Error()
//----------------------------------------------------------------------------------------
{
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::IsValid(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = mFileSpec.Valid();
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Failed(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
*_retval = mFileSpec.Failed();
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetLeafName(char * *aLeafName)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aLeafName)
*aLeafName = mFileSpec.GetLeafName();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::SetLeafName(const char * aLeafName)
//----------------------------------------------------------------------------------------
{
mFileSpec.SetLeafName(aLeafName);
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetParent(nsIFileSpec * *aParent)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aParent)
nsFileSpec parent;
mFileSpec.GetParent(parent);
return MakeInterface(parent, aParent);
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::MakeUnique()
//----------------------------------------------------------------------------------------
{
mFileSpec.MakeUnique();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::MakeUniqueWithSuggestedName(const char *suggestedName)
//----------------------------------------------------------------------------------------
{
mFileSpec.MakeUnique(suggestedName);
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetModDate(PRUint32 *aModDate)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aModDate)
nsFileSpec::TimeStamp stamp;
mFileSpec.GetModDate(stamp);
*aModDate = stamp;
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::ModDateChanged(PRUint32 oldStamp, PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = mFileSpec.ModDateChanged(oldStamp);
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::IsDirectory(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = mFileSpec.IsDirectory();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::IsFile(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = mFileSpec.IsFile();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Exists(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = mFileSpec.Exists();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::IsHidden(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = mFileSpec.IsHidden();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::IsSymlink(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = mFileSpec.IsSymlink();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::ResolveSymlink()
//----------------------------------------------------------------------------------------
{
PRBool ignore;
return mFileSpec.ResolveSymlink(ignore);
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetFileSize(PRUint32 *aFileSize)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aFileSize)
*aFileSize = mFileSpec.GetFileSize();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aDiskSpaceAvailable)
*aDiskSpaceAvailable = mFileSpec.GetDiskSpaceAvailable();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::AppendRelativeUnixPath(const char *relativePath)
//----------------------------------------------------------------------------------------
{
mFileSpec += relativePath;
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Touch()
//----------------------------------------------------------------------------------------
{
// create an empty file, like the UNIX touch command.
nsresult rv;
rv = OpenStreamForReadingAndWriting();
if (NS_FAILED(rv)) return rv;
rv = CloseStream();
return rv;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::CreateDir()
//----------------------------------------------------------------------------------------
{
mFileSpec.CreateDir();
return mFileSpec.Error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Truncate(const PRInt32 offset)
//----------------------------------------------------------------------------------------
{
return mFileSpec.Truncate(offset);
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Rename(const char *newLeafName)
//----------------------------------------------------------------------------------------
{
return mFileSpec.Rename(newLeafName);
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::CopyToDir(const nsIFileSpec *newParentDir)
//----------------------------------------------------------------------------------------
{
return mFileSpec.CopyToDir(FILESPEC(newParentDir));
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::MoveToDir(const nsIFileSpec *newParentDir)
//----------------------------------------------------------------------------------------
{
return mFileSpec.MoveToDir(FILESPEC(newParentDir));
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Execute(const char *args)
//----------------------------------------------------------------------------------------
{
return mFileSpec.Execute(args);
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReading()
//----------------------------------------------------------------------------------------
{
if (mInputStream || mOutputStream)
return NS_ERROR_FAILURE;
return NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec);
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::OpenStreamForWriting()
//----------------------------------------------------------------------------------------
{
if (mInputStream || mOutputStream)
return NS_ERROR_FAILURE;
return NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec);
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReadingAndWriting()
//----------------------------------------------------------------------------------------
{
if (mInputStream || mOutputStream)
return NS_ERROR_FAILURE;
nsresult result = NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec);
if (NS_SUCCEEDED(result))
result = NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec);
return result;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::CloseStream()
//----------------------------------------------------------------------------------------
{
NS_IF_RELEASE(mInputStream);
NS_IF_RELEASE(mOutputStream);
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::IsStreamOpen(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = (mInputStream || mOutputStream);
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetInputStream(nsIInputStream** _retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
if (!mInputStream) {
nsresult rv = OpenStreamForReading();
if (NS_FAILED(rv)) return rv;
}
*_retval = mInputStream;
NS_IF_ADDREF(mInputStream);
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetOutputStream(nsIOutputStream** _retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
if (!mOutputStream) {
nsresult rv = OpenStreamForWriting();
if (NS_FAILED(rv)) return rv;
}
*_retval = mOutputStream;
NS_IF_ADDREF(mOutputStream);
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::SetFileContents(const char* inString)
//----------------------------------------------------------------------------------------
{
nsresult rv = OpenStreamForWriting();
if (NS_FAILED(rv)) return rv;
PRInt32 count;
rv = Write(inString, PL_strlen(inString), &count);
nsresult rv2 = CloseStream();
return NS_FAILED(rv) ? rv : rv2;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetFileContents(char** _retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
*_retval = nsnull;
nsresult rv = OpenStreamForReading();
if (NS_FAILED(rv)) return rv;
PRInt32 theSize;
rv = GetFileSize((PRUint32*)&theSize);
if (NS_SUCCEEDED(rv))
rv = Read(_retval, theSize, &theSize);
if (NS_SUCCEEDED(rv))
(*_retval)[theSize] = 0;
nsresult rv2 = CloseStream();
return NS_FAILED(rv) ? rv : rv2;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::GetFileSpec(nsFileSpec *aFileSpec)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(aFileSpec)
*aFileSpec = mFileSpec;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::SetFromFileSpec(const nsFileSpec& aFileSpec)
//----------------------------------------------------------------------------------------
{
mFileSpec = aFileSpec;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Eof(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
if (!mInputStream)
return NS_ERROR_NULL_POINTER;
nsInputFileStream s(mInputStream);
*_retval = s.eof();
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Read(char** buffer, PRInt32 requestedCount, PRInt32 *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
TEST_OUT_PTR(buffer)
if (!mInputStream) {
nsresult rv = OpenStreamForReading();
if (NS_FAILED(rv)) return rv;
}
if (!*buffer)
*buffer = (char*)PR_Malloc(requestedCount + 1);
if (!mInputStream)
return NS_ERROR_NULL_POINTER;
nsInputFileStream s(mInputStream);
*_retval = s.read(*buffer, requestedCount);
return s.error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::ReadLine(char** line, PRInt32 bufferSize, PRBool *wasTruncated)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(wasTruncated)
TEST_OUT_PTR(line)
if (!mInputStream) {
nsresult rv = OpenStreamForReading();
if (NS_FAILED(rv)) return rv;
}
if (!*line)
*line = (char*)PR_Malloc(bufferSize + 1);
if (!mInputStream)
return NS_ERROR_NULL_POINTER;
nsInputFileStream s(mInputStream);
*wasTruncated = !s.readline(*line, bufferSize);
return s.error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Write(const char * data, PRInt32 requestedCount, PRInt32 *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
//if (!mOutputStream)
// return NS_ERROR_NULL_POINTER;
if (!mOutputStream) {
nsresult rv = OpenStreamForWriting();
if (NS_FAILED(rv))
return rv;
}
nsOutputFileStream s(mOutputStream);
*_retval = s.write(data, requestedCount);
return s.error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Flush()
//----------------------------------------------------------------------------------------
{
if (!mOutputStream)
return NS_ERROR_NULL_POINTER;
nsOutputFileStream s(mOutputStream);
s.flush();
return s.error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Seek(PRInt32 offset)
//----------------------------------------------------------------------------------------
{
nsresult result = NS_OK;
if (mOutputStream)
{
nsOutputFileStream os(mOutputStream);
os.seek(offset);
result = os.error();
}
if (NS_SUCCEEDED(result) && mInputStream)
{
nsInputFileStream is(mInputStream);
is.seek(offset);
result = is.error();
}
return result;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::Tell(PRInt32 *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
if (!mInputStream)
return NS_ERROR_NULL_POINTER;
nsInputFileStream s(mInputStream);
*_retval = s.tell();
return s.error();
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecImpl::EndLine()
//----------------------------------------------------------------------------------------
{
nsOutputFileStream s(mOutputStream);
s << nsEndl;
return s.error();
}
NS_IMPL_ISUPPORTS1(nsDirectoryIteratorImpl, nsIDirectoryIterator)
//----------------------------------------------------------------------------------------
nsDirectoryIteratorImpl::nsDirectoryIteratorImpl()
//----------------------------------------------------------------------------------------
: mDirectoryIterator(nsnull)
{
NS_INIT_ISUPPORTS();
}
//----------------------------------------------------------------------------------------
nsDirectoryIteratorImpl::~nsDirectoryIteratorImpl()
//----------------------------------------------------------------------------------------
{
delete mDirectoryIterator;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsDirectoryIteratorImpl::Init(nsIFileSpec *parent, PRBool resolveSymlink)
//----------------------------------------------------------------------------------------
{
delete mDirectoryIterator;
mDirectoryIterator = new nsDirectoryIterator(FILESPEC(parent), resolveSymlink);
if (!mDirectoryIterator)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsDirectoryIteratorImpl::Exists(PRBool *_retval)
//----------------------------------------------------------------------------------------
{
TEST_OUT_PTR(_retval)
if (!mDirectoryIterator)
return NS_ERROR_NULL_POINTER;
*_retval = mDirectoryIterator->Exists();
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsDirectoryIteratorImpl::Next()
//----------------------------------------------------------------------------------------
{
if (!mDirectoryIterator)
return NS_ERROR_NULL_POINTER;
(*mDirectoryIterator)++;
return NS_OK;
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsDirectoryIteratorImpl::GetCurrentSpec(nsIFileSpec * *aCurrentSpec)
//----------------------------------------------------------------------------------------
{
if (!mDirectoryIterator)
return NS_ERROR_NULL_POINTER;
return nsFileSpecImpl::MakeInterface(mDirectoryIterator->Spec(), aCurrentSpec);
}
//----------------------------------------------------------------------------------------
NS_METHOD nsDirectoryIteratorImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec)
//----------------------------------------------------------------------------------------
{
if (aIFileSpec == NULL)
return NS_ERROR_NULL_POINTER;
nsDirectoryIteratorImpl* it = new nsDirectoryIteratorImpl;
if (!it)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = it->QueryInterface(aIID, aIFileSpec);
if (NS_FAILED(rv))
{
delete it;
return rv;
}
return rv;
}
//----------------------------------------------------------------------------------------
NS_METHOD nsFileSpecImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec)
//----------------------------------------------------------------------------------------
{
if (aIFileSpec == NULL)
return NS_ERROR_NULL_POINTER;
nsFileSpecImpl* it = new nsFileSpecImpl;
if (!it)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = it->QueryInterface(aIID, aIFileSpec);
if (NS_FAILED(rv))
{
delete it;
return rv;
}
return rv;
}
//----------------------------------------------------------------------------------------
nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result)
//----------------------------------------------------------------------------------------
{
if (!result)
return NS_ERROR_NULL_POINTER;
return nsFileSpecImpl::MakeInterface(aSrcFileSpec, result);
}
//----------------------------------------------------------------------------------------
nsresult NS_NewFileSpec(nsIFileSpec** result)
//----------------------------------------------------------------------------------------
{
return nsFileSpecImpl::Create(nsnull, nsIFileSpec::GetIID(), (void**)result);
}
//----------------------------------------------------------------------------------------
nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result)
//----------------------------------------------------------------------------------------
{
return nsDirectoryIteratorImpl::Create(nsnull, nsIDirectoryIterator::GetIID(), (void**)result);
}

View File

@@ -0,0 +1,603 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// This file is included by nsFileSpec.cpp, and includes the Unix-specific
// implementations.
#include <sys/stat.h>
#include <sys/param.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include "nsError.h"
#include "prio.h" /* for PR_Rename */
#if defined(_SCO_DS)
#define _SVID3 /* for statvfs.h */
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#ifdef __bsdi__
#undef Free
#endif
#endif
#ifdef HAVE_STATVFS
#define STATFS statvfs
#else
#define STATFS statfs
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024 /* Guessing this is okay. Works for SCO. */
#endif
#if defined(__QNX__)
#include <unix.h> /* for realpath */
#define f_bavail f_bfree
#endif
#if defined(SUNOS4)
extern "C" int statfs(char *, struct statfs *);
#endif
#if defined(OSF1)
extern "C" int statvfs(const char *, struct statvfs *);
#endif
//----------------------------------------------------------------------------------------
void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs)
// Canonify, make absolute, and check whether directories exist
//----------------------------------------------------------------------------------------
{
if (ioPath.IsEmpty())
return;
if (inMakeDirs)
{
const mode_t mode = 0700;
nsFileSpecHelpers::MakeAllDirectories((const char*)ioPath, mode);
}
errno = 0; // needed?
if (ioPath[0] != '/')
{
// the ioPath that was passed in is relative. We must cat it to the cwd.
char buffer[MAXPATHLEN];
(void) getcwd(buffer, MAXPATHLEN);
strcat(buffer, "/");
strcat(buffer, ioPath);
ioPath = buffer;
}
} // nsFileSpecHelpers::Canonify
//----------------------------------------------------------------------------------------
void nsFileSpec::SetLeafName(const char* inLeafName)
//----------------------------------------------------------------------------------------
{
mPath.LeafReplace('/', inLeafName);
} // nsFileSpec::SetLeafName
//----------------------------------------------------------------------------------------
char* nsFileSpec::GetLeafName() const
//----------------------------------------------------------------------------------------
{
return mPath.GetLeaf('/');
} // nsFileSpec::GetLeafName
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::Exists() const
//----------------------------------------------------------------------------------------
{
struct stat st;
return !mPath.IsEmpty() && 0 == stat(mPath, &st);
} // nsFileSpec::Exists
//----------------------------------------------------------------------------------------
void nsFileSpec::GetModDate(TimeStamp& outStamp) const
//----------------------------------------------------------------------------------------
{
struct stat st;
if (!mPath.IsEmpty() && stat(mPath, &st) == 0)
outStamp = st.st_mtime;
else
outStamp = 0;
} // nsFileSpec::GetModDate
//----------------------------------------------------------------------------------------
PRUint32 nsFileSpec::GetFileSize() const
//----------------------------------------------------------------------------------------
{
struct stat st;
if (!mPath.IsEmpty() && stat(mPath, &st) == 0)
return (PRUint32)st.st_size;
return 0;
} // nsFileSpec::GetFileSize
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsFile() const
//----------------------------------------------------------------------------------------
{
struct stat st;
return !mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISREG(st.st_mode);
} // nsFileSpec::IsFile
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsDirectory() const
//----------------------------------------------------------------------------------------
{
struct stat st;
return !mPath.IsEmpty() && 0 == stat(mPath, &st) && S_ISDIR(st.st_mode);
} // nsFileSpec::IsDirectory
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsHidden() const
//----------------------------------------------------------------------------------------
{
PRBool hidden = PR_FALSE;
char *leafname = GetLeafName();
if (nsnull != leafname)
{
// rjc: don't return ".", "..", or any file/directory that begins with a "."
/* if ((!strcmp(leafname, ".")) || (!strcmp(leafname, ".."))) */
if (leafname[0] == '.')
{
hidden = PR_TRUE;
}
nsCRT::free(leafname);
}
return hidden;
} // nsFileSpec::IsHidden
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsSymlink() const
//----------------------------------------------------------------------------------------
{
struct stat st;
if (!mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISLNK(st.st_mode))
return PR_TRUE;
return PR_FALSE;
} // nsFileSpec::IsSymlink
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased)
//----------------------------------------------------------------------------------------
{
wasAliased = PR_FALSE;
char resolvedPath[MAXPATHLEN];
int charCount = readlink(mPath, (char*)&resolvedPath, MAXPATHLEN);
if (0 < charCount)
{
if (MAXPATHLEN > charCount)
resolvedPath[charCount] = '\0';
wasAliased = PR_TRUE;
/* if it's not an absolute path,
replace the leaf with what got resolved */
if (resolvedPath[0] != '/') {
SetLeafName(resolvedPath);
}
else {
mPath = (char*)&resolvedPath;
}
char* canonicalPath = realpath((const char *)mPath, resolvedPath);
NS_ASSERTION(canonicalPath, "realpath failed");
if (canonicalPath) {
mPath = (char*)&resolvedPath;
}
else {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
} // nsFileSpec::ResolveSymlink
//----------------------------------------------------------------------------------------
void nsFileSpec::GetParent(nsFileSpec& outSpec) const
//----------------------------------------------------------------------------------------
{
outSpec.mPath = mPath;
char* chars = (char*)outSpec.mPath;
chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any
char* cp = strrchr(chars, '/');
if (cp++)
outSpec.mPath.SetLength(cp - chars); // truncate.
} // nsFileSpec::GetParent
//----------------------------------------------------------------------------------------
void nsFileSpec::operator += (const char* inRelativePath)
//----------------------------------------------------------------------------------------
{
NS_ASSERTION(inRelativePath, "Attempt to do += with a null string");
if (!inRelativePath || mPath.IsEmpty())
return;
char endChar = mPath[(int)(strlen(mPath) - 1)];
if (endChar == '/')
mPath += "x";
else
mPath += "/x";
SetLeafName(inRelativePath);
} // nsFileSpec::operator +=
//----------------------------------------------------------------------------------------
void nsFileSpec::CreateDirectory(int mode)
//----------------------------------------------------------------------------------------
{
// Note that mPath is canonical!
if (mPath.IsEmpty())
return;
mkdir(mPath, mode);
} // nsFileSpec::CreateDirectory
//----------------------------------------------------------------------------------------
void nsFileSpec::Delete(PRBool inRecursive) const
// To check if this worked, call Exists() afterwards, see?
//----------------------------------------------------------------------------------------
{
if (IsDirectory())
{
if (inRecursive)
{
for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
{
nsFileSpec& child = (nsFileSpec&)i;
child.Delete(inRecursive);
}
}
rmdir(mPath);
}
else if (!mPath.IsEmpty())
remove(mPath);
} // nsFileSpec::Delete
//----------------------------------------------------------------------------------------
void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const
//----------------------------------------------------------------------------------------
{
if (IsDirectory())
{
if (!(newDir.Exists()))
{
newDir.CreateDirectory();
}
for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
{
nsFileSpec& child = (nsFileSpec&)i;
if (child.IsDirectory())
{
nsFileSpec tmpDirSpec(newDir);
char *leafname = child.GetLeafName();
tmpDirSpec += leafname;
nsCRT::free(leafname);
child.RecursiveCopy(tmpDirSpec);
}
else
{
child.RecursiveCopy(newDir);
}
}
}
else if (!mPath.IsEmpty())
{
nsFileSpec& filePath = (nsFileSpec&) *this;
if (!(newDir.Exists()))
{
newDir.CreateDirectory();
}
filePath.CopyToDir(newDir);
}
} // nsFileSpec::RecursiveCopy
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::Truncate(const PRInt32 offset) const
//----------------------------------------------------------------------------------------
{
char* Path = nsCRT::strdup(mPath);
PRInt32 rv = truncate(Path, offset) ;
nsCRT::free(Path) ;
if(!rv)
return NS_OK ;
else
return NS_ERROR_FAILURE ;
} // nsFileSpec::Truncate
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::Rename(const char* inNewName)
//----------------------------------------------------------------------------------------
{
NS_ASSERTION(inNewName, "Attempt to Rename with a null string");
// This function should not be used to move a file on disk.
if (mPath.IsEmpty() || strchr(inNewName, '/'))
return NS_FILE_FAILURE;
char* oldPath = nsCRT::strdup(mPath);
SetLeafName(inNewName);
if (PR_Rename(oldPath, mPath) != NS_OK)
{
// Could not rename, set back to the original.
mPath = oldPath;
return NS_FILE_FAILURE;
}
nsCRT::free(oldPath);
return NS_OK;
} // nsFileSpec::Rename
//----------------------------------------------------------------------------------------
static int CrudeFileCopy(const char* in, const char* out)
//----------------------------------------------------------------------------------------
{
struct stat in_stat;
int stat_result = -1;
char buf [1024];
FILE *ifp, *ofp;
int rbytes, wbytes;
if (!in || !out)
return -1;
stat_result = stat (in, &in_stat);
ifp = fopen (in, "r");
if (!ifp)
{
return -1;
}
ofp = fopen (out, "w");
if (!ofp)
{
fclose (ifp);
return -1;
}
while ((rbytes = fread (buf, 1, sizeof(buf), ifp)) > 0)
{
while (rbytes > 0)
{
if ( (wbytes = fwrite (buf, 1, rbytes, ofp)) < 0 )
{
fclose (ofp);
fclose (ifp);
unlink(out);
return -1;
}
rbytes -= wbytes;
}
}
fclose (ofp);
fclose (ifp);
if (stat_result == 0)
chmod (out, in_stat.st_mode & 0777);
return 0;
} // nsFileSpec::Rename
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const
//----------------------------------------------------------------------------------------
{
// We can only copy into a directory, and (for now) can not copy entire directories
nsresult result = NS_FILE_FAILURE;
if (inParentDirectory.IsDirectory() && (! IsDirectory() ) )
{
char *leafname = GetLeafName();
nsSimpleCharString destPath(inParentDirectory.GetCString());
destPath += "/";
destPath += leafname;
nsCRT::free(leafname);
result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), destPath));
}
return result;
} // nsFileSpec::CopyToDir
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory)
//----------------------------------------------------------------------------------------
{
// We can only copy into a directory, and (for now) can not copy entire directories
nsresult result = NS_FILE_FAILURE;
if (inNewParentDirectory.IsDirectory() && !IsDirectory())
{
char *leafname = GetLeafName();
nsSimpleCharString destPath(inNewParentDirectory.GetCString());
destPath += "/";
destPath += leafname;
nsCRT::free(leafname);
result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), (const char*)destPath));
if (result == NS_OK)
{
// cast to fix const-ness
((nsFileSpec*)this)->Delete(PR_FALSE);
*this = inNewParentDirectory + GetLeafName();
}
}
return result;
}
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::Execute(const char* inArgs ) const
//----------------------------------------------------------------------------------------
{
nsresult result = NS_FILE_FAILURE;
if (!mPath.IsEmpty() && !IsDirectory())
{
nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs;
result = NS_FILE_RESULT(system(fileNameWithArgs));
}
return result;
} // nsFileSpec::Execute
//----------------------------------------------------------------------------------------
PRInt64 nsFileSpec::GetDiskSpaceAvailable() const
//----------------------------------------------------------------------------------------
{
PRInt64 bytes; /* XXX dougt needs to fix this */
LL_I2L(bytes , LONG_MAX); // initialize to all the space in the world?
#if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H)
char curdir [MAXPATHLEN];
if (mPath.IsEmpty())
{
(void) getcwd(curdir, MAXPATHLEN);
if (!curdir)
return bytes; /* hope for the best as we did in cheddar */
}
else
sprintf(curdir, "%.200s", (const char*)mPath);
struct STATFS fs_buf;
#if defined(__QNX__) && !defined(HAVE_STATVFS) /* Maybe this should be handled differently? */
if (STATFS(curdir, &fs_buf, 0, 0) < 0)
#else
if (STATFS(curdir, &fs_buf) < 0)
#endif
return bytes; /* hope for the best as we did in cheddar */
#ifdef DEBUG_DISK_SPACE
printf("DiskSpaceAvailable: %d bytes\n",
fs_buf.f_bsize * (fs_buf.f_bavail - 1));
#endif
LL_I2L( bytes, (fs_buf.f_bsize * (fs_buf.f_bavail - 1) ) );
return bytes;
#else
/*
** This platform doesn't have statfs or statvfs, so we don't have much
** choice but to "hope for the best as we did in cheddar".
*/
return bytes;
#endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */
} // nsFileSpec::GetDiskSpace()
//========================================================================================
// nsDirectoryIterator
//========================================================================================
//----------------------------------------------------------------------------------------
nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymLinks)
//----------------------------------------------------------------------------------------
: mCurrent(inDirectory)
, mExists(PR_FALSE)
, mResoveSymLinks(resolveSymLinks)
, mStarting(inDirectory)
, mDir(nsnull)
{
mStarting += "sysygy"; // save off the starting directory
mCurrent += "sysygy"; // prepare the path for SetLeafName
mDir = opendir((const char*)nsFilePath(inDirectory));
++(*this);
} // nsDirectoryIterator::nsDirectoryIterator
//----------------------------------------------------------------------------------------
nsDirectoryIterator::~nsDirectoryIterator()
//----------------------------------------------------------------------------------------
{
if (mDir)
closedir(mDir);
} // nsDirectoryIterator::nsDirectoryIterator
//----------------------------------------------------------------------------------------
nsDirectoryIterator& nsDirectoryIterator::operator ++ ()
//----------------------------------------------------------------------------------------
{
mExists = PR_FALSE;
if (!mDir)
return *this;
char* dot = ".";
char* dotdot = "..";
struct dirent* entry = readdir(mDir);
if (entry && strcmp(entry->d_name, dot) == 0)
entry = readdir(mDir);
if (entry && strcmp(entry->d_name, dotdot) == 0)
entry = readdir(mDir);
if (entry)
{
mExists = PR_TRUE;
mCurrent = mStarting; // restore mCurrent to be the starting directory. ResolveSymlink() may have taken us to another directory
mCurrent.SetLeafName(entry->d_name);
if (mResoveSymLinks)
{
PRBool ignore;
mCurrent.ResolveSymlink(ignore);
}
}
return *this;
} // nsDirectoryIterator::operator ++
//----------------------------------------------------------------------------------------
nsDirectoryIterator& nsDirectoryIterator::operator -- ()
//----------------------------------------------------------------------------------------
{
return ++(*this); // can't do it backwards.
} // nsDirectoryIterator::operator --

View File

@@ -0,0 +1,726 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// This file is included by nsFileSpec.cp, and includes the Windows-specific
// implementations.
#include <sys/stat.h>
#include <direct.h>
#include <limits.h>
#include <stdlib.h>
#include "prio.h"
#include "nsError.h"
#include "windows.h"
#if (_MSC_VER == 1100)
#define INITGUID
#include "objbase.h"
DEFINE_OLEGUID(IID_IPersistFile, 0x0000010BL, 0, 0);
#endif
#include "shlobj.h"
#include "shellapi.h"
#include "shlguid.h"
#ifdef UNICODE
#define CreateDirectoryW CreateDirectory
#else
#define CreateDirectoryA CreateDirectory
#endif
//----------------------------------------------------------------------------------------
void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs)
// Canonify, make absolute, and check whether directories exist. This
// takes a (possibly relative) native path and converts it into a
// fully qualified native path.
//----------------------------------------------------------------------------------------
{
if (ioPath.IsEmpty())
return;
NS_ASSERTION(strchr((const char*)ioPath, '/') == 0,
"This smells like a Unix path. Native path expected! "
"Please fix.");
if (inMakeDirs)
{
const int mode = 0700;
nsSimpleCharString unixStylePath = ioPath;
nsFileSpecHelpers::NativeToUnix(unixStylePath);
nsFileSpecHelpers::MakeAllDirectories((const char*)unixStylePath, mode);
}
char buffer[_MAX_PATH];
errno = 0;
*buffer = '\0';
char* canonicalPath = _fullpath(buffer, ioPath, _MAX_PATH);
NS_ASSERTION( canonicalPath[0] != '\0', "Uh oh...couldn't convert" );
if (canonicalPath[0] == '\0')
return;
ioPath = canonicalPath;
} // nsFileSpecHelpers::Canonify
//----------------------------------------------------------------------------------------
void nsFileSpecHelpers::UnixToNative(nsSimpleCharString& ioPath)
// This just does string manipulation. It doesn't check reality, or canonify, or
// anything
//----------------------------------------------------------------------------------------
{
// Allow for relative or absolute. We can do this in place, because the
// native path is never longer.
if (ioPath.IsEmpty())
return;
// Strip initial slash for an absolute path
char* src = (char*)ioPath;
if (*src == '/')
{
// Since it was an absolute path, check for the drive letter
char* colonPointer = src + 2;
if (strstr(src, "|/") == colonPointer)
*colonPointer = ':';
// allocate new string by copying from ioPath[1]
nsSimpleCharString temp = src + 1;
ioPath = temp;
}
src = (char*)ioPath;
// Convert '/' to '\'.
while (*++src)
{
if (*src == '/')
*src = '\\';
}
} // nsFileSpecHelpers::UnixToNative
//----------------------------------------------------------------------------------------
void nsFileSpecHelpers::NativeToUnix(nsSimpleCharString& ioPath)
// This just does string manipulation. It doesn't check reality, or canonify, or
// anything. The unix path is longer, so we can't do it in place.
//----------------------------------------------------------------------------------------
{
if (ioPath.IsEmpty())
return;
// Convert the drive-letter separator, if present
nsSimpleCharString temp("/");
char* cp = (char*)ioPath + 1;
if (strstr(cp, ":\\") == cp)
*cp = '|'; // absolute path
else
temp[0] = '\0'; // relative path
// Convert '\' to '/'
for (; *cp; cp++)
{
if (*cp == '\\')
*cp = '/';
}
// Add the slash in front.
temp += ioPath;
ioPath = temp;
}
//----------------------------------------------------------------------------------------
nsFileSpec::nsFileSpec(const nsFilePath& inPath)
//----------------------------------------------------------------------------------------
{
*this = inPath;
}
//----------------------------------------------------------------------------------------
void nsFileSpec::operator = (const nsFilePath& inPath)
//----------------------------------------------------------------------------------------
{
mPath = (const char*)inPath;
nsFileSpecHelpers::UnixToNative(mPath);
mError = NS_OK;
} // nsFileSpec::operator =
//----------------------------------------------------------------------------------------
nsFilePath::nsFilePath(const nsFileSpec& inSpec)
//----------------------------------------------------------------------------------------
{
*this = inSpec;
} // nsFilePath::nsFilePath
//----------------------------------------------------------------------------------------
void nsFilePath::operator = (const nsFileSpec& inSpec)
//----------------------------------------------------------------------------------------
{
mPath = inSpec.mPath;
nsFileSpecHelpers::NativeToUnix(mPath);
} // nsFilePath::operator =
//----------------------------------------------------------------------------------------
void nsFileSpec::SetLeafName(const char* inLeafName)
//----------------------------------------------------------------------------------------
{
NS_ASSERTION(inLeafName, "Attempt to SetLeafName with a null string");
mPath.LeafReplace('\\', inLeafName);
} // nsFileSpec::SetLeafName
//----------------------------------------------------------------------------------------
char* nsFileSpec::GetLeafName() const
//----------------------------------------------------------------------------------------
{
return mPath.GetLeaf('\\');
} // nsFileSpec::GetLeafName
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::Exists() const
//----------------------------------------------------------------------------------------
{
struct stat st;
return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st);
} // nsFileSpec::Exists
//----------------------------------------------------------------------------------------
void nsFileSpec::GetModDate(TimeStamp& outStamp) const
//----------------------------------------------------------------------------------------
{
struct stat st;
if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0)
outStamp = st.st_mtime;
else
outStamp = 0;
} // nsFileSpec::GetModDate
//----------------------------------------------------------------------------------------
PRUint32 nsFileSpec::GetFileSize() const
//----------------------------------------------------------------------------------------
{
struct stat st;
if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0)
return (PRUint32)st.st_size;
return 0;
} // nsFileSpec::GetFileSize
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsFile() const
//----------------------------------------------------------------------------------------
{
struct stat st;
return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFREG & st.st_mode);
} // nsFileSpec::IsFile
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsDirectory() const
//----------------------------------------------------------------------------------------
{
struct stat st;
return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFDIR & st.st_mode);
} // nsFileSpec::IsDirectory
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsHidden() const
//----------------------------------------------------------------------------------------
{
PRBool hidden = PR_FALSE;
if (!mPath.IsEmpty())
{
DWORD attr = GetFileAttributes(mPath);
if (FILE_ATTRIBUTE_HIDDEN & attr)
hidden = PR_TRUE;
}
return hidden;
}
// nsFileSpec::IsHidden
//----------------------------------------------------------------------------------------
PRBool nsFileSpec::IsSymlink() const
//----------------------------------------------------------------------------------------
{
HRESULT hres;
IShellLink* psl;
PRBool isSymlink = PR_FALSE;
CoInitialize(NULL);
// Get a pointer to the IShellLink interface.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Get a pointer to the IPersistFile interface.
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hres))
{
WORD wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH);
// Load the shortcut.
hres = ppf->Load(wsz, STGM_READ);
if (SUCCEEDED(hres))
{
isSymlink = PR_TRUE;
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
psl->Release();
}
CoUninitialize();
return isSymlink;
}
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::ResolveSymlink(PRBool& wasSymlink)
//----------------------------------------------------------------------------------------
{
wasSymlink = PR_FALSE; // assume failure
HRESULT hres;
IShellLink* psl;
CoInitialize(NULL);
// Get a pointer to the IShellLink interface.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Get a pointer to the IPersistFile interface.
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hres))
{
WORD wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH);
// Load the shortcut.
hres = ppf->Load(wsz, STGM_READ);
if (SUCCEEDED(hres))
{
wasSymlink = PR_TRUE;
// Resolve the link.
hres = psl->Resolve(nsnull, SLR_NO_UI );
if (SUCCEEDED(hres))
{
char szGotPath[MAX_PATH];
WIN32_FIND_DATA wfd;
// Get the path to the link target.
hres = psl->GetPath( szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY );
if (SUCCEEDED(hres))
{
// Here we modify the nsFileSpec;
mPath = szGotPath;
mError = NS_OK;
}
}
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
psl->Release();
}
CoUninitialize();
if (SUCCEEDED(hres))
return NS_OK;
return NS_FILE_FAILURE;
}
//----------------------------------------------------------------------------------------
void nsFileSpec::GetParent(nsFileSpec& outSpec) const
//----------------------------------------------------------------------------------------
{
outSpec.mPath = mPath;
char* chars = (char*)outSpec.mPath;
chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any
char* cp = strrchr(chars, '\\');
if (cp++)
outSpec.mPath.SetLength(cp - chars); // truncate.
} // nsFileSpec::GetParent
//----------------------------------------------------------------------------------------
void nsFileSpec::operator += (const char* inRelativePath)
//----------------------------------------------------------------------------------------
{
NS_ASSERTION(inRelativePath, "Attempt to do += with a null string");
if (!inRelativePath || mPath.IsEmpty())
return;
if (mPath[mPath.Length() - 1] == '\\')
mPath += "x";
else
mPath += "\\x";
// If it's a (unix) relative path, make it native
nsSimpleCharString dosPath = inRelativePath;
nsFileSpecHelpers::UnixToNative(dosPath);
SetLeafName(dosPath);
} // nsFileSpec::operator +=
//----------------------------------------------------------------------------------------
void nsFileSpec::CreateDirectory(int /*mode*/)
//----------------------------------------------------------------------------------------
{
// Note that mPath is canonical!
if (!mPath.IsEmpty())
mkdir(nsNSPRPath(*this));
} // nsFileSpec::CreateDirectory
//----------------------------------------------------------------------------------------
void nsFileSpec::Delete(PRBool inRecursive) const
//----------------------------------------------------------------------------------------
{
if (IsDirectory())
{
if (inRecursive)
{
for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
{
nsFileSpec& child = (nsFileSpec&)i;
child.Delete(inRecursive);
}
}
rmdir(nsNSPRPath(*this));
}
else if (!mPath.IsEmpty())
{
remove(nsNSPRPath(*this));
}
} // nsFileSpec::Delete
//----------------------------------------------------------------------------------------
void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const
//----------------------------------------------------------------------------------------
{
if (IsDirectory())
{
if (!(newDir.Exists()))
{
newDir.CreateDirectory();
}
for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
{
nsFileSpec& child = (nsFileSpec&)i;
if (child.IsDirectory())
{
nsFileSpec tmpDirSpec(newDir);
char *leafname = child.GetLeafName();
tmpDirSpec += leafname;
nsCRT::free(leafname);
child.RecursiveCopy(tmpDirSpec);
}
else
{
child.RecursiveCopy(newDir);
}
}
}
else if (!mPath.IsEmpty())
{
nsFileSpec& filePath = (nsFileSpec&) *this;
if (!(newDir.Exists()))
{
newDir.CreateDirectory();
}
filePath.CopyToDir(newDir);
}
} // nsFileSpec::RecursiveCopy
// We have to implement this since there's no truncate() in system.
//----------------------------------------------------------------------------------------
nsresutl nsFileSpec::Truncate(const PRInt32 offset) const
{
char* oldPath = nsCRT::strdup(mPath);
nsFileSpec newFile = *this ;
newFile.MakeUnique() ;
nsInputFileStream inStream(*this) ;
nsOutputFileStream outStream(newFile) ;
PRUint32 buffer_size = 1024, len ;
char buffer[buffer_size] ;
PRUint32 bytes_read=0, bytes_written=0, size_left = offset ;
do {
if(size_left > buffer_size)
len = buffer_size ;
else
len = size_left ;
bytes_read = inStream.read((void*)buffer, len) ;
bytes_written = outStream.write(buffer, bytes_read) ;
if(bytes_written != bytes_read)
return NS_ERROR_FAILURE ;
size_left -= bytes_read ;
} while(!set_left) ;
outStream.flush() ;
outStream.close() ;
inStream.close() ;
// remove the original file
Delete(PR_TRUE) ;
// rename the new file
rv = newFile.Rename(oldPath) ;
return rv ;
} // nsFileSpec::Truncate
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::Rename(const char* inNewName)
//----------------------------------------------------------------------------------------
{
NS_ASSERTION(inNewName, "Attempt to Rename with a null string");
// This function should not be used to move a file on disk.
if (strchr(inNewName, '/'))
return NS_FILE_FAILURE;
char* oldPath = nsCRT::strdup(mPath);
SetLeafName(inNewName);
if (PR_Rename(oldPath, mPath) != NS_OK)
{
// Could not rename, set back to the original.
mPath = oldPath;
return NS_FILE_FAILURE;
}
nsCRT::free(oldPath);
return NS_OK;
} // nsFileSpec::Rename
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const
//----------------------------------------------------------------------------------------
{
// We can only copy into a directory, and (for now) can not copy entire directories
if (inParentDirectory.IsDirectory() && (! IsDirectory() ) )
{
char *leafname = GetLeafName();
nsSimpleCharString destPath(inParentDirectory.GetCString());
destPath += "\\";
destPath += leafname;
nsCRT::free(leafname);
// CopyFile returns non-zero if succeeds
int copyOK = CopyFile(GetCString(), destPath, PR_TRUE);
if (copyOK)
return NS_OK;
}
return NS_FILE_FAILURE;
} // nsFileSpec::CopyToDir
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory)
//----------------------------------------------------------------------------------------
{
// We can only copy into a directory, and (for now) can not copy entire directories
if (inNewParentDirectory.IsDirectory() && (! IsDirectory() ) )
{
char *leafname = GetLeafName();
nsSimpleCharString destPath(inNewParentDirectory.GetCString());
destPath += "\\";
destPath += leafname;
nsCRT::free(leafname);
// MoveFile returns non-zero if succeeds
int copyOK = MoveFile(GetCString(), destPath);
if (copyOK)
{
*this = inNewParentDirectory + GetLeafName();
return NS_OK;
}
}
return NS_FILE_FAILURE;
} // nsFileSpec::MoveToDir
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::Execute(const char* inArgs ) const
//----------------------------------------------------------------------------------------
{
if (!IsDirectory())
{
nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs;
int execResult = WinExec( fileNameWithArgs, SW_NORMAL );
if (execResult > 31)
return NS_OK;
}
return NS_FILE_FAILURE;
} // nsFileSpec::Execute
//----------------------------------------------------------------------------------------
PRInt64 nsFileSpec::GetDiskSpaceAvailable() const
//----------------------------------------------------------------------------------------
{
PRInt64 int64;
LL_I2L(int64 , LONG_MAX);
char aDrive[_MAX_DRIVE + 2];
_splitpath( (const char*)mPath, aDrive, NULL, NULL, NULL);
if (aDrive[0] == '\0')
{
// The back end is always trying to pass us paths that look
// like /c|/netscape/mail. See if we've got one of them
if (mPath.Length() > 2 && mPath[0] == '/' && mPath[2] == '|')
{
aDrive[0] = mPath[1];
aDrive[1] = ':';
aDrive[2] = '\0';
}
else
{
// Return bogus large number and hope for the best
return int64;
}
}
strcat(aDrive, "\\");
// Check disk space
DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus;
ULARGE_INTEGER liFreeBytesAvailableToCaller, liTotalNumberOfBytes, liTotalNumberOfFreeBytes;
double nBytes = 0;
BOOL (WINAPI* getDiskFreeSpaceExA)(LPCTSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes) = NULL;
HINSTANCE hInst = LoadLibrary("KERNEL32.DLL");
NS_ASSERTION(hInst != NULL, "COULD NOT LOAD KERNEL32.DLL");
if (hInst != NULL)
{
getDiskFreeSpaceExA = (BOOL (WINAPI*)(LPCTSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes))
GetProcAddress(hInst, "GetDiskFreeSpaceExA");
FreeLibrary(hInst);
}
if (getDiskFreeSpaceExA && (*getDiskFreeSpaceExA)(aDrive,
&liFreeBytesAvailableToCaller,
&liTotalNumberOfBytes,
&liTotalNumberOfFreeBytes))
{
nBytes = (double)(signed __int64)liFreeBytesAvailableToCaller.QuadPart;
}
else if ( GetDiskFreeSpace(aDrive, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus, &dwTotalClus))
{
nBytes = (double)dwFreeClus*(double)dwSecPerClus*(double) dwBytesPerSec;
}
return (PRInt64)nBytes;
}
//========================================================================================
// nsDirectoryIterator
//========================================================================================
//----------------------------------------------------------------------------------------
nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymlink)
//----------------------------------------------------------------------------------------
: mCurrent(inDirectory)
, mDir(nsnull)
, mStarting(inDirectory)
, mExists(PR_FALSE)
, mResoveSymLinks(resolveSymlink)
{
mDir = PR_OpenDir(inDirectory);
mCurrent += "dummy";
mStarting += "dummy";
++(*this);
} // nsDirectoryIterator::nsDirectoryIterator
//----------------------------------------------------------------------------------------
nsDirectoryIterator::~nsDirectoryIterator()
//----------------------------------------------------------------------------------------
{
if (mDir)
PR_CloseDir(mDir);
} // nsDirectoryIterator::nsDirectoryIterator
//----------------------------------------------------------------------------------------
nsDirectoryIterator& nsDirectoryIterator::operator ++ ()
//----------------------------------------------------------------------------------------
{
mExists = PR_FALSE;
if (!mDir)
return *this;
PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); // Ignore '.' && '..'
if (entry)
{
mExists = PR_TRUE;
mCurrent = mStarting;
mCurrent.SetLeafName(entry->name);
if (mResoveSymLinks)
{
PRBool ignore;
mCurrent.ResolveSymlink(ignore);
}
}
return *this;
} // nsDirectoryIterator::operator ++
//----------------------------------------------------------------------------------------
nsDirectoryIterator& nsDirectoryIterator::operator -- ()
//----------------------------------------------------------------------------------------
{
return ++(*this); // can't do it backwards.
} // nsDirectoryIterator::operator --

View File

@@ -0,0 +1,85 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
[ptr] native nsString(nsString);
%{ C++
#include "nsString.h"
%}
#include "nsIOutputStream.idl"
#include "nsrootidl.idl"
/**
* This interface allows consumption of primitive data types from a "binary
* stream" containing untagged, big-endian binary data, i.e. as produced by an
* implementation of nsIBinaryOutputStream. This might be used, for example,
* to implement network protocols or to read from architecture-neutral disk
* files, i.e. ones that can be read and written by both big-endian and
* little-endian platforms.
*
* @See nsIBinaryOutputStream
*/
[scriptable, uuid(7b456cb0-8772-11d3-90cf-0040056a906e)]
interface nsIBinaryInputStream : nsIInputStream {
void setInputStream(in nsIInputStream aInputStream);
PRBool readBoolean();
PRUint8 read8();
PRUint16 read16();
PRUint32 read32();
PRUint64 read64();
float readFloat();
double readDouble();
/**
* Read a NUL-terminated 8-bit char* string from a binary stream.
*/
string readStringZ();
/**
* Read a NUL-terminated 16-bit PRUnichar* string from a binary stream.
*/
wstring readWStringZ();
/**
* Read a NUL-terminated UTF8-encoded string from a binary stream, producing
* a NUL-terminated 16-bit PRUnichar* string argument as a result.
*/
wstring readUtf8Z();
/**
* Read an opaque byte array from a binary stream.
*/
void readBytes([size_is(aLength)] out string aString, in PRUint32 aLength);
/**
* Read a string (possibly containing embedded NULs) from a binary stream.
*/
[noscript] nsString readString();
};
%{C++
NS_COM nsresult
NS_NewBinaryInputStream(nsIBinaryInputStream* *aResult, nsIInputStream* aSrcStream);
%}

View File

@@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
[ptr] native nsString(nsString);
%{ C++
#include "nsString.h"
%}
#include "nsIOutputStream.idl"
#include "nsrootidl.idl"
/**
* This interface allows writing of primitive data types (integers,
* floating-point values, booleans, etc.) to a stream in a binary, untagged,
* fixed-endianness format. This might be used, for example, to implement
* network protocols or to produce architecture-neutral binary disk files,
* i.e. ones that can be read and written by both big-endian and little-endian
* platforms. Output is written in big-endian order (high-order byte first),
* as this is traditional network order.
*
* @See nsIBinaryInputStream
*/
[scriptable, uuid(204ee610-8765-11d3-90cf-0040056a906e)]
interface nsIBinaryOutputStream : nsIOutputStream {
void setOutputStream(in nsIOutputStream aOutputStream);
void writeBoolean(in PRBool aBoolean);
void write8(in PRUint8 aByte);
void write16(in PRUint16 a16);
void write32(in PRUint32 a32);
void write64(in PRUint64 a64);
void writeFloat(in float aFloat);
void writeDouble(in double aDouble);
/**
* Write a NUL-terminated 8-bit char* string to a binary stream.
*/
void writeStringZ(in string aString);
/**
* Write a NUL-terminated 16-bit PRUnichar* string to a binary stream.
*/
void writeWStringZ(in wstring aString);
/**
* Write a NUL-terminated UTF8-encoded string to a binary stream, produced
* from a NUL-terminated 16-bit PRUnichar* string argument.
*/
void writeUtf8Z(in wstring aString);
/**
* Write an opaque byte array to a binary stream.
*/
void writeBytes([size_is(aLength)] in string aString, in PRUint32 aLength);
/**
* Write a string (possibly containing embedded NULs) to a binary stream.
*/
[noscript] void writeString(in nsString aString);
};
%{C++
NS_COM nsresult
NS_NewBinaryOutputStream(nsIBinaryOutputStream* *aResult, nsIOutputStream* aDestStream);
%}

View File

@@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// This is the only correct cross-platform way to specify a file.
// Strings are not such a way. If you grew up on windows or unix, you
// may think they are. Welcome to reality.
#include "nsISupports.idl"
%{C++
#include "nsFileSpec.h" // for factory method
%}
interface nsIFileURL;
interface nsIFilePath;
interface nsIOutputStream;
interface nsIInputStream;
// Define Progid and CID
%{C++
// {A5740FA2-146E-11d3-B00D-00C04FC2E79B}
#define NS_FILESPEC_CID \
{ 0xa5740fa2, 0x146e, 0x11d3, { 0xb0, 0xd, 0x0, 0xc0, 0x4f, 0xc2, 0xe7, 0x9b } }
#define NS_FILESPEC_PROGID "component://netscape/filespec"
#define NS_FILESPEC_CLASSNAME "File Spec"
%}
native nsFileSpec(nsFileSpec);
[ref] native nsFileSpecRef(nsFileSpec);
[ptr] native nsFileSpecPtr(nsFileSpec);
[scriptable, uuid(d8c0a080-0868-11d3-915f-d9d889d48e3c)]
interface nsIFileSpec : nsISupports
{
void fromFileSpec([const] in nsIFileSpec original);
attribute string URLString;
attribute string unixStyleFilePath;
attribute string persistentDescriptorString;
attribute string nativePath;
readonly attribute string NSPRPath;
void error();
boolean isValid();
boolean failed();
attribute string leafName;
readonly attribute nsIFileSpec parent;
readonly attribute nsIInputStream inputStream;
readonly attribute nsIOutputStream outputStream;
boolean isChildOf(in nsIFileSpec possibleParent);
[noscript] readonly attribute nsFileSpec fileSpec;
[noscript] void setFromFileSpec([const] in nsFileSpecRef spec);
attribute string fileContents;
void makeUnique();
void makeUniqueWithSuggestedName(in string suggestedName);
readonly attribute unsigned long modDate;
boolean modDateChanged(in unsigned long oldStamp);
boolean isDirectory();
boolean isFile();
boolean exists();
boolean isHidden();
readonly attribute unsigned long fileSize;
readonly attribute long long diskSpaceAvailable;
void appendRelativeUnixPath(in string relativePath);
void createDir();
void touch();
boolean isSymlink();
void resolveSymlink();
void truncate([const] in long offset) ;
void rename([const] in string newLeafName);
void copyToDir([const] in nsIFileSpec newParentDir);
void moveToDir([const] in nsIFileSpec newParentDir);
void execute([const] in string args);
void openStreamForReading();
void openStreamForWriting();
void openStreamForReadingAndWriting();
void closeStream();
boolean isStreamOpen();
boolean eof();
long read(inout string buffer, in long requestedCount);
void readLine(inout string line, in long bufferSize, out boolean wasTruncated);
%{C++
// Check eof() before each call.
// CAUTION: false result only indicates line was truncated
// to fit buffer, or an error occurred (OTHER THAN eof).
%}
long write(in string data, in long requestedCount);
void flush();
void seek(in long offset);
long tell();
void endLine();
};
// Define Progid and CID
%{C++
// {a3020981-2018-11d3-915f-a957795b7ebc}
#define NS_DIRECTORYITERATOR_CID \
{ 0xa3020981, 0x2018, 0x11d3, { 0x91, 0x5f, 0xa9, 0x57, 0x79, 0x5b, 0x7e, 0xbc } }
#define NS_DIRECTORYITERATOR_PROGID "component://netscape/directoryiterator"
#define NS_DIRECTORYITERATOR_CLASSNAME "nsIDirectoryIterator"
%}
[scriptable, uuid(d8c0a083-0868-11d3-915f-d9d889d48e3c)]
interface nsIDirectoryIterator : nsISupports
{
void init(in nsIFileSpec parent, in boolean resolveSymlink);
boolean exists();
void next();
readonly attribute nsIFileSpec currentSpec;
};
%{C++
// Factory methods if you link with xpcom
NS_COM nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result);
NS_COM nsresult NS_NewFileSpec(nsIFileSpec** result);
NS_COM nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result);
#define NS_BOOL_ACCESSOR(_method) { PRBool yes; return NS_SUCCEEDED(f->_method(&yes)) && yes; }
inline PRBool Exists(nsIFileSpec* f) NS_BOOL_ACCESSOR(Exists)
inline PRBool Exists(nsIDirectoryIterator* f) NS_BOOL_ACCESSOR(Exists)
inline PRBool IsDirectory(nsIFileSpec* f) NS_BOOL_ACCESSOR(IsDirectory)
%}

View File

@@ -0,0 +1,74 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsISupports.idl"
#include "nsrootidl.idl"
interface nsIAllocator;
interface nsIInputStream;
interface nsIOutputStream;
/**
* The nsIStorageStream interface maintains an internal data buffer that can be
* filled using a single output stream. One or more independent input streams
* can be created to read the data from the buffer non-destructively.
*/
[scriptable, uuid(604ad9d0-753e-11d3-90ca-0040056a906e)]
interface nsIStorageStream : nsISupports
{
/**
* Get a reference to the one and only output stream for this instance.
* The zero-based startPosition argument is used is used to set the initial
* write cursor position. The startPosition cannot be set larger than the
* current buffer length. Calling this method has the side-effect of
* truncating the internal buffer to startPosition bytes.
*/
nsIOutputStream getOutputStream(in PRInt32 startPosition);
/**
* Create a new input stream to read data (written by the singleton output
* stream) from the internal buffer. Multiple, independent input streams
* can be created.
*/
nsIInputStream newInputStream(in PRInt32 startPosition);
/**
* The length attribute indicates the total number of bytes stored in the
* nsIStorageStream internal buffer, regardless of any consumption by input
* streams. Assigning to the length field can be used to truncate the
* buffer data, but can not be used when either the instance's output
* stream is in use.
*
* @See #writeInProgress */
attribute PRUint32 length;
/**
* True, when output stream has not yet been Close'ed
*/
readonly attribute boolean writeInProgress;
};
%{C++
// Factory method
NS_COM nsresult
NS_NewStorageStream(PRUint32 segmentSize, PRUint32 maxSize, nsIStorageStream **result);
%}

View File

@@ -0,0 +1,467 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsIStringStream.h"
#include "nsIFileStream.h"
#include "prerror.h"
#include "nsFileSpec.h"
#include "plstr.h"
//========================================================================================
class BasicStringImpl
: public nsIOutputStream
, public nsIInputStream
, public nsIRandomAccessStore
//========================================================================================
{
public:
BasicStringImpl()
: mOffset(0)
, mLastResult(NS_OK)
, mEOF(PR_FALSE)
{
NS_INIT_REFCNT();
}
virtual ~BasicStringImpl()
{
}
NS_IMETHOD Seek(PRSeekWhence whence, PRInt32 offset);
NS_IMETHOD Tell(PRIntn* outWhere)
{
*outWhere = mOffset;
return NS_OK;
}
NS_IMETHOD GetAtEOF(PRBool* outAtEOF)
{
*outAtEOF = mEOF;
return NS_OK;
}
NS_IMETHOD SetAtEOF(PRBool inAtEOF)
{
mEOF = inAtEOF;
return NS_OK;
}
NS_IMETHOD Available(PRUint32 *aLength)
{
NS_PRECONDITION(aLength != nsnull, "null ptr");
if (!aLength)
return NS_ERROR_NULL_POINTER;
*aLength = length();
return NS_OK;
}
NS_IMETHOD Read(char* aBuf,
PRUint32 aCount,
PRUint32 *aReadCount)
{
NS_PRECONDITION(aBuf != nsnull, "null ptr");
if (!aBuf)
return NS_ERROR_NULL_POINTER;
NS_PRECONDITION(aReadCount != nsnull, "null ptr");
if (!aReadCount)
return NS_ERROR_NULL_POINTER;
if (NS_FAILED(mLastResult))
return mLastResult;
PRInt32 bytesRead = read(aBuf, aCount);
if (NS_FAILED(mLastResult))
{
*aReadCount = 0;
return mLastResult;
}
*aReadCount = bytesRead;
if (bytesRead < (PRInt32)aCount)
SetAtEOF(PR_TRUE);
return NS_OK;
}
// nsIOutputStream interface
NS_IMETHOD Write(const char* aBuf,
PRUint32 aCount,
PRUint32 *aWriteCount)
{
NS_PRECONDITION(aBuf != nsnull, "null ptr");
NS_PRECONDITION(aWriteCount != nsnull, "null ptr");
if (NS_FAILED(mLastResult))
return mLastResult;
PRInt32 bytesWrit = write(aBuf, aCount);
if (NS_FAILED(mLastResult))
{
*aWriteCount = 0;
return mLastResult;
}
*aWriteCount = bytesWrit;
return NS_OK;
}
public:
// nsISupports interface
NS_DECL_ISUPPORTS
NS_IMETHOD Close() { return NS_OK; }
// nsIInputStream interface
NS_IMETHOD Flush() { return NS_OK; }
public:
nsresult get_result() const { return mLastResult; }
protected:
virtual PRInt32 length() const = 0;
virtual PRInt32 read(char* buf, PRUint32 count) = 0;
virtual PRInt32 write(const char*, PRUint32)
{
NS_ASSERTION(PR_FALSE, "Write to a const string");
mLastResult = NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR);
return -1;
}
protected:
PRUint32 mOffset;
nsresult mLastResult;
PRBool mEOF;
}; // class BasicStringImpl
//========================================================================================
class ConstCharImpl
: public BasicStringImpl
//========================================================================================
{
public:
ConstCharImpl(const char* inString, PRInt32 inLength = -1)
: mConstString(inString),
mLength(inLength == -1 ?
(inString ? strlen(inString) : 0) : inLength) {}
protected:
virtual PRInt32 length() const
{
return mLength - mOffset;
}
virtual PRInt32 read(char* buf, PRUint32 aCount)
{
PRInt32 maxCount = mLength - mOffset;
if ((PRInt32)aCount > maxCount)
aCount = maxCount;
memcpy(buf, mConstString + mOffset, aCount);
mOffset += aCount;
return aCount;
}
protected:
const char* mConstString;
size_t mLength;
}; // class ConstCharImpl
//========================================================================================
class CharImpl
: public ConstCharImpl
//========================================================================================
{
enum { kAllocQuantum = 256 };
public:
CharImpl(char** inString, PRInt32 inLength = -1)
: ConstCharImpl(*inString, inLength)
, mString(*inString)
, mAllocLength(mLength + 1)
, mOriginalLength(mLength)
{
if (!mString)
{
mAllocLength = kAllocQuantum;
mString = new char[mAllocLength];
if (!mString)
{
mLastResult = NS_ERROR_OUT_OF_MEMORY;
return;
}
mConstString = mString;
*mString = '\0';
}
}
~CharImpl()
{
if (mString)
{
delete [] mString;
}
}
virtual PRInt32 write(const char* buf, PRUint32 aCount)
{
if (!buf)
return 0;
PRInt32 maxCount = mAllocLength - 1 - mOffset;
if ((PRInt32)aCount > maxCount)
{
mAllocLength = aCount + 1 + mOffset + kAllocQuantum;
char* newString = new char[mAllocLength];
if (!newString)
{
mLastResult = NS_ERROR_OUT_OF_MEMORY;
return 0;
}
memcpy(newString, mString, mLength);
delete [] mString;
mString = newString;
mConstString = newString;
}
memcpy(mString + mOffset, buf, aCount);
mOffset += aCount;
if (mOffset > mOriginalLength)
mString[mOffset] = 0;
return aCount;
}
protected:
char*& mString;
size_t mAllocLength;
size_t mOriginalLength;
}; // class CharImpl
//========================================================================================
class ConstStringImpl
: public ConstCharImpl
//========================================================================================
{
public:
ConstStringImpl(const nsString& inString)
: ConstCharImpl(inString.ToNewCString(),
inString.Length())
{
}
~ConstStringImpl()
{
delete [] (char*)mConstString;
}
protected:
protected:
}; // class ConstStringImpl
//========================================================================================
class StringImpl
: public ConstStringImpl
// This is wrong, since it really converts to 1-char strings.
//========================================================================================
{
public:
StringImpl(nsString& inString)
: ConstStringImpl(inString)
, mString(inString)
{
}
protected:
virtual PRInt32 write(const char* buf, PRUint32 count)
{
if (!buf)
return 0;
// Clone our string as chars
char* cstring = mString.ToNewCString();
// Make a CharImpl and do the write
CharImpl chars(&cstring, mString.Length());
chars.Seek(PR_SEEK_SET, mOffset);
// Get the bytecount and result from the CharImpl
PRInt32 result = chars.write(buf,count);
mLastResult = chars.get_result();
// Set our string to match the new chars
chars.Seek(PR_SEEK_SET, 0);
size_t newLength;
chars.Available(&newLength);
mString.Assign(cstring, newLength);
// Set our const string also...
delete [] (char*)mConstString;
mConstString = cstring;
return result;
}
protected:
nsString& mString;
}; // class StringImpl
NS_IMPL_RELEASE(BasicStringImpl)
NS_IMPL_ADDREF(BasicStringImpl)
NS_IMPL_QUERY_HEAD(BasicStringImpl)
NS_IMPL_QUERY_BODY(nsIRandomAccessStore)
NS_IMPL_QUERY_BODY(nsIOutputStream)
NS_IMPL_QUERY_BODY(nsIInputStream)
if ( aIID.Equals(NS_GET_IID(nsIBaseStream)) )
foundInterface = NS_STATIC_CAST(nsIBaseStream*, NS_STATIC_CAST(nsIOutputStream*, this));
else
NS_IMPL_QUERY_TAIL(nsIOutputStream)
//----------------------------------------------------------------------------------------
NS_IMETHODIMP BasicStringImpl::Seek(PRSeekWhence whence, PRInt32 offset)
//----------------------------------------------------------------------------------------
{
mLastResult = NS_OK; // reset on a seek.
mEOF = PR_FALSE; // reset on a seek.
PRInt32 fileSize = length();
PRInt32 newPosition=-1;
switch (whence)
{
case PR_SEEK_CUR: newPosition = mOffset + offset; break;
case PR_SEEK_SET: newPosition = offset; break;
case PR_SEEK_END: newPosition = fileSize + offset; break;
}
if (newPosition < 0)
{
newPosition = 0;
mLastResult = NS_FILE_RESULT(PR_FILE_SEEK_ERROR);
}
if (newPosition >= fileSize)
{
newPosition = fileSize;
mEOF = PR_TRUE;
}
mOffset = newPosition;
return NS_OK;
} // StringImpl::Seek
//----------------------------------------------------------------------------------------
extern "C" NS_COM nsresult NS_NewStringInputStream(
nsISupports** aStreamResult,
const nsString& aStringToRead)
// Factory method to get an nsInputStream from a string. Result will implement all the
// file stream interfaces in nsIFileStream.h
//----------------------------------------------------------------------------------------
{
NS_PRECONDITION(aStreamResult != nsnull, "null ptr");
if (! aStreamResult)
return NS_ERROR_NULL_POINTER;
ConstStringImpl* stream = new ConstStringImpl(aStringToRead);
if (! stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aStreamResult = (nsISupports*)(void*)stream;
return NS_OK;
}
//----------------------------------------------------------------------------------------
extern "C" NS_COM nsresult NS_NewStringOutputStream(
nsISupports** aStreamResult,
nsString& aStringToChange)
// Factory method to get an nsOutputStream from a string. Result will implement all the
// file stream interfaces in nsIFileStream.h
//----------------------------------------------------------------------------------------
{
NS_PRECONDITION(aStreamResult != nsnull, "null ptr");
if (! aStreamResult)
return NS_ERROR_NULL_POINTER;
StringImpl* stream = new StringImpl(aStringToChange);
if (! stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aStreamResult = (nsISupports*)(void*)stream;
return NS_OK;
}
//----------------------------------------------------------------------------------------
extern "C" NS_COM nsresult NS_NewCharInputStream(
nsISupports** aStreamResult,
const char* aStringToRead)
// Factory method to get an nsInputStream from a string. Result will implement all the
// file stream interfaces in nsIFileStream.h
//----------------------------------------------------------------------------------------
{
NS_PRECONDITION(aStreamResult != nsnull, "null ptr");
if (! aStreamResult)
return NS_ERROR_NULL_POINTER;
ConstCharImpl* stream = new ConstCharImpl(aStringToRead);
if (! stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aStreamResult = (nsISupports*)(void*)stream;
return NS_OK;
}
//----------------------------------------------------------------------------------------
extern "C" NS_COM nsresult NS_NewCharOutputStream(
nsISupports** aStreamResult,
char** aStringToChange)
// Factory method to get an nsOutputStream to a string. Result will implement all the
// file stream interfaces in nsIFileStream.h
//----------------------------------------------------------------------------------------
{
NS_PRECONDITION(aStreamResult != nsnull, "null ptr");
NS_PRECONDITION(aStringToChange != nsnull, "null ptr");
if (!aStreamResult || !aStringToChange)
return NS_ERROR_NULL_POINTER;
CharImpl* stream = new CharImpl(aStringToChange);
if (! stream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(stream);
*aStreamResult = (nsISupports*)(void*)stream;
return NS_OK;
}
//----------------------------------------------------------------------------------------
extern "C" NS_COM nsresult NS_NewStringIOStream(
nsISupports** aStreamResult,
nsString& aStringToChange)
// Factory method to get an nsOutputStream to a string. Result will implement all the
// file stream interfaces in nsIFileStream.h
//----------------------------------------------------------------------------------------
{
return NS_NewStringOutputStream(aStreamResult, aStringToChange);
}
//----------------------------------------------------------------------------------------
extern "C" NS_COM nsresult NS_NewCharIOStream(
nsISupports** aStreamResult,
char** aStringToChange)
// Factory method to get an nsOutputStream to a string. Result will implement all the
// file stream interfaces in nsIFileStream.h
//----------------------------------------------------------------------------------------
{
return NS_NewCharOutputStream(aStreamResult, aStringToChange);
}

Some files were not shown because too many files have changed in this diff Show More