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