Bug 1660841 - Provide file creation time via nsIFile::creationTime{,ofLink} r=nika

Differential Revision: https://phabricator.services.mozilla.com/D96889
This commit is contained in:
Barret Rennie 2020-12-03 04:10:47 +00:00
Родитель 3ab2f47c1c
Коммит e0e9d2d31b
6 изменённых файлов: 135 добавлений и 10 удалений

Просмотреть файл

@ -311,6 +311,16 @@ FileDescriptorFile::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
FileDescriptorFile::GetCreationTime(PRTime* aCreationTime) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
FileDescriptorFile::GetCreationTimeOfLink(PRTime* aCreationTime) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
FileDescriptorFile::GetFileSize(int64_t* aFileSize) {
return NS_ERROR_NOT_IMPLEMENTED;

Просмотреть файл

@ -233,6 +233,16 @@ interface nsIFile : nsISupports
attribute PRTime lastModifiedTime;
attribute PRTime lastModifiedTimeOfLink;
/**
* The creation time of file in milliseconds from midnight, January 1, 1970
* GMT, if available.
*
* This attribute is only implemented on Windows and macOS. Accessing this
* on another platform will this will throw NS_ERROR_NOT_IMPLEMENTED.
*/
readonly attribute PRTime creationTime;
readonly attribute PRTime creationTimeOfLink;
/**
* WARNING! On the Mac, getting/setting the file size with nsIFile
* only deals with the size of the data fork. If you need to

Просмотреть файл

@ -126,6 +126,11 @@ using namespace mozilla;
return NS_ERROR_FILE_ACCESS_DENIED; \
} while (0)
static PRTime TimespecToMillis(const struct timespec& aTimeSpec) {
return PRTime(aTimeSpec.tv_sec) * PR_MSEC_PER_SEC +
PRTime(aTimeSpec.tv_nsec) / PR_NSEC_PER_MSEC;
}
/* directory enumerator */
class nsDirEnumeratorUnix final : public nsSimpleEnumerator,
public nsIDirectoryEnumerator {
@ -1134,17 +1139,11 @@ nsresult nsLocalFile::GetLastModifiedTimeImpl(PRTime* aLastModTime,
return NSRESULT_FOR_ERRNO();
}
int64_t modSec = 0;
int64_t modNSec = 0;
#if (defined(__APPLE__) && defined(__MACH__))
modSec = fileStats.st_mtimespec.tv_sec;
modNSec = fileStats.st_mtimespec.tv_nsec;
*aLastModTime = TimespecToMillis(fileStats.st_mtimespec);
#else
modSec = fileStats.st_mtim.tv_sec;
modNSec = fileStats.st_mtim.tv_nsec;
*aLastModTime = TimespecToMillis(fileStats.st_mtim);
#endif
*aLastModTime =
PRTime(modSec * PR_MSEC_PER_SEC) + PRTime(modNSec / PR_NSEC_PER_MSEC);
return NS_OK;
}
@ -1207,6 +1206,39 @@ nsLocalFile::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink) {
return SetLastModifiedTimeImpl(aLastModTimeOfLink, /* follow links? */ false);
}
NS_IMETHODIMP
nsLocalFile::GetCreationTime(PRTime* aCreationTime) {
return GetCreationTimeImpl(aCreationTime, false);
}
NS_IMETHODIMP
nsLocalFile::GetCreationTimeOfLink(PRTime* aCreationTimeOfLink) {
return GetCreationTimeImpl(aCreationTimeOfLink, /* aFollowLinks = */ true);
}
nsresult nsLocalFile::GetCreationTimeImpl(PRTime* aCreationTime,
bool aFollowLinks) {
CHECK_mPath();
if (NS_WARN_IF(!aCreationTime)) {
return NS_ERROR_INVALID_ARG;
}
#if defined(_DARWIN_FEATURE_64_BIT_INODE)
using StatFn = int (*)(const char*, struct STAT*);
StatFn statFn = aFollowLinks ? &STAT : &LSTAT;
struct STAT fileStats {};
if (statFn(mPath.get(), &fileStats) < 0) {
return NSRESULT_FOR_ERRNO();
}
*aCreationTime = TimespecToMillis(fileStats.st_birthtimespec);
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
/*
* Only send back permissions bits: maybe we want to send back the whole
* mode_t to permit checks against other file types?
@ -1600,7 +1632,8 @@ nsLocalFile::IsExecutable(bool* aResult) {
static const char* const executableExts[] = {
"air", // Adobe AIR installer
#ifdef MOZ_WIDGET_COCOA
"fileloc", // File location files can be used to point to other files.
"fileloc", // File location files can be used to point to other
// files.
#endif
"jar" // java application bundle
};
@ -2238,7 +2271,8 @@ static nsresult MacErrorMapper(OSErr inErr) {
}
static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr) {
// first see if the conversion would succeed and find the length of the result
// first see if the conversion would succeed and find the length of the
// result
CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
CFIndex charsConverted = ::CFStringGetBytes(
aInStrRef, CFRangeMake(0, inStrLen), kCFStringEncodingUTF8, 0, false,

Просмотреть файл

@ -88,6 +88,7 @@ class nsLocalFile final
nsresult SetLastModifiedTimeImpl(PRTime aLastModTime, bool aFollowLinks);
nsresult GetLastModifiedTimeImpl(PRTime* aLastModTime, bool aFollowLinks);
nsresult GetCreationTimeImpl(PRTime* aCreationTime, bool aFollowLinks);
};
#endif /* _nsLocalFileUNIX_H_ */

Просмотреть файл

@ -2225,6 +2225,39 @@ nsLocalFile::SetLastModifiedTimeOfLink(PRTime aLastModifiedTime) {
return SetLastModifiedTime(aLastModifiedTime);
}
NS_IMETHODIMP
nsLocalFile::GetCreationTime(PRTime* aCreationTime) {
CHECK_mWorkingPath();
if (NS_WARN_IF(!aCreationTime)) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv = ResolveAndStat();
NS_ENSURE_SUCCESS(rv, rv);
*aCreationTime = mFileInfo64.creationTime / PR_USEC_PER_MSEC;
return NS_OK;
}
NS_IMETHODIMP
nsLocalFile::GetCreationTimeOfLink(PRTime* aCreationTime) {
CHECK_mWorkingPath();
if (NS_WARN_IF(!aCreationTime)) {
return NS_ERROR_INVALID_ARG;
}
PRFileInfo64 info;
nsresult rv = GetFileInfo(mWorkingPath, &info);
NS_ENSURE_SUCCESS(rv, rv);
*aCreationTime = info.creationTime / PR_USEC_PER_MSEC;
return NS_OK;
}
nsresult nsLocalFile::SetModDate(PRTime aLastModifiedTime,
const wchar_t* aFilePath) {
// The FILE_FLAG_BACKUP_SEMANTICS is required in order to change the

Просмотреть файл

@ -134,3 +134,40 @@ function test_diskSpaceAvailable() {
file.remove(true);
}
function test_file_creation_time() {
const file = do_get_profile();
file.append("testfile");
if (file.exists()) {
file.remove(true);
}
const now = Date.now();
file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
Assert.ok(file.exists());
let creationTime;
try {
creationTime = file.creationTime;
} catch (e) {
if (e.name === "NS_ERROR_NOT_AVAILABLE") {
// Creation time is not supported on this platform.
file.remove(true);
return;
}
}
const diff = Math.abs(creationTime - now);
Assert.ok(diff < MAX_TIME_DIFFERENCE);
Assert.ok(creationTime === file.lastModifiedTime);
file.lastModifiedTime = now + MILLIS_PER_DAY;
Assert.ok(creationTime !== file.lastModifiedTime);
Assert.ok(creationTime === file.creationTime);
file.remove(true);
}