1 // =================================
  2 // Copyright (c) 2022 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 using System.Os;
  9 
 10 namespace System.IO
 11 {
 12     public const int pathMax = 4096;
 13     public const int statBufSize = 70;
 14 
 15     public string GetCurrentWorkingDirectory()
 16     {
 17         Buffer buffer(pathMax);
 18         char* buf = cast<char*>(cast<void*>(buffer.Mem()));
 19         long count = buffer.Size();
 20         GetCWD(bufcount);
 21         return string(buf);
 22     }
 23 
 24     public static class Directory
 25     {
 26         public static bool Exists(const string& directoryPath)
 27         {
 28             return DirectoryExists(directoryPath);
 29         }
 30         public static bool IsEmpty(const string& directoryPath)
 31         {
 32             return IsDirectoryEmpty(directoryPath);
 33         }
 34         public static void Create(const string& directoryPath)
 35         {
 36             Create(directoryPath0);
 37         }
 38         public static void Create(const string& directoryPathint mode)
 39         {
 40             CreateDirectory(directoryPathmode);
 41         }
 42         public static DateTime AccessTime(const string& directoryPath)
 43         {
 44             return GetDirectoryAccessTime(directoryPath);
 45         }
 46         public static DateTime ModificationTime(const string& directoryPath)
 47         {
 48             return GetDirectoryModificationTime(directoryPath);
 49         }
 50         public static void GetTimes(const string& directoryPathDateTime& accessTimeDateTime& modificationTime)
 51         {
 52             GetDirectoryTimes(directoryPathaccessTimemodificationTime);
 53         }
 54         public static void SetTimes(const string& directoryPathconst DateTime& accessTimeconst DateTime& modificationTime)
 55         {
 56             SetDirectoryTimes(directoryPathaccessTimemodificationTime);
 57         }
 58         public static void Remove(const string& directoryPath)
 59         {
 60             RemoveDirectory(directoryPath);
 61         }
 62     }
 63     
 64     public void CreateDirectory(const string& directoryPath)
 65     {
 66         CreateDirectory(directoryPath0);
 67     }
 68     
 69     public void CreateDirectory(const string& directoryPathint mode)
 70     {
 71         MkDir(directoryPath.Chars()mode);
 72     }
 73   
 74     public void CreateDirectories(const string& directoryPath)
 75     {
 76         CreateDirectories(directoryPath0);
 77     }
 78     
 79     public void CreateDirectories(const string& directoryPathint mode)
 80     {
 81         if (directoryPath.IsEmpty())
 82         {
 83             throw InvalidPathException("directory path is empty");
 84         }
 85         List<string> components = directoryPath.Split('/');
 86         int n = cast<int>(components.Count());
 87         string dir;
 88         int next = 0;
 89         if (components[0].IsEmpty())
 90         {
 91             dir = "/" + components[1];
 92             next = 2;
 93         }
 94         else
 95         {
 96             dir = components[0];
 97             next = 1;
 98         }
 99         if (!Directory.Exists(dir))
100         {
101             MkDir(dir.Chars()mode);
102         }
103         for (int i = next; i < n; ++i;)
104         {
105             dir = Path.Combine(dircomponents[i]);
106             if (!Directory.Exists(dir))
107             {
108                 MkDir(dir.Chars()mode);
109             }
110         }
111     }
112     
113     public bool DirectoryExists(const string& dirPath)
114     {
115         byte[statBufSize] statBuf;
116         int result = stat(dirPath.Chars()&statBuf[0]statBufSize);
117         if (result == -1)
118         {
119             SystemError systemError = GetSystemError();
120             if (systemError.errorCode == ENOTFOUND)
121             {
122                 return false;
123             }
124             else
125             {
126                 ThrowSystemError();
127             }
128         }
129         else
130         {
131             FileStatus status;
132             GetFileStatus(&statBuf[0]status);
133             if (status.fileType == FileType.directory)
134             {
135                 return true;
136             }
137             else
138             {
139                 throw FileSystemException("path '" + dirPath + "' is not a directory path");
140             }
141         }
142     }
143     
144     public bool IsDirectoryEmpty(const string& dirPath)
145     {
146         if (!DirectoryExists(dirPath))
147         {
148             throw FileSystemException("directory path '" + dirPath + "' does not exist");
149         }
150         DirectoryEntry entry;
151         DirectoryReader reader(dirPath);
152         while (reader.Read(entry))
153         {
154             if (entry.IsDot() || entry.IsDotDot())
155             {
156                 continue;
157             }
158             return false;
159         }
160         return true;
161     }
162     
163     public DateTime GetDirectoryAccessTime(const string& dirPath)
164     {
165         FileStatus status;
166         Stat(dirPath.Chars()status);
167         if (status.fileType != FileType.directory)
168         {
169             throw FileSystemException("path '" + dirPath + "' is not a directory path");
170         }
171         return status.atime;
172     }
173     
174     public DateTime GetDirectoryModificationTime(const string& dirPath)
175     {
176         FileStatus status;
177         Stat(dirPath.Chars()status);
178         if (status.fileType != FileType.directory)
179         {
180             throw FileSystemException("path '" + dirPath + "' is not a directory path");
181         }
182         return status.mtime;
183     }
184     
185     public void GetDirectoryTimes(const string& dirPathDateTime& accessTimeDateTime& modificationTime)
186     {
187         FileStatus status;
188         Stat(dirPath.Chars()status);
189         if (status.fileType != FileType.directory)
190         {
191             throw FileSystemException("path '" + dirPath + "' is not a directory path");
192         }
193         accessTime = status.atime;
194         modificationTime = status.mtime;
195     }
196     
197     public void SetDirectoryTimes(const string& dirPathconst DateTime& accessTimeconst DateTime& modificationTime)
198     {
199         UTime(dirPath.Chars()accessTimemodificationTime);
200     }
201     
202     public class DirectoryEntry
203     {
204         public nothrow DirectoryEntry() : inodeNumber(-1)name()
205         {
206         }
207         public nothrow DirectoryEntry(int inodeNumber_const string& name_) : inodeNumber(inodeNumber_)name(name_)
208         {
209         }
210         public nothrow bool IsDot() const
211         {
212             return name == ".";
213         }
214         public nothrow bool IsDotDot() const
215         {
216             return name == "..";
217         }
218         public int inodeNumber;
219         public string name;
220     }
221     
222     public const int directoryEntrySize = 256;
223     
224     public class DirectoryReader
225     {
226         public nothrow DirectoryReader(const string& dirPath) : dfd(OpenDir(dirPath.Chars()))
227         {
228         }
229         public bool Read(DirectoryEntry& dirEntry)
230         {
231             byte[directoryEntrySize] dirEntryBuf;
232             int result = ReadDir(dfd&dirEntryBuf[0]directoryEntrySize);
233             if (result == 1)
234             {
235                 MemoryReader reader(&dirEntryBuf[0]directoryEntrySize);
236                 dirEntry.inodeNumber = reader.ReadInt();
237                 dirEntry.name = reader.ReadString();
238                 return true;
239             }
240             return false;
241         }
242         public ~DirectoryReader()
243         {
244             try
245             {
246                 CloseDir(dfd);
247             }
248             catch (const Exception&)
249             {
250             }
251         }
252         private int dfd;
253     }
254 
255     public void RemoveDirectory(const string& dirPath)
256     {
257         Unlink(dirPath.Chars());
258     }
259 }