IDirectory.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. using Ryujinx.HLE.FileSystem;
  2. using Ryujinx.HLE.HOS.Ipc;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Text;
  7. namespace Ryujinx.HLE.HOS.Services.FspSrv
  8. {
  9. class IDirectory : IpcService, IDisposable
  10. {
  11. private const int DirectoryEntrySize = 0x310;
  12. private Dictionary<int, ServiceProcessRequest> _commands;
  13. public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
  14. private List<DirectoryEntry> _directoryEntries;
  15. private int _currentItemIndex;
  16. public event EventHandler<EventArgs> Disposed;
  17. public string DirectoryPath { get; private set; }
  18. private IFileSystemProvider _provider;
  19. public IDirectory(string directoryPath, int flags, IFileSystemProvider provider)
  20. {
  21. _commands = new Dictionary<int, ServiceProcessRequest>
  22. {
  23. { 0, Read },
  24. { 1, GetEntryCount }
  25. };
  26. _provider = provider;
  27. DirectoryPath = directoryPath;
  28. _directoryEntries = new List<DirectoryEntry>();
  29. if ((flags & 1) != 0)
  30. {
  31. _directoryEntries.AddRange(provider.GetDirectories(directoryPath));
  32. }
  33. if ((flags & 2) != 0)
  34. {
  35. _directoryEntries.AddRange(provider.GetFiles(directoryPath));
  36. }
  37. _currentItemIndex = 0;
  38. }
  39. // Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries)
  40. public long Read(ServiceCtx context)
  41. {
  42. long bufferPosition = context.Request.ReceiveBuff[0].Position;
  43. long bufferLen = context.Request.ReceiveBuff[0].Size;
  44. int maxReadCount = (int)(bufferLen / DirectoryEntrySize);
  45. int count = Math.Min(_directoryEntries.Count - _currentItemIndex, maxReadCount);
  46. for (int index = 0; index < count; index++)
  47. {
  48. long position = bufferPosition + index * DirectoryEntrySize;
  49. WriteDirectoryEntry(context, position, _directoryEntries[_currentItemIndex++]);
  50. }
  51. context.ResponseData.Write((long)count);
  52. return 0;
  53. }
  54. private void WriteDirectoryEntry(ServiceCtx context, long position, DirectoryEntry entry)
  55. {
  56. for (int offset = 0; offset < 0x300; offset += 8)
  57. {
  58. context.Memory.WriteInt64(position + offset, 0);
  59. }
  60. byte[] nameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(entry.Path));
  61. context.Memory.WriteBytes(position, nameBuffer);
  62. context.Memory.WriteInt32(position + 0x300, 0); //Padding?
  63. context.Memory.WriteInt32(position + 0x304, (byte)entry.EntryType);
  64. context.Memory.WriteInt64(position + 0x308, entry.Size);
  65. }
  66. // GetEntryCount() -> u64
  67. public long GetEntryCount(ServiceCtx context)
  68. {
  69. context.ResponseData.Write((long)_directoryEntries.Count);
  70. return 0;
  71. }
  72. public void Dispose()
  73. {
  74. Dispose(true);
  75. }
  76. protected virtual void Dispose(bool disposing)
  77. {
  78. if (disposing)
  79. {
  80. Disposed?.Invoke(this, EventArgs.Empty);
  81. }
  82. }
  83. }
  84. }