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