sbFileScan.cpp
Go to the documentation of this file.
1 /*
2  //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25  */
26 
32 // INCLUDES ===================================================================
33 #include "sbFileScan.h"
34 #include <nspr.h>
35 #include <prmem.h>
36 #include <prmon.h>
37 #include <prlog.h>
38 
39 #include <nsMemory.h>
40 #include <nsAutoLock.h> // for nsAutoMonitor
41 #include <nsIIOService.h>
42 #include <nsIURI.h>
43 #include <nsUnicharUtils.h>
44 #include <nsISupportsPrimitives.h>
45 #include <nsArrayUtils.h>
46 #include <nsThreadUtils.h>
47 #include <nsStringGlue.h>
48 #include <nsIMutableArray.h>
49 #include <nsIThreadPool.h>
50 #include <nsNetUtil.h>
51 #include <sbILibraryUtils.h>
52 #include <sbIDirectoryEnumerator.h>
53 #include <sbLockUtils.h>
54 #include <sbDebugUtils.h>
55 
56 
62 // CLASSES ====================================================================
63 //*****************************************************************************
64 // sbFileScanQuery Class
65 //*****************************************************************************
66 /* Implementation file */
68 
69 //-----------------------------------------------------------------------------
71  : m_pDirectoryLock(PR_NewLock())
72  , m_pCurrentPathLock(PR_NewLock())
73  , m_bSearchHidden(PR_FALSE)
74  , m_bRecurse(PR_FALSE)
75  , m_bWantLibraryContentURIs(PR_TRUE)
76  , m_pScanningLock(PR_NewLock())
77  , m_bIsScanning(PR_FALSE)
78  , m_pCallbackLock(PR_NewLock())
79  , m_pExtensionsLock(PR_NewLock())
80  , m_pFlaggedFileExtensionsLock(PR_NewLock())
81  , m_pCancelLock(PR_NewLock())
82  , m_bCancel(PR_FALSE)
83 {
84  NS_ASSERTION(m_pDirectoryLock, "FileScanQuery.m_pDirectoryLock failed");
85  NS_ASSERTION(m_pCurrentPathLock, "FileScanQuery.m_pCurrentPathLock failed");
86  NS_ASSERTION(m_pCallbackLock, "FileScanQuery.m_pCallbackLock failed");
87  NS_ASSERTION(m_pExtensionsLock, "FileScanQuery.m_pExtensionsLock failed");
88  NS_ASSERTION(m_pFlaggedFileExtensionsLock,
89  "FileScanQuery.m_pFlaggedFileExtensionsLock failed!");
90  NS_ASSERTION(m_pScanningLock, "FileScanQuery.m_pScanningLock failed");
91  NS_ASSERTION(m_pCancelLock, "FileScanQuery.m_pCancelLock failed");
92  MOZ_COUNT_CTOR(sbFileScanQuery);
93  init();
94 } //ctor
95 
96 //-----------------------------------------------------------------------------
97 sbFileScanQuery::sbFileScanQuery(const nsString & strDirectory,
98  const PRBool & bRecurse,
99  sbIFileScanCallback *pCallback)
100  : m_pDirectoryLock(PR_NewLock())
101  , m_strDirectory(strDirectory)
102  , m_pCurrentPathLock(PR_NewLock())
103  , m_bSearchHidden(PR_FALSE)
104  , m_bRecurse(bRecurse)
105  , m_bWantLibraryContentURIs(PR_TRUE)
106  , m_pScanningLock(PR_NewLock())
107  , m_bIsScanning(PR_FALSE)
108  , m_pCallbackLock(PR_NewLock())
109  , m_pCallback(pCallback)
110  , m_pExtensionsLock(PR_NewLock())
111  , m_pFlaggedFileExtensionsLock(PR_NewLock())
112  , m_pCancelLock(PR_NewLock())
113  , m_bCancel(PR_FALSE)
114 {
115  NS_ASSERTION(m_pDirectoryLock, "FileScanQuery.m_pDirectoryLock failed");
116  NS_ASSERTION(m_pCurrentPathLock, "FileScanQuery.m_pCurrentPathLock failed");
117  NS_ASSERTION(m_pCallbackLock, "FileScanQuery.m_pCallbackLock failed");
118  NS_ASSERTION(m_pExtensionsLock, "FileScanQuery.m_pExtensionsLock failed");
119  NS_ASSERTION(m_pFlaggedFileExtensionsLock,
120  "FileScanQuery.m_pFlaggedFileExtensionsLock failed!");
121  NS_ASSERTION(m_pScanningLock, "FileScanQuery.m_pScanningLock failed");
122  NS_ASSERTION(m_pCancelLock, "FileScanQuery.m_pCancelLock failed");
123  MOZ_COUNT_CTOR(sbFileScanQuery);
124  init();
125 } //ctor
126 
128 {
129  m_pFileStack = nsnull;
130  m_pFlaggedFileStack = nsnull;
131  m_lastSeenExtension = EmptyString();
132 
133  {
134  nsAutoLock lock(m_pExtensionsLock);
135  PRBool SB_UNUSED_IN_RELEASE(success) = m_Extensions.Init();
136  NS_ASSERTION(success, "FileScanQuery.m_Extensions failed to be initialized");
137  }
138 
139  {
140  nsAutoLock lock(m_pFlaggedFileExtensionsLock);
141 
142  PRBool SB_UNUSED_IN_RELEASE(success) = m_FlaggedExtensions.Init();
143  NS_ASSERTION(success,
144  "FileScanQuery.m_FlaggedExtensions failed to be initialized!");
145  }
146 
147  SB_PRLOG_SETUP(sbMediaImportFileScan);
148 }
149 
150 //-----------------------------------------------------------------------------
152 {
153  MOZ_COUNT_DTOR(sbFileScanQuery);
154  if (m_pDirectoryLock)
155  PR_DestroyLock(m_pDirectoryLock);
156  if (m_pCurrentPathLock)
157  PR_DestroyLock(m_pCurrentPathLock);
158  if (m_pCallbackLock)
159  PR_DestroyLock(m_pCallbackLock);
160  if (m_pExtensionsLock)
161  PR_DestroyLock(m_pExtensionsLock);
163  PR_DestroyLock(m_pFlaggedFileExtensionsLock);
164  if (m_pScanningLock)
165  PR_DestroyLock(m_pScanningLock);
166  if (m_pCancelLock)
167  PR_DestroyLock(m_pCancelLock);
168 } //dtor
169 
170 //-----------------------------------------------------------------------------
171 /* attribute boolean searchHidden; */
172 NS_IMETHODIMP sbFileScanQuery::GetSearchHidden(PRBool *aSearchHidden)
173 {
174  NS_ENSURE_ARG_POINTER(aSearchHidden);
175  *aSearchHidden = m_bSearchHidden;
176  return NS_OK;
177 } //GetSearchHidden
178 
179 //-----------------------------------------------------------------------------
180 NS_IMETHODIMP sbFileScanQuery::SetSearchHidden(PRBool aSearchHidden)
181 {
182  m_bSearchHidden = aSearchHidden;
183  return NS_OK;
184 } //SetSearchHidden
185 
186 //-----------------------------------------------------------------------------
187 /* void SetDirectory (in wstring strDirectory); */
188 NS_IMETHODIMP sbFileScanQuery::SetDirectory(const nsAString &strDirectory)
189 {
190  nsAutoLock lock(m_pDirectoryLock);
191 
192  nsresult rv;
193  if (!m_pFileStack) {
194  m_pFileStack =
195  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
196  NS_ENSURE_SUCCESS(rv, rv);
197  }
198  if (!m_pFlaggedFileStack) {
200  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
201  NS_ENSURE_SUCCESS(rv, rv);
202  }
203 
204  m_strDirectory = strDirectory;
205  return NS_OK;
206 } //SetDirectory
207 
208 //-----------------------------------------------------------------------------
209 /* wstring GetDirectory (); */
210 NS_IMETHODIMP sbFileScanQuery::GetDirectory(nsAString &_retval)
211 {
212  PR_Lock(m_pDirectoryLock);
213  _retval = m_strDirectory;
214  PR_Unlock(m_pDirectoryLock);
215  return NS_OK;
216 } //GetDirectory
217 
218 //-----------------------------------------------------------------------------
219 /* void SetRecurse (in PRBool bRecurse); */
220 NS_IMETHODIMP sbFileScanQuery::SetRecurse(PRBool bRecurse)
221 {
222  m_bRecurse = bRecurse;
223  return NS_OK;
224 } //SetRecurse
225 
226 //-----------------------------------------------------------------------------
227 /* PRBool GetRecurse (); */
228 NS_IMETHODIMP sbFileScanQuery::GetRecurse(PRBool *_retval)
229 {
230  NS_ENSURE_ARG_POINTER(_retval);
231  *_retval = m_bRecurse;
232  return NS_OK;
233 } //GetRecurse
234 
235 //-----------------------------------------------------------------------------
236 NS_IMETHODIMP sbFileScanQuery::AddFileExtension(const nsAString &strExtension)
237 {
238  nsAutoLock lock(m_pExtensionsLock);
239 
240  nsAutoString extStr(strExtension);
241  ToLowerCase(extStr);
242  if (!m_Extensions.GetEntry(extStr)) {
243  nsStringHashKey* hashKey = m_Extensions.PutEntry(extStr);
244  NS_ENSURE_TRUE(hashKey, NS_ERROR_OUT_OF_MEMORY);
245  }
246 
247  return NS_OK;
248 } //AddFileExtension
249 
250 //-----------------------------------------------------------------------------
251 NS_IMETHODIMP
252 sbFileScanQuery::AddFlaggedFileExtension(const nsAString & strExtension)
253 {
254  nsAutoLock lock(m_pFlaggedFileExtensionsLock);
255 
256  nsAutoString extStr(strExtension);
257  ToLowerCase(extStr);
258  if (!m_FlaggedExtensions.GetEntry(extStr)) {
259  nsStringHashKey *hashKey = m_FlaggedExtensions.PutEntry(extStr);
260  NS_ENSURE_TRUE(hashKey, NS_ERROR_OUT_OF_MEMORY);
261  }
262 
263  return NS_OK;
264 } //AddFlaggedFileExtension
265 
266 //-----------------------------------------------------------------------------
267 NS_IMETHODIMP
268 sbFileScanQuery::GetFlaggedExtensionsFound(PRBool *aOutIsFound)
269 {
270  NS_ENSURE_ARG_POINTER(aOutIsFound);
271 
272  *aOutIsFound = PR_FALSE;
273 
274  if (m_pFlaggedFileStack) {
275  PRUint32 length;
276  nsresult rv = m_pFlaggedFileStack->GetLength(&length);
277  NS_ENSURE_SUCCESS(rv, rv);
278 
279  *aOutIsFound = length > 0;
280  }
281 
282  return NS_OK;
283 }
284 
285 //-----------------------------------------------------------------------------
286 /* void SetCallback (in sbIFileScanCallback pCallback); */
287 NS_IMETHODIMP sbFileScanQuery::SetCallback(sbIFileScanCallback *pCallback)
288 {
289  NS_ENSURE_ARG_POINTER(pCallback);
290 
291  PR_Lock(m_pCallbackLock);
292 
293  m_pCallback = pCallback;
294 
295  PR_Unlock(m_pCallbackLock);
296 
297  return NS_OK;
298 } //SetCallback
299 
300 //-----------------------------------------------------------------------------
301 /* sbIFileScanCallback GetCallback (); */
302 NS_IMETHODIMP sbFileScanQuery::GetCallback(sbIFileScanCallback **_retval)
303 {
304  NS_ENSURE_ARG_POINTER(_retval);
305  PR_Lock(m_pCallbackLock);
306  NS_IF_ADDREF(*_retval = m_pCallback);
307  PR_Unlock(m_pCallbackLock);
308  return NS_OK;
309 } //GetCallback
310 
311 //-----------------------------------------------------------------------------
312 /* PRInt32 GetFileCount (); */
313 NS_IMETHODIMP sbFileScanQuery::GetFileCount(PRUint32 *_retval)
314 {
315  NS_ENSURE_ARG_POINTER(_retval);
316  if (m_pFileStack) {
317  m_pFileStack->GetLength(_retval);
318  } else {
319  // no stack, scanning never started
320  *_retval = 0;
321  }
322  LOG("sbFileScanQuery: reporting %d files\n", *_retval);
323  return NS_OK;
324 } //GetFileCount
325 
326 //-----------------------------------------------------------------------------
327 /* PRInt32 GetFlaggedFileCount (); */
328 NS_IMETHODIMP sbFileScanQuery::GetFlaggedFileCount(PRUint32 *_retval)
329 {
330  NS_ENSURE_ARG_POINTER(_retval);
331  if (m_pFlaggedFileStack) {
332  m_pFlaggedFileStack->GetLength(_retval);
333  }
334  else {
335  // no stack, scanning never started
336  *_retval = 0;
337  }
338 
339  LOG("sbFileScanQuery: reporting %d flagged files\n", *_retval);
340  return NS_OK;
341 } //GetFileCount
342 
343 //-----------------------------------------------------------------------------
344 /* void AddFilePath (in wstring strFilePath); */
345 NS_IMETHODIMP sbFileScanQuery::AddFilePath(const nsAString &strFilePath)
346 {
347  PRBool isFlagged = PR_FALSE;
348  const nsAutoString strExtension = GetExtensionFromFilename(strFilePath);
349  if (m_lastSeenExtension.IsEmpty() ||
350  !m_lastSeenExtension.Equals(strExtension, CaseInsensitiveCompare)) {
351  // m_lastSeenExtension could be set multiple times without lock guarded
352  // in theory. However, the race is benign and in practice, it is rare.
353  PRBool isValidExtension = VerifyFileExtension(strExtension, &isFlagged);
354  if (isValidExtension) {
355  m_lastSeenExtension = strExtension;
356  } else if (!isValidExtension && !isFlagged) {
357  LOG("sbFileScanQuery::AddFilePath, unrecognized extension: (%s) is seen\n",
358  NS_LossyConvertUTF16toASCII(strExtension).get());
359  return NS_OK;
360  }
361  }
362 
363  nsresult rv;
364  nsCOMPtr<nsISupportsString> string =
365  do_CreateInstance("@mozilla.org/supports-string;1", &rv);
366  NS_ENSURE_SUCCESS(rv, rv);
367 
368  rv = string->SetData(strFilePath);
369  NS_ENSURE_SUCCESS(rv, rv);
370 
371  if (isFlagged) {
372  rv = m_pFlaggedFileStack->AppendElement(string, PR_FALSE);
373  NS_ENSURE_SUCCESS(rv, rv);
374  }
375  else {
376  rv = m_pFileStack->AppendElement(string, PR_FALSE);
377  NS_ENSURE_SUCCESS(rv, rv);
378  }
379 
380  LOG("sbFileScanQuery::AddFilePath(%s)\n",
381  NS_LossyConvertUTF16toASCII(strFilePath).get());
382  return NS_OK;
383 } //AddFilePath
384 
385 //-----------------------------------------------------------------------------
386 /* wstring GetFilePath (in PRInt32 nIndex); */
387 NS_IMETHODIMP sbFileScanQuery::GetFilePath(PRUint32 nIndex, nsAString &_retval)
388 {
389  _retval = EmptyString();
390  NS_ENSURE_ARG_MIN(nIndex, 0);
391 
392  PRUint32 length;
393  m_pFileStack->GetLength(&length);
394  if (nIndex < length) {
395  nsresult rv;
396  nsCOMPtr<nsISupportsString> path = do_QueryElementAt(m_pFileStack, nIndex, &rv);
397  NS_ENSURE_SUCCESS(rv, rv);
398  path->GetData(_retval);
399  }
400 
401  return NS_OK;
402 } //GetFilePath
403 
404 //------------------------------------------------------------------------------
405 /* AString getFlaggedFilePath(in PRUint32 nIndex); */
406 NS_IMETHODIMP
407 sbFileScanQuery::GetFlaggedFilePath(PRUint32 nIndex, nsAString &retVal)
408 {
409  retVal = EmptyString();
410  NS_ENSURE_ARG_MIN(nIndex, 0);
411 
412  PRUint32 length;
413  m_pFlaggedFileStack->GetLength(&length);
414  if (nIndex < length) {
415  nsresult rv;
416  nsCOMPtr<nsISupportsString> path =
417  do_QueryElementAt(m_pFlaggedFileStack, nIndex, &rv);
418  NS_ENSURE_SUCCESS(rv, rv);
419 
420  path->GetData(retVal);
421  }
422 
423  return NS_OK;
424 } //getFlaggedFilePath
425 
426 //-----------------------------------------------------------------------------
427 /* PRBool IsScanning (); */
428 NS_IMETHODIMP sbFileScanQuery::IsScanning(PRBool *_retval)
429 {
430  NS_ENSURE_ARG_POINTER(_retval);
431  PR_Lock(m_pScanningLock);
432  *_retval = m_bIsScanning;
433  PR_Unlock(m_pScanningLock);
434  return NS_OK;
435 } //IsScanning
436 
437 //-----------------------------------------------------------------------------
438 /* void SetIsScanning (in PRBool bIsScanning); */
439 NS_IMETHODIMP sbFileScanQuery::SetIsScanning(PRBool bIsScanning)
440 {
441  PR_Lock(m_pScanningLock);
442  m_bIsScanning = bIsScanning;
443  PR_Unlock(m_pScanningLock);
444  return NS_OK;
445 } //SetIsScanning
446 
447 //-----------------------------------------------------------------------------
448 /* wstring GetLastFileFound (); */
449 NS_IMETHODIMP sbFileScanQuery::GetLastFileFound(nsAString &_retval)
450 {
451  PRUint32 length;
452  m_pFileStack->GetLength(&length);
453  if (length > 0) {
454  nsresult rv;
455  nsCOMPtr<nsISupportsString> path =
456  do_QueryElementAt(m_pFileStack, length - 1, &rv);
457  NS_ENSURE_SUCCESS(rv, rv);
458  path->GetData(_retval);
459  }
460  else {
461  _retval.Truncate();
462  }
463  return NS_OK;
464 } //GetLastFileFound
465 
466 //-----------------------------------------------------------------------------
467 /* wstring GetCurrentScanPath (); */
468 NS_IMETHODIMP sbFileScanQuery::GetCurrentScanPath(nsAString &_retval)
469 {
470  PR_Lock(m_pCurrentPathLock);
471  _retval = m_strCurrentPath;
472  PR_Unlock(m_pCurrentPathLock);
473  return NS_OK;
474 } //GetCurrentScanPath
475 
476 //-----------------------------------------------------------------------------
477 /* void SetCurrentScanPath (in wstring strScanPath); */
478 NS_IMETHODIMP sbFileScanQuery::SetCurrentScanPath(const nsAString &strScanPath)
479 {
480  PR_Lock(m_pCurrentPathLock);
481  m_strCurrentPath = strScanPath;
482  PR_Unlock(m_pCurrentPathLock);
483  return NS_OK;
484 } //SetCurrentScanPath
485 
486 //-----------------------------------------------------------------------------
487 /* void Cancel (); */
488 NS_IMETHODIMP sbFileScanQuery::Cancel()
489 {
490  PR_Lock(m_pCancelLock);
491  m_bCancel = PR_TRUE;
492  PR_Unlock(m_pCancelLock);
493  return NS_OK;
494 } //Cancel
495 
496 //-----------------------------------------------------------------------------
497 NS_IMETHODIMP sbFileScanQuery::GetResultRangeAsURIStrings(PRUint32 aStartIndex,
498  PRUint32 aEndIndex,
499  nsIArray** _retval)
500 {
501  PRUint32 length;
502  m_pFileStack->GetLength(&length);
503  NS_ENSURE_TRUE(aStartIndex < length, NS_ERROR_INVALID_ARG);
504  NS_ENSURE_TRUE(aEndIndex < length, NS_ERROR_INVALID_ARG);
505 
506  if (aStartIndex == 0 && aEndIndex == length - 1) {
507  NS_ADDREF(*_retval = m_pFileStack);
508  } else {
509  nsresult rv;
510  nsCOMPtr<nsIMutableArray> array =
511  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
512 
513  for (PRUint32 i = aStartIndex; i <= aEndIndex; i++) {
514  nsCOMPtr<nsISupportsString> uriSpec = do_QueryElementAt(m_pFileStack, i);
515  if (!uriSpec) {
516  continue;
517  }
518  rv = array->AppendElement(uriSpec, PR_FALSE);
519  NS_ENSURE_SUCCESS(rv, rv);
520 #if PR_LOGGING
521  nsAutoString s;
522  if (NS_SUCCEEDED(uriSpec->GetData(s)) && !s.IsEmpty()) {
523  LOG("sbFileScanQuery:: fetched URI %s\n", NS_LossyConvertUTF16toASCII(s).get());
524  }
525 #endif /* PR_LOGGING */
526  }
527  NS_ADDREF(*_retval = array);
528  }
529  LOG("sbFileScanQuery:: fetched URIs %d through %d\n", aStartIndex, aEndIndex);
530 
531  return NS_OK;
532 }
533 
534 //-----------------------------------------------------------------------------
535 /* PRBool IsCancelled (); */
536 NS_IMETHODIMP sbFileScanQuery::IsCancelled(PRBool *_retval)
537 {
538  NS_ENSURE_ARG_POINTER(_retval);
539  PR_Lock(m_pCancelLock);
540  *_retval = m_bCancel;
541  PR_Unlock(m_pCancelLock);
542  return NS_OK;
543 } //IsCancelled
544 
545 //-----------------------------------------------------------------------------
546 nsString sbFileScanQuery::GetExtensionFromFilename(const nsAString &strFilename)
547 {
548  nsAutoString str(strFilename);
549 
550  PRInt32 index = str.RFindChar(NS_L('.'));
551  if (index > -1)
552  return nsString(Substring(str, index + 1, str.Length() - index));
553 
554  return EmptyString();
555 } //GetExtensionFromFilename
556 
557 //-----------------------------------------------------------------------------
558 PRBool sbFileScanQuery::VerifyFileExtension(const nsAString &strExtension,
559  PRBool *aOutIsFlaggedExtension)
560 {
561  NS_ENSURE_ARG_POINTER(aOutIsFlaggedExtension);
562 
563  *aOutIsFlaggedExtension = PR_FALSE;
564  PRBool isValid = PR_FALSE;
565  nsAutoString extString;
566 
567  { // scoped lock
568  nsAutoLock lock(m_pExtensionsLock);
569 
570  extString = PromiseFlatString(strExtension);
571  ToLowerCase(extString);
572  isValid = m_Extensions.GetEntry(extString) != nsnull;
573  }
574 
575  // If the extension isn't valid, check to see if it is a flagged file
576  // extension and set the out param.
577  if (!isValid) {
578  { // scoped lock
579  nsAutoLock lock(m_pFlaggedFileExtensionsLock);
580 
581  *aOutIsFlaggedExtension =
582  m_FlaggedExtensions.GetEntry(extString) != nsnull;
583  }
584  }
585 
586  return isValid;
587 } //VerifyFileExtension
588 
589 //-----------------------------------------------------------------------------
590 /* attribute boolean wantContentURLs; */
591 NS_IMETHODIMP sbFileScanQuery::
592  GetWantLibraryContentURIs(PRBool *aWantLibraryContentURIs)
593 {
594  NS_ENSURE_ARG_POINTER(aWantLibraryContentURIs);
595  *aWantLibraryContentURIs = m_bWantLibraryContentURIs;
596  return NS_OK;
597 } //GetWantLibraryContentURIs
598 
599 //-----------------------------------------------------------------------------
600 NS_IMETHODIMP sbFileScanQuery::
601  SetWantLibraryContentURIs(PRBool aWantLibraryContentURIs)
602 {
603  m_bWantLibraryContentURIs = aWantLibraryContentURIs;
604  return NS_OK;
605 } //SetWantLibraryContentURIs
606 
607 
608 //*****************************************************************************
609 // sbFileScan Class
610 //*****************************************************************************
612 
613 //------------------------------------------------------------------------------
615 : m_ScanQueryQueueLock(nsAutoLock::NewLock("sbFileScan.m_ScanQueriesLock"))
616 , m_ScanQueryProcessorIsRunning(0)
617 , m_ThreadShouldShutdown(PR_FALSE)
618 , m_Finalized(PR_FALSE)
619 {
620  NS_ASSERTION(m_ScanQueryQueueLock, "sbFileScan.m_ScanQueriesLock failed");
621  MOZ_COUNT_CTOR(sbFileScan);
622 } //ctor
623 
624 //-----------------------------------------------------------------------------
626 {
627  MOZ_COUNT_DTOR(sbFileScan);
628  nsresult rv = NS_OK;
629  if (!m_Finalized) {
630  rv = Finalize();
631  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "sbFileScan::Finalize failed");
632  }
633  NS_ASSERTION(NS_SUCCEEDED(rv),
634  "Unable to shut down the query processor thread");
635 
636  if (m_ScanQueryQueueLock) {
637  nsAutoLock::DestroyLock(m_ScanQueryQueueLock);
638  }
639 } //dtor
640 
641 nsresult
643 {
644  // Shutdown the query processor thread if it is running.
646  m_ThreadShouldShutdown = PR_TRUE;
647 
648  nsCOMPtr<nsIThread> currentThread = do_GetCurrentThread();
649  NS_ENSURE_TRUE(currentThread, NS_ERROR_FAILURE);
650 
651  // Wait for the thread to get to a safe spot before shutting down. Shutting
652  // down the thread will cause problems if it's about to proxy.
654  NS_ProcessPendingEvents(currentThread);
656  PR_Sleep(PR_MillisecondsToInterval(100));
657  }
658  }
659  }
660 
661  return NS_OK;
662 }
663 
664 //-----------------------------------------------------------------------------
665 /* void SubmitQuery (in sbIFileScanQuery pQuery); */
666 NS_IMETHODIMP sbFileScan::SubmitQuery(sbIFileScanQuery *pQuery)
667 {
668  NS_ENSURE_ARG_POINTER(pQuery);
669  pQuery->AddRef();
670 
671  {
672  nsAutoLock autoQueryQueueLock(m_ScanQueryQueueLock);
673 
674  pQuery->SetIsScanning(PR_TRUE);
675  m_ScanQueryQueue.push_back(pQuery);
676  }
677 
678  // Start the query processor thread if needed.
681  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
682  "ERROR: Could not start the query processor thread!");
683  }
684 
685  return NS_OK;
686 } //SubmitQuery
687 
688 //-----------------------------------------------------------------------------
689 /* void finalize(); */
690 NS_IMETHODIMP sbFileScan::Finalize()
691 {
692  nsresult rv;
693  if (m_Finalized) {
694  NS_WARNING("sbFileScan::Finalize called more than once");
695  return NS_OK;
696  }
697  m_Finalized = PR_TRUE;
698  rv = Shutdown();
699  NS_ENSURE_SUCCESS(rv, rv);
700  return NS_OK;
701 }
702 
703 //-----------------------------------------------------------------------------
704 nsresult
706 {
707  // Start the query processor thread if it isn't already running and if the
708  // file scan service isn't shutting down.
710  nsresult rv;
711  nsCOMPtr<nsIThreadPool> threadPoolService =
712  do_GetService("@songbirdnest.com/Songbird/ThreadPoolService;1", &rv);
713  NS_ENSURE_SUCCESS(rv, rv);
714 
715  nsCOMPtr<nsIRunnable> runnable =
716  NS_NEW_RUNNABLE_METHOD(sbFileScan, this, RunProcessScanQueries);
717  NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);
718 
719  rv = threadPoolService->Dispatch(runnable, NS_DISPATCH_NORMAL);
720  NS_ENSURE_SUCCESS(rv, rv);
721  }
722 
723  return NS_OK;
724 }
725 
726 //-----------------------------------------------------------------------------
727 void
729 {
730  PR_AtomicSet(&m_ScanQueryProcessorIsRunning, 1);
731 
732  // This method will be run on a background thread and will process any scan
733  // queries as they are pushed into the process queue.
734  while (PR_TRUE) {
735  nsCOMPtr<sbIFileScanQuery> curScanQuery;
736  {
737  nsAutoLock queriesLock(m_ScanQueryQueueLock);
738 
739  // Ensure that there is at least one query to run and that the thread
740  // should be running.
741  if (m_ScanQueryQueue.size() == 0 || m_ThreadShouldShutdown) {
742  // Nothing in the query queue to process, break out of the thread.
743  break;
744  }
745 
746  // Now get the next scan query.
747  // NOTE: This query was already addref'd when it was pushed into the
748  // the query queue.
749  curScanQuery = dont_AddRef(m_ScanQueryQueue.front());
750  m_ScanQueryQueue.pop_front();
751  }
752 
753  if (!curScanQuery) {
754  // Fail safe.
755  continue;
756  }
757 
758  // Process this current scan query now.
759  nsresult rv;
760  rv = curScanQuery->SetIsScanning(PR_TRUE);
761  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
762  "WARNING: Could not inform the scan query to isScanning=true!");
763 
764  rv = ScanDirectory(curScanQuery);
765  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
766  "WARNING: Could not scan the current directory!");
767 
768  rv = curScanQuery->SetIsScanning(PR_FALSE);
769  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
770  "WARNING: Could not inform the scan query to isScanning=false!");
771  }
772 
773  PR_AtomicSet(&m_ScanQueryProcessorIsRunning, 0);
774 }
775 
776 //-----------------------------------------------------------------------------
777 nsresult
779 {
780  dirstack_t dirStack;
781  fileentrystack_t fileEntryStack;
782  entrystack_t entryStack;
783  nsresult rv;
784 
785  PRInt32 nFoundCount = 0;
786 
787  nsCOMPtr<nsILocalFile> pFile = do_CreateInstance("@mozilla.org/file/local;1");
788  nsCOMPtr<sbILibraryUtils> pLibraryUtils =
789  do_GetService("@songbirdnest.com/Songbird/library/Manager;1", &rv);
790  NS_ENSURE_SUCCESS(rv, rv);
791 
792  sbIFileScanCallback *pCallback = nsnull;
793  pQuery->GetCallback(&pCallback);
794 
795  PRBool bSearchHidden = PR_FALSE;
796  pQuery->GetSearchHidden(&bSearchHidden);
797 
798  PRBool bRecurse = PR_FALSE;
799  pQuery->GetRecurse(&bRecurse);
800 
801  nsString strTheDirectory;
802  pQuery->GetDirectory(strTheDirectory);
803 
804  PRBool bWantLibraryContentURIs = PR_TRUE;
805  pQuery->GetWantLibraryContentURIs(&bWantLibraryContentURIs);
806 
807  rv = pFile->InitWithPath(strTheDirectory);
808  if(NS_FAILED(rv)) return rv;
809 
810  PRBool bFlag = PR_FALSE;
811  pFile->IsDirectory(&bFlag);
812 
813  if(pCallback)
814  {
815  pCallback->OnFileScanStart();
816  }
817 
818  if(bFlag)
819  {
820  sbIDirectoryEnumerator * pDirEntries;
821  rv = sbGetDirectoryEntries(pFile, &pDirEntries);
822  NS_ENSURE_SUCCESS(rv, rv);
823 
824  PRBool keepRunning = !m_ThreadShouldShutdown;
825 
826  while(keepRunning)
827  {
828  // Allow us to get the hell out of here.
829  PRBool cancel = PR_FALSE;
830  pQuery->IsCancelled(&cancel);
831 
832  if (cancel) {
833  break;
834  }
835 
836  PRBool bHasMore = PR_FALSE;
837  rv = pDirEntries->HasMoreElements(&bHasMore);
838  nsCOMPtr<nsIFile> pEntry;
839  if(NS_SUCCEEDED(rv) && bHasMore) {
840  rv = pDirEntries->GetNext(getter_AddRefs(pEntry));
841  }
842 
843  if(NS_SUCCEEDED(rv) && pEntry)
844  {
845  PRBool bIsFile = PR_FALSE, bIsDirectory = PR_FALSE, bIsHidden = PR_FALSE;
846  pEntry->IsFile(&bIsFile);
847  pEntry->IsDirectory(&bIsDirectory);
848  pEntry->IsHidden(&bIsHidden);
849 
850  // If it's special, we always want to skip it. This causes files with a
851  // dot prefix to be treated as hidden which they are on Mac and Linux.
852  // Windows will include dot prefixed file as it did before the
853  // file scan reimplementation in bug 24478
854  PRBool isSpecial = PR_FALSE;
855  pEntry->IsSpecial(&isSpecial);
856 
857 #if XP_MACOSX
858  // If the path begins with a ._ we need to ignore on Mac. The Mac
859  // API's filter out these files as that designates that they are
860  // temporary files.
861  nsString fileName;
862  rv = pEntry->GetLeafName(fileName);
863  NS_ENSURE_SUCCESS(rv, rv);
864  isSpecial |= (fileName.Length() >= 2 &&
865  fileName[0] == PRUnichar('.') &&
866  fileName[1] == PRUnichar('_'));
867 #endif
868  if(!isSpecial && (!bIsHidden || bSearchHidden))
869  {
870  if(bIsFile)
871  {
872  // Get a library content URI for the file.
873  nsCOMPtr<nsIURI> pURI;
874  if (bWantLibraryContentURIs) {
875  rv = pLibraryUtils->GetFileContentURI(pEntry,
876  getter_AddRefs(pURI));
877  } else {
878  rv = NS_NewFileURI(getter_AddRefs(pURI), pEntry);
879  }
880 
881  // Get the file URI spec.
882  nsCAutoString spec;
883  if (NS_SUCCEEDED(rv)) {
884  rv = pURI->GetSpec(spec);
885  LOG("sbFileScan::ScanDirectory (C++) found spec: %s\n",
886  spec.get());
887  }
888 
889  // Add the file path to the query.
890  if (NS_SUCCEEDED(rv)) {
891  nsString strPath = NS_ConvertUTF8toUTF16(spec);
892  pQuery->AddFilePath(strPath);
893  nFoundCount += 1;
894 
895  if(pCallback)
896  {
897  pCallback->OnFileScanFile(strPath, nFoundCount);
898  }
899  }
900  }
901  else if(bIsDirectory && bRecurse)
902  {
903  sbIDirectoryEnumerator * pMoreEntries;
904  rv = CallCreateInstance(SB_DIRECTORYENUMERATOR_CONTRACTID,
905  &pMoreEntries);
906  NS_ENSURE_SUCCESS(rv, rv);
907 
908  rv = pMoreEntries->SetFilesOnly(PR_FALSE);
909  NS_ENSURE_SUCCESS(rv, rv);
910  rv = pMoreEntries->SetMaxDepth(1);
911  NS_ENSURE_SUCCESS(rv, rv);
912  rv = pMoreEntries->Enumerate(pEntry);
913  NS_ENSURE_SUCCESS(rv, rv);
914 
915  if(pEntry)
916  {
917  dirStack.push_back(pDirEntries);
918  fileEntryStack.push_back(pEntry);
919  entryStack.push_back(pEntry);
920 
921  pDirEntries = pMoreEntries;
922  }
923  }
924  }
925  }
926  else
927  {
928  if(dirStack.size())
929  {
930  NS_IF_RELEASE(pDirEntries);
931 
932  pDirEntries = dirStack.back();
933 
934  dirStack.pop_back();
935  fileEntryStack.pop_back();
936  entryStack.pop_back();
937  }
938  else
939  {
940  if(pCallback)
941  {
942  pCallback->OnFileScanEnd();
943  }
944 
945  NS_IF_RELEASE(pCallback);
946  NS_IF_RELEASE(pDirEntries);
947 
948  return NS_OK;
949  }
950  }
951 
952  // Yield.
953  PR_Sleep(PR_MillisecondsToInterval(0));
954 
955  // Check thread shutdown flag since it's possible for our thread
956  // to be in shutdown without the query being cancelled.
957  keepRunning = !m_ThreadShouldShutdown;
958  }
959  NS_IF_RELEASE(pDirEntries);
960 
961  }
962  else if(NS_SUCCEEDED(pFile->IsFile(&bFlag)) && bFlag)
963  {
964  pQuery->AddFilePath(strTheDirectory);
965  }
966 
967  if(pCallback)
968  {
969  pCallback->OnFileScanEnd();
970  }
971 
972  NS_IF_RELEASE(pCallback);
973 
974  dirstack_t::iterator it = dirStack.begin();
975  for(; it != dirStack.end(); ++it) {
976  NS_IF_RELEASE(*it);
977  }
978 
979  dirStack.clear();
980  fileEntryStack.clear();
981  entryStack.clear();
982 
983  return NS_OK;
984 } //ScanDirectory
std::deque< nsCOMPtr< nsIFile > > entrystack_t
Definition: sbFileScan.h:170
GeneratorThread currentThread
nsresult Shutdown()
Definition: sbFileScan.cpp:642
PRBool VerifyFileExtension(const nsAString &strExtension, PRBool *aOutIsFlaggedExtension)
Definition: sbFileScan.cpp:558
PRLock * m_pCancelLock
Definition: sbFileScan.h:131
#define SB_PRLOG_SETUP(x)
Definition: sbDebugUtils.h:115
return NS_OK
nsresult ScanDirectory(sbIFileScanQuery *pQuery)
Definition: sbFileScan.cpp:778
#define LOG(args)
PRLock * m_ScanQueryQueueLock
Definition: sbFileScan.h:174
PRBool m_bWantLibraryContentURIs
Definition: sbFileScan.h:110
NS_IMPL_ISUPPORTS1(sbDeviceCapabilitiesUtils, sbIDeviceCapabilitiesUtils) sbDeviceCapabilitiesUtils
inArray array
std::deque< nsCOMPtr< nsIFile > > fileentrystack_t
Definition: sbFileScan.h:169
PRLock * m_pScanningLock
Definition: sbFileScan.h:112
PRBool m_bRecurse
Definition: sbFileScan.h:109
PRLock * m_pExtensionsLock
Definition: sbFileScan.h:122
nsresult sbGetDirectoryEntries(nsIFile *aFile, sbIDirectoryEnumerator **aDirEntryEnumerator)
PRLock * m_pFlaggedFileExtensionsLock
Definition: sbFileScan.h:125
queryqueue_t m_ScanQueryQueue
Definition: sbFileScan.h:175
nsresult StartProcessScanQueriesProcessor()
Definition: sbFileScan.cpp:705
std::deque< sbIDirectoryEnumerator * > dirstack_t
Definition: sbFileScan.h:168
The callback to the sbIFileScanQuery interface.
Definition: sbIFileScan.idl:57
virtual ~sbFileScanQuery()
Definition: sbFileScan.cpp:151
PRLock * m_pCurrentPathLock
Definition: sbFileScan.h:105
void RunProcessScanQueries()
Definition: sbFileScan.cpp:728
PRLock * m_pCallbackLock
Definition: sbFileScan.h:115
#define SB_DIRECTORYENUMERATOR_CONTRACTID
PRBool m_bCancel
Definition: sbFileScan.h:132
nsTHashtable< nsStringHashKey > m_FlaggedExtensions
Definition: sbFileScan.h:126
nsString m_strCurrentPath
Definition: sbFileScan.h:106
_window init
Definition: FeedWriter.js:1144
nsCOMPtr< sbIFileScanCallback > m_pCallback
Definition: sbFileScan.h:116
NS_IMPL_THREADSAFE_ISUPPORTS1(sbDeviceCapsCompatibility, sbIDeviceCapsCompatibility) sbDeviceCapsCompatibility
nsString m_strDirectory
Definition: sbFileScan.h:103
PRBool m_bSearchHidden
Definition: sbFileScan.h:108
PRBool m_bIsScanning
Definition: sbFileScan.h:113
PRBool m_ThreadShouldShutdown
Definition: sbFileScan.h:180
virtual ~sbFileScan()
Definition: sbFileScan.cpp:625
nsString GetExtensionFromFilename(const nsAString &strFilename)
Definition: sbFileScan.cpp:546
nsCOMPtr< nsIMutableArray > m_pFileStack
Definition: sbFileScan.h:119
nsString m_lastSeenExtension
Definition: sbFileScan.h:129
The engine in which to execute sbIFileScanQuery objects.
PRLock * m_pDirectoryLock
Definition: sbFileScan.h:102
nsCOMPtr< nsIMutableArray > m_pFlaggedFileStack
Definition: sbFileScan.h:120
PRInt32 m_ScanQueryProcessorIsRunning
Definition: sbFileScan.h:177
An object to scan through the files of a folder (and optionally subfolders)
_getSelectedPageStyle s i
PRBool m_Finalized
Definition: sbFileScan.h:181
#define SB_UNUSED_IN_RELEASE(decl)
Definition: sbDebugUtils.h:55
nsTHashtable< nsStringHashKey > m_Extensions
Definition: sbFileScan.h:123