Example #1
0
            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);
                }
            }
Example #2
0
        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;
        }
Example #3
0
        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);
        }
Example #4
0
        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)));
        }
Example #6
0
        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
            }
        }