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