LCOV - code coverage report
Current view: directory - netwerk/base/src - nsDirectoryIndexStream.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 145 118 81.4 %
Date: 2012-06-02 Functions: 13 13 100.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* vim:set sw=4 sts=4 et cin: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Bradley Baetz <bbaetz@cs.mcgill.ca>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : 
      41                 : /*
      42                 : 
      43                 :   The converts a filesystem directory into an "HTTP index" stream per
      44                 :   Lou Montulli's original spec:
      45                 : 
      46                 :   http://www.mozilla.org/projects/netlib/dirindexformat.html
      47                 : 
      48                 :  */
      49                 : 
      50                 : #include "nsEscape.h"
      51                 : #include "nsDirectoryIndexStream.h"
      52                 : #include "nsXPIDLString.h"
      53                 : #include "prio.h"
      54                 : #include "prlog.h"
      55                 : #include "prlong.h"
      56                 : #ifdef PR_LOGGING
      57                 : static PRLogModuleInfo* gLog;
      58                 : #endif
      59                 : 
      60                 : #include "nsISimpleEnumerator.h"
      61                 : #include "nsICollation.h"
      62                 : #include "nsILocale.h"
      63                 : #include "nsILocaleService.h"
      64                 : #include "nsCollationCID.h"
      65                 : #include "nsIPlatformCharset.h"
      66                 : #include "nsReadableUtils.h"
      67                 : #include "nsURLHelper.h"
      68                 : #include "nsNetUtil.h"
      69                 : #include "nsCRT.h"
      70                 : #include "nsNativeCharsetUtils.h"
      71                 : 
      72                 : // NOTE: This runs on the _file transport_ thread.
      73                 : // The problem is that now that we're actually doing something with the data,
      74                 : // we want to do stuff like i18n sorting. However, none of the collation stuff
      75                 : // is threadsafe.
      76                 : // So THIS CODE IS ASCII ONLY!!!!!!!! This is no worse than the current
      77                 : // behaviour, though. See bug 99382.
      78                 : // When this is fixed, #define THREADSAFE_I18N to get this code working
      79                 : 
      80                 : //#define THREADSAFE_I18N
      81                 : 
      82               3 : nsDirectoryIndexStream::nsDirectoryIndexStream()
      83               3 :     : mOffset(0), mStatus(NS_OK), mPos(0)
      84                 : {
      85                 : #ifdef PR_LOGGING
      86               3 :     if (! gLog)
      87               2 :         gLog = PR_NewLogModule("nsDirectoryIndexStream");
      88                 : #endif
      89                 : 
      90               3 :     PR_LOG(gLog, PR_LOG_DEBUG,
      91                 :            ("nsDirectoryIndexStream[%p]: created", this));
      92               3 : }
      93                 : 
      94            1295 : static int compare(nsIFile* aElement1, nsIFile* aElement2, void* aData)
      95                 : {
      96            1295 :     if (!NS_IsNativeUTF8()) {
      97                 :         // don't check for errors, because we can't report them anyway
      98               0 :         nsAutoString name1, name2;
      99               0 :         aElement1->GetLeafName(name1);
     100               0 :         aElement2->GetLeafName(name2);
     101                 : 
     102                 :         // Note - we should do the collation to do sorting. Why don't we?
     103                 :         // Because that is _slow_. Using TestProtocols to list file:///dev/
     104                 :         // goes from 3 seconds to 22. (This may be why nsXULSortService is
     105                 :         // so slow as well).
     106                 :         // Does this have bad effects? Probably, but since nsXULTree appears
     107                 :         // to use the raw RDF literal value as the sort key (which ammounts to an
     108                 :         // strcmp), it won't be any worse, I think.
     109                 :         // This could be made faster, by creating the keys once,
     110                 :         // but CompareString could still be smarter - see bug 99383 - bbaetz
     111                 :         // NB - 99393 has been WONTFIXed. So if the I18N code is ever made
     112                 :         // threadsafe so that this matters, we'd have to pass through a
     113                 :         // struct { nsIFile*, PRUint8* } with the pre-calculated key.
     114               0 :         return Compare(name1, name2);
     115                 :     }
     116                 : 
     117            2590 :     nsCAutoString name1, name2;
     118            1295 :     aElement1->GetNativeLeafName(name1);
     119            1295 :     aElement2->GetNativeLeafName(name2);
     120                 : 
     121            1295 :     return Compare(name1, name2);
     122                 : }
     123                 : 
     124                 : nsresult
     125               3 : nsDirectoryIndexStream::Init(nsIFile* aDir)
     126                 : {
     127                 :     nsresult rv;
     128                 :     bool isDir;
     129               3 :     rv = aDir->IsDirectory(&isDir);
     130               3 :     if (NS_FAILED(rv)) return rv;
     131               3 :     NS_PRECONDITION(isDir, "not a directory");
     132               3 :     if (!isDir)
     133               0 :         return NS_ERROR_ILLEGAL_VALUE;
     134                 : 
     135                 : #ifdef PR_LOGGING
     136               3 :     if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {
     137               0 :         nsCAutoString path;
     138               0 :         aDir->GetNativePath(path);
     139               0 :         PR_LOG(gLog, PR_LOG_DEBUG,
     140                 :                ("nsDirectoryIndexStream[%p]: initialized on %s",
     141                 :                 this, path.get()));
     142                 :     }
     143                 : #endif
     144                 : 
     145                 :     // Sigh. We have to allocate on the heap because there are no
     146                 :     // assignment operators defined.
     147               6 :     nsCOMPtr<nsISimpleEnumerator> iter;
     148               3 :     rv = aDir->GetDirectoryEntries(getter_AddRefs(iter));
     149               3 :     if (NS_FAILED(rv)) return rv;
     150                 : 
     151                 :     // Now lets sort, because clients expect it that way
     152                 :     // XXX - should we do so here, or when the first item is requested?
     153                 :     // XXX - use insertion sort instead?
     154                 : 
     155                 :     bool more;
     156               6 :     nsCOMPtr<nsISupports> elem;
     157             206 :     while (NS_SUCCEEDED(iter->HasMoreElements(&more)) && more) {
     158             200 :         rv = iter->GetNext(getter_AddRefs(elem));
     159             200 :         if (NS_SUCCEEDED(rv)) {
     160             400 :             nsCOMPtr<nsIFile> file = do_QueryInterface(elem);
     161             200 :             if (file)
     162             200 :                 mArray.AppendObject(file); // addrefs
     163                 :         }
     164                 :     }
     165                 : 
     166                 : #ifdef THREADSAFE_I18N
     167                 :     nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID,
     168                 :                                                   &rv);
     169                 :     if (NS_FAILED(rv)) return rv;
     170                 : 
     171                 :     nsCOMPtr<nsILocale> locale;
     172                 :     rv = ls->GetApplicationLocale(getter_AddRefs(locale));
     173                 :     if (NS_FAILED(rv)) return rv;
     174                 :     
     175                 :     nsCOMPtr<nsICollationFactory> cf = do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID,
     176                 :                                                          &rv);
     177                 :     if (NS_FAILED(rv)) return rv;
     178                 : 
     179                 :     nsCOMPtr<nsICollation> coll;
     180                 :     rv = cf->CreateCollation(locale, getter_AddRefs(coll));
     181                 :     if (NS_FAILED(rv)) return rv;
     182                 : 
     183                 :     mArray.Sort(compare, coll);
     184                 : #else
     185               3 :     mArray.Sort(compare, nsnull);
     186                 : #endif
     187                 : 
     188               3 :     mBuf.AppendLiteral("300: ");
     189               6 :     nsCAutoString url;
     190               3 :     rv = net_GetURLSpecFromFile(aDir, url);
     191               3 :     if (NS_FAILED(rv)) return rv;
     192               3 :     mBuf.Append(url);
     193               3 :     mBuf.Append('\n');
     194                 : 
     195               3 :     mBuf.AppendLiteral("200: filename content-length last-modified file-type\n");
     196                 : 
     197               3 :     return NS_OK;
     198                 : }
     199                 : 
     200               6 : nsDirectoryIndexStream::~nsDirectoryIndexStream()
     201                 : {
     202               3 :     PR_LOG(gLog, PR_LOG_DEBUG,
     203                 :            ("nsDirectoryIndexStream[%p]: destroyed", this));
     204               3 : }
     205                 : 
     206                 : nsresult
     207               3 : nsDirectoryIndexStream::Create(nsIFile* aDir, nsIInputStream** aResult)
     208                 : {
     209               3 :     nsDirectoryIndexStream* result = new nsDirectoryIndexStream();
     210               3 :     if (! result)
     211               0 :         return NS_ERROR_OUT_OF_MEMORY;
     212                 : 
     213                 :     nsresult rv;
     214               3 :     rv = result->Init(aDir);
     215               3 :     if (NS_FAILED(rv)) {
     216               0 :         delete result;
     217               0 :         return rv;
     218                 :     }
     219                 : 
     220               3 :     *aResult = result;
     221               3 :     NS_ADDREF(*aResult);
     222               3 :     return NS_OK;
     223                 : }
     224                 : 
     225              68 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsDirectoryIndexStream, nsIInputStream)
     226                 : 
     227                 : // The below routines are proxied to the UI thread!
     228                 : NS_IMETHODIMP
     229               2 : nsDirectoryIndexStream::Close()
     230                 : {
     231               2 :     mStatus = NS_BASE_STREAM_CLOSED;
     232               2 :     return NS_OK;
     233                 : }
     234                 : 
     235                 : NS_IMETHODIMP
     236             930 : nsDirectoryIndexStream::Available(PRUint32* aLength)
     237                 : {
     238             930 :     if (NS_FAILED(mStatus))
     239               0 :         return mStatus;
     240                 : 
     241                 :     // If there's data in our buffer, use that
     242             930 :     if (mOffset < (PRInt32)mBuf.Length()) {
     243             465 :         *aLength = mBuf.Length() - mOffset;
     244             465 :         return NS_OK;
     245                 :     }
     246                 : 
     247                 :     // Returning one byte is not ideal, but good enough
     248             465 :     *aLength = (mPos < mArray.Count()) ? 1 : 0;
     249             465 :     return NS_OK;
     250                 : }
     251                 : 
     252                 : NS_IMETHODIMP
     253             314 : nsDirectoryIndexStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aReadCount)
     254                 : {
     255             314 :     if (mStatus == NS_BASE_STREAM_CLOSED) {
     256               0 :         *aReadCount = 0;
     257               0 :         return NS_OK;
     258                 :     }
     259             314 :     if (NS_FAILED(mStatus))
     260               0 :         return mStatus;
     261                 : 
     262             314 :     PRUint32 nread = 0;
     263                 : 
     264                 :     // If anything is enqueued (or left-over) in mBuf, then feed it to
     265                 :     // the reader first.
     266           11909 :     while (mOffset < (PRInt32)mBuf.Length() && aCount != 0) {
     267           11281 :         *(aBuf++) = char(mBuf.CharAt(mOffset++));
     268           11281 :         --aCount;
     269           11281 :         ++nread;
     270                 :     }
     271                 : 
     272                 :     // Room left?
     273             314 :     if (aCount > 0) {
     274             159 :         mOffset = 0;
     275             159 :         mBuf.Truncate();
     276                 : 
     277                 :         // Okay, now we'll suck stuff off of our iterator into the mBuf...
     278             518 :         while (PRUint32(mBuf.Length()) < aCount) {
     279             205 :             bool more = mPos < mArray.Count();
     280             205 :             if (!more) break;
     281                 : 
     282                 :             // don't addref, for speed - an addref happened when it
     283                 :             // was placed in the array, so it's not going to go stale
     284             200 :             nsIFile* current = mArray.ObjectAt(mPos);
     285             200 :             ++mPos;
     286                 : 
     287                 : #ifdef PR_LOGGING
     288             200 :             if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {
     289               0 :                 nsCAutoString path;
     290               0 :                 current->GetNativePath(path);
     291               0 :                 PR_LOG(gLog, PR_LOG_DEBUG,
     292                 :                        ("nsDirectoryIndexStream[%p]: iterated %s",
     293                 :                         this, path.get()));
     294                 :             }
     295                 : #endif
     296                 : 
     297                 :             // rjc: don't return hidden files/directories!
     298                 :             // bbaetz: why not?
     299                 :             nsresult rv;
     300                 : #ifndef XP_UNIX
     301                 :             bool hidden = false;
     302                 :             current->IsHidden(&hidden);
     303                 :             if (hidden) {
     304                 :                 PR_LOG(gLog, PR_LOG_DEBUG,
     305                 :                        ("nsDirectoryIndexStream[%p]: skipping hidden file/directory",
     306                 :                         this));
     307                 :                 continue;
     308                 :             }
     309                 : #endif
     310                 : 
     311             200 :             PRInt64 fileSize = 0;
     312             200 :             current->GetFileSize( &fileSize );
     313                 : 
     314             200 :             PRInt64 fileInfoModifyTime = 0;
     315             200 :             current->GetLastModifiedTime( &fileInfoModifyTime );
     316             200 :             fileInfoModifyTime *= PR_USEC_PER_MSEC;
     317                 : 
     318             200 :             mBuf.AppendLiteral("201: ");
     319                 : 
     320                 :             // The "filename" field
     321             200 :             char* escaped = nsnull;
     322             200 :             if (!NS_IsNativeUTF8()) {
     323               0 :                 nsAutoString leafname;
     324               0 :                 rv = current->GetLeafName(leafname);
     325               0 :                 if (NS_FAILED(rv)) return rv;
     326               0 :                 if (!leafname.IsEmpty())
     327               0 :                     escaped = nsEscape(NS_ConvertUTF16toUTF8(leafname).get(), url_Path);
     328                 :             } else {
     329             400 :                 nsCAutoString leafname;
     330             200 :                 rv = current->GetNativeLeafName(leafname);
     331             200 :                 if (NS_FAILED(rv)) return rv;
     332             200 :                 if (!leafname.IsEmpty())
     333             200 :                     escaped = nsEscape(leafname.get(), url_Path);
     334                 :             }
     335             200 :             if (escaped) {
     336             200 :                 mBuf += escaped;
     337             200 :                 mBuf.Append(' ');
     338             200 :                 nsMemory::Free(escaped);
     339                 :             }
     340                 : 
     341                 :             // The "content-length" field
     342             200 :             mBuf.AppendInt(fileSize, 10);
     343             200 :             mBuf.Append(' ');
     344                 : 
     345                 :             // The "last-modified" field
     346                 :             PRExplodedTime tm;
     347             200 :             PR_ExplodeTime(fileInfoModifyTime, PR_GMTParameters, &tm);
     348                 :             {
     349                 :                 char buf[64];
     350             200 :                 PR_FormatTimeUSEnglish(buf, sizeof(buf), "%a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ", &tm);
     351             200 :                 mBuf.Append(buf);
     352                 :             }
     353                 : 
     354                 :             // The "file-type" field
     355             200 :             bool isFile = true;
     356             200 :             current->IsFile(&isFile);
     357             200 :             if (isFile) {
     358             147 :                 mBuf.AppendLiteral("FILE ");
     359                 :             }
     360                 :             else {
     361                 :                 bool isDir;
     362              53 :                 rv = current->IsDirectory(&isDir);
     363              53 :                 if (NS_FAILED(rv)) return rv; 
     364              53 :                 if (isDir) {
     365              53 :                     mBuf.AppendLiteral("DIRECTORY ");
     366                 :                 }
     367                 :                 else {
     368                 :                     bool isLink;
     369               0 :                     rv = current->IsSymlink(&isLink);
     370               0 :                     if (NS_FAILED(rv)) return rv; 
     371               0 :                     if (isLink) {
     372               0 :                         mBuf.AppendLiteral("SYMBOLIC-LINK ");
     373                 :                     }
     374                 :                 }
     375                 :             }
     376                 : 
     377             200 :             mBuf.Append('\n');
     378                 :         }
     379                 : 
     380                 :         // ...and once we've either run out of directory entries, or
     381                 :         // filled up the buffer, then we'll push it to the reader.
     382            3732 :         while (mOffset < (PRInt32)mBuf.Length() && aCount != 0) {
     383            3414 :             *(aBuf++) = char(mBuf.CharAt(mOffset++));
     384            3414 :             --aCount;
     385            3414 :             ++nread;
     386                 :         }
     387                 :     }
     388                 : 
     389             314 :     *aReadCount = nread;
     390             314 :     return NS_OK;
     391                 : }
     392                 : 
     393                 : NS_IMETHODIMP
     394               1 : nsDirectoryIndexStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
     395                 : {
     396               1 :     return NS_ERROR_NOT_IMPLEMENTED;
     397                 : }
     398                 : 
     399                 : NS_IMETHODIMP
     400               3 : nsDirectoryIndexStream::IsNonBlocking(bool *aNonBlocking)
     401                 : {
     402               3 :     *aNonBlocking = false;
     403               3 :     return NS_OK;
     404                 : }

Generated by: LCOV version 1.7