diff options
author | Clay Sweetser <clay.sweetser@gmail.com> | 2014-04-11 12:33:53 -0400 |
---|---|---|
committer | Clay Sweetser <clay.sweetser@gmail.com> | 2014-04-16 03:35:07 -0400 |
commit | 37ac424e9a5a1564055f99ffcc0fa6ff4321d5f4 (patch) | |
tree | dc2b9acb060ee0d1c67a12b1472d0fafa9d9ba2a /lib/pure | |
parent | 941cc937d3670f71884f9cac97b71a1f86cebbad (diff) | |
download | Nim-37ac424e9a5a1564055f99ffcc0fa6ff4321d5f4.tar.gz |
Added Windows implementation of getFileInfo procedures
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/os.nim | 123 |
1 files changed, 103 insertions, 20 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index faca17e98..11c84570f 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -448,6 +448,8 @@ proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} = proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} = ## Returns the `file`'s creation time. + ## Note that under posix OS's, the returned time may actually be the time at + ## which the file's attribute's were last modified. when defined(posix): var res: TStat if stat(file, res) < 0'i32: osError(osLastError()) @@ -777,6 +779,25 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} = elif defined(posix): result = path[0] == '/' +when defined(Windows): + proc openHandle(path: string, followSymlink=true): THandle = + var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL + if not followSymlink: + flags = flags or FILE_FLAG_OPEN_REPARSE_POINT + + when useWinUnicode: + result = createFileW( + newWideCString(path), 0'i32, + FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, + nil, OPEN_EXISTING, flags, 0 + ) + else: + result = createFileA( + path, 0'i32, + FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, + nil, OPEN_EXISTING, flags, 0 + ) + proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} = ## Returns True if both pathname arguments refer to the same physical @@ -787,26 +808,8 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", ## sym-linked paths to the same file or directory. when defined(Windows): var success = true - - when useWinUnicode: - var p1 = newWideCString(path1) - var p2 = newWideCString(path2) - template openHandle(path: expr): expr = - createFileW(path, 0'i32, FILE_SHARE_DELETE or FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL, 0) - - var f1 = openHandle(p1) - var f2 = openHandle(p2) - - else: - template openHandle(path: expr): expr = - createFileA(path, 0'i32, FILE_SHARE_DELETE or FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL, 0) - - var f1 = openHandle(path1) - var f2 = openHandle(path2) + var f1 = openHandle(path1) + var f2 = openHandle(path2) var lastErr: TOSErrorCode if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE: @@ -1747,4 +1750,84 @@ proc expandTilde*(path: string): string = else: result = path +when defined(Windows): + type + DeviceId = int32 + FileId = int64 +type + FileInfo = object + ## Contains information associated with a file object. + id: tuple[device: DeviceId, file: FileId] # Device and file id. + kind: TPathComponent # Kind of file object - directory, symlink, etc. + size: BiggestInt # Size of file. + permissions: set[TFilePermission] # File permissions + linkCount: BiggestInt # Number of hard links the file object has. + lastAccessTime: TTime # Time file was last accessed. + lastWriteTime: TTime # Time file was last modified/written to. + creationTime: TTime # Time file was created. Not supported on all systems! + + +proc getFileInfo*(handle: THandle, result: var FileInfo) = + ## Retrieves file information for the file object represented by the given + ## handle. + ## + ## If the information cannot be retrieved, such as when the file handle + ## is invalid, an error will be thrown. + # Done: ID, Kind, Size, Permissions, Link Count + when defined(Windows): + template toTime(e): expr = winTimeToUnixTime(rdFileTime(e)) + var info: TBY_HANDLE_FILE_INFORMATION + if getFileInformationByHandle(handle, addr info) == 0: + osError(osLastError()) + result.id.device = info.dwVolumeSerialNumber + result.id.file = info.nFileIndexLow or (info.nFileIndexHigh shl 32) + result.size = info.nFileSizeLow or (info.nFileSizeHigh shl 32) + result.linkCount = info.nNumberOfLinks + result.lastAccessTime = toTime(info.ftLastAccessTime) + result.lastWriteTime = toTime(info.ftLastWriteTime) + result.creationTime = toTime(info.ftCreationTime) + + # Retrieve permissions + # TODO - Use a more accurate method of getting permissions? + if (info.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32: + result.permissions = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, + fpOthersExec, fpOthersRead} + else: + result.permissions = {fpUserExec..fpOthersRead} + + # Retrieve file kind + # Should we include more file kinds? + result.kind = pcFile + if (info.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32: + result.kind = pcDir + # Should we optimize for the case when it's definately known that the file + # isn't a symlink (see the below procedure's "followSymlink") + if (info.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32: + result.kind = succ(result.kind) + + else: + var rawInfo: TStat + if stat(handle, rawInfo) < 0'i32: osError(osLastError()) + +proc getFileInfo*(path: string, followSymlink = true): FileInfo = + ## Retrieves file information for the file object pointed to by `path`. + ## + ## Due to intrinsic differences between operating systems, the information + ## contained by the returned `FileInfo` structure will be slightly different + ## across platforms, and in some cases, incomplete or inaccurate. + ## + ## When `followSymlink` is true, symlinks are followed and the information + ## retrieved is information related to the symlink's target. Otherwise, + ## information on the symlink itself is retrieved. + ## + ## If the information cannot be retrieved, such as when the path doesn't + ## exist, or when permission restrictions prevent the program from retrieving + ## file information, an error will be thrown. + when defined(Windows): + var handle = openHandle(path, followSymlink) + if handle == INVALID_HANDLE_VALUE: + osError(osLastError()) + getFileInfo(handle, result) + closeHandle(handle) + {.pop.} |