1- using ITHit . FileSystem . Windows ;
1+ using ITHit . FileSystem ;
2+ using ITHit . FileSystem . Windows ;
23using System ;
34using System . Collections . Generic ;
45using System . IO ;
56using System . Text ;
7+ using System . Threading . Tasks ;
68
79namespace VirtualFileSystem
810{
911 /// <summary>
10- /// Custom data stored with a file or folder placeholder, such ETag and original file/folder path. Max 4KB.
12+ /// Custom data stored with a file or folder placeholder, such original file/folder path. Max 4KB.
1113 /// </summary>
1214 /// <remarks>To avoid storing metatadata and keep footprit small, this class is is using custom serialization.</remarks>
1315 internal class CustomData
1416 {
15- /// <summary>
16- /// File ETag. Used to verify that the file on the server is not modified during client to server synchronization.
17- /// </summary>
18- /// <remarks>This field is required if the server does not provide locking capabilities.</remarks>
19- internal string ETag = "" ;
20-
2117 /// <summary>
2218 /// Keeps the original file/folder path. Used to sync file/folder from user file system to remote storage
2319 /// if this app was not running when the file/folder was moved or renamed. This field allows to avoid
2420 /// delete-create sequence during client to server synchronization after app failure.
2521 /// </summary>
2622 internal string OriginalPath = "" ;
2723
28- /// <summary>
29- /// Used for Microsoft Office lock files (~$file.ext) to store custom data during transactional save.
30- /// The original MS Office file is renamed and than deleted. As a result the ETag is lost and we can not
31- /// send the ETag to the server when saving the file.
32- /// As a solution, we copy custom data from the original file during lock file creation into this field.
33- /// When the original file is being saved, we read ETag from the lock file.
34- /// </summary>
35- internal byte [ ] SavedData = new byte [ ] { } ;
36-
3724 /// <summary>
3825 /// Serializes all custom data fields into the byte array.
3926 /// </summary>
@@ -44,10 +31,7 @@ internal byte[] Serialize()
4431 {
4532 using ( BinaryWriter writer = new BinaryWriter ( m ) )
4633 {
47- writer . Write ( ETag ) ;
4834 writer . Write ( OriginalPath ) ;
49- writer . Write ( SavedData . Length ) ;
50- writer . Write ( SavedData ) ;
5135 }
5236 return m . ToArray ( ) ;
5337 }
@@ -70,29 +54,27 @@ internal static CustomData Desserialize(byte[] data)
7054 {
7155 using ( BinaryReader reader = new BinaryReader ( m ) )
7256 {
73- obj . ETag = reader . ReadString ( ) ;
7457 obj . OriginalPath = reader . ReadString ( ) ;
75- obj . SavedData = reader . ReadBytes ( reader . ReadInt32 ( ) ) ;
7658 }
7759 }
7860 return obj ;
7961 }
8062 }
8163
8264 /// <summary>
83- /// Placeholder methods to get and set custom data associated with a placeholder, such as ETah and OriginalPath.
65+ /// Placeholder methods to get and set custom data associated with a placeholder, such as OriginalPath.
8466 /// </summary>
8567 internal static class PlaceholderItemExtensions
8668 {
87- public static void SetCustomData ( this PlaceholderItem placeholder , string eTag , string originalPath )
69+ public static void SetCustomData ( this PlaceholderItem placeholder , string originalPath )
8870 {
89- CustomData customData = new CustomData { ETag = eTag , OriginalPath = originalPath } ;
71+ CustomData customData = new CustomData { OriginalPath = originalPath } ;
9072 placeholder . SetCustomData ( customData . Serialize ( ) ) ;
9173 }
9274
93- public static void SetCustomData ( Microsoft . Win32 . SafeHandles . SafeFileHandle safeHandle , string eTag , string originalPath )
75+ public static void SetCustomData ( Microsoft . Win32 . SafeHandles . SafeFileHandle safeHandle , string originalPath )
9476 {
95- CustomData customData = new CustomData { ETag = eTag , OriginalPath = originalPath } ;
77+ CustomData customData = new CustomData { OriginalPath = originalPath } ;
9678 PlaceholderItem . SetCustomData ( safeHandle , customData . Serialize ( ) ) ;
9779 }
9880
@@ -112,38 +94,6 @@ public static string GetOriginalPath(this PlaceholderItem placeholder)
11294 return customData . OriginalPath ;
11395 }
11496
115- public static void SetETag ( this PlaceholderItem placeholder , string eTag )
116- {
117- byte [ ] customDataRaw = placeholder . GetCustomData ( ) ;
118- CustomData customData = ( customDataRaw . Length > 0 ) ? CustomData . Desserialize ( customDataRaw ) : new CustomData ( ) ;
119-
120- customData . ETag = eTag ;
121- placeholder . SetCustomData ( customData . Serialize ( ) ) ;
122- }
123-
124- public static string GetETag ( this PlaceholderItem placeholder )
125- {
126- byte [ ] customDataRaw = placeholder . GetCustomData ( ) ;
127- CustomData customData = ( customDataRaw . Length > 0 ) ? CustomData . Desserialize ( customDataRaw ) : new CustomData ( ) ;
128- return customData . ETag ;
129- }
130-
131- public static void SetSavedData ( this PlaceholderItem placeholder , byte [ ] saveData )
132- {
133- byte [ ] customDataRaw = placeholder . GetCustomData ( ) ;
134- CustomData customData = ( customDataRaw . Length > 0 ) ? CustomData . Desserialize ( customDataRaw ) : new CustomData ( ) ;
135-
136- customData . SavedData = saveData ;
137- placeholder . SetCustomData ( customData . Serialize ( ) ) ;
138- }
139-
140- public static byte [ ] GetSavedData ( this PlaceholderItem placeholder )
141- {
142- byte [ ] customDataRaw = placeholder . GetCustomData ( ) ;
143- CustomData customData = ( customDataRaw . Length > 0 ) ? CustomData . Desserialize ( customDataRaw ) : new CustomData ( ) ;
144- return customData . SavedData ;
145- }
146-
14797 /// <summary>
14898 /// Returns true if the file was moved in the user file system and changes not yet synched to the remote storage.
14999 /// </summary>
@@ -160,5 +110,20 @@ public static bool IsMoved(this PlaceholderItem placeholder)
160110 return ! originalPath . Equals ( placeholder . Path , StringComparison . InvariantCultureIgnoreCase ) ;
161111 }
162112
113+ public static bool IsNew ( this PlaceholderItem placeholder )
114+ {
115+ // ETag presence signals if the item is new.
116+ // However, ETag file may not exists during move operation,
117+ // additionally checking OriginalPath presence.
118+ // Can not rely on OriginalPath only,
119+ // because MS Office transactional save deletes and recreates the file.
120+
121+ string originalPath = placeholder . GetOriginalPath ( ) ;
122+
123+ bool eTagFileExists = File . Exists ( ETag . GetETagFilePath ( placeholder . Path ) ) ;
124+
125+ return ! eTagFileExists && string . IsNullOrEmpty ( originalPath ) ;
126+ }
127+
163128 }
164129}
0 commit comments