# HG changeset patch # User Geoff Voelker # Date 893374872 0 # Node ID d0b03ce6dcf57b7b358da971077f55e9beb971a9 # Parent f654c3b16214a8ca99e92b9feb2448e08bf71384 (fstat, utime): New functions; these are provided in conjunction with stat to make handling of file timestamps consistent. (convert_from_time_t): Fix calculation of low-order bits. (sys_unlink): Allow read-only files to be unlinked as on Unix. diff -r f654c3b16214 -r d0b03ce6dcf5 src/w32.c --- a/src/w32.c Thu Apr 23 23:40:46 1998 +0000 +++ b/src/w32.c Thu Apr 23 23:41:12 1998 +0000 @@ -31,6 +31,7 @@ #include #include #include +#include /* must include CRT headers *before* config.h */ #include "config.h" @@ -1501,7 +1502,11 @@ int sys_unlink (const char * path) { - return _unlink (map_w32_filename (path, NULL)); + path = map_w32_filename (path, NULL); + + /* On Unix, unlink works without write permission. */ + _chmod (path, 0666); + return _unlink (path); } static FILETIME utc_base_ft; @@ -1540,8 +1545,6 @@ return (time_t) (ret * 1e-7); } -#if 0 -/* in case we ever have need of this */ void convert_from_time_t (time_t time, FILETIME * pft) { @@ -1569,9 +1572,8 @@ /* time in 100ns units since 1-Jan-1601 */ tmp = (long double) time * 1e7 + utc_base; pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024)); - pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime); + pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime); } -#endif #if 0 /* No reason to keep this; faking inode values either by hashing or even @@ -1811,6 +1813,143 @@ return 0; } +/* Provide fstat and utime as well as stat for consistent handling of + file timestamps. */ +int +fstat (int desc, struct stat * buf) +{ + HANDLE fh = (HANDLE) _get_osfhandle (desc); + BY_HANDLE_FILE_INFORMATION info; + DWORD fake_inode; + int permission; + + switch (GetFileType (fh) & ~FILE_TYPE_REMOTE) + { + case FILE_TYPE_DISK: + buf->st_mode = _S_IFREG; + if (!GetFileInformationByHandle (fh, &info)) + { + errno = EACCES; + return -1; + } + break; + case FILE_TYPE_PIPE: + buf->st_mode = _S_IFIFO; + goto non_disk; + case FILE_TYPE_CHAR: + case FILE_TYPE_UNKNOWN: + default: + buf->st_mode = _S_IFCHR; + non_disk: + memset (&info, 0, sizeof (info)); + info.dwFileAttributes = 0; + info.ftCreationTime = utc_base_ft; + info.ftLastAccessTime = utc_base_ft; + info.ftLastWriteTime = utc_base_ft; + } + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + buf->st_mode = _S_IFDIR; + buf->st_nlink = 2; /* doesn't really matter */ + fake_inode = 0; /* this doesn't either I think */ + } + else + { + buf->st_nlink = info.nNumberOfLinks; + /* Might as well use file index to fake inode values, but this + is not guaranteed to be unique unless we keep a handle open + all the time (even then there are situations where it is + not unique). Reputedly, there are at most 48 bits of info + (on NTFS, presumably less on FAT). */ + fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh; + } + + /* MSVC defines _ino_t to be short; other libc's might not. */ + if (sizeof (buf->st_ino) == 2) + buf->st_ino = fake_inode ^ (fake_inode >> 16); + else + buf->st_ino = fake_inode; + + /* consider files to belong to current user */ + buf->st_uid = 0; + buf->st_gid = 0; + + buf->st_dev = info.dwVolumeSerialNumber; + buf->st_rdev = info.dwVolumeSerialNumber; + + buf->st_size = info.nFileSizeLow; + + /* Convert timestamps to Unix format. */ + buf->st_mtime = convert_time (info.ftLastWriteTime); + buf->st_atime = convert_time (info.ftLastAccessTime); + if (buf->st_atime == 0) buf->st_atime = buf->st_mtime; + buf->st_ctime = convert_time (info.ftCreationTime); + if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime; + + /* determine rwx permissions */ + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + permission = _S_IREAD; + else + permission = _S_IREAD | _S_IWRITE; + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + permission |= _S_IEXEC; + else + { +#if 0 /* no way of knowing the filename */ + char * p = strrchr (name, '.'); + if (p != NULL && + (stricmp (p, ".exe") == 0 || + stricmp (p, ".com") == 0 || + stricmp (p, ".bat") == 0 || + stricmp (p, ".cmd") == 0)) + permission |= _S_IEXEC; +#endif + } + + buf->st_mode |= permission | (permission >> 3) | (permission >> 6); + + return 0; +} + +int +utime (const char *name, struct utimbuf *times) +{ + struct utimbuf deftime; + HANDLE fh; + FILETIME mtime; + FILETIME atime; + + if (times == NULL) + { + deftime.modtime = deftime.actime = time (NULL); + times = &deftime; + } + + /* Need write access to set times. */ + fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, 0, NULL); + if (fh) + { + convert_from_time_t (times->actime, &atime); + convert_from_time_t (times->modtime, &mtime); + if (!SetFileTime (fh, NULL, &atime, &mtime)) + { + CloseHandle (fh); + errno = EACCES; + return -1; + } + CloseHandle (fh); + } + else + { + errno = EINVAL; + return -1; + } + return 0; +} + #ifdef HAVE_SOCKETS /* Wrappers for winsock functions to map between our file descriptors