PageRenderTime 43ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sys/dotnet/fan/sys/LocalFile.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 541 lines | 408 code | 67 blank | 66 comment | 75 complexity | 6aafd2fe797d3f00a8c3d85335f43ff1 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2006, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 28 Jan 07 Andy Frank Creation
  7. //
  8. using System.Collections;
  9. using System.Text;
  10. using FileInfo = System.IO.FileInfo;
  11. using FileStream = System.IO.FileStream;
  12. using FileSystemInfo = System.IO.FileSystemInfo;
  13. using DirectoryInfo = System.IO.DirectoryInfo;
  14. namespace Fan.Sys
  15. {
  16. /// <summary>
  17. /// LocalFile represents a file or directory in the local file system.
  18. /// </summary>
  19. public class LocalFile : File
  20. {
  21. //////////////////////////////////////////////////////////////////////////
  22. // Conversions
  23. //////////////////////////////////////////////////////////////////////////
  24. public static Uri fileToUri(FileSystemInfo file, bool isDir)
  25. {
  26. return pathToUri(file.FullName, isDir);
  27. }
  28. public static Uri pathToUri(string path, bool isDir)
  29. {
  30. return pathToUri(path, isDir, null);
  31. }
  32. public static Uri pathToUri(string path, bool isDir, string scheme)
  33. {
  34. int len = path.Length;
  35. StringBuilder s = new StringBuilder(path.Length+2);
  36. // if scheme was specified
  37. if (scheme != null) s.Append(scheme).Append(':');
  38. // deal with Windoze drive name
  39. if (len > 2 && path[1] == ':' && path[0] != '\\')
  40. s.Append('/');
  41. // map characters
  42. for (int i=0; i<len; ++i)
  43. {
  44. int c = path[i];
  45. switch (c)
  46. {
  47. case '?':
  48. case '#': s.Append('\\').Append((char)c); break;
  49. case '\\': s.Append('/'); break;
  50. default: s.Append((char)c); break;
  51. }
  52. }
  53. // add trailing slash if not present
  54. if (isDir && (s.Length == 0 || s[s.Length-1] != '\\'))
  55. s.Append('/');
  56. return Uri.fromStr(s.ToString());
  57. }
  58. public static FileSystemInfo uriToFile(Uri uri)
  59. {
  60. if (uri.scheme() != null && uri.scheme() != "file")
  61. throw ArgErr.make("Invalid Uri scheme for local file: " + uri).val;
  62. string path = uriToPath(uri);
  63. if (System.IO.Directory.Exists(path)) return new DirectoryInfo(path);
  64. if (System.IO.File.Exists(path)) return new FileInfo(path);
  65. if (uri.isDir()) return new DirectoryInfo(path);
  66. return new FileInfo(path);
  67. }
  68. public static string uriToPath(Uri uri)
  69. {
  70. string path = uri.m_pathStr;
  71. bool dir = uri.isDir();
  72. int len = path.Length;
  73. StringBuilder s = new StringBuilder(path.Length);
  74. for (int i=0; i<len; ++i)
  75. {
  76. int c = path[i];
  77. if (i == 0 && c == '/' && path.Contains(":")) continue; // skip abs
  78. if (i == len-1 && c == '/' && dir) continue; // skip trailing slash
  79. switch (c)
  80. {
  81. case '\\': break;
  82. case '/': s.Append('\\'); break;
  83. default: s.Append((char)c); break;
  84. }
  85. }
  86. return s.ToString();
  87. }
  88. public static string fileNameToUriName(string name)
  89. {
  90. int len = name.Length;
  91. StringBuilder s = null;
  92. for (int i=0; i<len; ++i)
  93. {
  94. int c = name[i];
  95. switch (c)
  96. {
  97. case '?':
  98. case '#':
  99. if (s == null) { s = new StringBuilder(); s.Append(name, 0, i); }
  100. s.Append('\\').Append((char)c);
  101. break;
  102. default:
  103. if (s != null) s.Append((char)c);
  104. break;
  105. }
  106. }
  107. return s == null ? name: s.ToString();
  108. }
  109. //////////////////////////////////////////////////////////////////////////
  110. // Construction
  111. //////////////////////////////////////////////////////////////////////////
  112. public static Uri toUri(FileSystemInfo file)
  113. {
  114. return fileToUri(file, file is DirectoryInfo);
  115. }
  116. public LocalFile(Uri uri)
  117. : this(uri, uriToFile(uri)) {}
  118. public LocalFile(FileSystemInfo file)
  119. : this(file, file is DirectoryInfo) {}
  120. public LocalFile(FileSystemInfo file, bool isDir)
  121. : this(fileToUri(file, isDir), file) {}
  122. public LocalFile(Uri uri, FileSystemInfo file)
  123. : base(uri)
  124. {
  125. this.m_file = file;
  126. if (System.IO.Directory.Exists(file.FullName))
  127. {
  128. if (!uri.isDir())
  129. throw IOErr.make("Must use trailing slash for dir: " + uri).val;
  130. }
  131. else if (System.IO.File.Exists(file.FullName))
  132. {
  133. if (uri.isDir())
  134. throw IOErr.make("Cannot use trailing slash for file: " + uri).val;
  135. }
  136. }
  137. //////////////////////////////////////////////////////////////////////////
  138. // Obj
  139. //////////////////////////////////////////////////////////////////////////
  140. public override Type @typeof() { return Sys.LocalFileType; }
  141. //////////////////////////////////////////////////////////////////////////
  142. // File
  143. //////////////////////////////////////////////////////////////////////////
  144. public override bool exists()
  145. {
  146. return m_file.Exists;
  147. }
  148. public override Long size()
  149. {
  150. if (m_file is DirectoryInfo) return null;
  151. m_file.Refresh();
  152. return Long.valueOf((m_file as FileInfo).Length);
  153. }
  154. public override DateTime modified()
  155. {
  156. return m_file.Exists ? DateTime.dotnet(m_file.LastAccessTime.Ticks) : null;
  157. }
  158. public override void modified(DateTime time)
  159. {
  160. m_file.LastAccessTime = new System.DateTime(time.dotnet());
  161. }
  162. public override string osPath()
  163. {
  164. return uriToPath(m_uri);
  165. }
  166. public override File parent()
  167. {
  168. Uri parent = m_uri.parent();
  169. if (parent == null) return null;
  170. return new LocalFile(parent, uriToFile(parent));
  171. }
  172. public override List list()
  173. {
  174. int len = 0;
  175. FileSystemInfo[] list = null;
  176. if (m_file is DirectoryInfo)
  177. {
  178. list = (m_file as DirectoryInfo).GetFileSystemInfos();
  179. len = list.Length;
  180. }
  181. List acc = new List(Sys.FileType, len);
  182. for (int i=0; i<len; i++)
  183. {
  184. FileSystemInfo f = list[i];
  185. string name = fileNameToUriName(f.Name);
  186. acc.add(new LocalFile(m_uri.plusName(name, f is DirectoryInfo), f));
  187. }
  188. return acc;
  189. }
  190. public override File normalize()
  191. {
  192. // TODO - not sure how this should work in .NET
  193. bool isDir = m_file is DirectoryInfo;
  194. FileSystemInfo canonical;
  195. if (isDir)
  196. canonical = new DirectoryInfo(m_file.FullName);
  197. else
  198. canonical = new FileInfo(m_file.FullName);
  199. Uri uri = pathToUri(canonical.FullName, isDir, "file");
  200. return new LocalFile(uri, canonical);
  201. }
  202. public override File plus(Uri uri, bool checkSlash)
  203. {
  204. return make(m_uri.plus(uri), checkSlash);
  205. }
  206. //////////////////////////////////////////////////////////////////////////
  207. // File Management
  208. //////////////////////////////////////////////////////////////////////////
  209. public override File create()
  210. {
  211. if (isDir())
  212. createDir();
  213. else
  214. createFile();
  215. return this;
  216. }
  217. private void createFile()
  218. {
  219. if (m_file.Exists)
  220. {
  221. if (m_file is DirectoryInfo)
  222. throw IOErr.make("Already exists as dir: " + m_file).val;
  223. }
  224. else
  225. {
  226. DirectoryInfo parent = (m_file as FileInfo).Directory;
  227. if (!parent.Exists)
  228. {
  229. try
  230. {
  231. System.IO.Directory.CreateDirectory(parent.FullName);
  232. }
  233. catch (System.Exception e)
  234. {
  235. throw IOErr.make("Cannot create dir: " + parent, e).val;
  236. }
  237. }
  238. try
  239. {
  240. // TODO - not sure how this should work yet
  241. FileStream fs = (m_file as FileInfo).Create();
  242. fs.Close();
  243. m_file.Refresh();
  244. }
  245. catch (System.IO.IOException e)
  246. {
  247. throw IOErr.make(e).val;
  248. }
  249. }
  250. }
  251. private void createDir()
  252. {
  253. if (m_file.Exists)
  254. {
  255. if (!(m_file is DirectoryInfo))
  256. throw IOErr.make("Already exists as file: " + m_file).val;
  257. }
  258. else
  259. {
  260. try
  261. {
  262. System.IO.Directory.CreateDirectory(m_file.FullName);
  263. m_file.Refresh();
  264. }
  265. catch (System.Exception e)
  266. {
  267. throw IOErr.make("Cannot create dir: " + m_file, e).val;
  268. }
  269. }
  270. }
  271. public override File moveTo(File to)
  272. {
  273. if (isDir() != to.isDir())
  274. {
  275. if (isDir())
  276. throw ArgErr.make("moveTo must be dir `" + to + "`").val;
  277. else
  278. throw ArgErr.make("moveTo must not be dir `" + to + "`").val;
  279. }
  280. if (!(to is LocalFile))
  281. throw IOErr.make("Cannot move LocalFile to " + to.@typeof()).val;
  282. LocalFile dest = (LocalFile)to;
  283. if (dest.exists())
  284. throw IOErr.make("moveTo already exists: " + to).val;
  285. try
  286. {
  287. if (m_file is FileInfo)
  288. (m_file as FileInfo).MoveTo((dest.m_file as FileInfo).FullName);
  289. else
  290. (m_file as DirectoryInfo).MoveTo((dest.m_file as DirectoryInfo).FullName);
  291. }
  292. catch (System.IO.IOException)
  293. {
  294. throw IOErr.make("moveTo failed: " + to).val;
  295. }
  296. return to;
  297. }
  298. public override void delete()
  299. {
  300. if (!exists()) return;
  301. if (m_file is DirectoryInfo)
  302. {
  303. List kids = list();
  304. for (int i=0; i<kids.sz(); i++)
  305. (kids.get(i) as File).delete();
  306. }
  307. try
  308. {
  309. m_file.Delete();
  310. m_file.Refresh();
  311. }
  312. catch (System.Exception e)
  313. {
  314. throw IOErr.make("Cannot delete: " + m_file, e).val;
  315. }
  316. }
  317. public override File deleteOnExit()
  318. {
  319. m_deleteOnExit.Add(m_file);
  320. return this;
  321. }
  322. //////////////////////////////////////////////////////////////////////////
  323. // IO
  324. //////////////////////////////////////////////////////////////////////////
  325. public override Buf open(string mode)
  326. {
  327. try
  328. {
  329. System.IO.FileMode fm;
  330. System.IO.FileAccess fa;
  331. string s = mode;
  332. if (s == "r")
  333. {
  334. fm = System.IO.FileMode.Open;
  335. fa = System.IO.FileAccess.Read;
  336. }
  337. else if (s == "w")
  338. {
  339. fm = System.IO.FileMode.OpenOrCreate;
  340. fa = System.IO.FileAccess.Write;
  341. }
  342. else if (s == "rw")
  343. {
  344. fm = System.IO.FileMode.OpenOrCreate;
  345. fa = System.IO.FileAccess.ReadWrite;
  346. }
  347. else
  348. {
  349. throw new System.IO.IOException("Unsupported mode: " + mode);
  350. }
  351. return new FileBuf(this, (m_file as FileInfo).Open(fm, fa));
  352. }
  353. catch (System.IO.IOException e)
  354. {
  355. throw IOErr.make(e).val;
  356. }
  357. }
  358. public override Buf mmap(string mode, long pos, Long size)
  359. {
  360. try
  361. {
  362. // map mode
  363. /*
  364. MmapBuf.FileRights mode;
  365. if (mode.val.equals("r")) { mode = MmapBuff.FileRights.Read; }
  366. else if (mode.val.equals("rw")) { mode = MmapBuff.FileRights.ReadWrite; }
  367. else if (mode.val.equals("p")) throw ArgErr.make("Private mode not supported.").val;
  368. else throw ArgErr.make("Invalid mode: " + mode).val;
  369. // verify mode is 'r' or 'rw'
  370. if (mode.val.equals("p")) throw ArgErr.make("Private mode not supported.").val;
  371. if (!mode.val.equals("r") || !mode.val.equals("rw")) throw ArgErr.make("Invalid mode: " + mode).val;
  372. // if size is null, use file size
  373. if (size == null) size = size();
  374. // traverse the various Java APIs
  375. //RandomAccessFile fp = new RandomAccessFile(file, rw);
  376. //FileChannel chan = fp.getChannel();
  377. //MappedByteBuffer mmap = chan.map(mm, pos.val, size.val);
  378. */
  379. return new MmapBuf(this, mode, pos, size);
  380. }
  381. catch (System.IO.IOException e)
  382. {
  383. throw IOErr.make(e).val;
  384. }
  385. }
  386. public override InStream @in(Long bufSize)
  387. {
  388. try
  389. {
  390. System.IO.Stream stream = (m_file as FileInfo).OpenRead();
  391. return SysInStream.make(stream, bufSize);
  392. }
  393. catch (System.IO.IOException e)
  394. {
  395. throw IOErr.make(e).val;
  396. }
  397. }
  398. public override OutStream @out(bool append, Long bufSize)
  399. {
  400. try
  401. {
  402. FileInfo f = (FileInfo)m_file;
  403. System.IO.Directory.CreateDirectory(f.DirectoryName);
  404. System.IO.Stream fout = f.Open(
  405. append ? System.IO.FileMode.Append : System.IO.FileMode.Create,
  406. System.IO.FileAccess.Write);
  407. System.IO.Stream bout = SysOutStream.toBuffered(fout, bufSize);
  408. m_file.Refresh();
  409. return new LocalFileOutStream(bout/*, fout.getFD()*/);
  410. }
  411. catch (System.IO.IOException e)
  412. {
  413. throw IOErr.make(e).val;
  414. }
  415. }
  416. internal class LocalFileOutStream : SysOutStream
  417. {
  418. public LocalFileOutStream(System.IO.Stream @out/*, FileDescriptor fd*/)
  419. : base(@out)
  420. {
  421. /*this.fd = fd;*/
  422. }
  423. public override OutStream sync()
  424. {
  425. try
  426. {
  427. flush();
  428. /*fd.sync();*/
  429. return this;
  430. }
  431. catch (System.IO.IOException e)
  432. {
  433. throw IOErr.make(e).val;
  434. }
  435. }
  436. /*FileDescriptor fd;*/
  437. }
  438. //////////////////////////////////////////////////////////////////////////
  439. // ProcessExit
  440. //////////////////////////////////////////////////////////////////////////
  441. static ArrayList m_deleteOnExit = new ArrayList();
  442. static LocalFile()
  443. {
  444. System.AppDomain.CurrentDomain.ProcessExit
  445. += new System.EventHandler(handleProcessExit);
  446. }
  447. static void handleProcessExit(object sender, System.EventArgs args)
  448. {
  449. foreach (FileSystemInfo f in m_deleteOnExit)
  450. {
  451. try
  452. {
  453. if (f is DirectoryInfo)
  454. (f as DirectoryInfo).Delete(true);
  455. else
  456. f.Delete();
  457. }
  458. catch (System.IO.DirectoryNotFoundException) {} // ok
  459. catch (System.IO.FileNotFoundException) {} // ok
  460. }
  461. }
  462. //////////////////////////////////////////////////////////////////////////
  463. // C#
  464. //////////////////////////////////////////////////////////////////////////
  465. public FileSystemInfo toDotnet() { return m_file; }
  466. //////////////////////////////////////////////////////////////////////////
  467. // Fields
  468. //////////////////////////////////////////////////////////////////////////
  469. internal FileSystemInfo m_file = null;
  470. }
  471. }