1 //
2 // Mono.Unix/UnixDirectoryInfo.cs
3 //
4 // Authors:
5 //   Jonathan Pryor (jonpryor@vt.edu)
6 //
7 // (C) 2004-2006 Jonathan Pryor
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 
29 using System;
30 using System.Collections;
31 using System.IO;
32 using System.Text;
33 using System.Text.RegularExpressions;
34 using Mono.Unix;
35 
36 namespace Mono.Unix {
37 
38 	public sealed class UnixDirectoryInfo : UnixFileSystemInfo
39 	{
UnixDirectoryInfo(string path)40 		public UnixDirectoryInfo (string path)
41 			: base (path)
42 		{
43 		}
44 
UnixDirectoryInfo(string path, Native.Stat stat)45 		internal UnixDirectoryInfo (string path, Native.Stat stat)
46 			: base (path, stat)
47 		{
48 		}
49 
50 		public override string Name {
51 			get {
52 				string r = UnixPath.GetFileName (FullPath);
53 				if (r == null || r.Length == 0)
54 					return FullPath;
55 				return r;
56 			}
57 		}
58 
59 		public UnixDirectoryInfo Parent {
60 			get {
61 				if (FullPath == "/")
62 					return this;
63 				string dirname = UnixPath.GetDirectoryName (FullPath);
64 				if (dirname == "")
65 					throw new InvalidOperationException ("Do not know parent directory for path `" + FullPath + "'");
66 				return new UnixDirectoryInfo (dirname);
67 			}
68 		}
69 
70 		public UnixDirectoryInfo Root {
71 			get {
72 				string root = UnixPath.GetPathRoot (FullPath);
73 				if (root == null)
74 					return null;
75 				return new UnixDirectoryInfo (root);
76 			}
77 		}
78 
79 		[CLSCompliant (false)]
Create(Mono.Unix.Native.FilePermissions mode)80 		public void Create (Mono.Unix.Native.FilePermissions mode)
81 		{
82 			int r = Mono.Unix.Native.Syscall.mkdir (FullPath, mode);
83 			UnixMarshal.ThrowExceptionForLastErrorIf (r);
84 			base.Refresh ();
85 		}
86 
Create(FileAccessPermissions mode)87 		public void Create (FileAccessPermissions mode)
88 		{
89 			Create ((Native.FilePermissions) mode);
90 		}
91 
Create()92 		public void Create ()
93 		{
94 			Mono.Unix.Native.FilePermissions mode =
95 				Mono.Unix.Native.FilePermissions.ACCESSPERMS;
96 			Create (mode);
97 		}
98 
Delete()99 		public override void Delete ()
100 		{
101 			Delete (false);
102 		}
103 
Delete(bool recursive)104 		public void Delete (bool recursive)
105 		{
106 			if (recursive) {
107 				foreach (UnixFileSystemInfo e in GetFileSystemEntries ()) {
108 					UnixDirectoryInfo d = e as UnixDirectoryInfo;
109 					if (d != null)
110 						d.Delete (true);
111 					else
112 						e.Delete ();
113 				}
114 			}
115 			int r = Native.Syscall.rmdir (FullPath);
116 			UnixMarshal.ThrowExceptionForLastErrorIf (r);
117 			base.Refresh ();
118 		}
119 
GetEntries()120 		public Native.Dirent[] GetEntries ()
121 		{
122 			IntPtr dirp = Native.Syscall.opendir (FullPath);
123 			if (dirp == IntPtr.Zero)
124 				UnixMarshal.ThrowExceptionForLastError ();
125 
126 			bool complete = false;
127 			try {
128 				Native.Dirent[] entries = GetEntries (dirp);
129 				complete = true;
130 				return entries;
131 			}
132 			finally {
133 				int r = Native.Syscall.closedir (dirp);
134 				// don't throw an exception if an exception is in progress
135 				if (complete)
136 					UnixMarshal.ThrowExceptionForLastErrorIf (r);
137 			}
138 		}
139 
GetEntries(IntPtr dirp)140 		private static Native.Dirent[] GetEntries (IntPtr dirp)
141 		{
142 			ArrayList entries = new ArrayList ();
143 
144 			int r;
145 			IntPtr result;
146 			do {
147 				Native.Dirent d = new Native.Dirent ();
148 				r = Native.Syscall.readdir_r (dirp, d, out result);
149 				if (r == 0 && result != IntPtr.Zero)
150 					// don't include current & parent dirs
151 					if (d.d_name != "." && d.d_name != "..")
152 						entries.Add (d);
153 			} while  (r == 0 && result != IntPtr.Zero);
154 			if (r != 0)
155 				UnixMarshal.ThrowExceptionForLastErrorIf (r);
156 
157 			return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
158 		}
159 
GetEntries(Regex regex)160 		public Native.Dirent[] GetEntries (Regex regex)
161 		{
162 			IntPtr dirp = Native.Syscall.opendir (FullPath);
163 			if (dirp == IntPtr.Zero)
164 				UnixMarshal.ThrowExceptionForLastError ();
165 
166 			try {
167 				return GetEntries (dirp, regex);
168 			}
169 			finally {
170 				int r = Native.Syscall.closedir (dirp);
171 				UnixMarshal.ThrowExceptionForLastErrorIf (r);
172 			}
173 		}
174 
GetEntries(IntPtr dirp, Regex regex)175 		private static Native.Dirent[] GetEntries (IntPtr dirp, Regex regex)
176 		{
177 			ArrayList entries = new ArrayList ();
178 
179 			int r;
180 			IntPtr result;
181 			do {
182 				Native.Dirent d = new Native.Dirent ();
183 				r = Native.Syscall.readdir_r (dirp, d, out result);
184 				if (r == 0 && result != IntPtr.Zero && regex.Match (d.d_name).Success) {
185 					// don't include current & parent dirs
186 					if (d.d_name != "." && d.d_name != "..")
187 						entries.Add (d);
188 				}
189 			} while  (r == 0 && result != IntPtr.Zero);
190 			if (r != 0)
191 				UnixMarshal.ThrowExceptionForLastError ();
192 
193 			return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
194 		}
195 
GetEntries(string regex)196 		public Native.Dirent[] GetEntries (string regex)
197 		{
198 			Regex re = new Regex (regex);
199 			return GetEntries (re);
200 		}
201 
GetFileSystemEntries()202 		public UnixFileSystemInfo[] GetFileSystemEntries ()
203 		{
204 			Native.Dirent[] dentries = GetEntries ();
205 			return GetFileSystemEntries (dentries);
206 		}
207 
GetFileSystemEntries(Native.Dirent[] dentries)208 		private UnixFileSystemInfo[] GetFileSystemEntries (Native.Dirent[] dentries)
209 		{
210 			UnixFileSystemInfo[] entries = new UnixFileSystemInfo[dentries.Length];
211 			for (int i = 0; i != entries.Length; ++i)
212 				entries [i] = UnixFileSystemInfo.GetFileSystemEntry (
213 						UnixPath.Combine (FullPath, dentries[i].d_name));
214 			return entries;
215 		}
216 
GetFileSystemEntries(Regex regex)217 		public UnixFileSystemInfo[] GetFileSystemEntries (Regex regex)
218 		{
219 			Native.Dirent[] dentries = GetEntries (regex);
220 			return GetFileSystemEntries (dentries);
221 		}
222 
GetFileSystemEntries(string regex)223 		public UnixFileSystemInfo[] GetFileSystemEntries (string regex)
224 		{
225 			Regex re = new Regex (regex);
226 			return GetFileSystemEntries (re);
227 		}
228 
GetCurrentDirectory()229 		public static string GetCurrentDirectory ()
230 		{
231 			StringBuilder buf = new StringBuilder (16);
232 			IntPtr r = IntPtr.Zero;
233 			do {
234 				buf.Capacity *= 2;
235 				r = Native.Syscall.getcwd (buf, (ulong) buf.Capacity);
236 			} while (r == IntPtr.Zero && Native.Syscall.GetLastError() == Native.Errno.ERANGE);
237 			if (r == IntPtr.Zero)
238 				UnixMarshal.ThrowExceptionForLastError ();
239 			return buf.ToString ();
240 		}
241 
SetCurrentDirectory(string path)242 		public static void SetCurrentDirectory (string path)
243 		{
244 			int r = Native.Syscall.chdir (path);
245 			UnixMarshal.ThrowExceptionForLastErrorIf (r);
246 		}
247 	}
248 }
249 
250 // vim: noexpandtab
251