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>
24 #include <rx/rx_queue.h>
26 #include <afs/afsint.h>
30 #include "viceinode.h"
31 #include <afs/errmap_nt.h>
33 #define BASEFILEATTRIBUTE FILE_ATTRIBUTE_NORMAL
35 /* nt_unlink - unlink a case sensitive name.
37 * nt_unlink supports the nt_dec call.
39 * This nt_unlink has the delete on last close semantics of the Unix unlink
40 * with a minor twist. Subsequent CreateFile calls on this file can succeed
41 * if they open for delete. If a CreateFile call tries to create a new file
42 * with the same name it will fail. Fortunately, neither case should occur
51 GENERIC_READ
| GENERIC_WRITE
| DELETE
,
52 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
54 BASEFILEATTRIBUTE
| FILE_FLAG_DELETE_ON_CLOSE
| FILE_FLAG_POSIX_SEMANTICS
,
56 if (fh
!= INVALID_HANDLE_VALUE
)
59 errno
= nterr_nt2unix(GetLastError(), ENOENT
);
65 /* nt_open - open an NT handle for a file.
68 * the handle or -1 on error.
71 nt_open(const char *name
, int flags
, int mode
)
75 DWORD nt_share
= FILE_SHARE_READ
;
77 /* Really use the sequential one for data files, random for meta data. */
78 DWORD FandA
= BASEFILEATTRIBUTE
| FILE_FLAG_SEQUENTIAL_SCAN
;
81 if ((flags
& O_RDWR
) || (flags
& O_WRONLY
)) {
82 nt_access
|= GENERIC_WRITE
;
83 nt_share
|= FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
85 if ((flags
& O_RDWR
) || (flags
== O_RDONLY
))
86 nt_access
|= GENERIC_READ
;
89 switch (flags
& (O_CREAT
| O_EXCL
| O_TRUNC
)) {
91 nt_create
= OPEN_EXISTING
;
94 nt_create
= OPEN_ALWAYS
;
96 case O_CREAT
| O_TRUNC
:
97 nt_create
= CREATE_ALWAYS
;
99 case O_CREAT
| O_EXCL
:
100 case O_CREAT
| O_EXCL
| O_TRUNC
:
101 nt_create
= CREATE_NEW
;
104 nt_create
= TRUNCATE_EXISTING
;
106 case O_TRUNC
| O_EXCL
:
114 fh
= CreateFile(name
, nt_access
, nt_share
, NULL
, nt_create
, FandA
, NULL
);
115 if (fh
== INVALID_HANDLE_VALUE
) {
116 DWORD gle
= GetLastError();
117 errno
= nterr_nt2unix(gle
, EBADF
);
127 code
= CloseHandle(fd
);
129 errno
= nterr_nt2unix(GetLastError(), EBADF
);
136 nt_write(FD_t fd
, void *buf
, afs_sfsize_t size
)
141 code
= WriteFile((HANDLE
) fd
, buf
, (DWORD
) size
, &nbytes
, NULL
);
144 errno
= nterr_nt2unix(GetLastError(), EBADF
);
151 nt_pwrite(FD_t fd
, const void * buf
, afs_sfsize_t count
, afs_foff_t offset
)
154 * same comment as read
159 OVERLAPPED overlap
= {0};
160 LARGE_INTEGER liOffset
;
162 liOffset
.QuadPart
= offset
;
163 overlap
.Offset
= liOffset
.LowPart
;
164 overlap
.OffsetHigh
= liOffset
.HighPart
;
166 code
= WriteFile((HANDLE
) fd
, (void *)buf
, (DWORD
) count
, &nbytes
, &overlap
);
169 errno
= nterr_nt2unix(GetLastError(), EBADF
);
172 return (ssize_t
)nbytes
;
176 nt_read(FD_t fd
, void *buf
, afs_sfsize_t size
)
181 code
= ReadFile((HANDLE
) fd
, buf
, (DWORD
) size
, &nbytes
, NULL
);
184 DWORD gle
= GetLastError();
185 if (gle
!= ERROR_HANDLE_EOF
) {
186 errno
= nterr_nt2unix(GetLastError(), EBADF
);
194 nt_pread(FD_t fd
, void * buf
, afs_sfsize_t count
, afs_foff_t offset
)
197 * This really ought to call NtReadFile
201 OVERLAPPED overlap
= {0};
202 LARGE_INTEGER liOffset
;
204 * Cast through a LARGE_INTEGER - make no assumption about
205 * byte ordering and leave that to the compiler..
207 liOffset
.QuadPart
= offset
;
208 overlap
.Offset
= liOffset
.LowPart
;
209 overlap
.OffsetHigh
= liOffset
.HighPart
;
211 code
= ReadFile((HANDLE
) fd
, (void *)buf
, (DWORD
) count
, &nbytes
, &overlap
);
214 DWORD gle
= GetLastError();
215 if (gle
!= ERROR_HANDLE_EOF
) {
216 errno
= nterr_nt2unix(GetLastError(), EBADF
);
220 return (ssize_t
)nbytes
;
226 BY_HANDLE_FILE_INFORMATION finfo
;
227 LARGE_INTEGER FileSize
;
229 if (!GetFileInformationByHandle(fd
, &finfo
))
232 FileSize
.HighPart
= finfo
.nFileSizeHigh
;
233 FileSize
.LowPart
= finfo
.nFileSizeLow
;
234 return FileSize
.QuadPart
;
239 nt_getFileCreationTime(FD_t fd
, FILETIME
* ftime
)
241 BY_HANDLE_FILE_INFORMATION finfo
;
243 if (!GetFileInformationByHandle(fd
, &finfo
))
246 *ftime
= finfo
.ftCreationTime
;
252 nt_setFileCreationTime(FD_t fd
, FILETIME
* ftime
)
254 return !SetFileTime(fd
, ftime
, NULL
, NULL
);
266 cdrive
= 'A' + (n
- 1);
269 cdrive
= _toupper(cdrive
);
271 (void)sprintf(sdrive
, "\\\\.\\%c:", cdrive
);
272 drive_fd
= nt_open(sdrive
, O_RDWR
, 0666);
273 if (drive_fd
== INVALID_FD
) {
277 if (!FlushFileBuffers((HANDLE
) drive_fd
)) {
278 errno
= nterr_nt2unix(GetLastError(), EBADF
);
287 /* Currently nt_ftruncate only tested to shrink a file. */
289 nt_ftruncate(FD_t fd
, afs_foff_t len
)
291 LARGE_INTEGER length
;
293 length
.QuadPart
= len
;
295 if (SetFilePointerEx(fd
, length
, NULL
, FILE_BEGIN
)
297 errno
= nterr_nt2unix(GetLastError(), EBADF
);
300 if (!SetEndOfFile(fd
)) {
301 errno
= nterr_nt2unix(GetLastError(), EBADF
);
311 int code
= FlushFileBuffers(fd
);
312 return code
== 0 ? -1 : 0;
317 nt_seek(FD_t fd
, afs_foff_t off
, int whence
)
320 LARGE_INTEGER offset
;
323 if (SEEK_SET
== whence
) {
325 } else if (SEEK_END
== whence
) {
327 } else if (SEEK_CUR
== whence
) {
328 where
= FILE_CURRENT
;
333 offset
.QuadPart
= off
;
335 code
= SetFilePointerEx(fd
, offset
, NULL
, where
);
337 errno
= nterr_nt2unix(GetLastError(), EBADF
);
344 * converts a device number (2-25) into a drive letter name.
347 * drive - assumes drive is a pointer to a string at least 3 bytes long.
348 * dev - drive number 2-25, since A-C already in use.
351 * Returns pointer to end of drive if successful, else NULL.
355 nt_DevToDrive(char *drive
, int dev
)
357 if (dev
< 2 || dev
> 25) {
359 return; /* Invalid drive */
361 drive
[0] = (char)('A' + dev
);
370 * converts a drive letter to a device number (2-25)
373 * drive - assumes drive is a pointer to a string at least 3 bytes long.
376 * dev - drive number 2-25 if successful (A-C already in use), else -1
380 nt_DriveToDev(char *drive
)
385 dev
= toupper(*drive
) - 'A';
386 if ((dev
< 2) || (dev
> 25))