summaryrefslogtreecommitdiff
path: root/src/os_windows/os_stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/os_windows/os_stat.c')
-rw-r--r--src/os_windows/os_stat.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/os_windows/os_stat.c b/src/os_windows/os_stat.c
new file mode 100644
index 00000000..11248886
--- /dev/null
+++ b/src/os_windows/os_stat.c
@@ -0,0 +1,231 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "db_config.h"
+
+#include "db_int.h"
+
+/*
+ * Raw data reads must be done in multiples of the disk sector size. Currently
+ * the sector size is either 512 bytes or 4096 bytes. So we set the
+ * MAX_SECTOR_SIZE to 4096.
+ */
+#define MAX_SECTOR_SIZE 4096
+
+/*
+ * Find the cluster size of the file system that would contain the given path.
+ * If the value can't be determined, an error is returned.
+ */
+int
+__os_get_cluster_size(path, psize)
+ const char *path;
+ u_int32_t *psize;
+{
+
+#if (WINVER < 0x500) || defined(DB_WINCE)
+ /*
+ * WinCE and versions of Windows earlier than Windows NT don't have
+ * the APIs required to retrieve the cluster size.
+ */
+ *psize = DB_DEF_IOSIZE;
+ return (0);
+#else
+ BYTE clustershift, sectorshift, *pcluster;
+ char buffer[MAX_SECTOR_SIZE];
+ DWORD flags, infolen, length, mcl, name_size;
+ HANDLE vhandle;
+ int ret;
+ NTFS_VOLUME_DATA_BUFFER ntfsinfo;
+ size_t name_len;
+ TCHAR *env_path, name_buffer[MAX_PATH + 1], root_path[MAX_PATH + 1];
+ WORD *psector;
+
+ if (path == NULL || psize == NULL) {
+ return (EINVAL);
+ }
+
+ name_size = MAX_PATH + 1;
+ *psize = 0;
+
+ TO_TSTRING(NULL, path, env_path, ret);
+ if (ret != 0)
+ return (ret);
+ /* Retrieve the volume root path where the input path resides. */
+ if (!GetVolumePathName(env_path, root_path, name_size)) {
+ FREE_STRING(NULL, env_path);
+ return (__os_posix_err(__os_get_syserr()));
+ }
+ FREE_STRING(NULL, env_path);
+
+ /* Get the volume GUID name from the root path. */
+ if (!GetVolumeNameForVolumeMountPoint(
+ root_path, name_buffer, name_size))
+ return (__os_posix_err(__os_get_syserr()));
+
+ /* Delete the last trail "\" in the GUID name. */
+ name_len = _tcsclen(name_buffer);
+ if (name_len > 0)
+ name_buffer[name_len - 1] = _T('\0');
+
+ /* Create a handle to the volume. */
+ vhandle = CreateFile(name_buffer, FILE_READ_ATTRIBUTES | FILE_READ_DATA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ /* If open failed, return error */
+ if (vhandle == INVALID_HANDLE_VALUE)
+ return (__os_posix_err(__os_get_syserr()));
+
+ /* Get the volume information through the root path. */
+ if (!GetVolumeInformation(root_path, NULL, name_size, NULL, &mcl,
+ &flags, name_buffer, name_size)) {
+ ret = __os_posix_err(__os_get_syserr());
+ CloseHandle(vhandle);
+ return (ret);
+ }
+
+ ret = 0;
+ if (_tcscmp(name_buffer, _T("NTFS")) == 0) {
+ /*
+ * If this is NTFS file system, use FSCTL_GET_NTFS_VOLUME_DATA
+ * to get the cluster size.
+ */
+ if (DeviceIoControl(
+ vhandle, /* volume handle */
+ FSCTL_GET_NTFS_VOLUME_DATA, /* Control Code */
+ NULL, /* not use */
+ 0, /* not use */
+ &ntfsinfo, /* output buffer */
+ sizeof(NTFS_VOLUME_DATA_BUFFER),/* output buffer length */
+ &infolen, /* number of returned bytes */
+ NULL)) /* ignore here */
+ *psize = ntfsinfo.BytesPerCluster;
+ else
+ ret = __os_posix_err(__os_get_syserr());
+ } else if (_tcscmp(name_buffer, _T("exFAT")) == 0) {
+ /*
+ * If this is exFAT file system, read the information of sector
+ * and cluster from the BPB on sector 0
+ * +6C H: BYTE SectorSizeShift
+ * +6D H: BYTE ClusterShift
+ */
+ if (ReadFile(vhandle, buffer, MAX_SECTOR_SIZE, &length, NULL)) {
+ sectorshift = *(BYTE *)(&buffer[0x6C]);
+ clustershift = *(BYTE *)(&buffer[0x6D]);
+ *psize = 1 << sectorshift;
+ *psize = (*psize) << clustershift;
+ }
+ else
+ ret = __os_posix_err(__os_get_syserr());
+ } else if (_tcscmp(name_buffer, _T("FAT")) == 0 ||
+ _tcscmp(name_buffer, _T("FAT32")) == 0) {
+ /*
+ * If this is FAT or FAT32 file system, read the information of
+ * sector and cluster from the BPB on sector 0.
+ * +0B H: WORD Bytes per Sector.
+ * +0D H: BYTE Sectors Per Cluster.
+ */
+ if (ReadFile(vhandle, buffer, MAX_SECTOR_SIZE, &length, NULL)) {
+ psector = (WORD *)(&buffer[0x0B]);
+ pcluster = (BYTE *)(&buffer[0x0D]);
+ *psize = (*psector) * (*pcluster);
+ }
+ else
+ ret = __os_posix_err(__os_get_syserr());
+ }
+
+ CloseHandle(vhandle);
+ return (ret);
+#endif
+}
+
+/*
+ * __os_exists --
+ * Return if the file exists.
+ */
+int
+__os_exists(env, path, isdirp)
+ ENV *env;
+ const char *path;
+ int *isdirp;
+{
+ DB_ENV *dbenv;
+ DWORD attrs;
+ _TCHAR *tpath;
+ int ret;
+
+ dbenv = env == NULL ? NULL : env->dbenv;
+
+ TO_TSTRING(env, path, tpath, ret);
+ if (ret != 0)
+ return (ret);
+
+ if (dbenv != NULL &&
+ FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
+ __db_msg(env, DB_STR_A("0033", "fileops: stat %s",
+ "%s"), path);
+
+ RETRY_CHK(
+ ((attrs = GetFileAttributes(tpath)) == (DWORD)-1 ? 1 : 0), ret);
+ if (ret == 0) {
+ if (isdirp != NULL)
+ *isdirp = (attrs & FILE_ATTRIBUTE_DIRECTORY);
+ } else
+ ret = __os_posix_err(ret);
+
+ FREE_STRING(env, tpath);
+ return (ret);
+}
+
+/*
+ * __os_ioinfo --
+ * Return file size and I/O size; abstracted to make it easier
+ * to replace.
+ */
+int
+__os_ioinfo(env, path, fhp, mbytesp, bytesp, iosizep)
+ ENV *env;
+ const char *path;
+ DB_FH *fhp;
+ u_int32_t *mbytesp, *bytesp, *iosizep;
+{
+ int ret;
+ BY_HANDLE_FILE_INFORMATION bhfi;
+ unsigned __int64 filesize;
+ u_int32_t io_sz;
+
+ RETRY_CHK((!GetFileInformationByHandle(fhp->handle, &bhfi)), ret);
+ if (ret != 0) {
+ __db_syserr(env, ret, DB_STR("0034",
+ "GetFileInformationByHandle"));
+ return (__os_posix_err(ret));
+ }
+
+ filesize = ((unsigned __int64)bhfi.nFileSizeHigh << 32) +
+ bhfi.nFileSizeLow;
+
+ /* Return the size of the file. */
+ if (mbytesp != NULL)
+ *mbytesp = (u_int32_t)(filesize / MEGABYTE);
+ if (bytesp != NULL)
+ *bytesp = (u_int32_t)(filesize % MEGABYTE);
+
+ if (iosizep != NULL) {
+ /*
+ * Attempt to retrieve a file system cluster size, if the
+ * call succeeds, and the value returned is reasonable,
+ * use it as the default page size. Otherwise use a
+ * reasonable default value.
+ */
+ if (__os_get_cluster_size(path, &io_sz) != 0 || io_sz < 1025)
+ *iosizep = DB_DEF_IOSIZE;
+ else
+ *iosizep = io_sz;
+ }
+ return (0);
+}