예제 #1
0
        /// <inheritdoc />
        public FileTimestamps GetFileTimestamps(string path, bool followSymlink)
        {
            var statBuffer = new StatBuffer();

            unsafe
            {
                if (StatFile(path, followSymlink, ref statBuffer) != 0)
                {
                    throw new BuildXLException(I($"Failed to stat file '{path}' to get its timestamps - error: {Marshal.GetLastWin32Error()}"));
                }
            }

            var creationTime = new Timespec()
            {
                Tv_sec = statBuffer.TimeCreation, Tv_nsec = statBuffer.TimeNSecCreation
            };
            var lastChangeTimeTime = new Timespec()
            {
                Tv_sec = statBuffer.TimeLastStatusChange, Tv_nsec = statBuffer.TimeNSecLastStatusChange
            };
            var lastWriteTime = new Timespec()
            {
                Tv_sec = statBuffer.TimeLastModification, Tv_nsec = statBuffer.TimeNSecLastModification
            };
            var accessTime = new Timespec()
            {
                Tv_sec = statBuffer.TimeLastAccess, Tv_nsec = statBuffer.TimeNSecLastAccess
            };

            return(new FileTimestamps(
                       creationTime: creationTime.ToUtcTime(),
                       lastChangeTime: lastChangeTimeTime.ToUtcTime(),
                       lastWriteTime: lastWriteTime.ToUtcTime(),
                       accessTime: accessTime.ToUtcTime()));
        }
예제 #2
0
        /// <inheritdoc />
        public void SetFileTimestamps(string path, FileTimestamps timestamps, bool followSymlink)
        {
            Contract.Requires(timestamps.CreationTime >= UnixEpoch);
            Contract.Requires(timestamps.AccessTime >= UnixEpoch);
            Contract.Requires(timestamps.LastWriteTime >= UnixEpoch);
            Contract.Requires(timestamps.LastChangeTime >= UnixEpoch);

            var statBuffer = new StatBuffer();

            Timespec creationTime         = Timespec.CreateFromUtcDateTime(timestamps.CreationTime);
            Timespec lastAccessTime       = Timespec.CreateFromUtcDateTime(timestamps.AccessTime);
            Timespec lastModificationTime = Timespec.CreateFromUtcDateTime(timestamps.LastWriteTime);
            Timespec lastStatusChangeTime = Timespec.CreateFromUtcDateTime(timestamps.LastChangeTime);

            statBuffer.TimeCreation     = creationTime.Tv_sec;
            statBuffer.TimeNSecCreation = creationTime.Tv_nsec;

            statBuffer.TimeLastAccess     = lastAccessTime.Tv_sec;
            statBuffer.TimeNSecLastAccess = lastAccessTime.Tv_nsec;

            statBuffer.TimeLastModification     = lastModificationTime.Tv_sec;
            statBuffer.TimeNSecLastModification = lastModificationTime.Tv_nsec;

            statBuffer.TimeLastStatusChange     = lastStatusChangeTime.Tv_sec;
            statBuffer.TimeNSecLastStatusChange = lastStatusChangeTime.Tv_nsec;

            int result = SetTimeStampsForFilePath(path, followSymlink, statBuffer);

            if (result != 0)
            {
                throw new BuildXLException("Failed to open a file to set its timestamps - error: " + Marshal.GetLastWin32Error());
            }
        }
예제 #3
0
        /// <inheritdoc/>
        public (FileIdAndVolumeId, Usn)? TryGetVersionedFileIdentityByHandle(SafeFileHandle fileHandle)
        {
            var statBuffer = new StatBuffer();

            unsafe
            {
                if (StatFileDescriptor(fileHandle, ref statBuffer) != 0)
                {
                    return(default);
예제 #4
0
        /// <summary>
        /// Gets device and inode number.
        /// </summary>
        public int GetDeviceAndInodeNumbers(string path, bool followSymlink, out ulong device, out ulong inode)
        {
            var statBuffer = new StatBuffer();

            int result = StatFile(path, followSymlink, ref statBuffer);

            device = unchecked ((ulong)statBuffer.DeviceID);
            inode  = unchecked ((ulong)statBuffer.InodeNumber);

            return(result);
        }
예제 #5
0
        /// <inheritdoc />
        public uint GetHardLinkCount(string path)
        {
            var statBuffer = new StatBuffer();

            if (StatFile(path, true, ref statBuffer) != 0)
            {
                throw new BuildXLException(I($"Failed to stat file '{path}' to get its hardlink count - error: {Marshal.GetLastWin32Error()}"));
            }

            // TODO: Change hardlink count return type to ulong.
            return(unchecked ((uint)statBuffer.HardLinks));
        }
예제 #6
0
        /// <inheritdoc/>
        public FileIdAndVolumeId?TryGetFileIdentityByHandle(SafeFileHandle fileHandle)
        {
            var statBuffer = new StatBuffer();

            unsafe
            {
                return(StatFileDescriptor(fileHandle, ref statBuffer) != 0
                    ? default
                    : new FileIdAndVolumeId(
                           unchecked ((ulong)statBuffer.DeviceID),
                           new FileId(UnusedFileIdPart, unchecked ((ulong)statBuffer.InodeNumber))));
            }
        }
예제 #7
0
파일: IO.cs 프로젝트: microsoft/BuildXL
        /// <summary>
        /// Sets atime and mtime to current time.
        /// </summary>
        public static int Touch(string pathname, bool followSymlink)
        {
            var timespec = Timespec.CreateFromUtcDateTime(DateTime.UtcNow);
            var buf      = new StatBuffer
            {
                TimeLastAccess           = timespec.Tv_sec,
                TimeNSecLastAccess       = timespec.Tv_nsec,
                TimeLastModification     = timespec.Tv_sec,
                TimeNSecLastModification = timespec.Tv_nsec,
            };

            return(SetTimeStampsForFilePath(pathname, followSymlink, buf));
        }
예제 #8
0
        private static int StatFile(int fd, string path, bool followSymlink, ref StatBuffer statBuf)
        {
            // using 'fstatat' instead of the newer 'statx' because Ubuntu 18.04 doesn't have iit
            var buf    = new stat_buf();
            int result = StatFile(fd, path, followSymlink, ref buf);

            if (result != 0)
            {
                return(ERROR);
            }
            else
            {
                Translate(buf, ref statBuf);
                return(0);
            }
        }
예제 #9
0
 /// <summary>OSX specific implementation of <see cref="IO.StatFileDescriptor"/> </summary>
 internal unsafe static int StatFileDescriptor(SafeFileHandle fd, ref StatBuffer statBuf)
 => StatFileDescriptor(fd, ref statBuf, sizeof(StatBuffer));
예제 #10
0
 public static int Stat(string path, [Out] out StatBuffer buf)
 {
     return(__XStat64(STAT_VER, path, out buf));
 }
예제 #11
0
        /// <summary>
        /// Linux specific implementation of <see cref="IO.SetTimeStampsForFilePath"/>
        /// </summary>
        /// <remarks>
        /// Only atime and mtime are settable
        /// </remarks>
        internal static int SetTimeStampsForFilePath(string path, bool followSymlink, StatBuffer buf)
        {
            int flags = followSymlink ? 0 : AT_SYMLINK_NOFOLLOW;
            var atime = new Timespec {
                Tv_sec = buf.TimeLastAccess, Tv_nsec = buf.TimeNSecLastAccess
            };
            var mtime = new Timespec {
                Tv_sec = buf.TimeLastModification, Tv_nsec = buf.TimeNSecLastModification
            };

            return(utimensat(AT_FDCWD, path, new[] { atime, mtime }, flags));
        }
예제 #12
0
 /// <summary>Linux specific implementation of <see cref="IO.StatFileDescriptor"/> </summary>
 public static int StatFileDescriptor(SafeFileHandle fd, ref StatBuffer statBuf)
 {
     return(StatFile(ToInt(fd), string.Empty, followSymlink: false, ref statBuf));
 }
예제 #13
0
 public static int StatFileDescriptor(SafeFileHandle fd, ref StatBuffer statBuf)
 => StatFileDescriptor(fd, ref statBuf, Marshal.SizeOf(statBuf));
예제 #14
0
 public static int StatFile(string path, bool followSymlink, ref StatBuffer statBuf)
 => StatFile(path, followSymlink, ref statBuf, Marshal.SizeOf(statBuf));
예제 #15
0
 /// <summary>Linux specific implementation of <see cref="IO.StatFile"/> </summary>
 internal static int StatFile(string path, bool followSymlink, ref StatBuffer statBuf)
 {
     Contract.Requires(!string.IsNullOrEmpty(path));
     return(StatFile(AT_FDCWD, path, followSymlink, ref statBuf));
 }
예제 #16
0
 public Bar(int historySize)
 {
     mAverageValues = new StatBuffer(historySize);
 }
예제 #17
0
 public Bar()
 {
     mAverageValues = new StatBuffer(5);
 }
예제 #18
0
        /// <inheritdoc />
        public void InKernelFileCopy(string source, string destination, bool followSymlink)
        {
            SafeFileHandle sourceHandle;
            OpenFileResult openResult = m_fileSystem.TryCreateOrOpenFile(
                source,
                FileDesiredAccess.GenericRead,
                FileShare.Read | FileShare.Delete,
                FileMode.Open,
                followSymlink ? FileFlagsAndAttributes.FileFlagOpenReparsePoint : FileFlagsAndAttributes.None,
                out sourceHandle);

            if (!openResult.Succeeded)
            {
                throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Failed to open source file '{source}' in {nameof(InKernelFileCopy)}"));
            }

            using (sourceHandle)
            {
                // Ignore return of PosixFadvise(), the file handle was opened successfully above
                // and the advice hint is a less important optimization.
                Interop.Unix.IO.PosixFadvise(sourceHandle, 0, 0, AdviceHint.POSIX_FADV_SEQUENTIAL);

                SafeFileHandle destinationHandle;
                openResult = m_fileSystem.TryCreateOrOpenFile(
                    destination,
                    FileDesiredAccess.GenericRead | FileDesiredAccess.GenericWrite,
                    FileShare.Read | FileShare.Write | FileShare.Delete,
                    FileMode.Create,
                    FileFlagsAndAttributes.None,
                    out destinationHandle);

                if (!openResult.Succeeded)
                {
                    throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Failed to open destination file '{destination}' in {nameof(InKernelFileCopy)}"));
                }

                using (destinationHandle)
                {
                    var statBuffer = new StatBuffer();
                    if (StatFileDescriptor(sourceHandle, ref statBuffer) != 0)
                    {
                        throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Failed to stat source file '{source}' for size query in {nameof(InKernelFileCopy)}"));
                    }

                    var  length      = statBuffer.Size;
                    long bytesCopied = 0;
                    int  lastError   = 0;

                    do
                    {
                        bytesCopied = Interop.Unix.IO.CopyFileRange(sourceHandle, IntPtr.Zero, destinationHandle, IntPtr.Zero, s_copyBufferSizeMax);
                        if (bytesCopied == -1)
                        {
                            lastError = Marshal.GetLastWin32Error();
                            break;
                        }

                        length -= bytesCopied;
                    } while (length > 0 && bytesCopied > 0);

                    // copy_file_range() is available in kernel versions > 4.5, let's try sendfile() if copy_file_range() is not implemented
                    if (lastError == (int)Errno.ENOSYS)
                    {
                        length      = statBuffer.Size;
                        bytesCopied = 0;
                        lastError   = 0;

                        do
                        {
                            bytesCopied = Interop.Unix.IO.SendFile(sourceHandle, destinationHandle, IntPtr.Zero, s_copyBufferSizeMax);
                            if (bytesCopied == -1)
                            {
                                lastError = Marshal.GetLastWin32Error();
                                break;
                            }

                            length -= bytesCopied;
                        } while (length > 0 && bytesCopied > 0);
                    }

                    if (lastError != 0)
                    {
                        throw new NativeWin32Exception(lastError, I($"{nameof(InKernelFileCopy)} failed  copying '{source}' to '{destination}' with error code: {lastError}"));
                    }
                }
            }
        }
예제 #19
0
 /// <summary>OSX specific implementation of <see cref="IO.StatFile"/> </summary>
 internal unsafe static int StatFile(string path, bool followSymlink, ref StatBuffer statBuf)
 => StatFile(path, followSymlink, ref statBuf, sizeof(StatBuffer));
예제 #20
0
 private static extern int StatFile(string path, bool followSymlink, ref StatBuffer statBuf, long statBufferSize);
 public static int LStat(string pathname, [Out] out StatBuffer buf)
 {
     return(__LXStat64(STAT_VER, pathname, out buf));
 }
예제 #22
0
 private static extern int StatFileDescriptor(SafeFileHandle fd, ref StatBuffer statBuf, long statBufferSize);
 private static extern int __LXStat64(int vers, string pathname, [Out] out StatBuffer buf);
예제 #24
0
 public static extern int SetTimeStampsForFilePath(string path, bool followSymlink, StatBuffer buffer);
예제 #25
0
파일: IO.cs 프로젝트: microsoft/BuildXL
 /// <summary>
 /// Implements the standard unix 'stat' command.
 /// </summary>
 /// <returns>
 /// Upon successful completion a value of 0 is returned and the result is stored in <paramref name="statBuf"/>;
 /// otherwise, a value of -1 is returned and <see cref="Marshal.GetLastWin32Error"/> is set to indicate the error.
 /// </returns>
 public static int StatFile(string path, bool followSymlink, ref StatBuffer statBuf) => IsMacOS
     ? Impl_Mac.StatFile(path, followSymlink, ref statBuf)
     : Impl_Linux.StatFile(path, followSymlink, ref statBuf);
예제 #26
0
파일: IO.cs 프로젝트: microsoft/BuildXL
 /// <summary>
 /// Same as <see cref="StatFile" /> except that the target file is given as a file descriptor (<paramref name="fd" />).
 /// </summary>
 public static int StatFileDescriptor(SafeFileHandle fd, ref StatBuffer statBuf) => IsMacOS
     ? Impl_Mac.StatFileDescriptor(fd, ref statBuf)
     : Impl_Linux.StatFileDescriptor(fd, ref statBuf);
예제 #27
0
파일: IO.cs 프로젝트: microsoft/BuildXL
 /// <summary>
 /// Sets the creation, modification, change and access time of a file specified at path
 /// </summary>
 /// <returns>Returns zero in case of success, otherwise error</returns>
 public static int SetTimeStampsForFilePath(string path, bool followSymlink, StatBuffer buffer) => IsMacOS
     ? Impl_Mac.SetTimeStampsForFilePath(path, followSymlink, buffer)
     : Impl_Linux.SetTimeStampsForFilePath(path, followSymlink, buffer);
예제 #28
0
 public static extern int Stat(string path, [Out] out StatBuffer statBuffer);
예제 #29
0
        /// <inheritdoc />
        public Possible <Unit> InKernelFileCopy(string source, string destination, bool followSymlink)
        {
            SafeFileHandle sourceHandle;
            OpenFileResult openResult = m_fileSystem.TryCreateOrOpenFile(
                source,
                FileDesiredAccess.GenericRead,
                FileShare.Read | FileShare.Delete,
                FileMode.Open,
                followSymlink ? FileFlagsAndAttributes.FileFlagOpenReparsePoint : FileFlagsAndAttributes.None,
                out sourceHandle);

            if (!openResult.Succeeded)
            {
                return(new NativeFailure(Marshal.GetLastWin32Error(), I($"Failed to open source file '{source}' in {nameof(InKernelFileCopy)}")));
            }

            using (sourceHandle)
            {
                // Ignore return of PosixFadvise(), the file handle was opened successfully above
                // and the advice hint is a less important optimization.
                Interop.Unix.IO.PosixFadvise(sourceHandle, 0, 0, AdviceHint.POSIX_FADV_SEQUENTIAL);

                SafeFileHandle destinationHandle;
                openResult = m_fileSystem.TryCreateOrOpenFile(
                    destination,
                    FileDesiredAccess.GenericRead | FileDesiredAccess.GenericWrite,
                    FileShare.Read | FileShare.Write | FileShare.Delete,
                    FileMode.Create,
                    FileFlagsAndAttributes.None,
                    out destinationHandle);

                if (!openResult.Succeeded)
                {
                    return(new NativeFailure(Marshal.GetLastWin32Error(), I($"Failed to open destination file '{destination}' in {nameof(InKernelFileCopy)}")));
                }

                using (destinationHandle)
                {
                    var statBuffer = new StatBuffer();
                    if (StatFileDescriptor(sourceHandle, ref statBuffer) != 0)
                    {
                        return(new NativeFailure(Marshal.GetLastWin32Error(), I($"Failed to stat source file '{source}' for size query in {nameof(InKernelFileCopy)}")));
                    }

                    var  length      = statBuffer.Size;
                    long bytesCopied = 0;
                    int  lastError   = 0;

                    do
                    {
                        bytesCopied = CopyBytes(sourceHandle, destinationHandle);
                        if (bytesCopied == -1)
                        {
                            return(new NativeFailure(Marshal.GetLastWin32Error(), I($"{nameof(InKernelFileCopy)} failed  copying '{source}' to '{destination}' with error code: {lastError}")));
                        }

                        length -= bytesCopied;
                    } while (length > 0 && bytesCopied > 0);

                    return(Unit.Void);
                }
            }
        }