int S_windows_open_exclusive(char *who, char *path, int flags) { HANDLE hfile; int fd; DWORD access = 0; DWORD crdisp = 0; /* could implement this later with more difficulty */ if ((flags & (O_TRUNC|O_CREAT)) == (O_TRUNC|O_CREAT)) S_error("open_exclusive", "O_TRUNC|O_CREAT not supported"); if (flags & O_RDWR) access |= GENERIC_READ|GENERIC_WRITE; if (flags & O_RDONLY) access |= GENERIC_READ; if (flags & O_WRONLY) access |= GENERIC_WRITE; if (flags & O_CREAT) crdisp = OPEN_ALWAYS; if (flags & O_TRUNC) crdisp = TRUNCATE_EXISTING; hfile = CreateFile(path, access, 0, (SECURITY_ATTRIBUTES *)0, crdisp, FILE_ATTRIBUTE_NORMAL, (HANDLE)0); if (hfile == INVALID_HANDLE_VALUE) S_error1(who, "~a", s_ErrorString(GetLastError())); flags &= O_RDONLY|O_WRONLY|O_RDWR|O_APPEND; fd = _open_osfhandle((long)hfile, flags); if (fd == -1) S_error(who, "open_osfhandle failed"); return fd; }
/* raises an exception if insufficient space cannot be malloc'd. returns NULL if utf-8 path cannot be converted to wchars. otherwise returns a freshly allocated, wide-character version of inpath with ~ (home directory) prefix expanded, if possible */ wchar_t *S_malloc_wide_pathname(const char *inpath) { size_t n; char *path; wchar_t *wpath; path = S_malloc_pathname(inpath); n = strlen(path) + 1; /* counting on utf-8 representation having at least as many chars as wchar representation */ if ((wpath = (wchar_t *)malloc(n * sizeof(wchar_t))) == NULL) { free(path); S_error("expand_pathname", "malloc failed"); } if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, (int)n) == 0) { free(path); free(wpath); return NULL; } free(path); return wpath; }
/* primitive version of flock compatible with Windows 95/98/ME. A better version could be implemented for Windows NT/2000/XP using LockFileEx. */ int S_windows_flock(int fd, int operation) { HANDLE hfile = (HANDLE)_get_osfhandle(fd); switch (operation) { case LOCK_EX|LOCK_NB: if (LockFile(hfile, 0, 0, 0x0fffffff, 0)) return 0; errno = EWOULDBLOCK; return -1; case LOCK_EX: while (LockFile(hfile, 0, 0, 0x0fffffff, 0) == 0) Sleep(10); return 0; case LOCK_SH: case LOCK_SH|LOCK_NB: S_error("flock", "shared locks unsupported"); return -1; case LOCK_UN: case LOCK_UN|LOCK_NB: UnlockFile(hfile, 0, 0, 0x0fffffff, 0); return 0; default: errno = EINVAL; return -1; } }
/* raises an exception if insufficient space cannot be malloc'd. otherwise returns a freshly allocated version of inpath with ~ (home directory) prefix expanded, if possible */ char *S_malloc_pathname(const char *inpath) { char *outpath; const char *ip; #ifdef WIN32 if (*inpath == '~' && (*(ip = inpath + 1) == 0 || DIRMARKERP(*ip))) { const char *homedrive, *homepath; size_t n1, n2, n3; if ((homedrive = getenv("HOMEDRIVE")) != NULL && (homepath = getenv("HOMEPATH")) != NULL) { n1 = strlen(homedrive); n2 = strlen(homepath); n3 = strlen(ip) + 1; if ((outpath = malloc(n1 + n2 + n3)) == NULL) S_error("expand_pathname", "malloc failed"); memcpy(outpath, homedrive, n1); memcpy(outpath + n1, homepath, n2); memcpy(outpath + n1 + n2, ip, n3); return outpath; } } #else /* WIN32 */ if (*inpath == '~') { const char *dir; size_t n1, n2; struct passwd *pwent; if (*(ip = inpath + 1) == 0 || DIRMARKERP(*ip)) { if ((dir = getenv("HOME")) == NULL) if ((pwent = getpwuid(getuid())) != NULL) dir = pwent->pw_dir; } else { char *userbuf; const char *user_start = ip; do { ip += 1; } while (*ip != 0 && !DIRMARKERP(*ip)); if ((userbuf = malloc(ip - user_start + 1)) == NULL) S_error("expand_pathname", "malloc failed"); memcpy(userbuf, user_start, ip - user_start); userbuf[ip - user_start] = 0; dir = (pwent = getpwnam(userbuf)) != NULL ? pwent->pw_dir : NULL; free(userbuf); } if (dir != NULL) { n1 = strlen(dir); n2 = strlen(ip) + 1; if ((outpath = malloc(n1 + n2)) == NULL) S_error("expand_pathname", "malloc failed"); memcpy(outpath, dir, n1); memcpy(outpath + n1, ip, n2); return outpath; } } #endif /* WIN32 */ /* if no ~ or tilde dir can't be found, copy inpath */ { size_t n = strlen(inpath) + 1; outpath = (char *)malloc(n); memcpy(outpath, inpath, n); return outpath; } }