sbFileSystemTree.h
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-2009 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 
27 #ifndef sbFileSystemTree_h_
28 #define sbFileSystemTree_h_
29 
30 #include <nsAutoPtr.h>
31 #include <nsStringAPI.h>
32 #include <nsILocalFile.h>
33 #include <nsIThread.h>
34 #include <nsTArray.h>
35 #include <prlock.h>
36 #include <stack>
37 #include "sbFileSystemNode.h"
39 #include "sbFileSystemTreeState.h"
40 #include "sbPIFileSystemTree.h"
41 
44 struct NodeContext;
45 
46 typedef nsTArray<nsRefPtr<sbFileSystemNodeChange> > sbNodeChangeArray;
47 typedef nsTArray<nsRefPtr<sbFileSystemPathChange> > sbPathChangeArray;
48 typedef std::stack<NodeContext> sbNodeContextStack;
49 
50 
51 //------------------------------------------------------------------------------
52 // A class to build a tree snapsot of a filesystem specified at a root.
53 //------------------------------------------------------------------------------
55 {
56  friend class sbFileSystemTreeState;
57 
58 public:
60  virtual ~sbFileSystemTree();
61 
63  NS_DECL_SBPIFILESYSTEMTREE
64 
65  //
66  // \brief Initialize the tree with a given path.
67  // \param aPath The file path to root from.
68  // \param aIsRecursive If the tree should watch recursively from the
69  // given path.
70  //
71  nsresult Init(const nsAString & aPath, PRBool aIsRecursive);
72 
73  //
74  // \brief Init a tree from a saved session.
75  // \param aSessionGuid The saved tree session GUID.
76  //
77  nsresult InitWithTreeSession(nsID & aSessionID);
78 
79  //
80  // \brief Inform the tree to sync at a given path.
81  // \param aPath The path to sync at.
82  //
83  nsresult Update(const nsAString & aPath);
84 
85  //
86  // \brief Set the tree listener.
87  // \param The listener to assign for this tree.
88  //
89  nsresult SetListener(sbFileSystemTreeListener *aListener);
90 
91  //
92  // \brief Clear the tree listener.
93  //
94  nsresult ClearListener();
95 
96  //
97  // \brief Save the current state of a tree. The session ID passed in
98  // to this method can be used in |InitWithTreeSession()| to restore
99  // a tree from a save performed in this method.
100  // \param aSessionID The session ID to associate to the saved tree.
101  //
102  nsresult SaveTreeSession(const nsID & aSessionID);
103 
104  //
105  // \brief Get a string that has a native trailing path component.
106  // For example:
107  // INPUT: "/foo/bar"
108  // OUTPUT: "/foo/bar/"
109  //
110  nsString EnsureTrailingPath(const nsAString & aFilePath);
111 
112 protected:
113  //
114  // \brief Internal initialization method.
115  //
116  nsresult InitTree();
117 
118  //
119  // \brief Add children to a given parent node at a specified path.
120  // \param aPath The path of the children to add.
121  // \param aParentNode The parent node of the children to add.
122  // \param aBuildDiscoveredDirArray Option to enable logging all directories
123  // discovered into |mDiscoveredDirs|. This is usually only done on
124  // the initial tree build.
125  // \param aNotifyListener Option to notify listeners of each node that
126  // is added to the child list.
127  //
128  nsresult AddChildren(const nsAString & aPath,
129  sbFileSystemNode *aParentNode,
130  PRBool aBuildDiscoveredDirArray,
131  PRBool aNotifyListener);
132 
133  //
134  // \brief Get the children that are currently at the given path and
135  // assign them a parent node.
136  // \param aPath The path to get the children at.
137  // \param aParentNode The parent node to assign to each of the nodes.
138  // \param aNodeMap The child node map to assign the path's children to.
139  //
140  nsresult GetChildren(const nsAString & aPath,
141  sbFileSystemNode *aParentNode,
142  sbNodeMap & aNodeMap);
143 
144  //
145  // \brief Get a node from the from the current saved snapshot at a
146  // specified path. Note that the absolute path for |aRootSearchNode|
147  // is assumed to be the same as the current absolute root path for
148  // the tree.
149  // \param aPath The path of the node to find
150  // \param aRootSearchNode The root node to search from.
151  // \param aNodeRetVal The result node of the search.
152  //
153  nsresult GetNode(const nsAString & aPath,
154  sbFileSystemNode * aRootSearchNode,
155  sbFileSystemNode **aNodeRetVal);
156 
157  //
158  // \brief Create a node for a given |nsIFile| spec.
159  // \param aFile The file spec to use for the node creation
160  // \param aParentNode The parent node to assign to the new node.
161  // \param aNodeRetVal The out-param result node.
162  //
163  nsresult CreateNode(nsIFile *aFile,
164  sbFileSystemNode *aParentNode,
165  sbFileSystemNode **aNodeRetVal);
166 
167  //
168  // \brief This method looks at all the current directory entries and
169  // generates a change log of all the differences between the
170  // children that are currently stored in |aNode|.
171  // \param aNode The path node that is used for comparing its children
172  // against.
173  // \param aNodePath The absolute path of the |aNode|.
174  // \param aOutChangeArray The arrary of changes (as nodes) found during
175  // the compare.
176  //
177  nsresult GetNodeChanges(sbFileSystemNode *aNode,
178  const nsAString & aNodePath,
179  sbNodeChangeArray & aOutChangeArray);
180 
181  //
182  // \brief This method compares an old root node (usually from
183  // de-serialization) to the current root node. All changes are
184  // are reported as paths and assigned into the passed in array.
185  // \param aOldRootNode The old root node to compare against the current
186  // root node.
187  // \param aOutChangeArray The path change array to append all found changes
188  // into.
189  //
190  nsresult GetTreeChanges(sbFileSystemNode *aOldRootNode,
191  sbPathChangeArray & aOutChangeArray);
192 
193  //
194  // \brief Notify the tree listeners that a directory was added by informing
195  // them of all the children inside the new directory. This function
196  // will not report the change event specified at the passed in full
197  // path.
198  // \param aAddedDirNode The node representing the directory that was added.
199  // \param aFullPath The absolute path of the new directory.
200  //
201  nsresult NotifyDirAdded(sbFileSystemNode *aAddedDirNode,
202  nsAString & aFullPath);
203 
204  //
205  // \brief Notify the tree listeners that a directory was removed by
206  // informing them off all the children inside the directory. This
207  // function will not report the change event specified at the passed
208  // in full path.
209  // \param aRemovedDirNode The node representing the directory that was
210  // removed.
211  // \param aFullPath The absolute path of the removed directory.
212  //
213  nsresult NotifyDirRemoved(sbFileSystemNode *aRemovedDirNode,
214  nsAString & aFullPath);
215 
216  //
217  // \brief Utility method for getting a enumerator of the entries in a
218  // directory at a given path.
219  // \param aPath The path to get the entries at.
220  // \param aResultEnum The out-param enumerator for the entries.
221  //
222  static nsresult GetPathEntries(const nsAString & aPath,
223  nsISimpleEnumerator **aResultEnum);
224 
225  //
226  // \brief Compare the timestamps on two nodes to determine if there has
227  // been modification (via last modification time stamps).
228  // \param aNode1 The first node to compare against the second.
229  // \param aNode2 The second node to compare against the first.
230  // \param aIsSame Sets PR_TRUE if the nodes are the same, PR_FALSE if not.
231  //
232  static nsresult CompareNodes(sbFileSystemNode *aNode1,
233  sbFileSystemNode *aNode2,
234  PRBool *aIsSame);
235 
236  //
237  // \brief Report all nodes and their children that are contained in a node
238  // stack. |aContextStack| should have at least one or more nodes to
239  // start with. Use this method if an entire chunk of a tree needs to
240  // be reported with the same change event type.
241  // \param aContextStack The node context stack.
242  // \param aChangeType The change type to report.
243  // \param aChangeArray The change array to append the changes onto.
244  //
245  nsresult CreateTreeEvents(sbNodeContextStack & aContextStack,
246  EChangeType aChangeType,
247  sbPathChangeArray & aChangeArray);
248 
249  //
250  // \brief Utility method for creating and appending a change item to
251  // a change array with a given node and change type.
252  // \param aChangedNode The node that has changed to use with the change item.
253  // \param aChangeType The change type for the change item.
254  // \param aChangeArray The change array to append the change item onto.
255  //
256  static nsresult AppendCreateNodeChangeItem(sbFileSystemNode *aChangedNode,
257  EChangeType aChangeType,
258  sbNodeChangeArray & aChangeArray);
259 
260  //
261  // \brief Utility method for creating and appending a change item to a
262  // change array with a given event path and change type.
263  // \param aEventPath The absolute path of the event.
264  // \param aChangeType The type of change for the change item.
265  // \param aChangeArray The change array to append the change item onto.
266  //
267  static nsresult AppendCreatePathChangeItem(const nsAString & aEventPath,
268  EChangeType aChangeType,
269  sbPathChangeArray & aChangeArray);
270 
271  //
272  // \brief Background thread method for doing the initial build of the
273  // file system tree. Once the build is complete, the listeners
274  // will be notified via the |OnTreeReady()| function.
275  //
276  void RunBuildThread();
277 
278  //
279  // \brief Internal method for informing tree listeners that the tree has been
280  // built on the main thread.
281  //
282  void NotifyBuildComplete();
283 
284  //
285  // \brief Internal method for informing tree listeners that the tree could
286  // not start up because the root watch path is not available.
287  //
289 
290  //
291  // \brief Internal method for informing tree listeners that the tree could
292  // not be restored from a previous session on the main thread.
293  //
294  void NotifySessionLoadError();
295 
296 private:
297  nsRefPtr<sbFileSystemNode> mRootNode;
298  nsCOMPtr<nsIThread> mOwnerContextThread;
299  nsCOMPtr<nsILocalFile> mRootFile;
300  sbFileSystemTreeListener *mListener;
301  nsString mRootPath;
302  PRBool mIsRecursiveBuild;
303  PRBool mShouldLoadSession;
304  PRBool mIsIntialized;
305  PRLock *mRootNodeLock;
306  PRLock *mListenerLock;
307  sbStringArray mDiscoveredDirs;
308  sbPathChangeArray mSessionChanges;
309  nsID mSavedSessionID;
310 };
311 
312 #endif
313 
nsresult SetListener(sbFileSystemTreeListener *aListener)
nsresult NotifyDirAdded(sbFileSystemNode *aAddedDirNode, nsAString &aFullPath)
nsresult GetNode(const nsAString &aPath, sbFileSystemNode *aRootSearchNode, sbFileSystemNode **aNodeRetVal)
_updateCookies aPath
nsresult SaveTreeSession(const nsID &aSessionID)
static nsresult GetPathEntries(const nsAString &aPath, nsISimpleEnumerator **aResultEnum)
nsresult GetChildren(const nsAString &aPath, sbFileSystemNode *aParentNode, sbNodeMap &aNodeMap)
nsTArray< nsString > sbStringArray
nsresult InitWithTreeSession(nsID &aSessionID)
nsresult GetNodeChanges(sbFileSystemNode *aNode, const nsAString &aNodePath, sbNodeChangeArray &aOutChangeArray)
nsresult GetTreeChanges(sbFileSystemNode *aOldRootNode, sbPathChangeArray &aOutChangeArray)
NS_DECL_ISUPPORTS NS_DECL_SBPIFILESYSTEMTREE nsresult Init(const nsAString &aPath, PRBool aIsRecursive)
nsresult AddChildren(const nsAString &aPath, sbFileSystemNode *aParentNode, PRBool aBuildDiscoveredDirArray, PRBool aNotifyListener)
nsresult CreateNode(nsIFile *aFile, sbFileSystemNode *aParentNode, sbFileSystemNode **aNodeRetVal)
static nsresult AppendCreatePathChangeItem(const nsAString &aEventPath, EChangeType aChangeType, sbPathChangeArray &aChangeArray)
std::map< nsString, nsRefPtr< sbFileSystemNode > > sbNodeMap
nsresult NotifyDirRemoved(sbFileSystemNode *aRemovedDirNode, nsAString &aFullPath)
nsTArray< nsRefPtr< sbFileSystemPathChange > > sbPathChangeArray
virtual ~sbFileSystemTree()
nsTArray< nsRefPtr< sbFileSystemNodeChange > > sbNodeChangeArray
std::stack< NodeContext > sbNodeContextStack
static nsresult CompareNodes(sbFileSystemNode *aNode1, sbFileSystemNode *aNode2, PRBool *aIsSame)
nsresult Update(const nsAString &aPath)
nsString EnsureTrailingPath(const nsAString &aFilePath)
nsresult CreateTreeEvents(sbNodeContextStack &aContextStack, EChangeType aChangeType, sbPathChangeArray &aChangeArray)
static nsresult AppendCreateNodeChangeItem(sbFileSystemNode *aChangedNode, EChangeType aChangeType, sbNodeChangeArray &aChangeArray)