2 // ExtendedAttribute.cs
4 // Copyright (C) 2004 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
27 // FIXME: This is not portable to Win32
32 using System
.Runtime
.InteropServices
;
35 namespace Beagle
.Util
{
37 public class ExtendedAttribute
{
39 // FIXME: Once Mono 1.1/1.2 is required, we should start using the
40 // xattr bindings which are now present in the Mono.Unix.Syscall class.
41 // The interface provided via Syscall in future Mono versions will support both
42 // Linux/FreeBSD attributes transparently.
45 [DllImport (ExternalStringsHack
.XattrLib
, SetLastError
=true)]
46 static extern int lsetxattr (string path
, string name
, byte[] value, uint size
, int flags
);
48 [DllImport (ExternalStringsHack
.XattrLib
, SetLastError
=true)]
49 static extern int lgetxattr (string path
, string name
, byte[] value, uint size
);
51 [DllImport (ExternalStringsHack
.XattrLib
, SetLastError
=true)]
52 static extern int lremovexattr (string path
, string name
);
55 // Very similar to Linux xattrs, but the namespace is provided as a
56 // parameter as opposed to a string prefix to the name.
57 [DllImport (ExternalStringsHack
.XattrLib
, SetLastError
=true)]
58 static extern int extattr_set_link (string path
, int attrnamespace
, string attrname
, byte[] value, uint size
);
60 [DllImport (ExternalStringsHack
.XattrLib
, SetLastError
=true)]
61 static extern int extattr_get_link (string path
, int attrnamespace
, string attrname
, byte[] value, uint size
);
63 [DllImport (ExternalStringsHack
.XattrLib
, SetLastError
=true)]
64 static extern int extattr_delete_link (string path
, int attrnamespace
, string attrname
);
66 private static string AddPrefix (string name
)
69 return "user.Beagle." + name
;
71 return "Beagle." + name
;
75 static Encoding encoding
= new UTF8Encoding ();
77 public static void Set (string path
, string name
, string value)
79 if (! FileSystem
.Exists (path
))
80 throw new IOException (path
);
82 name
= AddPrefix (name
);
84 byte[] buffer
= encoding
.GetBytes (value);
86 int retval
= lsetxattr (path
, name
, buffer
, (uint) buffer
.Length
, 0);
88 int retval
= extattr_set_link (path
, 1, name
, buffer
, (uint) buffer
.Length
);
91 throw new IOException ("Could not set extended attribute on " + path
+ ": " + Syscall
.strerror (Marshal
.GetLastWin32Error ()));
94 public static bool Exists (string path
, string name
)
96 if (! FileSystem
.Exists (path
))
97 throw new IOException (path
);
99 name
= AddPrefix (name
);
101 byte[] buffer
= null;
103 int size
= lgetxattr (path
, name
, buffer
, 0);
105 int size
= extattr_get_link (path
, 1, name
, buffer
, 0);
111 public static string Get (string path
, string name
)
113 if (! FileSystem
.Exists (path
))
114 throw new IOException (path
);
116 name
= AddPrefix (name
);
118 byte[] buffer
= null;
120 int size
= lgetxattr (path
, name
, buffer
, 0);
122 int size
= extattr_get_link (path
, 1, name
, buffer
, 0);
126 buffer
= new byte [size
];
128 int retval
= lgetxattr (path
, name
, buffer
, (uint) size
);
130 int retval
= extattr_get_link (path
, 1, name
, buffer
, (uint) size
);
133 throw new IOException ("Could not get extended attribute on " + path
+ ": " + Syscall
.strerror (Marshal
.GetLastWin32Error ()));
135 return encoding
.GetString (buffer
);
138 public static void Remove (string path
, string name
)
140 if (! FileSystem
.Exists (path
))
141 throw new IOException (path
);
143 name
= AddPrefix (name
);
146 int retval
= lremovexattr (path
, name
);
148 int retval
= extattr_delete_link (path
, 1, name
);
151 throw new IOException ("Could not remove extended attribute on " + path
+ ": " + Syscall
.strerror (Marshal
.GetLastWin32Error ()));
154 // Check to see if it is possible to get and set attributes on a given file.
155 public static bool Test (string path
)
157 const string test_key
= "__test_key__";
158 const string test_value
= "__test_value__";
161 Set (path
, test_key
, test_value
);
162 if (Get (path
, test_key
) != test_value
)
164 Remove (path
, test_key
);
165 return Get (path
, test_key
) == null;
167 } catch (Exception ex
) {
172 private static bool ea_support_tested
= false;
173 private static bool ea_supported
= false;
175 public static bool Supported
{
177 if (ea_support_tested
)
180 ea_supported
= Test (PathFinder
.HomeDir
);
181 ea_support_tested
= true;