Skip to content

Foundation: make FileManager build on Windows again #2206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Foundation/FileManager+POSIX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,32 @@ internal func _contentsEqual(atPath path1: String, andPath path2: String) -> Boo
return nil
}
}

internal func _updateTimes(atPath path: String, withFileSystemRepresentation fsr: UnsafePointer<Int8>, creationTime: Date? = nil, accessTime: Date? = nil, modificationTime: Date? = nil) throws {
let stat = try _lstatFile(atPath: path, withFileSystemRepresentation: fsr)

let accessDate = accessTime ?? stat.lastAccessDate
let modificationDate = modificationTime ?? stat.lastModificationDate

let (accessTimeSince1970Seconds, accessTimeSince1970FractionsOfSecond) = modf(accessDate.timeIntervalSince1970)
let accessTimeval = timeval(tv_sec: time_t(accessTimeSince1970Seconds), tv_usec: suseconds_t(1.0e9 * accessTimeSince1970FractionsOfSecond))

let (modificationTimeSince1970Seconds, modificationTimeSince1970FractionsOfSecond) = modf(modificationDate.timeIntervalSince1970)
let modificationTimeval = timeval(tv_sec: time_t(modificationTimeSince1970Seconds), tv_usec: suseconds_t(1.0e9 * modificationTimeSince1970FractionsOfSecond))

let array = [accessTimeval, modificationTimeval]
let errnoValue = array.withUnsafeBufferPointer { (bytes) -> Int32? in
if utimes(fsr, bytes.baseAddress) < 0 {
return errno
} else {
return nil
}
}

if let error = errnoValue {
throw _NSErrorWithErrno(error, reading: false, path: path)
}
}
}

extension FileManager.NSPathDirectoryEnumerator {
Expand Down
27 changes: 27 additions & 0 deletions Foundation/FileManager+Win32.swift
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,33 @@ extension FileManager {
return temp._bridgeToObjectiveC().appendingPathComponent(dest)
}

internal func _updateTimes(atPath path: String,
withFileSystemRepresentation fsr: UnsafePointer<Int8>,
creationTime: Date? = nil,
accessTime: Date? = nil,
modificationTime: Date? = nil) throws {
let stat = try _lstatFile(atPath: path, withFileSystemRepresentation: fsr)

var atime: FILETIME =
FILETIME(from: time_t((accessTime ?? stat.lastAccessDate).timeIntervalSince1970))
var mtime: FILETIME =
FILETIME(from: time_t((modificationTime ?? stat.lastModificationDate).timeIntervalSince1970))

let hFile: HANDLE = String(utf8String: fsr)!.withCString(encodedAs: UTF16.self) {
CreateFileW($0, DWORD(GENERIC_WRITE), DWORD(FILE_SHARE_WRITE),
nil, DWORD(OPEN_EXISTING), 0, nil)
}
if hFile == INVALID_HANDLE_VALUE {
throw _NSErrorWithWindowsError(GetLastError(), reading: true)
}
defer { CloseHandle(hFile) }

if !SetFileTime(hFile, nil, &atime, &mtime) {
throw _NSErrorWithWindowsError(GetLastError(), reading: false)
}

}

internal class NSURLDirectoryEnumerator : DirectoryEnumerator {
var _options : FileManager.DirectoryEnumerationOptions
var _errorHandler : ((URL, Error) -> Bool)?
Expand Down
28 changes: 3 additions & 25 deletions Foundation/FileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -371,32 +371,10 @@ open class FileManager : NSObject {
}
#endif
}

// Set dates as the very last step, to avoid other operations overwriting these values:

if newModificationDate != nil || newAccessDate != nil {
let stat = try _lstatFile(atPath: path, withFileSystemRepresentation: fsRep)

let accessDate = newAccessDate ?? stat.lastAccessDate
let modificationDate = newModificationDate ?? stat.lastModificationDate

let (accessTimeSince1970Seconds, accessTimeSince1970FractionsOfSecond) = modf(accessDate.timeIntervalSince1970)
let accessTimeval = timeval(tv_sec: time_t(accessTimeSince1970Seconds), tv_usec: suseconds_t(1.0e9 * accessTimeSince1970FractionsOfSecond))

let (modificationTimeSince1970Seconds, modificationTimeSince1970FractionsOfSecond) = modf(modificationDate.timeIntervalSince1970)
let modificationTimeval = timeval(tv_sec: time_t(modificationTimeSince1970Seconds), tv_usec: suseconds_t(1.0e9 * modificationTimeSince1970FractionsOfSecond))

let array = [accessTimeval, modificationTimeval]
let errnoValue = array.withUnsafeBufferPointer { (bytes) -> Int32? in
if utimes(fsRep, bytes.baseAddress) < 0 {
return errno
} else {
return nil
}
}

if let error = errnoValue {
throw _NSErrorWithErrno(error, reading: false, path: path)
}
// Set dates as the very last step, to avoid other operations overwriting these values:
try _updateTimes(atPath: path, withFileSystemRepresentation: fsRep, accessTime: newAccessDate, modificationTime: newModificationDate)
}
})
}
Expand Down
8 changes: 5 additions & 3 deletions Foundation/NSURL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1799,8 +1799,10 @@ fileprivate extension URLResourceValuesStorage {
result[key] = try attribute(.size)
case .totalFileAllocatedSizeKey: fallthrough // FIXME: This should add the size of any metadata.
case .fileAllocatedSizeKey:
#if !os(Windows)
let stat = try urlStat()
result[key] = Int(stat.st_blocks) * Int(stat.st_blksize)
#endif
case .isAliasFileKey:
// swift-corelibs-foundation does not support aliases and bookmarks.
break
Expand Down Expand Up @@ -2042,7 +2044,7 @@ extension stat {
#elseif os(Android)
return Date(timeIntervalSince1970: st_mtime, nanoseconds: st_mtime_nsec)
#elseif os(Windows)
return Date(timeIntervalSince1970: st_mtime)
return Date(timeIntervalSince1970: TimeInterval(st_mtime))
#else
return Date(timespec: st_mtim)
#endif
Expand All @@ -2054,7 +2056,7 @@ extension stat {
#elseif os(Android)
return Date(timeIntervalSince1970: st_atime, nanoseconds: st_atime_nsec)
#elseif os(Windows)
return Date(timeIntervalSince1970: st_atime)
return Date(timeIntervalSince1970: TimeInterval(st_atime))
#else
return Date(timespec: st_atim)
#endif
Expand All @@ -2066,7 +2068,7 @@ extension stat {
#elseif os(Android)
return Date(timeIntervalSince1970: st_ctime, nanoseconds: st_ctime_nsec)
#elseif os(Windows)
return Date(timeIntervalSince1970: st_ctime)
return Date(timeIntervalSince1970: TimeInterval(st_ctime))
#else
return Date(timespec: st_ctim)
#endif
Expand Down