2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
15 #if defined(AFS_AIX_ENV)
17 #include <sys/statfs.h>
20 #include <sys/ioccom.h>
22 #if defined(AFS_DUX40_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV) || (defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN100_ENV))
23 #include <sys/ioctl.h>
25 #ifndef AFS_DARWIN100_ENV
28 #endif /* AFS_AIX_ENV */
30 #include <afs/afs_assert.h>
35 typedef off64_t osi_lloff_t;
36 #define osi_llseek lseek64
37 #else /* O_LARGEFILE */
38 #ifdef AFS_HAVE_LLSEEK
39 typedef offset_t osi_lloff_t;
40 #define osi_llseek llseek
41 #else /* AFS_HAVE_LLSEEK */
42 typedef off_t osi_lloff_t;
43 #define osi_llseek lseek
44 #endif /* AFS_HAVE_LLSEEK */
45 #endif /* O_LARGEFILE */
48 * This macro should be used inside assertions wherever offset/hyper
49 * conversion occur. A good compiler in a 64 bit environment will
50 * elide the entire statement if the offset type is 64 bits wide.
52 #define osi_hFitsInOff(val) \
53 ((sizeof(osi_lloff_t) == 4) ? (((val) & 0xffffffff00000000LL) == 0) : 1)
55 /************ End of osi wrappers ***********************************/
57 /* Implementation of user space device I/O for regular POSIX files. */
60 usd_FileRead(usd_handle_t usd, char *buf, afs_uint32 nbytes,
63 int fd = (intptr_t)(usd->handle);
66 got = read(fd, buf, nbytes);
78 usd_FileWrite(usd_handle_t usd, char *buf, afs_uint32 nbytes,
81 int fd = (intptr_t)(usd->handle);
84 sent = write(fd, buf, nbytes);
95 extern osi_lloff_t osi_llseek(int, osi_lloff_t, int);
98 usd_FileSeek(usd_handle_t usd, afs_int64 reqOff, int whence,
101 int fd = (intptr_t)(usd->handle);
104 if (!osi_hFitsInOff(reqOff))
107 lloff = osi_llseek(fd, reqOff, whence);
108 if (lloff == (((osi_lloff_t) 0) - 1))
117 usd_FileIoctl(usd_handle_t usd, int req, void *arg)
119 int fd = (intptr_t)(usd->handle);
122 #else /* O_LARGEFILE */
124 #endif /* O_LARGEFILE */
126 struct statfs fsinfo; /* AIX stat structure doesn't have st_blksize */
127 #endif /* AFS_AIX_ENV */
132 case USD_IOCTL_GETBLKSIZE:
134 code = fstatfs(fd, &fsinfo);
136 *((long *)arg) = (long)4096;
140 #endif /* AFS_AIX_ENV */
141 case USD_IOCTL_GETTYPE:
142 case USD_IOCTL_GETDEV:
143 case USD_IOCTL_GETSIZE:
145 code = fstat64(fd, &info);
146 #else /* O_LARGEFILE */
147 code = fstat(fd, &info);
148 #endif /* O_LARGEFILE */
155 case USD_IOCTL_GETTYPE:
156 *(int *)arg = info.st_mode & S_IFMT;
158 case USD_IOCTL_GETDEV:
159 if (!(S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)))
160 return ENODEV; /* not a device */
161 *(dev_t *) arg = info.st_rdev;
163 case USD_IOCTL_GETSIZE:
164 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode))
165 return ENOTTY; /* shouldn't be a device */
166 *(afs_int64 *)arg = info.st_size;
168 case USD_IOCTL_GETFULLNAME:
169 *(char **)arg = usd->fullPathName;
172 case USD_IOCTL_SETSIZE:
174 /* We could just use ftruncate in all cases. (This even works on AIX;
175 * I tried it). -blake 931118 */
177 /* However, I'm pretty sure this doesn't work on Ultrix so I am
178 * unsure about OSF/1 and HP/UX. 931118 */
180 size = *(afs_int64 *) arg;
181 if (!osi_hFitsInOff(size))
184 code = ftruncate64(fd, size);
185 #else /* O_LARGEFILE */
186 code = ftruncate(fd, size);
187 #endif /* O_LARGEFILE */
192 case USD_IOCTL_TAPEOPERATION:
194 #ifdef AFS_DARWIN100_ENV
197 usd_tapeop_t *tapeOpp = (usd_tapeop_t *) arg;
198 #if defined(AFS_AIX_ENV)
199 struct stop os_tapeop;
201 if (tapeOpp->tp_op == USDTAPE_WEOF) {
202 os_tapeop.st_op = STWEOF;
203 } else if (tapeOpp->tp_op == USDTAPE_REW) {
204 os_tapeop.st_op = STREW;
205 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
206 os_tapeop.st_op = STFSF;
207 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
208 os_tapeop.st_op = STRSF;
209 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
211 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
214 /* unsupported tape operation */
217 os_tapeop.st_count = tapeOpp->tp_count;
219 code = ioctl(fd, STIOCTOP, &os_tapeop);
221 struct mtop os_tapeop;
223 if (tapeOpp->tp_op == USDTAPE_WEOF) {
224 os_tapeop.mt_op = MTWEOF;
225 } else if (tapeOpp->tp_op == USDTAPE_REW) {
226 os_tapeop.mt_op = MTREW;
227 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
228 os_tapeop.mt_op = MTFSF;
229 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
230 os_tapeop.mt_op = MTBSF;
231 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
233 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
236 /* unsupported tape operation */
239 os_tapeop.mt_count = tapeOpp->tp_count;
241 code = ioctl(fd, MTIOCTOP, &os_tapeop);
242 #endif /* AFS_AIX_ENV */
252 case USD_IOCTL_GETBLKSIZE:
253 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)) {
254 *((long *)arg) = (long)4096;
258 *((long *)arg) = (long)fsinfo.f_bsize;
259 #else /* AFS_AIX_ENV */
260 *((long *)arg) = (long)info.st_blksize;
261 #endif /* AFS_AIX_ENV */
271 usd_FileClose(usd_handle_t usd)
273 int fd = (intptr_t)(usd->handle);
277 /* I can't really believe this is necessary. On the one hand the user
278 * space code always uses character devices, which aren't supposed to do
279 * any buffering. On the other, I very much doubt fsyncing a regular file
280 * being salvaged is ever necessary. But the salvager used to do this
281 * before returning, so... */
283 if (usd->openFlags & (O_WRONLY | O_RDWR)) {
285 code = usd_FileIoctl(usd, USD_IOCTL_GETTYPE, &mode);
286 if (code == 0 && S_ISBLK(mode)) {
296 if (usd->fullPathName)
297 free(usd->fullPathName);
304 usd_FileOpen(const char *path, int flags, int mode, usd_handle_t * usdP)
314 oflags = (flags & USD_OPEN_RDWR) ? O_RDWR : O_RDONLY;
316 #ifdef O_SYNC /* AFS_DARWIN_ENV XXX */
317 if (flags & USD_OPEN_SYNC)
321 if (flags & USD_OPEN_CREATE)
325 fd = open64(path, oflags | O_LARGEFILE, mode);
326 #else /* O_LARGEFILE */
327 fd = open(path, oflags, mode);
328 #endif /* O_LARGEFILE */
332 usd = (usd_handle_t) malloc(sizeof(*usd));
333 memset(usd, 0, sizeof(*usd));
334 usd->handle = (void *)(intptr_t)fd;
335 usd->read = usd_FileRead;
336 usd->write = usd_FileWrite;
337 usd->seek = usd_FileSeek;
338 usd->ioctl = usd_FileIoctl;
339 usd->close = usd_FileClose;
340 usd->fullPathName = (char *)malloc(strlen(path) + 1);
341 strcpy(usd->fullPathName, path);
342 usd->openFlags = flags;
345 if (flags & (USD_OPEN_RLOCK | USD_OPEN_WLOCK)) {
348 #else /* O_LARGEFILE */
350 #endif /* O_LARGEFILE */
352 /* make sure both lock bits aren't set */
353 assert(~flags & (USD_OPEN_RLOCK | USD_OPEN_WLOCK));
355 fl.l_type = ((flags & USD_OPEN_RLOCK) ? F_RDLCK : F_WRLCK);
356 fl.l_whence = SEEK_SET;
357 fl.l_start = (osi_lloff_t) 0;
358 fl.l_len = (osi_lloff_t) 0; /* whole file */
360 code = fcntl(fd, F_SETLK64, &fl);
361 #else /* O_LARGEFILE */
362 code = fcntl(fd, F_SETLK, &fl);
363 #endif /* O_LARGEFILE */
367 /* If we're trying to obtain a write lock on a real disk, then the
368 * aggregate must not be attached by the kernel. If so, unlock it
370 * WARNING: The code to check for the above has been removed when this
371 * file was ported from DFS src. It should be put back if
372 * this library is used to access hard disks
376 if (code == 0 && usdP)
384 usd_FileDummyClose(usd_handle_t usd)
391 usd_Open(const char *path, int oflag, int mode, usd_handle_t * usdP)
393 return usd_FileOpen(path, oflag, mode, usdP);
397 usd_FileStandardInput(usd_handle_t * usdP)
404 usd = (usd_handle_t) malloc(sizeof(*usd));
405 memset(usd, 0, sizeof(*usd));
406 usd->handle = (void *)((unsigned long)0);
407 usd->read = usd_FileRead;
408 usd->write = usd_FileWrite;
409 usd->seek = usd_FileSeek;
410 usd->ioctl = usd_FileIoctl;
411 usd->close = usd_FileDummyClose;
412 usd->fullPathName = "STDIN";
420 usd_StandardInput(usd_handle_t * usdP)
422 return usd_FileStandardInput(usdP);
426 usd_FileStandardOutput(usd_handle_t * usdP)
433 usd = (usd_handle_t) malloc(sizeof(*usd));
434 memset(usd, 0, sizeof(*usd));
435 usd->handle = (void *)((unsigned long)1);
436 usd->read = usd_FileRead;
437 usd->write = usd_FileWrite;
438 usd->seek = usd_FileSeek;
439 usd->ioctl = usd_FileIoctl;
440 usd->close = usd_FileDummyClose;
441 usd->fullPathName = "STDOUT";
449 usd_StandardOutput(usd_handle_t * usdP)
451 return usd_FileStandardOutput(usdP);