34
34
public class FileAttributesStore_ExtendedAttribute : IFileAttributesStore {
38
// 2: Replace LastIndexedTime with LastAttrTime
39
// 3: Store EA's using a CSV format
40
// Format: "Version[2] Fingerprint,Uid,LastWriteTime,LastAttrTime,FilterVersion[3] FilterName"
41
private const int EA_VERSION = 3;
36
43
public static bool Disable = false;
38
45
private string index_fingerprint;
40
47
public FileAttributesStore_ExtendedAttribute (string index_fingerprint)
42
49
this.index_fingerprint = index_fingerprint;
47
// 2: Replace LastIndexedTime with LastAttrTime
48
const int EA_VERSION = 2;
50
// FIXME: We should probably serialize the data into a lump and attach
51
// it to just one EA. The current method has an inherent race condition:
52
// if the file changes out from under us mid-Read or mid-Write, all sorts
53
// of weirdness could ensue.
55
const string fingerprint_attr = "Fingerprint";
56
const string unique_id_attr = "Uid";
57
const string last_mtime_attr = "MTime";
58
const string last_attrtime_attr = "AttrTime";
59
const string filter_attr = "Filter";
61
52
public FileAttributes Read (string path)
68
tmp = ExtendedAttribute.Get (path, fingerprint_attr);
70
|| int.Parse (tmp.Substring (0, 2)) != EA_VERSION
71
|| (index_fingerprint != null && tmp.Substring (3) != index_fingerprint))
58
string tmp = ExtendedAttribute.Get (path);
63
string[] csv = tmp.Split (',');
65
if (int.Parse (csv [0].Substring (0, 2)) != EA_VERSION
66
|| (index_fingerprint != null && csv [0].Substring (3) != index_fingerprint))
74
69
FileAttributes attr = new FileAttributes ();
76
string uid_str = ExtendedAttribute.Get (path, unique_id_attr);
77
attr.UniqueId = GuidFu.FromShortString (uid_str);
70
attr.UniqueId = GuidFu.FromShortString (csv [1]);
80
attr.LastWriteTime = StringFu.StringToDateTime (ExtendedAttribute.Get (path, last_mtime_attr));
82
attr.LastAttrTime = StringFu.StringToDateTime (ExtendedAttribute.Get (path, last_attrtime_attr));
72
attr.LastWriteTime = StringFu.StringToDateTime (csv [2]);
73
attr.LastAttrTime = StringFu.StringToDateTime (csv [3]);
84
tmp = ExtendedAttribute.Get (path, filter_attr);
86
attr.FilterVersion = int.Parse (tmp.Substring (0, 3));
87
attr.FilterName = tmp.Substring (4);
75
if (! String.IsNullOrEmpty (csv [4])) {
76
attr.FilterVersion = int.Parse (csv [4].Substring (0, 3));
77
attr.FilterName = csv [4].Substring (4);
108
tmp = String.Format ("{0:00} {1}", EA_VERSION, index_fingerprint);
109
ExtendedAttribute.Set (attr.Path, fingerprint_attr, tmp);
111
// Try to read the EA we just set. If we
112
// can't, they won't be much use to us --- so
113
// just return false.
114
string what_we_just_wrote;
116
what_we_just_wrote = ExtendedAttribute.Get (attr.Path, fingerprint_attr);
117
} catch (Exception ex) {
120
if (what_we_just_wrote != tmp)
123
ExtendedAttribute.Set (attr.Path, unique_id_attr, GuidFu.ToShortString (attr.UniqueId));
124
ExtendedAttribute.Set (attr.Path, last_mtime_attr,
125
StringFu.DateTimeToString (attr.LastWriteTime));
127
if (attr.HasFilterInfo) {
128
tmp = String.Format ("{0:000} {1}", attr.FilterVersion, attr.FilterName);
129
ExtendedAttribute.Set (attr.Path, filter_attr, tmp);
132
// This has to be the last thing we write out, to get LastAttrTime as close
133
// to the ctime as possible.
96
if (ExtendedAttribute.OldExists (attr.Path, "Fingerprint"))
97
DropObsoleteAttributes (attr.Path);
99
string fingerprint = String.Format ("{0:00} {1}", EA_VERSION, index_fingerprint);
100
string uid = GuidFu.ToShortString (attr.UniqueId);
101
string mtime = StringFu.DateTimeToString (attr.LastWriteTime);
103
string filter = String.Empty;
105
if (attr.HasFilterInfo)
106
filter = String.Format ("{0:000} {1}", attr.FilterVersion, attr.FilterName);
134
108
attr.LastAttrTime = DateTime.UtcNow;
135
ExtendedAttribute.Set (attr.Path, last_attrtime_attr,
136
StringFu.DateTimeToString (attr.LastAttrTime));
109
string attrtime = StringFu.DateTimeToString (attr.LastAttrTime);
111
string [] csv = {fingerprint, uid, mtime, attrtime, filter};
112
ExtendedAttribute.Set (attr.Path, String.Join (",", csv));
139
115
} catch (IOException e) {
140
116
// An IOException here probably means that we don't have the right
158
ExtendedAttribute.Remove (path, fingerprint_attr);
159
ExtendedAttribute.Remove (path, unique_id_attr);
160
ExtendedAttribute.Remove (path, last_mtime_attr);
161
ExtendedAttribute.Remove (path, last_attrtime_attr);
162
ExtendedAttribute.Remove (path, filter_attr);
164
} catch (Exception e) {
134
ExtendedAttribute.Remove (path);
165
136
// FIXME: Do something smarter with the exception.
140
// IMPORTANT: Remove this post 0.3.3 release!
141
private void DropObsoleteAttributes (string path)
144
ExtendedAttribute.RemoveOld (path, "Fingerprint");
145
ExtendedAttribute.RemoveOld (path, "Uid");
146
ExtendedAttribute.RemoveOld (path, "MTime");
147
ExtendedAttribute.RemoveOld (path, "AttrTime");
148
ExtendedAttribute.RemoveOld (path, "Filter");
150
// And some others from Joe's favorite list :-)
151
ExtendedAttribute.RemoveOld (path, "Name");
152
ExtendedAttribute.RemoveOld (path, "IndexTime");
169
156
// There are no transactions for EAs
171
158
public void BeginTransaction ()