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