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