2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /* I/O operations for the Windows NT platforms. */
12 #include <afsconfig.h>
13 #include <afs/param.h>
23 #include <afs/afsutil.h>
25 #include <afs/afsint.h>
29 #include "viceinode.h"
31 #include <afs/afs_assert.h>
32 #include <afs/errmap_nt.h>
34 #define BASEFILEATTRIBUTE FILE_ATTRIBUTE_NORMAL
36 /* nt_unlink - unlink a case sensitive name.
38 * nt_unlink supports the nt_dec call.
40 * This nt_unlink has the delete on last close semantics of the Unix unlink
41 * with a minor twist. Subsequent CreateFile calls on this file can succeed
42 * if they open for delete. If a CreateFile call tries to create a new file
43 * with the same name it will fail. Fortunately, neither case should occur
52 GENERIC_READ | GENERIC_WRITE | DELETE,
53 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
55 BASEFILEATTRIBUTE | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_POSIX_SEMANTICS,
57 if (fh != INVALID_HANDLE_VALUE)
60 errno = nterr_nt2unix(GetLastError(), ENOENT);
66 /* nt_open - open an NT handle for a file.
69 * the handle or -1 on error.
72 nt_open(const char *name, int flags, int mode)
76 DWORD nt_share = FILE_SHARE_READ;
78 /* Really use the sequential one for data files, random for meta data. */
79 DWORD FandA = BASEFILEATTRIBUTE | FILE_FLAG_SEQUENTIAL_SCAN;
82 if ((flags & O_RDWR) || (flags & O_WRONLY)) {
83 nt_access |= GENERIC_WRITE;
84 nt_share |= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
86 if ((flags & O_RDWR) || (flags == O_RDONLY))
87 nt_access |= GENERIC_READ;
90 switch (flags & (O_CREAT | O_EXCL | O_TRUNC)) {
92 nt_create = OPEN_EXISTING;
95 nt_create = OPEN_ALWAYS;
97 case O_CREAT | O_TRUNC:
98 nt_create = CREATE_ALWAYS;
100 case O_CREAT | O_EXCL:
101 case O_CREAT | O_EXCL | O_TRUNC:
102 nt_create = CREATE_NEW;
105 nt_create = TRUNCATE_EXISTING;
107 case O_TRUNC | O_EXCL:
115 fh = CreateFile(name, nt_access, nt_share, NULL, nt_create, FandA, NULL);
116 if (fh == INVALID_HANDLE_VALUE) {
117 DWORD gle = GetLastError();
118 errno = nterr_nt2unix(gle, EBADF);
128 code = CloseHandle(fd);
130 errno = nterr_nt2unix(GetLastError(), EBADF);
137 nt_write(FD_t fd, void *buf, afs_sfsize_t size)
142 code = WriteFile((HANDLE) fd, buf, (DWORD) size, &nbytes, NULL);
145 errno = nterr_nt2unix(GetLastError(), EBADF);
152 nt_pwrite(FD_t fd, const void * buf, afs_sfsize_t count, afs_foff_t offset)
155 * same comment as read
160 OVERLAPPED overlap = {0};
161 LARGE_INTEGER liOffset;
163 liOffset.QuadPart = offset;
164 overlap.Offset = liOffset.LowPart;
165 overlap.OffsetHigh = liOffset.HighPart;
167 code = WriteFile((HANDLE) fd, (void *)buf, (DWORD) count, &nbytes, &overlap);
170 errno = nterr_nt2unix(GetLastError(), EBADF);
173 return (ssize_t)nbytes;
177 nt_read(FD_t fd, void *buf, afs_sfsize_t size)
182 code = ReadFile((HANDLE) fd, buf, (DWORD) size, &nbytes, NULL);
185 DWORD gle = GetLastError();
186 if (gle != ERROR_HANDLE_EOF) {
187 errno = nterr_nt2unix(GetLastError(), EBADF);
195 nt_pread(FD_t fd, void * buf, afs_sfsize_t count, afs_foff_t offset)
198 * This really ought to call NtReadFile
202 OVERLAPPED overlap = {0};
203 LARGE_INTEGER liOffset;
205 * Cast through a LARGE_INTEGER - make no assumption about
206 * byte ordering and leave that to the compiler..
208 liOffset.QuadPart = offset;
209 overlap.Offset = liOffset.LowPart;
210 overlap.OffsetHigh = liOffset.HighPart;
212 code = ReadFile((HANDLE) fd, (void *)buf, (DWORD) count, &nbytes, &overlap);
215 DWORD gle = GetLastError();
216 if (gle != ERROR_HANDLE_EOF) {
217 errno = nterr_nt2unix(GetLastError(), EBADF);
221 return (ssize_t)nbytes;
227 BY_HANDLE_FILE_INFORMATION finfo;
228 LARGE_INTEGER FileSize;
230 if (!GetFileInformationByHandle(fd, &finfo))
233 FileSize.HighPart = finfo.nFileSizeHigh;
234 FileSize.LowPart = finfo.nFileSizeLow;
235 return FileSize.QuadPart;
240 nt_getFileCreationTime(FD_t fd, FILETIME * ftime)
242 BY_HANDLE_FILE_INFORMATION finfo;
244 if (!GetFileInformationByHandle(fd, &finfo))
247 *ftime = finfo.ftCreationTime;
253 nt_setFileCreationTime(FD_t fd, FILETIME * ftime)
255 return !SetFileTime(fd, ftime, NULL, NULL);
267 cdrive = 'A' + (n - 1);
270 cdrive = _toupper(cdrive);
272 (void)sprintf(sdrive, "\\\\.\\%c:", cdrive);
273 drive_fd = nt_open(sdrive, O_RDWR, 0666);
274 if (drive_fd == INVALID_FD) {
278 if (!FlushFileBuffers((HANDLE) drive_fd)) {
279 errno = nterr_nt2unix(GetLastError(), EBADF);
288 /* Currently nt_ftruncate only tested to shrink a file. */
290 nt_ftruncate(FD_t fd, afs_foff_t len)
292 LARGE_INTEGER length;
294 length.QuadPart = len;
296 if (SetFilePointerEx(fd, length, NULL, FILE_BEGIN)
298 errno = nterr_nt2unix(GetLastError(), EBADF);
301 if (!SetEndOfFile(fd)) {
302 errno = nterr_nt2unix(GetLastError(), EBADF);
312 int code = FlushFileBuffers(fd);
313 return code == 0 ? -1 : 0;
318 nt_seek(FD_t fd, afs_foff_t off, int whence)
321 LARGE_INTEGER offset;
324 if (SEEK_SET == whence) {
326 } else if (SEEK_END == whence) {
328 } else if (SEEK_CUR == whence) {
329 where = FILE_CURRENT;
334 offset.QuadPart = off;
336 code = SetFilePointerEx(fd, offset, NULL, where);
338 errno = nterr_nt2unix(GetLastError(), EBADF);
345 * converts a device number (2-25) into a drive letter name.
348 * drive - assumes drive is a pointer to a string at least 3 bytes long.
349 * dev - drive number 2-25, since A-C already in use.
352 * Returns pointer to end of drive if successful, else NULL.
356 nt_DevToDrive(char *drive, int dev)
358 if (dev < 2 || dev > 25) {
360 return; /* Invalid drive */
362 drive[0] = (char)('A' + dev);
371 * converts a drive letter to a device number (2-25)
374 * drive - assumes drive is a pointer to a string at least 3 bytes long.
377 * dev - drive number 2-25 if successful (A-C already in use), else -1
381 nt_DriveToDev(char *drive)
386 dev = toupper(*drive) - 'A';
387 if ((dev < 2) || (dev > 25))