static IEnumerable <(string Path, string Name, Result <Stat, FsException> Stat)> Ret(IntPtr dir, string path) { var dirent = new Dirent(); while (true) { var res = Syscall.readdir_r(dir, dirent, out var resDirent); if (res != 0) { throw new FsException("Failed to read directory entry", path); } if (resDirent == NullPtr) { break; } if (dirent.d_name == "." || dirent.d_name == "..") { continue; } var newPath = Path.Join(path, dirent.d_name); if (Syscall.stat(newPath, out var stat) != 0) { yield return(newPath, dirent.d_name, new FsException("Failed to stat", path)); } yield return(newPath, dirent.d_name, stat); } }
private FileType GetKind(Dirent e) { switch ((DirentType)e.d_type) { case DirentType.DT_DIR: return(FileType.Directory); case DirentType.DT_LNK: return(FileType.Symlink); case DirentType.DT_REG: return(FileType.File); case DirentType.DT_BLK: return(FileType.BlockDevice); case DirentType.DT_CHR: return(FileType.CharDevice); default: return(FileType.Unsupported); } //return FileType.Unsupported; }
private Dirent readDirent() { var ret = new Dirent() { ino = _stream.ReadInt32LE(), type = _stream.ReadInt32LE(), namelen = _stream.ReadInt32LE(), entsize = _stream.ReadUInt32LE() }; ret.name = _stream.ReadASCIINullTerminated(ret.namelen); _stream.Position = (_stream.Position + 7) & (~7L); return(ret); }
public PosixFile(Dirent entry) { unixEntry = entry; // used for clone() this.SnapFullPath = entry.d_name; this.Name = this.SnapFullPath.Substring(this.SnapFullPath.LastIndexOf('/') + 1); ID = (long)entry.d_ino; this.Kind = GetKind(entry); //this.IsSparse = false; // try to get ID version (inode generation number), for easier delete/move/renames detection // EOPNOTSUP = 95 Stat entryStat; if (this.Kind != FileType.Symlink) { //Syscall.fstat(fd, out entryStat); Syscall.stat(this.SnapFullPath, out entryStat); string[] xattrs = new string[16]; Syscall.listxattr(this.SnapFullPath, out xattrs); GetXattrs(xattrs); } else { Syscall.lstat(this.SnapFullPath, out entryStat); System.Text.StringBuilder sb = new System.Text.StringBuilder(2048); Syscall.readlink(this.SnapFullPath, sb); this.TargetName = sb.ToString(); //Console.WriteLine ("symlink pointing to "+targetName); } //this.LastAccessedTime = Utils.GetDateTimeFromUnixTime(entryStat.st_atime); this.LastMetadataModifiedTime = entryStat.st_ctime; this.LastModifiedTime = entryStat.st_mtime; this.CreateTime = 0; //DateTime.MinValue.ToFileTimeUtc(); this.Permissions = (uint)entryStat.st_mode; if (this.Kind == FileType.File) // though dirs also have sizes, useless to get it { this.FileSize = entryStat.st_size; } this.OwnerUser = entryStat.st_uid; this.OwnerGroup = entryStat.st_gid; this.SpecialAttributes = 0; // TODO!!! BlockMetadata = new FileBlockMetadata(); //Syscall.close(fd); }
private static Dirent[] GetEntries(IntPtr dirp, Regex regex) { int num; IntPtr intPtr; ArrayList arrayLists = new ArrayList(); do { Dirent dirent = new Dirent(); num = Syscall.readdir_r(dirp, dirent, out intPtr); if (num != 0 || !(intPtr != IntPtr.Zero) || !regex.Match(dirent.d_name).Success || !(dirent.d_name != ".") || !(dirent.d_name != "..")) { continue; } arrayLists.Add(dirent); }while (num == 0 && intPtr != IntPtr.Zero); if (num != 0) { UnixMarshal.ThrowExceptionForLastError(); } return((Dirent[])arrayLists.ToArray(typeof(Dirent))); }
unsafe static IList <DirectoryEntry> Scan(string path, bool recurse, Predicate <string> cb_shouldskipdir) { if (recurse) { bool first = true; IntPtr str = Marshal.StringToHGlobalAnsi(path); try { IntPtr[] arr = new IntPtr[] { str, IntPtr.Zero }; IntPtr handle; fixed(IntPtr *arg = arr) handle = fts_open(new IntPtr(arg), FTS_NOCHDIR | FTS_PHYSICAL, IntPtr.Zero); if (handle == IntPtr.Zero) { throw new Exception("failed to fts_open"); } try { FTSENT *ent = fts_read(handle); if (ent == null) { return(__empty); } List <DirectoryEntry> ret = new List <DirectoryEntry>(); while (ent != null) { //Console.WriteLine("ent: " + ent->ToString()); bool isfile; if (ent->fts_info == FTS_F) { isfile = true; } else if (ent->fts_info == FTS_D) { isfile = false; } else { ent = fts_read(handle); continue; } bool skip = false; string fullpath = Marshal.PtrToStringAnsi(ent->fts_path); if (!isfile && cb_shouldskipdir != null) { if (cb_shouldskipdir != null && cb_shouldskipdir(fullpath)) { fts_set(handle, ent, FTS_SKIP); skip = true; } } if (!skip) { if (first) { first = false; } else { long mtime = (long)ent->fts_statp->st_mtimespec.tv_sec; ret.Add(new DirectoryEntry(fullpath, mtime, isfile)); } } ent = fts_read(handle); } return(ret); } finally { fts_close(handle); } } finally { Marshal.FreeHGlobal(str); } } else { #if !HAVE_MONO_POSIX // I've verified that this returns the exact same timestamps as the other branch of code // on linux + mac. In theory, this should perform just as well, but unsure. We can optimize // further later with p/invoke if necessary var ret = new List <DirectoryEntry>(); DirectoryInfo info = new DirectoryInfo(path); foreach (var entry in info.EnumerateFileSystemInfos()) { var attrs = entry.Attributes & ~(FileAttributes.Hidden | FileAttributes.ReadOnly); if ((attrs & FileAttributes.Directory) != 0) { ret.Add(new DirectoryEntry(path, entry.FullName, 0, false)); } else { ret.Add(new DirectoryEntry(path, entry.FullName, (entry.LastWriteTimeUtc.Ticks - EPOCH_TICKS) / 10000000, true)); } } return(ret); #else var ret = new List <DirectoryEntry>(); IntPtr dirp = Syscall.opendir(path); if (dirp == IntPtr.Zero) { throw new Exception("opendir: error " + Stdlib.GetLastError()); } try { do { Dirent d = Syscall.readdir(dirp); if (d == null) { Errno rc = Stdlib.GetLastError(); if (rc == Errno.ENOENT || rc == 0) { break; // done } throw new Exception("readdir: error " + rc); } if (d.d_type == READDIR_ISFILE) { Stat st; string fn = Path.Combine(path, d.d_name); if (Syscall.stat(fn, out st) != 0) { throw new Exception("stat \"" + fn + "\": error " + Stdlib.GetLastError()); } ret.Add(new DirectoryEntry(path, d.d_name, st.st_mtime, true)); } else if (d.d_type == READDIR_ISDIRECTORY) { if (d.d_name == "." || d.d_name == "..") { continue; } ret.Add(new DirectoryEntry(path, d.d_name, 0, false)); } }while (dirp != IntPtr.Zero); } finally { Syscall.closedir(dirp); } return(ret); #endif } }