217 lines
7.5 KiB
C
217 lines
7.5 KiB
C
/*****************************************************************************\
|
|
* *
|
|
* Filename utime.c *
|
|
* *
|
|
* Description Updated utime() and port of standard C library's lutime() *
|
|
* *
|
|
* Notes TO DO: Create W, A, U versions of ResolveLinks(), then *
|
|
* create W, A, U versions of utime(). *
|
|
* *
|
|
* History *
|
|
* 2014-02-12 JFL Created this module. *
|
|
* 2014-06-04 JFL Fixed minors issues in debugging code. *
|
|
* 2014-07-02 JFL Added support for pathnames >= 260 characters. *
|
|
* 2016-08-25 JFL Added missing routine utimeA(). *
|
|
* *
|
|
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
|
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
|
\*****************************************************************************/
|
|
|
|
#define _UTF8_SOURCE /* Generate the UTF-8 version of Windows print routines */
|
|
|
|
#define _CRT_SECURE_NO_WARNINGS 1 /* Avoid Visual C++ security warnings */
|
|
|
|
#include <errno.h>
|
|
#include "sys/msvcTime.h" /* Must be included before any direct or indirect <windows.h> inclusion */
|
|
#include "msvcUtime.h"
|
|
#include "msvcDebugm.h"
|
|
#include "msvcLimits.h"
|
|
|
|
#if defined(_DEBUG)
|
|
#include <stdio.h>
|
|
#endif /* defined(_DEBUG) */
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
#include <io.h> /* For MSVC's _get_osfhandle() */
|
|
#include "msvcUnistd.h" /* For MsvcLibX's ResolveLinks() */
|
|
|
|
/* Convert a Windows FILETIME to a Unix time_t.
|
|
A FILETIME is the number of 100-nanosecond intervals since January 1, 1601.
|
|
A time_t is the number of 1-second intervals since January 1, 1970. */
|
|
|
|
time_t Filetime2Time_t(FILETIME *pFT) {
|
|
ULARGE_INTEGER ull;
|
|
ull.LowPart = pFT->dwLowDateTime;
|
|
ull.HighPart = pFT->dwHighDateTime;
|
|
return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
|
|
}
|
|
|
|
void Time_t2Filetime(time_t ft, FILETIME *pFT) {
|
|
ULARGE_INTEGER ull;
|
|
ull.QuadPart = ft + 11644473600ULL;
|
|
ull.QuadPart *= 10000000UL;
|
|
pFT->dwLowDateTime = ull.LowPart;
|
|
pFT->dwHighDateTime = ull.HighPart;
|
|
}
|
|
|
|
DEBUG_CODE(
|
|
int Utimbuf2String(char *buf, size_t bufsize, const struct utimbuf *times) {
|
|
struct tm *pTime;
|
|
int n;
|
|
if (!times) {
|
|
return _snprintf(buf, bufsize, "NULL");
|
|
}
|
|
pTime = localtime(&(times->modtime)); /* Time of last data modification */
|
|
n = _snprintf(buf, bufsize, "{%4d-%02d-%02d %02d:%02d:%02d, ...}",
|
|
pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday,
|
|
pTime->tm_hour, pTime->tm_min, pTime->tm_sec);
|
|
return n;
|
|
}
|
|
);
|
|
|
|
/* Low level subroutine used by all the other routines below. */
|
|
int hutime(HANDLE hFile, const struct utimbuf *times) {
|
|
FILETIME ftLastAccess; /* last access time */
|
|
FILETIME ftLastWrite; /* last write time */
|
|
int iErr;
|
|
struct utimbuf now;
|
|
|
|
if (!times) {
|
|
now.actime = now.modtime = time(NULL);
|
|
times = &now;
|
|
}
|
|
|
|
Time_t2Filetime(times->actime, &ftLastAccess);
|
|
Time_t2Filetime(times->modtime, &ftLastWrite);
|
|
iErr = !SetFileTime(hFile, NULL, &ftLastAccess, &ftLastWrite);
|
|
if (iErr) {
|
|
errno = Win32ErrorToErrno();
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Same as 'utime', but does not follow symbolic links. */
|
|
int lutimeW(const WCHAR *path, const struct utimbuf *times) {
|
|
DWORD dwAttr;
|
|
DWORD dwFlagsAndAttributes;
|
|
int iErr;
|
|
HANDLE hLink;
|
|
|
|
DEBUG_CODE({
|
|
char buf[100];
|
|
char szUtf8[UTF8_PATH_MAX];
|
|
Utimbuf2String(buf, sizeof(buf), times);
|
|
DEBUG_WSTR2UTF8(path, szUtf8, sizeof(szUtf8));
|
|
DEBUG_ENTER(("lutime(\"%s\", %s);\n", szUtf8, buf));
|
|
});
|
|
|
|
dwAttr = GetFileAttributesW(path);
|
|
if (dwAttr == INVALID_FILE_ATTRIBUTES) {
|
|
errno = ENOENT;
|
|
RETURN_INT_COMMENT(-1, ("File does not exist\n"));
|
|
}
|
|
|
|
dwFlagsAndAttributes = FILE_FLAG_OPEN_REPARSE_POINT;
|
|
if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) dwFlagsAndAttributes |= FILE_FLAG_BACKUP_SEMANTICS;
|
|
hLink = CreateFileW(path, /* lpFileName, */
|
|
FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess, */
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode, */
|
|
NULL, /* lpSecurityAttributes, */
|
|
OPEN_EXISTING, /* dwCreationDisposition, */
|
|
dwFlagsAndAttributes, /* dwFlagsAndAttributes, */
|
|
NULL /* hTemplateFile */
|
|
);
|
|
XDEBUG_PRINTF(("CreateFile() = 0x%p\n", hLink));
|
|
if (hLink == INVALID_HANDLE_VALUE) {
|
|
errno = Win32ErrorToErrno();
|
|
RETURN_INT_COMMENT(-1, ("Cannot open the pathname\n"));
|
|
}
|
|
|
|
iErr = hutime(hLink, times);
|
|
CloseHandle(hLink);
|
|
RETURN_INT_COMMENT(iErr, ("errno = %d\n", iErr ? errno : 0));
|
|
}
|
|
|
|
int lutimeA(const char *path, const struct utimbuf *times) {
|
|
WCHAR wszPath[PATH_MAX];
|
|
int n;
|
|
|
|
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
|
n = MultiByteToWidePath(CP_ACP, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
|
path, /* lpMultiByteStr, */
|
|
wszPath, /* lpWideCharStr, */
|
|
COUNTOF(wszPath) /* cchWideChar, */
|
|
);
|
|
if (!n) {
|
|
errno = Win32ErrorToErrno();
|
|
DEBUG_ENTER(("lutimeA(\"%s\", %p);\n", path, times));
|
|
RETURN_INT_COMMENT(-1, ("errno=%d - %s\n", errno, strerror(errno)));
|
|
}
|
|
return lutimeW(wszPath, times);
|
|
}
|
|
|
|
int lutimeU(const char *path, const struct utimbuf *times) {
|
|
WCHAR wszPath[PATH_MAX];
|
|
int n;
|
|
|
|
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
|
n = MultiByteToWidePath(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
|
path, /* lpMultiByteStr, */
|
|
wszPath, /* lpWideCharStr, */
|
|
COUNTOF(wszPath) /* cchWideChar, */
|
|
);
|
|
if (!n) {
|
|
errno = Win32ErrorToErrno();
|
|
DEBUG_ENTER(("lutimeU(\"%s\", %p);\n", path, times));
|
|
RETURN_INT_COMMENT(-1, ("errno=%d - %s\n", errno, strerror(errno)));
|
|
}
|
|
return lutimeW(wszPath, times);
|
|
}
|
|
|
|
/* Same as 'utime', but takes an open file descriptor instead of a name. */
|
|
int futime(int fd, const struct utimbuf *times) {
|
|
return hutime((HANDLE)_get_osfhandle(fd), times);
|
|
}
|
|
|
|
/* Change the file access time to times->actime and its modification time to times->modtime. */
|
|
int utimeA(const char *file, const struct utimbuf *times) {
|
|
char buf[PATH_MAX];
|
|
int iErr;
|
|
|
|
DEBUG_CODE({
|
|
char buf[100];
|
|
Utimbuf2String(buf, sizeof(buf), times);
|
|
DEBUG_ENTER(("utime(\"%s\", %s);\n", file, buf));
|
|
});
|
|
|
|
iErr = ResolveLinksA(file, buf, sizeof(buf));
|
|
if (iErr) RETURN_INT_COMMENT(iErr, ("Cannot resolve the link\n"));
|
|
|
|
iErr = lutimeA(buf, times);
|
|
RETURN_INT_COMMENT(iErr, ("errno = %d\n", iErr ? errno : 0));
|
|
}
|
|
|
|
/* Change the file access time to times->actime and its modification time to times->modtime. */
|
|
int utimeU(const char *file, const struct utimbuf *times) {
|
|
char buf[UTF8_PATH_MAX];
|
|
int iErr;
|
|
|
|
DEBUG_CODE({
|
|
char buf[100];
|
|
Utimbuf2String(buf, sizeof(buf), times);
|
|
DEBUG_ENTER(("utime(\"%s\", %s);\n", file, buf));
|
|
});
|
|
|
|
iErr = ResolveLinksU(file, buf, sizeof(buf));
|
|
if (iErr) RETURN_INT_COMMENT(iErr, ("Cannot resolve the link\n"));
|
|
|
|
iErr = lutimeU(buf, times);
|
|
RETURN_INT_COMMENT(iErr, ("errno = %d\n", iErr ? errno : 0));
|
|
}
|
|
|
|
#endif /* defined(_WIN32) */
|
|
|