~ifolder-dev/simias/trunk-packaging

« back to all changes in this revision

Viewing changes to src/core/Sync/.svn/text-base/FileMonitor.cs.svn-base

  • Committer: Jorge O. Castro
  • Date: 2007-12-03 06:56:46 UTC
  • Revision ID: jorge@ubuntu.com-20071203065646-mupcnjcwgm5mnhyt
* Remove a bunch of .svn directories we no longer need.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
 |
3
 
 | Copyright (c) 2007 Novell, Inc.
4
 
 | All Rights Reserved.
5
 
 |
6
 
 | This program is free software; you can redistribute it and/or
7
 
 | modify it under the terms of version 2 of the GNU General Public License as
8
 
 | published by the Free Software Foundation.
9
 
 |
10
 
 | This program is distributed in the hope that it will be useful,
11
 
 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 | GNU General Public License for more details.
14
 
 |
15
 
 | You should have received a copy of the GNU General Public License
16
 
 | along with this program; if not, contact Novell, Inc.
17
 
 |
18
 
 | To contact Novell about this file by physical or electronic mail,
19
 
 | you may find current contact information at www.novell.com 
20
 
 |
21
 
 | Author: Dale Olds <olds@novell.com>
22
 
 |                      Russ Young
23
 
 |***************************************************************************/
24
 
 
25
 
 
26
 
using System;
27
 
using System.Threading;
28
 
using System.Collections;
29
 
using System.IO;
30
 
using System.Diagnostics;
31
 
using System.Text;
32
 
 
33
 
using Simias.Storage;
34
 
using Simias;
35
 
using Simias.Client;
36
 
using Simias.Client.Event;
37
 
using Simias.Service;
38
 
using Simias.Event;
39
 
 
40
 
#if MONO
41
 
#if MONONATIVE
42
 
        // This is used if configure.in detected mono 1.1.13 or newer
43
 
        using Mono.Unix.Native;
44
 
#else
45
 
        using Mono.Unix;
46
 
#endif
47
 
#endif
48
 
 
49
 
 
50
 
namespace Simias.Sync
51
 
{
52
 
 
53
 
        //---------------------------------------------------------------------------
54
 
        /// <summary>
55
 
        /// class to sync a portion of the file system with a collection
56
 
        /// applying iFolder specific behavior
57
 
        /// </summary>
58
 
 
59
 
        /* TODO: need to handle if we are on a case-insensitive file system and file name
60
 
         * changes only by case? Actually this would be a rather rare optimization and
61
 
         * probably not worth it for the dredger (except perhaps for a directory rename).
62
 
         * If the event system is up, we catch it as a rename. If not, the dredger treats
63
 
         * it as a delete and create. Dredger should always be case sensitive.
64
 
         */
65
 
 
66
 
        public class FileWatcher
67
 
        {
68
 
                internal static readonly ISimiasLog log = SimiasLogManager.GetLogger(typeof(FileWatcher));
69
 
 
70
 
                /// <summary>
71
 
                /// The collection to monitor.
72
 
                /// </summary>
73
 
                public Collection collection = null;
74
 
 
75
 
                /* TODO: onServer needs to be removed. It controls how tombstones are handled:
76
 
                 *   they are deleted on the server but left on the client. What it
77
 
                 *   really needs to be is deleted if there is no upstream server. Perhaps
78
 
                 *   the best way to handle it would be for this code to always leave a
79
 
                 *   tombstone, but the sync code would just remove them if there was no
80
 
                 *   upstream server.
81
 
                 */
82
 
                bool onServer = false;
83
 
                const string lastDredgeProp = "LastDredgeTime";
84
 
                DateTime dredgeTimeStamp;
85
 
                bool needToDredge = true;
86
 
                int limit = 100;
87
 
                int ct = 0;
88
 
                public bool NeedToDredge
89
 
                {
90
 
                        set { needToDredge = value; }
91
 
                }
92
 
                DateTime lastDredgeTime = DateTime.MinValue;
93
 
                bool foundChange;
94
 
                string rootPath;
95
 
                
96
 
                bool                                            disposed;
97
 
//              string                                          collectionId;
98
 
                internal FileSystemWatcher      watcher;
99
 
                Hashtable                                       changes = new Hashtable();
100
 
                Hashtable                                       oldNames = new Hashtable();
101
 
                EventPublisher  eventPublisher = new EventPublisher();
102
 
                
103
 
                
104
 
                internal class fileChangeEntry : IComparable
105
 
                {
106
 
                        internal static int                             settleTime = 2;
107
 
                        internal static int                             counter = 0;
108
 
                        internal FileSystemEventArgs    eArgs;
109
 
                        internal int                                    eventNumber;
110
 
                        internal DateTime                               eventTime;
111
 
 
112
 
                        internal fileChangeEntry(FileSystemEventArgs e)
113
 
                        {
114
 
                                eArgs = e;
115
 
                                eventNumber = Interlocked.Increment(ref counter);
116
 
                                eventTime = DateTime.Now;
117
 
                        }
118
 
                
119
 
                        internal void update(FileSystemEventArgs e)
120
 
                        {
121
 
                                eArgs = e;
122
 
                                eventTime = DateTime.Now;
123
 
                        }
124
 
 
125
 
                        internal void update()
126
 
                        {
127
 
                                eventTime = DateTime.Now;
128
 
                        }
129
 
                        
130
 
                        #region IComparable Members
131
 
 
132
 
                        public int CompareTo(object obj)
133
 
                        {
134
 
                                fileChangeEntry cobj = obj as fileChangeEntry;
135
 
                                return eventNumber.CompareTo(cobj.eventNumber);
136
 
                        }
137
 
 
138
 
                        #endregion
139
 
                }
140
 
 
141
 
                /// <summary>
142
 
                /// Creates a dredger for this collection and dredges the system.
143
 
                /// </summary>
144
 
                /// <param name="collection"></param>
145
 
                /// <param name="onServer"></param>
146
 
                public FileWatcher(Collection collection, bool onServer)
147
 
                {
148
 
                        // TODO: Syncronize the dredger with the sync engine.
149
 
                        this.collection = collection;
150
 
                        this.onServer = onServer;
151
 
//                      this.collectionId = collection.ID;
152
 
                        
153
 
//                      if (!MyEnvironment.Mono)
154
 
//                      {
155
 
                                // We are on .Net use events to watch for changes.
156
 
                                DirNode rootDir = collection.GetRootDirectory();
157
 
                                if (rootDir != null)
158
 
                                {
159
 
                                        string rootPath = collection.GetRootDirectory().GetFullPath(collection);
160
 
                                        watcher = new FileSystemWatcher(rootPath);
161
 
                                        log.Debug("New File Watcher at {0}", rootPath);
162
 
                                        watcher.Changed += new FileSystemEventHandler(OnChanged);
163
 
                                        watcher.Created += new FileSystemEventHandler(OnCreated);
164
 
                                        watcher.Deleted += new FileSystemEventHandler(OnDeleted);
165
 
                                        watcher.Renamed += new RenamedEventHandler(OnRenamed);
166
 
                                        watcher.Error += new ErrorEventHandler(watcher_Error);
167
 
                                        watcher.IncludeSubdirectories = true;
168
 
                                        watcher.EnableRaisingEvents = true;
169
 
                                        // Now dredge to find any files that were changed while we were down.
170
 
                                }
171
 
//                      }
172
 
                        disposed = false;
173
 
                }
174
 
 
175
 
                /// <summary>
176
 
                /// // Delete the specified node.
177
 
                /// </summary>
178
 
                /// <param name="node">The node to delete.</param>
179
 
                void DeleteNode(Node node)
180
 
                {
181
 
                        Log.log.Debug("File Monitor deleting orphaned node {0}, {1}", node.Name, node.ID);
182
 
                        
183
 
                        // Check to see if this is a ghost file.
184
 
                        // If it is we do not want to delete the node.
185
 
                        if (node.Properties.GetSingleProperty(PropertyTags.GhostFile) != null)
186
 
                                return;
187
 
                        
188
 
                        // Check to see if we have a collision.
189
 
                        bool isDir = (collection.BaseType == NodeTypes.DirNodeType);
190
 
                        if (collection.HasCollisions(node))
191
 
                        {
192
 
                                Conflict cNode = new Conflict(collection, node);
193
 
                                if (cNode.IsFileNameConflict)
194
 
                                {
195
 
                                        // This is a name collision make sure that we delete the right node.
196
 
                                        // Only delete if the file no longer exists.
197
 
                                        if (Path.GetFileName(cNode.FileNameConflictPath) != node.Name)
198
 
                                        {
199
 
                                                node = Conflict.GetConflictingNode(collection, node as FileNode);
200
 
                                                if (node == null)
201
 
                                                        return;
202
 
                                                cNode = new Conflict(collection, node);
203
 
                                        }
204
 
                                        if (File.Exists(cNode.FileNameConflictPath))
205
 
                                        {
206
 
                                                return;
207
 
                                        }
208
 
                                }
209
 
                                cNode.DeleteConflictFile();
210
 
                        }
211
 
                        Node[] deleted = collection.Delete(node, PropertyTags.Parent);
212
 
                        collection.Commit(deleted);
213
 
                        eventPublisher.RaiseEvent(new FileSyncEventArgs(collection.ID, isDir ? ObjectType.Directory : ObjectType.File, true, node.Name, 0, 0, 0, Direction.Local));
214
 
                        foundChange = true;
215
 
                }
216
 
 
217
 
                public static void RenameDirsChildren(Collection collection, DirNode dn, string oldRelativePath)
218
 
                {
219
 
                        string relativePath = dn.GetRelativePath();
220
 
                        // We need to rename all of the children nodes.
221
 
                        ArrayList nodeList = new ArrayList();
222
 
                        ICSList csnList = collection.Search(PropertyTags.FileSystemPath, oldRelativePath, SearchOp.Begins);
223
 
                        foreach (ShallowNode csn in csnList)
224
 
                        {
225
 
                                // Skip the dirnode.
226
 
                                if (csn.ID == dn.ID)
227
 
                                        continue;
228
 
 
229
 
                                Node childNode = collection.GetNodeByID(csn.ID);
230
 
                                if (childNode != null)
231
 
                                {
232
 
                                        Property childRP = childNode.Properties.GetSingleProperty(PropertyTags.FileSystemPath);
233
 
                                        if (childRP != null)
234
 
                                        {
235
 
                                                string newRP = childRP.ValueString;
236
 
                                                if (newRP.Length > oldRelativePath.Length && newRP.StartsWith(oldRelativePath) && newRP[oldRelativePath.Length] == '/')
237
 
                                                {
238
 
                                                        childRP.SetPropertyValue(newRP.Replace(oldRelativePath, relativePath));
239
 
                                                        childNode.Properties.ModifyNodeProperty(childRP);
240
 
                                                        nodeList.Add(childNode);
241
 
                                                }
242
 
                                        }
243
 
                                }
244
 
                        }
245
 
                        collection.Commit((Node[])nodeList.ToArray(typeof(Node)));
246
 
                }
247
 
                public static void SetRenamePropertyForDirChildren(Collection collection, DirNode dn, string oldRelativePath)
248
 
                {
249
 
                        string relativePath = dn.GetRelativePath();
250
 
                        // We need to rename all of the children nodes.
251
 
                        ArrayList nodeList = new ArrayList();
252
 
 
253
 
                        ICSList csnList = collection.Search(PropertyTags.FileSystemPath, oldRelativePath, SearchOp.Begins);
254
 
                        foreach (ShallowNode csn in csnList)
255
 
                        {
256
 
                                // Skip the dirnode.
257
 
                                if (csn.ID == dn.ID)
258
 
                                        continue;
259
 
        
260
 
                                Node childNode = collection.GetNodeByID(csn.ID);
261
 
                                if (childNode != null)
262
 
                                {
263
 
                                        Property p = new Property(PropertyTags.ReNamed, true);
264
 
                                        p.LocalProperty = true;
265
 
                                        childNode.Properties.ModifyProperty(p); 
266
 
                                        nodeList.Add(childNode);                                        
267
 
                                }
268
 
                                else
269
 
                                        log.Debug("SetRenamePropertyForDirChildren  child node null");
270
 
                        }
271
 
                        collection.Commit((Node[])nodeList.ToArray(typeof(Node)));
272
 
                }
273
 
 
274
 
                bool ExecuteBitSet(string path)
275
 
                {
276
 
#if MONO
277
 
                        if (MyEnvironment.Unix)
278
 
                        {
279
 
                                // Get the posix access flags for owner.
280
 
                                Stat sStat;
281
 
                                if (Syscall.stat(path, out sStat) == 0)
282
 
                                {
283
 
                                        if ((sStat.st_mode & FilePermissions.S_IXUSR) != 0)
284
 
                                        {
285
 
                                                return true;
286
 
                                        }
287
 
                                }
288
 
                        }
289
 
#endif 
290
 
                        return false;
291
 
                }
292
 
 
293
 
                /// <summary>
294
 
                /// Create a FileNode for the specified file.
295
 
                /// </summary>
296
 
                /// <param name="path">The path to the node to create.</param>
297
 
                /// <param name="parentNode">The parent of the node to create.</param>
298
 
                /// <param name="conflict">The node should be created with a conflict.</param>
299
 
                /// <returns>The new FileNode.</returns>
300
 
                FileNode CreateFileNode(string path, DirNode parentNode, bool conflict)
301
 
                {
302
 
                        if (isSyncFile(path) || collection.HasCollisions(parentNode))
303
 
                                return null;
304
 
                        FileNode fnode = new FileNode(collection, parentNode, Path.GetFileName(path));
305
 
                        if (ExecuteBitSet(path))
306
 
                        {
307
 
                                // The execute bit is set for the user save the value.
308
 
                                fnode.Properties.ModifyProperty(SyncFile.ModeProperty, SyncFile.FAMode.Execute);
309
 
                        }
310
 
                                        
311
 
                        log.Debug("Adding file node for {0} {1}", path, fnode.ID);
312
 
                        // Make sure that we support the Simias Name Space.
313
 
                        if (!SyncFile.IsNameValid(fnode.Name))
314
 
                        {
315
 
                                conflict = true;
316
 
                        }
317
 
                        if (conflict)
318
 
                        {
319
 
                                // We have a name collision set the collision state.
320
 
                                fnode = Conflict.CreateNameConflict(collection, fnode, path) as FileNode;
321
 
                        }
322
 
                        collection.Commit(fnode);
323
 
                        eventPublisher.RaiseEvent(new FileSyncEventArgs(collection.ID, ObjectType.File, false, fnode.Name, 0, 0, 0, Direction.Local));
324
 
                        foundChange = true;
325
 
                        return fnode;
326
 
                }
327
 
 
328
 
                /// <summary>
329
 
                /// Modify the FileNode for the changed file.
330
 
                /// </summary>
331
 
                /// <param name="path">The path of the file that has changed.</param>
332
 
                /// <param name="fn">The node to modify.</param>
333
 
                /// <param name="hasChanges">If the node has changes set to true.</param>
334
 
                void ModifyFileNode(string path, BaseFileNode fn, bool hasChanges)
335
 
                {
336
 
                        // here we are just checking for modified files
337
 
                        FileInfo fi = new FileInfo(path);
338
 
                        TimeSpan ts = fi.LastWriteTime - fn.LastWriteTime;
339
 
 
340
 
                        // Fat32 has a 2 second time resolution, Linux has a 1 second resolution. Check for > 1;
341
 
                        if ((fi.Length != fn.Length || ((uint)ts.Seconds > 1)) && (fn.UpdateFileInfo(collection, path)))
342
 
                        {
343
 
                                hasChanges = true;
344
 
                                log.Debug("Updating file node for {0} {1}", path, fn.ID);
345
 
                        }
346
 
                        if (!SyncFile.IsNameValid(fn.Name))
347
 
                        {
348
 
                                // This is a conflict.
349
 
                                fn = Conflict.CreateNameConflict(collection, fn, path) as BaseFileNode;
350
 
                                hasChanges = true;
351
 
                        }
352
 
                        bool exAlready = false;
353
 
                        if (fn.Properties.GetSingleProperty(SyncFile.ModeProperty) != null)
354
 
                                exAlready = true;
355
 
                        if (ExecuteBitSet(path))
356
 
                        {
357
 
                                if (!exAlready)
358
 
                                {
359
 
                                        // The execute bit is set for the user save the value.
360
 
                                        fn.Properties.ModifyProperty(SyncFile.ModeProperty, SyncFile.FAMode.Execute);
361
 
                                        hasChanges = true;
362
 
                                }
363
 
                        }
364
 
                        else if (exAlready)
365
 
                        {
366
 
                                fn.Properties.DeleteSingleProperty(SyncFile.ModeProperty);
367
 
                                hasChanges = true;
368
 
                        }
369
 
                        if (hasChanges)
370
 
                        {
371
 
                                collection.Commit(fn);
372
 
                                eventPublisher.RaiseEvent(new FileSyncEventArgs(collection.ID, ObjectType.File, false, fn.Name, 0, 0, 0, Direction.Local));
373
 
                                foundChange = true;
374
 
                        }
375
 
                }
376
 
 
377
 
                /// <summary>
378
 
                /// Rename the file node.
379
 
                /// </summary>
380
 
                /// <param name="newName">The new name.</param>
381
 
                /// <param name="node">The node to rename.</param>
382
 
                /// <returns>The renamed node.</returns>
383
 
                BaseFileNode RenameFileNode(string newName, BaseFileNode node)
384
 
                {
385
 
                        node.Name = Path.GetFileName(newName);
386
 
                        string relativePath = GetNormalizedRelativePath(rootPath, newName);
387
 
                        node.Properties.ModifyNodeProperty(new Property(PropertyTags.FileSystemPath, Syntax.String, relativePath));
388
 
                        // The file may have been modified.  If it has, we need to make sure the length is updated.
389
 
                        FileInfo fi = new FileInfo(newName);
390
 
                        if (fi.Length != node.Length)
391
 
                                node.UpdateFileInfo(collection, newName);
392
 
 
393
 
                        //set the local rename property for dir children
394
 
                        //this local property will be checked and cleard in the  the sync method ploadFile()
395
 
                        Property p = new Property(PropertyTags.ReNamed, true);
396
 
                        p.LocalProperty = true;
397
 
                        node.Properties.ModifyProperty(p); 
398
 
                        
399
 
                        // Commit the directory.
400
 
                        collection.Commit(node);
401
 
                        return node;
402
 
                }
403
 
 
404
 
                /// <summary>
405
 
                /// Rename the directory and fixup children.
406
 
                /// </summary>
407
 
                /// <param name="newPath">The new name of the dir.</param>
408
 
                /// <param name="node">The dir node to rename.</param>
409
 
                /// <returns>The modified node.</returns>
410
 
                DirNode RenameDirNode(string newPath, DirNode node)
411
 
                {
412
 
                        node.Name = Path.GetFileName(newPath);
413
 
                        string relativePath = GetNormalizedRelativePath(rootPath, newPath);
414
 
                        string oldRelativePath = node.Properties.GetSingleProperty(PropertyTags.FileSystemPath).ValueString;
415
 
                        node.Properties.ModifyNodeProperty(new Property(PropertyTags.FileSystemPath, Syntax.String, relativePath));
416
 
 
417
 
                        //set the local rename property for dir children
418
 
                        //this local property will be checked and cleard in the  the sync method ploadFile()
419
 
                        SetRenamePropertyForDirChildren(collection, node, oldRelativePath);
420
 
                        
421
 
                        // Commit the directory.
422
 
                        collection.Commit(node);
423
 
                        // We need to rename all of the children nodes.
424
 
                        RenameDirsChildren(collection, node, oldRelativePath);
425
 
                        DoSubtree(newPath, node, node.ID, true);
426
 
                        return node;
427
 
                }
428
 
 
429
 
                /// <summary>
430
 
                /// Create a DirNode for the specified directory.
431
 
                /// </summary>
432
 
                /// <param name="path">The path to the directory.</param>
433
 
                /// <param name="parentNode">The parent DirNode.</param>
434
 
                /// <param name="conflict">The node should be created with a conflict.</param>
435
 
                /// <returns>The new DirNode.</returns>
436
 
                DirNode CreateDirNode(string path, DirNode parentNode, bool conflict)
437
 
                {
438
 
                        if (isSyncFile(path))
439
 
                                return null;
440
 
 
441
 
                        string fName = Path.GetFileName(path);
442
 
                        DirNode dnode = new DirNode(collection, parentNode, fName);
443
 
                        log.Debug("Adding dir node for {0} {1}", path, dnode.ID);
444
 
                        // Make sure that we support the Simias Name Space.
445
 
                        if (!SyncFile.IsNameValid(dnode.Name) || SyncFile.DoesNodeExist(collection, parentNode, fName))
446
 
                        {
447
 
                                conflict = true;
448
 
                        }
449
 
                        if (conflict)
450
 
                        {
451
 
                                // We have a name collision set the collision state.
452
 
                                dnode = Conflict.CreateNameConflict(collection, dnode, path) as DirNode;
453
 
                        }
454
 
                        collection.Commit(dnode);
455
 
                        eventPublisher.RaiseEvent(new FileSyncEventArgs(collection.ID, ObjectType.Directory, false, dnode.Name, 0, 0, 0, Direction.Local));
456
 
                        if (!conflict)
457
 
                                DoSubtree(path, dnode, dnode.ID, true);
458
 
                        foundChange = true;
459
 
                        return dnode;
460
 
                }
461
 
 
462
 
                /// <summary>
463
 
                /// 
464
 
                /// </summary>
465
 
                /// <param name="oldPath"></param>
466
 
                /// <param name="newPath"></param>
467
 
                /// <returns></returns>
468
 
                bool HasParentChanged(string oldPath, string newPath)
469
 
                {
470
 
                        if (MyEnvironment.Windows)
471
 
                        {
472
 
                                return String.Compare(Path.GetDirectoryName(oldPath), Path.GetDirectoryName(newPath), true) == 0 ? false : true;
473
 
                        }
474
 
                        else
475
 
                        {
476
 
                                return (!(Path.GetDirectoryName(oldPath).Equals(Path.GetDirectoryName(newPath))));
477
 
                        }
478
 
                }
479
 
 
480
 
                /// <summary>
481
 
                /// 
482
 
                /// </summary>
483
 
                /// <param name="rootPath"></param>
484
 
                /// <param name="path"></param>
485
 
                /// <returns></returns>
486
 
                public static string GetNormalizedRelativePath(string rootPath, string path)
487
 
                {
488
 
                        string relPath = path.Replace(rootPath, "");
489
 
                        relPath = relPath.TrimStart(Path.DirectorySeparatorChar);
490
 
                        if (Path.DirectorySeparatorChar != '/')
491
 
                                relPath = relPath.Replace('\\', '/');
492
 
                        return relPath;
493
 
                }
494
 
 
495
 
                /// <summary>
496
 
                /// Get a ShallowNode for the named file or directory.
497
 
                /// </summary>
498
 
                /// <param name="path">Path to the file.</param>
499
 
                /// <param name="haveConflict"></param>
500
 
                /// <returns>The ShallowNode for this file.</returns>
501
 
                ShallowNode GetShallowNodeForFile(string path, out bool haveConflict)
502
 
                {
503
 
                        ShallowNode sNode = null;
504
 
                        haveConflict = false;
505
 
                        string relPath = GetNormalizedRelativePath(rootPath, path);
506
 
                        
507
 
                        ICSList nodeList;
508
 
                        nodeList = collection.Search(PropertyTags.FileSystemPath, relPath, SearchOp.Equal);
509
 
                        foreach (ShallowNode sn in nodeList)
510
 
                        {
511
 
                                if (sn.Name == Path.GetFileName(path))
512
 
                                {
513
 
                                        sNode = sn;
514
 
                                }
515
 
                                else
516
 
                                {
517
 
                                        haveConflict = true;
518
 
                                        sNode = sNode == null ? sn : sNode;
519
 
                                }
520
 
                        }
521
 
                        return sNode;
522
 
                }
523
 
 
524
 
                /// <summary>
525
 
                /// Return the parent for this path.
526
 
                /// </summary>
527
 
                /// <param name="path">Path to the file whose parent is wanted.</param>
528
 
                /// <returns></returns>
529
 
                DirNode GetParentNode(string path)
530
 
                {
531
 
                        bool haveConflict;
532
 
                        ShallowNode sn = GetShallowNodeForFile(Path.GetDirectoryName(path), out haveConflict);
533
 
                        if (sn != null)
534
 
                        {
535
 
                                return (DirNode)collection.GetNodeByID(sn.ID);
536
 
                        }
537
 
                        return null;
538
 
                }
539
 
 
540
 
                /// <summary>
541
 
                /// Check if the file is an internal sync file.
542
 
                /// </summary>
543
 
                /// <param name="name"></param>
544
 
                /// <returns></returns>
545
 
                private bool isSyncFile(string name)
546
 
                {
547
 
                        string fname = Path.GetFileName(name);
548
 
                        return fname.StartsWith(".simias.");
549
 
                }
550
 
 
551
 
 
552
 
                /// <summary>
553
 
                /// 
554
 
                /// </summary>
555
 
                /// <param name="parent"></param>
556
 
                /// <param name="sn"></param>
557
 
                /// <param name="path"></param>
558
 
                /// <param name="isDir"></param>
559
 
                void DoShallowNode(DirNode parent, ShallowNode sn, string path, bool isDir)
560
 
                {
561
 
                        Node node = null;
562
 
                        DirNode dn = null;
563
 
                        FileNode fn = null;
564
 
                        string name = Path.GetFileName(path);
565
 
                
566
 
                        // don't let temp files from sync, into the collection as regular nodes
567
 
                        if (isSyncFile(name))
568
 
                                return;
569
 
 
570
 
                        // If the lastwritetime has not changed the node is up to date.
571
 
                        if (File.GetLastWriteTime(path) <= lastDredgeTime)
572
 
                        {
573
 
                                if (isDir)
574
 
                                        DoSubtree(path, null, sn.ID, false);
575
 
                                return;
576
 
                        }
577
 
 
578
 
                        // If the case of the names does not match we have a conflict.
579
 
                        if (name != sn.Name)
580
 
                        {
581
 
                                if (isDir)
582
 
                                {
583
 
                                        CreateDirNode(path, parent, true);
584
 
                                }
585
 
                                else
586
 
                                {
587
 
                                        CreateFileNode(path, parent, true);
588
 
                                }
589
 
                                return;
590
 
                        }
591
 
 
592
 
                        node = Node.NodeFactory(collection, sn);
593
 
                        if (isDir)
594
 
                        {
595
 
                                // This is a directory.
596
 
                                dn = node as DirNode;
597
 
                                if (dn == null)
598
 
                                {
599
 
                                        // This node is the wrong type.
600
 
                                        DeleteNode(node);
601
 
                                        dn = CreateDirNode(path, parent, false);
602
 
                                }
603
 
                                else
604
 
                                {
605
 
                                        DoSubtree(path, dn, dn.ID, true);
606
 
                                }
607
 
                        }
608
 
                        else
609
 
                        {
610
 
                                fn = node as FileNode;
611
 
                                if (fn != null)
612
 
                                {
613
 
                                        ModifyFileNode(path, fn, false);
614
 
                                }
615
 
                                else
616
 
                                {
617
 
                                        DeleteNode(node);
618
 
                                        fn = CreateFileNode(path, parent, false);
619
 
                                }
620
 
                        }
621
 
                }
622
 
 
623
 
        
624
 
                /// <summary>
625
 
                /// 
626
 
                /// </summary>
627
 
                /// <param name="parentNode"></param>
628
 
                /// <param name="path"></param>
629
 
                /// <param name="isDir"></param>
630
 
                void DoNode(DirNode parentNode, string path, bool isDir)
631
 
                {
632
 
                        string name = Path.GetFileName(path);
633
 
 
634
 
                        if (isSyncFile(name))
635
 
                                return;
636
 
                
637
 
                        // find if node for this file or dir already exists
638
 
                        bool haveConflict;
639
 
                        ShallowNode sn = GetShallowNodeForFile(path, out haveConflict);
640
 
                        if (sn != null)
641
 
                        {
642
 
                                DoShallowNode(parentNode, sn, path, isDir);
643
 
                        }
644
 
                }
645
 
 
646
 
                /// <summary>
647
 
                /// Checks to see if the current file is a recursive symlink.
648
 
                /// </summary>
649
 
                /// <param name="path">The path of the possible link.</param>
650
 
                /// <returns>true if recursive link</returns>
651
 
                bool IsRecursiveLink(string path)
652
 
                {
653
 
#if MONO
654
 
                        Stat stat;
655
 
                        if (Syscall.lstat(path, out stat) == 0)
656
 
                        {
657
 
                                if ((stat.st_mode & FilePermissions.S_IFLNK) != 0)
658
 
                                {
659
 
                                        // If the path begins with the link path this is a recursive link.
660
 
                                        StringBuilder stringBuff = new StringBuilder(1024);
661
 
                                        if (Syscall.readlink(path, stringBuff, (ulong)stringBuff.Capacity) != -1)
662
 
                                        {
663
 
                                                string linkPath = stringBuff.ToString();
664
 
                                                if (!Path.IsPathRooted(linkPath))
665
 
                                                {
666
 
                                                        linkPath = Path.Combine(Path.GetDirectoryName(path), linkPath);
667
 
                                                        linkPath = Path.GetFullPath(linkPath) + "/";
668
 
                                                }
669
 
                                                // We need to check for link to a link.
670
 
                                                if (IsRecursiveLink(linkPath))
671
 
                                                        return true;
672
 
                                else if (path.StartsWith(linkPath))
673
 
                                                        return true;
674
 
                                        }
675
 
                                }
676
 
                        }
677
 
#else
678
 
                        if ((File.GetAttributes(path) & FileAttributes.ReparsePoint) != 0)
679
 
                        {
680
 
                                // We need to determine if the link is recursive.
681
 
                                // Lets check to see if we have any of the directories in our hiarchy.
682
 
                                // Strip of our name.
683
 
                                string parentPath = Path.GetDirectoryName(path);
684
 
                                string[] fsEntries = Directory.GetDirectories(path);
685
 
                                foreach (string dPath in fsEntries)
686
 
                                {
687
 
                                        // If any of the directory names match my parent path we could be recursive.
688
 
                                        // Get the name of the child directory.
689
 
                                        string childDir = Path.GetFileName(dPath);
690
 
                                        int sIndex = parentPath.IndexOf(childDir);
691
 
                                        if (sIndex != -1)
692
 
                                        {
693
 
                                                if (parentPath[sIndex -1] == Path.DirectorySeparatorChar
694
 
                                                        && (((sIndex + childDir.Length) == parentPath.Length) 
695
 
                                                        || parentPath[sIndex + childDir.Length] == Path.DirectorySeparatorChar))
696
 
                                                {
697
 
                                                        // We have a possible recursion problem.
698
 
                                                        // We need to see if the directories are the same
699
 
                                                        // We will do it by creating a child file and checking for existance
700
 
                                                        // in the suspect directory.
701
 
                                                        string suspectFile = Path.Combine(parentPath.Substring(0, sIndex - 1), ".simias.tmp");
702
 
                                                        string localFile = Path.Combine(path, ".simias.tmp");
703
 
                                                        File.Create(localFile).Close();
704
 
                                                        try
705
 
                                                        {
706
 
                                                                if (File.Exists(suspectFile))
707
 
                                                                        return true;
708
 
                                                        }
709
 
                                                        finally
710
 
                                                        {
711
 
                                                                File.Delete(localFile);
712
 
                                                        }
713
 
                                                }
714
 
                                        }
715
 
                                }
716
 
                        }
717
 
#endif
718
 
                        return false;
719
 
                }
720
 
 
721
 
                private bool CheckSuspend
722
 
                {
723
 
                        // Read the limit from the setup
724
 
                        //limit = Simias.Client.SimiasSetup.Limit;
725
 
                        //log.Debug("Ramesh: Setting the limit to {0}", limit);
726
 
                        get
727
 
                        {
728
 
                                ct++;
729
 
                        
730
 
                                if( ct > limit)
731
 
                                {
732
 
                                        ct =0;
733
 
                                        return true;
734
 
                                }
735
 
                                return false;
736
 
                        }
737
 
                }
738
 
 
739
 
                /// <summary>
740
 
                /// 
741
 
                /// </summary>
742
 
                /// <param name="path"></param>
743
 
                /// <param name="dnode"></param>
744
 
                /// <param name="nodeID"></param>
745
 
                /// <param name="subTreeHasChanged"></param>
746
 
                void DoSubtree(string path, DirNode dnode, string nodeID, bool subTreeHasChanged)
747
 
                {
748
 
                        if (Simias.Service.Manager.ShuttingDown)
749
 
                                return;
750
 
 
751
 
                        try
752
 
                        {
753
 
                                //Log.Spew("Dredger processing subtree of path {0}", path);
754
 
                                if (!SyncFile.IsNameValid(Path.GetFileName(path)))
755
 
                                {
756
 
                                        // This is a name collision this needs to be resolved before
757
 
                                        // the files can be added.
758
 
                                        return;
759
 
                                }
760
 
 
761
 
                                // Make sure we are not a recursive reparse point or symlink
762
 
                                if (IsRecursiveLink(path))
763
 
                                        return;
764
 
                                
765
 
                                if (subTreeHasChanged)
766
 
                                {
767
 
                                        // A file or directory has been added or deleted from this directory. We need to find it.
768
 
                                        Hashtable existingNodes = new Hashtable();
769
 
                                        // Put all the existing nodes in a hashtable to match against the file system.
770
 
                                        foreach (ShallowNode sn in collection.Search(PropertyTags.Parent, new Relationship(collection.ID, dnode.ID)))
771
 
                                        {
772
 
                                                if (Simias.Service.Manager.ShuttingDown)
773
 
                                                        return;
774
 
                        
775
 
                                                existingNodes[sn.Name] = sn;
776
 
                                        }
777
 
 
778
 
                                        // Look for new and modified files.
779
 
                                        foreach (string file in Directory.GetFiles(path))
780
 
                                        {
781
 
                                                if (Simias.Service.Manager.ShuttingDown)
782
 
                                                        return;
783
 
                                                if(CheckSuspend)
784
 
                                                {
785
 
                                                        Thread.Sleep(0);
786
 
                                                }
787
 
 
788
 
                                                string fName = Path.GetFileName(file);
789
 
                                                ShallowNode sn = (ShallowNode)existingNodes[fName];
790
 
                                                if (sn != null)
791
 
                                                {
792
 
                                                        DoShallowNode(dnode, sn, file, false);
793
 
                                                        existingNodes.Remove(fName);
794
 
                                                }
795
 
                                                else
796
 
                                                {
797
 
                                                        // The file is new create a new file node.
798
 
                                                        CreateFileNode(file, dnode, false);
799
 
                                                }
800
 
                                        }
801
 
 
802
 
                                        // look for new directories
803
 
                                        foreach (string dir in Directory.GetDirectories(path))
804
 
                                        {
805
 
                                                if (Simias.Service.Manager.ShuttingDown)
806
 
                                                        return;
807
 
                                                if(CheckSuspend)
808
 
                                                {
809
 
                                                        Thread.Sleep(0);
810
 
                                                }
811
 
                                                string dName = Path.GetFileName(dir);
812
 
                                                ShallowNode sn = (ShallowNode)existingNodes[dName];
813
 
                                                if (sn != null)
814
 
                                                {
815
 
                                                        DoShallowNode(dnode, sn, dir, true);
816
 
                                                        existingNodes.Remove(dName);
817
 
                                                }
818
 
                                                else
819
 
                                                {
820
 
                                                        // The directory is new create a new directory node.
821
 
                                                        DirNode newDir = CreateDirNode(dir, dnode, false);
822
 
                                                }
823
 
                                        }
824
 
                                        // look for deleted files.
825
 
                                        // All remaining nodes need to be deleted.
826
 
                                        foreach (ShallowNode sn in existingNodes.Values)
827
 
                                        {
828
 
                                                if (Simias.Service.Manager.ShuttingDown)
829
 
                                                        return;
830
 
                                                if(CheckSuspend)
831
 
                                                {
832
 
                                                        Thread.Sleep(0);
833
 
                                                }
834
 
                                                DeleteNode(new Node(collection, sn));
835
 
                                        }
836
 
                                }
837
 
                                else
838
 
                                {
839
 
                                        // Just look for modified files.
840
 
                                        foreach (string file in Directory.GetFiles(path))
841
 
                                        {
842
 
                                                if (Simias.Service.Manager.ShuttingDown)
843
 
                                                        return;
844
 
                                                if(CheckSuspend)
845
 
                                                {
846
 
                                                        Thread.Sleep(0);
847
 
                                                }
848
 
                                                if (File.GetLastWriteTime(file) > lastDredgeTime)
849
 
                                                {
850
 
                                                        if (dnode == null)
851
 
                                                                dnode = collection.GetNodeByID(nodeID) as DirNode;
852
 
                                                        DoNode(dnode, file, false);
853
 
                                                }
854
 
                                        }
855
 
                        
856
 
                                        foreach (string dir in Directory.GetDirectories(path))
857
 
                                        {
858
 
                                                if (Simias.Service.Manager.ShuttingDown)
859
 
                                                        return;
860
 
                                                if(CheckSuspend)
861
 
                                                {
862
 
                                                        Thread.Sleep(0);
863
 
                                                }
864
 
                                                if (Directory.GetLastWriteTime(dir) > lastDredgeTime)
865
 
                                                {
866
 
                                                        if (dnode == null)
867
 
                                                                dnode = collection.GetNodeByID(nodeID) as DirNode;
868
 
                                                        DoNode(dnode, dir, true);
869
 
                                                }
870
 
                                                else 
871
 
                                                {
872
 
                                                        bool haveConflict;
873
 
                                                        ShallowNode sn = GetShallowNodeForFile(dir, out haveConflict);
874
 
                                                        if (sn != null)
875
 
                                                                DoSubtree(dir, null, sn.ID, false);
876
 
                                                        else
877
 
                                                        {
878
 
                                                                // This should never happen but if it does recall with the modified true.
879
 
                                                                DoSubtree(path, dnode, nodeID, true);
880
 
                                                                break;
881
 
                                                        }
882
 
                                                }
883
 
                                        }
884
 
                                }
885
 
                        }
886
 
                        catch (Exception ex)
887
 
                        {
888
 
                                Log.log.Debug(ex, "Failed adding contents of directory {0}", path);
889
 
                        }
890
 
                }
891
 
 
892
 
                /// <summary>
893
 
                /// Dredge the Managed path.
894
 
                /// </summary>
895
 
                /// <param name="path"></param>
896
 
                void DoManagedPath(string path)
897
 
                {
898
 
//                      DirectoryInfo tmpDi = new DirectoryInfo(path);
899
 
                
900
 
                        // merge files from file system to store
901
 
                        foreach (string file in Directory.GetFiles(path))
902
 
                        {
903
 
                                if (File.GetLastWriteTime(file) > lastDredgeTime && !isSyncFile(file))
904
 
                                {
905
 
                                        // here we are just checking for modified files
906
 
                                        // Because we create temporary journal files in the store managed area,
907
 
                                        // we make sure there is a corresponding node before we proceed.
908
 
                                        Node node = collection.GetNodeByID(Path.GetFileName(file));
909
 
                                        if ((node != null) && node.IsType(NodeTypes.BaseFileNodeType))
910
 
                                        {
911
 
                                                BaseFileNode unode = (BaseFileNode)collection.GetNodeByID(Path.GetFileName(file));
912
 
                                                if (unode != null)
913
 
                                                {
914
 
                                                        // Don't allow journal files (or temporary journal files) to be updated from the client.
915
 
                                                        if (!unode.IsType("Journal") &&
916
 
                                                                !unode.IsType(NodeTypes.FileNodeType))
917
 
                                                        {
918
 
                                                                DateTime lastWrote = File.GetLastWriteTime(file);
919
 
                                                                DateTime created = File.GetCreationTime(file);
920
 
                                                                if (unode.LastWriteTime != lastWrote)
921
 
                                                                {
922
 
                                                                        unode.LastWriteTime = lastWrote;
923
 
                                                                        unode.CreationTime = created;
924
 
                                                                        log.Debug("Updating store file node for {0} {1}", path, file);
925
 
                                                                        collection.Commit(unode);
926
 
                                                                        foundChange = true;
927
 
                                                                }
928
 
                                                        }
929
 
                                                }
930
 
                                        }
931
 
                                }
932
 
                        }
933
 
                }
934
 
 
935
 
                /// <summary>
936
 
                /// Dredge the file sytem to find changes.
937
 
                /// </summary>
938
 
                public void CheckForFileChanges()
939
 
                {
940
 
                        collection.Refresh();
941
 
 
942
 
                        if (watcher == null || needToDredge)
943
 
                        {
944
 
                                Dredge();
945
 
                                needToDredge = false;
946
 
                        }
947
 
                        else
948
 
                        {
949
 
                                try
950
 
                                {
951
 
                                        // Make sure the root directory still exists.
952
 
                                        if (!Directory.Exists(collection.GetRootDirectory().GetFullPath(collection)))
953
 
                                        {
954
 
                                                collection.Commit(collection.Delete());
955
 
                                                return;
956
 
                                        }
957
 
                                        
958
 
                                        dredgeTimeStamp = DateTime.Now;
959
 
                                        fileChangeEntry[] fChanges;
960
 
 
961
 
                                        lock (changes)
962
 
                                        {
963
 
                                                fChanges = new fileChangeEntry[changes.Count];
964
 
                                                changes.Values.CopyTo(fChanges, 0);
965
 
                                        }
966
 
 
967
 
                                        // Sort these by time that way they will be put in the change log in order.
968
 
                                        Array.Sort(fChanges);
969
 
 
970
 
                                        foreach (fileChangeEntry fc in fChanges)
971
 
                                        {
972
 
                                                if (fc.eArgs.ChangeType == WatcherChangeTypes.Renamed)
973
 
                                                {
974
 
                                                        RenamedEventArgs args = (RenamedEventArgs)fc.eArgs;
975
 
                                                        log.Debug("Queued Event ---- {0}: {1} -> {2}", args.ChangeType, args.OldFullPath, args.FullPath);
976
 
                                                }
977
 
                                                else
978
 
                                                {
979
 
                                                        log.Debug("Queued Event ---- {0}: {1}", fc.eArgs.ChangeType, fc.eArgs.FullPath);
980
 
                                                }
981
 
                        
982
 
                                                string fullName = GetName(fc.eArgs.FullPath);
983
 
                                                bool isDir = false;
984
 
 
985
 
                                                if (fullName == null)
986
 
                                                {
987
 
                                                        lock(changes)
988
 
                                                        {
989
 
                                                                changes.Remove(fc.eArgs.FullPath);
990
 
                                                        }
991
 
                                                        continue;
992
 
                                                }
993
 
 
994
 
                                                FileInfo fi = new FileInfo(fullName);
995
 
                                                isDir = (fi.Attributes & FileAttributes.Directory) > 0;
996
 
 
997
 
                                                // Make sure that we let modifications settle.
998
 
                                                TimeSpan tSpan = DateTime.Now - fc.eventTime;
999
 
                        if (tSpan.Seconds < fileChangeEntry.settleTime)
1000
 
                                                {
1001
 
                                                        continue;
1002
 
                                                }
1003
 
 
1004
 
                                                if (!isDir && fi.Exists)
1005
 
                                                {
1006
 
                                                        tSpan = DateTime.Now - fi.LastWriteTime;
1007
 
                                                        if (tSpan.Seconds < fileChangeEntry.settleTime)
1008
 
                                                                continue;
1009
 
                                                }
1010
 
                                                
1011
 
                                                bool haveConflict;
1012
 
                                                ShallowNode sn = GetShallowNodeForFile(fullName, out haveConflict);
1013
 
                                                Node node = null;
1014
 
                                                DirNode dn = null;
1015
 
                                                BaseFileNode fn = null;
1016
 
 
1017
 
                                                if (sn != null)
1018
 
                                                {
1019
 
                                                        node = collection.GetNodeByID(sn.ID);
1020
 
                                                        fn = node as BaseFileNode;
1021
 
                                                        dn = node as DirNode;
1022
 
                                                        // Make sure the type is still valid.
1023
 
                                                        if (fi.Exists && ((isDir && fn != null) || (!isDir && dn != null)))
1024
 
                                                        {
1025
 
                                                                needToDredge = true;
1026
 
                                                                break;
1027
 
                                                        }
1028
 
                                                        
1029
 
                                                        // We have a node update it.
1030
 
                                                        switch (fc.eArgs.ChangeType)
1031
 
                                                        {
1032
 
                                                                case WatcherChangeTypes.Created:
1033
 
                                                                case WatcherChangeTypes.Changed:
1034
 
                                                                        if (!isDir)
1035
 
                                                                                ModifyFileNode(fullName, fn, false);
1036
 
                                                                        break;
1037
 
                                                                case WatcherChangeTypes.Deleted:
1038
 
                                                                        DeleteNode(node);
1039
 
                                                                        break;
1040
 
                                                                case WatcherChangeTypes.Renamed:
1041
 
                                                                {
1042
 
                                                                        RenamedEventArgs args = (RenamedEventArgs)fc.eArgs;
1043
 
                                                                        oldNames.Remove(args.OldFullPath);
1044
 
 
1045
 
                                                                        // Remove any name collisions.
1046
 
                                                                        if (collection.HasCollisions(node))
1047
 
                                                                        {
1048
 
                                                                                if (collection.GetCollisionType(node) == CollisionType.File)
1049
 
                                                                                        node = Conflict.RemoveNameConflict(collection, node);
1050
 
                                                                        }
1051
 
                                                                        // Check for a name conflict.
1052
 
                                                                        if (!SyncFile.IsNameValid(args.Name))
1053
 
                                                                        {
1054
 
                                                                                // This is a conflict.
1055
 
                                                                                node = Conflict.CreateNameConflict(collection, node, fullName);
1056
 
                                                                        }
1057
 
 
1058
 
                                                                        
1059
 
                                                                        // Since we are here we have a node already.
1060
 
                                                                        // Make sure the case of the names has not changed.
1061
 
                                                                        if (Path.GetFileName(fullName) == node.Name)
1062
 
                                                                        {
1063
 
                                                                                // This is a rename back to the original name update it.
1064
 
                                                                                if (!isDir)
1065
 
                                                                                        ModifyFileNode(fullName, fn, false);
1066
 
                                                                                else
1067
 
                                                                                        DoSubtree(fullName, dn, node.ID, true);
1068
 
                                                                        }
1069
 
                                                                        else
1070
 
                                                                        {
1071
 
                                                                                // This is a case rename.
1072
 
                                                                                if (!isDir)
1073
 
                                                                                {
1074
 
                                                                                        node = RenameFileNode(fullName, fn);
1075
 
                                                                                }
1076
 
                                                                                else
1077
 
                                                                                {
1078
 
                                                                                        node = RenameDirNode(fullName, dn);
1079
 
                                                                                }
1080
 
                                                                        }
1081
 
                                                                        
1082
 
                                                                        // Make sure that there is not a node for the old name.
1083
 
                                                                        sn = GetShallowNodeForFile(args.OldFullPath, out haveConflict);
1084
 
                                                                        if (sn != null && sn.ID != node.ID)
1085
 
                                                                        {
1086
 
                                                                                // If the file no longer exists delet the node.
1087
 
                                                                                if (!File.Exists(args.OldFullPath))
1088
 
                                                                                {
1089
 
                                                                                        node = collection.GetNodeByID(sn.ID);
1090
 
                                                                                        DeleteNode(node);
1091
 
                                                                                }
1092
 
                                                                        }
1093
 
                                                                        break;
1094
 
                                                                }
1095
 
                                                        }
1096
 
                                                }
1097
 
                                                else
1098
 
                                                {
1099
 
                                                        // The node does not exist.
1100
 
                                                        switch (fc.eArgs.ChangeType)
1101
 
                                                        {
1102
 
                                                                case WatcherChangeTypes.Deleted:
1103
 
                                                                        // The node does not exist just continue.
1104
 
                                                                        break;
1105
 
                                                                case WatcherChangeTypes.Created:
1106
 
                                                                case WatcherChangeTypes.Changed:
1107
 
                                                                        // The node does not exist create it.
1108
 
                                                                        if (isDir)
1109
 
                                                                        {
1110
 
                                                                                CreateDirNode(fullName, GetParentNode(fullName), haveConflict);
1111
 
                                                                        }
1112
 
                                                                        else
1113
 
                                                                        {
1114
 
                                                                                CreateFileNode(fullName, GetParentNode(fullName), haveConflict);
1115
 
                                                                        }
1116
 
                                                                        break;
1117
 
 
1118
 
                                                                case WatcherChangeTypes.Renamed:
1119
 
                                                                        // Check if there is a node for the old name.
1120
 
                                                                        // Get the node from the old name.
1121
 
                                                                        RenamedEventArgs args = (RenamedEventArgs)fc.eArgs;
1122
 
                                                                        oldNames.Remove(args.OldFullPath);
1123
 
                                                                        DirNode parent = null;
1124
 
                                                                        sn = GetShallowNodeForFile(args.OldFullPath, out haveConflict);
1125
 
                                                                        if (sn != null)
1126
 
                                                                        {
1127
 
                                                                                node = collection.GetNodeByID(sn.ID);
1128
 
                                                                                fn = node as FileNode;
1129
 
                                                                                dn = node as DirNode;
1130
 
 
1131
 
                                                                                // Remove any name collisions.
1132
 
                                                                                if (collection.HasCollisions(node))
1133
 
                                                                                {
1134
 
                                                                                        if (collection.GetCollisionType(node) == CollisionType.File)
1135
 
                                                                                                node = Conflict.RemoveNameConflict(collection, node);
1136
 
                                                                                }
1137
 
                                                                                // Check for a name conflict.
1138
 
                                                                                if (!SyncFile.IsNameValid(Path.GetFileName(fullName)))
1139
 
                                                                                {
1140
 
                                                                                        // This is a conflict.
1141
 
                                                                                        node = Conflict.CreateNameConflict(collection, node, fullName);
1142
 
                                                                                }
1143
 
 
1144
 
                                                                                // Make sure the parent has not changed.
1145
 
                                                                                if (HasParentChanged(args.OldFullPath, fullName))
1146
 
                                                                                {
1147
 
                                                                                        // We have a new parent find the parent node.
1148
 
                                                                                        parent = GetParentNode(fullName);
1149
 
                                                                                        if (parent != null)
1150
 
                                                                                        {
1151
 
                                                                                                // We have a parent reset the parent node.
1152
 
                                                                                                node.Properties.ModifyNodeProperty(PropertyTags.Parent, new Relationship(collection.ID, parent.ID));
1153
 
                                                                                        }
1154
 
                                                                                        else
1155
 
                                                                                        {
1156
 
                                                                                                // We do not have a node for the parent.
1157
 
                                                                                                // Do a dredge.
1158
 
                                                                                                needToDredge = true;
1159
 
                                                                                                break;
1160
 
                                                                                        }
1161
 
                                                                                }
1162
 
                                                                                if (!isDir)
1163
 
                                                                                {
1164
 
                                                                                        node = RenameFileNode(fullName, node as BaseFileNode);
1165
 
                                                                                }
1166
 
                                                                                else
1167
 
                                                                                {
1168
 
                                                                                        node = RenameDirNode(fullName, node as DirNode);
1169
 
                                                                                }
1170
 
                                                                        }
1171
 
                                                                        else
1172
 
                                                                        {
1173
 
                                                                                // The node does not exist create it.
1174
 
                                                                                haveConflict = sn == null ? false : true;
1175
 
                                                                                Node tempNode;
1176
 
                                                                                if (isDir)
1177
 
                                                                                {
1178
 
                                                                                        tempNode = CreateDirNode(fullName, GetParentNode(fullName), haveConflict);
1179
 
                                                                                }
1180
 
                                                                                else
1181
 
                                                                                {
1182
 
                                                                                        tempNode = CreateFileNode(fullName, GetParentNode(fullName), haveConflict);
1183
 
                                                                                }
1184
 
                                                                        }
1185
 
                                                                        break;
1186
 
                                                        }
1187
 
                                                }
1188
 
                                                lock(changes)
1189
 
                                                {
1190
 
                                                        changes.Remove(fc.eArgs.FullPath);
1191
 
                                                }
1192
 
                                        }
1193
 
 
1194
 
                                        if (needToDredge)
1195
 
                                        {
1196
 
                                                Dredge();
1197
 
                                                needToDredge = false;
1198
 
                                        }
1199
 
                                        else
1200
 
                                        {
1201
 
                                                DoManagedPath(collection.ManagedPath);
1202
 
                                        }
1203
 
                                }
1204
 
                                catch
1205
 
                                {
1206
 
                                        Dredge();
1207
 
                                        needToDredge = false;
1208
 
                                }
1209
 
                        }
1210
 
                        if (foundChange)
1211
 
                        {
1212
 
                                // We may have just created or deleted nodes wait for the events to settle.
1213
 
                                // We will wait for 2 seconds because of file time resolution on fat32
1214
 
                                // This will ensure that we don't miss any changes.
1215
 
                                Thread.Sleep(2000);
1216
 
                        }
1217
 
                }
1218
 
 
1219
 
                /// <summary>
1220
 
                /// Find File changes by dredging the file system.
1221
 
                /// </summary>
1222
 
                public void Dredge()
1223
 
                {
1224
 
                        // Clear the event changes since we are going to dredge.
1225
 
                        lock (changes)
1226
 
                        {
1227
 
                                changes.Clear();
1228
 
                        }
1229
 
                                
1230
 
                        collection.Refresh();
1231
 
                        foundChange = false;
1232
 
                
1233
 
                        try
1234
 
                        {
1235
 
                                lastDredgeTime = (DateTime)(collection.Properties.GetSingleProperty(lastDredgeProp).Value);
1236
 
                        }
1237
 
                        catch
1238
 
                        {
1239
 
                                // Set found change so the lastDredgeTime will get updated.
1240
 
                                foundChange = true;
1241
 
                                log.Debug("Failed to get the last dredge time");
1242
 
                        }
1243
 
                        // Make sure that the RootDir still exists. IF it has been deleted on a slave remove the collection
1244
 
                        // And exit.
1245
 
                        DirNode dn = collection.GetRootDirectory();
1246
 
                        if (dn != null)
1247
 
                        {
1248
 
                                rootPath = dn.Properties.GetSingleProperty(PropertyTags.Root).Value as string;
1249
 
                                string path = dn.GetFullPath(collection);
1250
 
                                if (onServer || Directory.Exists(path))
1251
 
                                {
1252
 
                                        DoSubtree(path, dn, dn.ID, Directory.GetLastWriteTime(path) > lastDredgeTime ? true : false);
1253
 
                                }
1254
 
                                else
1255
 
                                {
1256
 
                                        // The directory no loger exits. Delete the collection.
1257
 
                                        collection.Delete();
1258
 
                                        collection.Commit();
1259
 
                                        foundChange = false;
1260
 
                                }
1261
 
                        }
1262
 
        
1263
 
                        DoManagedPath(collection.ManagedPath);
1264
 
                
1265
 
                        if (foundChange)
1266
 
                        {
1267
 
                                Property tsp = new Property(lastDredgeProp, dredgeTimeStamp);
1268
 
                                tsp.LocalProperty = true;
1269
 
                                collection.Properties.ModifyProperty(tsp);
1270
 
                                collection.Properties.State = PropertyList.PropertyListState.Internal;
1271
 
                                collection.Commit(collection);
1272
 
                        }
1273
 
                }
1274
 
 
1275
 
                
1276
 
 
1277
 
                /// <summary>
1278
 
                /// Finalizer.
1279
 
                /// </summary>
1280
 
                ~FileWatcher()
1281
 
                {
1282
 
                        Dispose(true);
1283
 
                }
1284
 
 
1285
 
                private string GetName(string fullPath)
1286
 
                {
1287
 
                        if (MyEnvironment.Windows)
1288
 
                        {
1289
 
                                try
1290
 
                                {
1291
 
                                        string path = rootPath;
1292
 
                                        // We need to get the name with case preserved.
1293
 
                                        string relPath = fullPath.Replace(rootPath, "");
1294
 
                                        relPath = relPath.TrimStart(Path.DirectorySeparatorChar);
1295
 
                                        string[] pathComponents = relPath.Split(Path.DirectorySeparatorChar);
1296
 
                                        foreach (string pc in pathComponents)
1297
 
                                        {
1298
 
                                                //string[] caseSensitivePath = Directory.GetFileSystemEntries(Path.GetDirectoryName(fullPath), Path.GetFileName(fullPath));
1299
 
                                                string[] caseSensitivePath = Directory.GetFileSystemEntries(path, pc);
1300
 
                                                if (caseSensitivePath.Length == 1)
1301
 
                                                {
1302
 
                                                        // We should only have one match.
1303
 
                                                        path = Path.Combine(path, Path.GetFileName(caseSensitivePath[0]));
1304
 
                                                }
1305
 
                                                else
1306
 
                                                {
1307
 
                                                        // We didn't find the component return the passed in name.
1308
 
                                                        return fullPath;
1309
 
                                                }
1310
 
                                        }
1311
 
                                        fullPath = path;
1312
 
                                }
1313
 
                                catch {}
1314
 
                        }
1315
 
 
1316
 
                        // If this is a sync generated file return null.
1317
 
                        if (isSyncFile(fullPath))
1318
 
                                return null;
1319
 
 
1320
 
                        return fullPath;
1321
 
                }
1322
 
 
1323
 
                private void OnChanged(object source, FileSystemEventArgs e)
1324
 
                {
1325
 
                        string fullPath = e.FullPath;
1326
 
                        
1327
 
                        log.Debug("Changed ---- {0}", e.FullPath);
1328
 
                        if (isSyncFile(e.Name))
1329
 
                                return;
1330
 
                        
1331
 
                        lock (changes)
1332
 
                        {
1333
 
                                fileChangeEntry entry = (fileChangeEntry)changes[fullPath];
1334
 
                                if (entry != null)
1335
 
                                {
1336
 
                                        // This file has already been modified.
1337
 
                                        // Combine the state.
1338
 
                                        switch (entry.eArgs.ChangeType)
1339
 
                                        {
1340
 
                                                case WatcherChangeTypes.Created:
1341
 
                                                case WatcherChangeTypes.Deleted:
1342
 
                                                case WatcherChangeTypes.Changed:
1343
 
                                                        entry.update(e);
1344
 
                                                        break;
1345
 
                                                case WatcherChangeTypes.Renamed:
1346
 
                                                        entry.update();
1347
 
                                                        break;
1348
 
                                        }
1349
 
                                }
1350
 
                                else
1351
 
                                {
1352
 
                                        changes[fullPath] = new fileChangeEntry(e);
1353
 
                                }
1354
 
                        }
1355
 
                }
1356
 
 
1357
 
                private void OnRenamed(object source, RenamedEventArgs e)
1358
 
                {
1359
 
                        string fullPath = e.FullPath;
1360
 
                        log.Debug("Renamed ---- {0} -> {1}", e.OldFullPath, e.FullPath);
1361
 
                        
1362
 
                        if (isSyncFile(e.Name) || isSyncFile(e.OldName))
1363
 
                                return;
1364
 
                        
1365
 
                        lock (changes)
1366
 
                        {
1367
 
                                // Any changes made to the old file need to be removed.
1368
 
                                changes.Remove(e.OldFullPath);
1369
 
                                changes[fullPath] = new fileChangeEntry(e);
1370
 
                                oldNames[e.OldFullPath] = e.FullPath;
1371
 
                                // If We have an oldName of the new name this is a rename back.
1372
 
                                // Create the node for the original rename.
1373
 
                                string createName = (string)oldNames[e.FullPath];
1374
 
                                if (createName != null)
1375
 
                                {
1376
 
                                        oldNames.Remove(e.FullPath);
1377
 
 
1378
 
                                        if (File.Exists(createName))
1379
 
                                        {
1380
 
                                                changes[createName] = new fileChangeEntry(
1381
 
                                                        new FileSystemEventArgs(
1382
 
                                                        WatcherChangeTypes.Created, Path.GetDirectoryName(createName), Path.GetFileName(createName)));
1383
 
                                        }
1384
 
                                }
1385
 
                        }
1386
 
                }
1387
 
 
1388
 
                private void OnDeleted(object source, FileSystemEventArgs e)
1389
 
                {
1390
 
                        string fullPath = e.FullPath;
1391
 
                        log.Debug("Deleted ---- {0}", e.FullPath);
1392
 
                        
1393
 
                        if (isSyncFile(e.Name))
1394
 
                                return;
1395
 
                                                
1396
 
                        lock (changes)
1397
 
                        {
1398
 
                                // Check to see if we had a pending rename.
1399
 
                                // If so we may need to delete both the new and old
1400
 
                                // name.
1401
 
                                fileChangeEntry entry = (fileChangeEntry)changes[fullPath];
1402
 
                                changes[fullPath] = new fileChangeEntry(e);
1403
 
                                if (entry != null && entry.eArgs.ChangeType == WatcherChangeTypes.Renamed)
1404
 
                                {
1405
 
                                        RenamedEventArgs args = entry.eArgs as RenamedEventArgs;
1406
 
                                        if (!changes.Contains(args.OldFullPath))
1407
 
                                        {
1408
 
                                                // We do not have a file by the old name delete it.
1409
 
                                                changes[args.OldFullPath] = new fileChangeEntry(
1410
 
                                                        new FileSystemEventArgs(
1411
 
                                                                WatcherChangeTypes.Deleted, Path.GetDirectoryName(args.OldFullPath), args.OldName));
1412
 
                                        }
1413
 
                                        // Now remove the old name entry.
1414
 
                                        oldNames.Remove(args.OldFullPath);
1415
 
                                }
1416
 
                        }
1417
 
                }
1418
 
 
1419
 
                private void OnCreated(object source, FileSystemEventArgs e)
1420
 
                {
1421
 
                        string fullPath = e.FullPath;
1422
 
                        log.Debug("Created ---- {0}", e.FullPath);
1423
 
                        
1424
 
                        if (isSyncFile(e.Name))
1425
 
                                return;
1426
 
                                                
1427
 
                        lock (changes)
1428
 
                        {
1429
 
                                changes[fullPath] = new fileChangeEntry(e);
1430
 
                        }
1431
 
                }
1432
 
 
1433
 
                private void watcher_Error(object sender, ErrorEventArgs e)
1434
 
                {
1435
 
                        // We have lost events. we need to dredge.
1436
 
                        needToDredge = true;
1437
 
                }
1438
 
        
1439
 
                private void Dispose(bool inFinalize)
1440
 
                {
1441
 
                        lock (this)
1442
 
                        {
1443
 
                                if (!disposed)
1444
 
                                {
1445
 
                                        if (!inFinalize)
1446
 
                                        {
1447
 
                                                System.GC.SuppressFinalize(this);
1448
 
                                        }
1449
 
                                        if (watcher != null)
1450
 
                                        {
1451
 
                                                watcher.Dispose();
1452
 
                                        }
1453
 
                                        disposed = true;
1454
 
                                }
1455
 
                        }
1456
 
                }
1457
 
 
1458
 
                #region IDisposable Members
1459
 
 
1460
 
                /// <summary>
1461
 
                /// Called to cleanup unmanaged resources.
1462
 
                /// </summary>
1463
 
                public void Dispose()
1464
 
                {
1465
 
                        Dispose(false);
1466
 
                }
1467
 
 
1468
 
                #endregion
1469
 
 
1470
 
        }
1471
 
}