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