Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
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 | |
8 | */ | |
9 | ||
10 | /* I/O operations for the Windows NT platforms. */ | |
11 | ||
12 | #include <afsconfig.h> | |
13 | #include <afs/param.h> | |
14 | ||
15 | #include <roken.h> | |
16 | ||
17 | #ifdef AFS_NT40_ENV | |
18 | #include <direct.h> | |
19 | #include <windows.h> | |
20 | #include <winnt.h> | |
21 | #include <winbase.h> | |
22 | #include <lock.h> | |
23 | #include <afs/afsutil.h> | |
24 | #include <rx/rx_queue.h> | |
25 | #include "nfs.h" | |
26 | #include <afs/afsint.h> | |
27 | #include "ihandle.h" | |
28 | #include "vnode.h" | |
29 | #include "volume.h" | |
30 | #include "viceinode.h" | |
31 | #include <afs/errmap_nt.h> | |
32 | ||
33 | #define BASEFILEATTRIBUTE FILE_ATTRIBUTE_NORMAL | |
34 | ||
35 | /* nt_unlink - unlink a case sensitive name. | |
36 | * | |
37 | * nt_unlink supports the nt_dec call. | |
38 | * | |
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 | |
43 | * as part of nt_dec. | |
44 | */ | |
45 | int | |
46 | nt_unlink(char *name) | |
47 | { | |
48 | HANDLE fh; | |
49 | ||
50 | fh = CreateFile(name, | |
51 | GENERIC_READ | GENERIC_WRITE | DELETE, | |
52 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
53 | NULL, OPEN_EXISTING, | |
54 | BASEFILEATTRIBUTE | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_POSIX_SEMANTICS, | |
55 | NULL); | |
56 | if (fh != INVALID_HANDLE_VALUE) | |
57 | CloseHandle(fh); | |
58 | else { | |
59 | errno = nterr_nt2unix(GetLastError(), ENOENT); | |
60 | return -1; | |
61 | } | |
62 | return 0; | |
63 | } | |
64 | ||
65 | /* nt_open - open an NT handle for a file. | |
66 | * | |
67 | * Return Value: | |
68 | * the handle or -1 on error. | |
69 | */ | |
70 | FD_t | |
71 | nt_open(const char *name, int flags, int mode) | |
72 | { | |
73 | HANDLE fh; | |
74 | DWORD nt_access = 0; | |
75 | DWORD nt_share = FILE_SHARE_READ; | |
76 | DWORD nt_create = 0; | |
77 | /* Really use the sequential one for data files, random for meta data. */ | |
78 | DWORD FandA = BASEFILEATTRIBUTE | FILE_FLAG_SEQUENTIAL_SCAN; | |
79 | ||
80 | /* set access */ | |
81 | if ((flags & O_RDWR) || (flags & O_WRONLY)) { | |
82 | nt_access |= GENERIC_WRITE; | |
83 | nt_share |= FILE_SHARE_WRITE | FILE_SHARE_DELETE; | |
84 | } | |
85 | if ((flags & O_RDWR) || (flags == O_RDONLY)) | |
86 | nt_access |= GENERIC_READ; | |
87 | ||
88 | /* set creation */ | |
89 | switch (flags & (O_CREAT | O_EXCL | O_TRUNC)) { | |
90 | case 0: | |
91 | nt_create = OPEN_EXISTING; | |
92 | break; | |
93 | case O_CREAT: | |
94 | nt_create = OPEN_ALWAYS; | |
95 | break; | |
96 | case O_CREAT | O_TRUNC: | |
97 | nt_create = CREATE_ALWAYS; | |
98 | break; | |
99 | case O_CREAT | O_EXCL: | |
100 | case O_CREAT | O_EXCL | O_TRUNC: | |
101 | nt_create = CREATE_NEW; | |
102 | break; | |
103 | case O_TRUNC: | |
104 | nt_create = TRUNCATE_EXISTING; | |
105 | break; | |
106 | case O_TRUNC | O_EXCL: | |
107 | case O_EXCL: | |
108 | default: | |
109 | errno = EINVAL; | |
110 | return INVALID_FD; | |
111 | break; | |
112 | } | |
113 | ||
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); | |
118 | } | |
119 | return fh; | |
120 | } | |
121 | ||
122 | int | |
123 | nt_close(FD_t fd) | |
124 | { | |
125 | BOOL code; | |
126 | ||
127 | code = CloseHandle(fd); | |
128 | if (!code) { | |
129 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
130 | return -1; | |
131 | } | |
132 | return 0; | |
133 | } | |
134 | ||
135 | int | |
136 | nt_write(FD_t fd, void *buf, afs_sfsize_t size) | |
137 | { | |
138 | BOOL code; | |
139 | DWORD nbytes; | |
140 | ||
141 | code = WriteFile((HANDLE) fd, buf, (DWORD) size, &nbytes, NULL); | |
142 | ||
143 | if (!code) { | |
144 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
145 | return -1; | |
146 | } | |
147 | return (int)nbytes; | |
148 | } | |
149 | ||
150 | int | |
151 | nt_pwrite(FD_t fd, const void * buf, afs_sfsize_t count, afs_foff_t offset) | |
152 | { | |
153 | /* | |
154 | * same comment as read | |
155 | */ | |
156 | ||
157 | DWORD nbytes; | |
158 | BOOL code; | |
159 | OVERLAPPED overlap = {0}; | |
160 | LARGE_INTEGER liOffset; | |
161 | ||
162 | liOffset.QuadPart = offset; | |
163 | overlap.Offset = liOffset.LowPart; | |
164 | overlap.OffsetHigh = liOffset.HighPart; | |
165 | ||
166 | code = WriteFile((HANDLE) fd, (void *)buf, (DWORD) count, &nbytes, &overlap); | |
167 | ||
168 | if (!code) { | |
169 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
170 | return -1; | |
171 | } | |
172 | return (ssize_t)nbytes; | |
173 | } | |
174 | ||
175 | int | |
176 | nt_read(FD_t fd, void *buf, afs_sfsize_t size) | |
177 | { | |
178 | BOOL code; | |
179 | DWORD nbytes; | |
180 | ||
181 | code = ReadFile((HANDLE) fd, buf, (DWORD) size, &nbytes, NULL); | |
182 | ||
183 | if (!code) { | |
184 | DWORD gle = GetLastError(); | |
185 | if (gle != ERROR_HANDLE_EOF) { | |
186 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
187 | return -1; | |
188 | } | |
189 | } | |
190 | return (int)nbytes; | |
191 | } | |
192 | ||
193 | int | |
194 | nt_pread(FD_t fd, void * buf, afs_sfsize_t count, afs_foff_t offset) | |
195 | { | |
196 | /* | |
197 | * This really ought to call NtReadFile | |
198 | */ | |
199 | DWORD nbytes; | |
200 | BOOL code; | |
201 | OVERLAPPED overlap = {0}; | |
202 | LARGE_INTEGER liOffset; | |
203 | /* | |
204 | * Cast through a LARGE_INTEGER - make no assumption about | |
205 | * byte ordering and leave that to the compiler.. | |
206 | */ | |
207 | liOffset.QuadPart = offset; | |
208 | overlap.Offset = liOffset.LowPart; | |
209 | overlap.OffsetHigh = liOffset.HighPart; | |
210 | ||
211 | code = ReadFile((HANDLE) fd, (void *)buf, (DWORD) count, &nbytes, &overlap); | |
212 | ||
213 | if (!code) { | |
214 | DWORD gle = GetLastError(); | |
215 | if (gle != ERROR_HANDLE_EOF) { | |
216 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
217 | return -1; | |
218 | } | |
219 | } | |
220 | return (ssize_t)nbytes; | |
221 | } | |
222 | ||
223 | afs_sfsize_t | |
224 | nt_size(FD_t fd) | |
225 | { | |
226 | BY_HANDLE_FILE_INFORMATION finfo; | |
227 | LARGE_INTEGER FileSize; | |
228 | ||
229 | if (!GetFileInformationByHandle(fd, &finfo)) | |
230 | return -1; | |
231 | ||
232 | FileSize.HighPart = finfo.nFileSizeHigh; | |
233 | FileSize.LowPart = finfo.nFileSizeLow; | |
234 | return FileSize.QuadPart; | |
235 | } | |
236 | ||
237 | ||
238 | int | |
239 | nt_getFileCreationTime(FD_t fd, FILETIME * ftime) | |
240 | { | |
241 | BY_HANDLE_FILE_INFORMATION finfo; | |
242 | ||
243 | if (!GetFileInformationByHandle(fd, &finfo)) | |
244 | return -1; | |
245 | ||
246 | *ftime = finfo.ftCreationTime; | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
251 | int | |
252 | nt_setFileCreationTime(FD_t fd, FILETIME * ftime) | |
253 | { | |
254 | return !SetFileTime(fd, ftime, NULL, NULL); | |
255 | } | |
256 | ||
257 | int | |
258 | nt_sync(int cdrive) | |
259 | { | |
260 | FD_t drive_fd; | |
261 | char sdrive[32]; | |
262 | int n; | |
263 | ||
264 | n = cdrive; | |
265 | if (n <= 26) { | |
266 | cdrive = 'A' + (n - 1); | |
267 | } | |
268 | ||
269 | cdrive = _toupper(cdrive); | |
270 | ||
271 | (void)sprintf(sdrive, "\\\\.\\%c:", cdrive); | |
272 | drive_fd = nt_open(sdrive, O_RDWR, 0666); | |
273 | if (drive_fd == INVALID_FD) { | |
274 | return -1; | |
275 | } | |
276 | ||
277 | if (!FlushFileBuffers((HANDLE) drive_fd)) { | |
278 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
279 | nt_close(drive_fd); | |
280 | return -1; | |
281 | } | |
282 | nt_close(drive_fd); | |
283 | return 0; | |
284 | } | |
285 | ||
286 | ||
287 | /* Currently nt_ftruncate only tested to shrink a file. */ | |
288 | int | |
289 | nt_ftruncate(FD_t fd, afs_foff_t len) | |
290 | { | |
291 | LARGE_INTEGER length; | |
292 | ||
293 | length.QuadPart = len; | |
294 | ||
295 | if (SetFilePointerEx(fd, length, NULL, FILE_BEGIN) | |
296 | == 0xffffffff) { | |
297 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
298 | return -1; | |
299 | } | |
300 | if (!SetEndOfFile(fd)) { | |
301 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
302 | return -1; | |
303 | } | |
304 | return 0; | |
305 | } | |
306 | ||
307 | ||
308 | int | |
309 | nt_fsync(FD_t fd) | |
310 | { | |
311 | int code = FlushFileBuffers(fd); | |
312 | return code == 0 ? -1 : 0; | |
313 | } | |
314 | ||
315 | ||
316 | int | |
317 | nt_seek(FD_t fd, afs_foff_t off, int whence) | |
318 | { | |
319 | int code; | |
320 | LARGE_INTEGER offset; | |
321 | int where; | |
322 | ||
323 | if (SEEK_SET == whence) { | |
324 | where = FILE_BEGIN; | |
325 | } else if (SEEK_END == whence) { | |
326 | where = FILE_END; | |
327 | } else if (SEEK_CUR == whence) { | |
328 | where = FILE_CURRENT; | |
329 | } else { | |
330 | errno = EINVAL; | |
331 | return -1; | |
332 | } | |
333 | offset.QuadPart = off; | |
334 | ||
335 | code = SetFilePointerEx(fd, offset, NULL, where); | |
336 | if (0 == code) { | |
337 | errno = nterr_nt2unix(GetLastError(), EBADF); | |
338 | return -1; | |
339 | } | |
340 | return 0; | |
341 | } | |
342 | ||
343 | /* nt_DevToDrive | |
344 | * converts a device number (2-25) into a drive letter name. | |
345 | * | |
346 | * Arguments: | |
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. | |
349 | * | |
350 | * Return Value: | |
351 | * Returns pointer to end of drive if successful, else NULL. | |
352 | * | |
353 | */ | |
354 | void | |
355 | nt_DevToDrive(char *drive, int dev) | |
356 | { | |
357 | if (dev < 2 || dev > 25) { | |
358 | errno = EINVAL; | |
359 | return; /* Invalid drive */ | |
360 | } | |
361 | drive[0] = (char)('A' + dev); | |
362 | drive[1] = ':'; | |
363 | drive[2] = '\0'; | |
364 | ||
365 | return; | |
366 | ||
367 | } | |
368 | ||
369 | /* nt_DriveToDev | |
370 | * converts a drive letter to a device number (2-25) | |
371 | * | |
372 | * Arguments: | |
373 | * drive - assumes drive is a pointer to a string at least 3 bytes long. | |
374 | * | |
375 | * Return Value: | |
376 | * dev - drive number 2-25 if successful (A-C already in use), else -1 | |
377 | * | |
378 | */ | |
379 | int | |
380 | nt_DriveToDev(char *drive) | |
381 | { | |
382 | int dev = -1; | |
383 | ||
384 | if (drive) | |
385 | dev = toupper(*drive) - 'A'; | |
386 | if ((dev < 2) || (dev > 25)) | |
387 | return -1; | |
388 | ||
389 | return dev; | |
390 | } | |
391 | #endif |