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>
17 #include <sys/types.h>
20 #if defined(AFS_AIX_ENV)
22 #include <sys/statfs.h>
25 #include <sys/ioccom.h>
28 #endif /* AFS_AIX_ENV */
29 #if defined(AFS_DUX40_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV)
30 #include <sys/ioctl.h>
42 #include <afs/debug.h>
46 typedef off64_t osi_lloff_t;
47 #define osi_llseek lseek64
48 #else /* O_LARGEFILE */
49 #ifdef AFS_HAVE_LLSEEK
50 typedef offset_t osi_lloff_t;
51 #define osi_llseek llseek
52 #else /* AFS_HAVE_LLSEEK */
53 typedef off_t osi_lloff_t;
54 #define osi_llseek lseek
55 #endif /* AFS_HAVE_LLSEEK */
56 #endif /* O_LARGEFILE */
59 * This macro should be used inside assertions wherever offset/hyper
60 * conversion occur. A good compiler in a 64 bit environment will
61 * elide the entire statement if the offset type is 64 bits wide.
63 #define osi_hFitsInOff(ahyper, noff) \
64 ((sizeof(noff) == 4) ? hfitsin32(ahyper) : 1)
66 #define osi_h2off(ahyper, noff) \
67 ((sizeof(noff) == 4) \
68 ? ((noff) = (osi_lloff_t)hgetlo(ahyper))\
69 : ((noff) = ((osi_lloff_t)hgethi(ahyper)<<32) | (osi_lloff_t)hgetlo(ahyper)))
71 #define osi_off2h(noff, ahyper) \
72 ((sizeof(noff) == 4) \
73 ? (hset32(ahyper, (int)noff)) \
74 : (hset64(ahyper, (int)((noff>>32)&0xffffffff), ((int)noff&0xffffffff))))
77 /************ End of osi wrappers ***********************************/
79 /* Implementation of user space device I/O for regular POSIX files. */
81 static int usd_FileRead(
87 int fd = (int)(usd->handle);
90 got = read(fd, buf, nbytes);
101 static int usd_FileWrite(
107 int fd = (int)(usd->handle);
110 sent = write(fd, buf, nbytes);
121 extern osi_lloff_t osi_llseek(int, osi_lloff_t, int);
123 static int usd_FileSeek(
127 afs_hyper_t *curOffP)
129 int fd = (int)(usd->handle);
132 if (!osi_hFitsInOff(reqOff, lloff))
135 osi_h2off(reqOff, lloff);
136 lloff = osi_llseek(fd, lloff, whence);
137 if (lloff == (((osi_lloff_t)0) - 1))
140 osi_off2h(lloff, *curOffP);
145 static int usd_FileIoctl(usd_handle_t usd, int req, void *arg)
147 int fd = (int)(usd->handle);
150 #else /* O_LARGEFILE */
152 #endif /* O_LARGEFILE */
154 struct statfs fsinfo; /* AIX stat structure doesn't have st_blksize */
155 #endif /* AFS_AIX_ENV */
161 case USD_IOCTL_GETBLKSIZE:
163 code = fstatfs(fd, &fsinfo);
165 *((long *)arg) = (long)4096;
169 #endif /* AFS_AIX_ENV */
170 case USD_IOCTL_GETTYPE:
171 case USD_IOCTL_GETDEV:
172 case USD_IOCTL_GETSIZE:
174 code = fstat64(fd, &info);
175 #else /* O_LARGEFILE */
176 code = fstat(fd, &info);
177 #endif /* O_LARGEFILE */
184 case USD_IOCTL_GETTYPE:
185 *(int *)arg = info.st_mode & S_IFMT;
187 case USD_IOCTL_GETDEV:
188 if (!(S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)))
189 return ENODEV; /* not a device */
190 *(dev_t *)arg = info.st_rdev;
192 case USD_IOCTL_GETSIZE:
193 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode))
194 return ENOTTY; /* shouldn't be a device */
195 osi_off2h(info.st_size, *(afs_hyper_t *)arg);
197 case USD_IOCTL_GETFULLNAME:
198 *(char **)arg = usd->fullPathName;
201 case USD_IOCTL_SETSIZE:
203 /* We could just use ftruncate in all cases. (This even works on AIX;
204 * I tried it). -blake 931118 */
206 /* However, I'm pretty sure this doesn't work on Ultrix so I am
207 * unsure about OSF/1 and HP/UX. 931118 */
209 size = *(afs_hyper_t *)arg;
210 if (!osi_hFitsInOff(size, off))
212 osi_h2off(size, off);
214 code = ftruncate64 (fd, off);
215 #else /* O_LARGEFILE */
216 code = ftruncate (fd, off);
217 #endif /* O_LARGEFILE */
222 case USD_IOCTL_TAPEOPERATION:
224 usd_tapeop_t *tapeOpp = (usd_tapeop_t *)arg;
225 #if defined(AFS_AIX_ENV)
226 struct stop os_tapeop;
228 if (tapeOpp->tp_op == USDTAPE_WEOF) {
229 os_tapeop.st_op = STWEOF;
230 } else if (tapeOpp->tp_op == USDTAPE_REW) {
231 os_tapeop.st_op = STREW;
232 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
233 os_tapeop.st_op = STFSF;
234 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
235 os_tapeop.st_op = STRSF;
236 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
238 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
241 /* unsupported tape operation */
244 os_tapeop.st_count = tapeOpp->tp_count;
246 code = ioctl(fd, STIOCTOP, &os_tapeop);
248 struct mtop os_tapeop;
250 if (tapeOpp->tp_op == USDTAPE_WEOF) {
251 os_tapeop.mt_op = MTWEOF;
252 } else if (tapeOpp->tp_op == USDTAPE_REW) {
253 os_tapeop.mt_op = MTREW;
254 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
255 os_tapeop.mt_op = MTFSF;
256 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
257 os_tapeop.mt_op = MTBSF;
258 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
260 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
263 /* unsupported tape operation */
266 os_tapeop.mt_count = tapeOpp->tp_count;
268 code = ioctl(fd, MTIOCTOP, &os_tapeop);
269 #endif /* AFS_AIX_ENV */
279 case USD_IOCTL_GETBLKSIZE:
280 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)) {
281 *((long *)arg) = (long)4096;
285 *((long *)arg) = (long)fsinfo.f_bsize;
286 #else /* AFS_AIX_ENV */
287 *((long *)arg) = (long)info.st_blksize;
288 #endif /* AFS_AIX_ENV */
297 static int usd_FileClose(usd_handle_t usd)
299 int fd = (int)(usd->handle);
303 /* I can't really believe this is necessary. On the one hand the user
304 * space code always uses character devices, which aren't supposed to do
305 * any buffering. On the other, I very much doubt fsyncing a regular file
306 * being salvaged is ever necessary. But the salvager used to do this
307 * before returning, so... */
309 if (usd->openFlags & (O_WRONLY|O_RDWR)) {
311 code = usd_FileIoctl(usd, USD_IOCTL_GETTYPE, &mode);
315 /* on AIX3.1 can't fsync raw disk device */
330 if (usd->fullPathName)
331 free(usd->fullPathName);
337 static int usd_FileOpen(
351 oflags = (flags & USD_OPEN_RDWR) ? O_RDWR : O_RDONLY;
353 #ifdef O_SYNC /* AFS_DARWIN_ENV XXX */
354 if (flags & USD_OPEN_SYNC)
358 if (flags & USD_OPEN_CREATE)
362 fd = open64(path, oflags | O_LARGEFILE, mode);
363 #else /* O_LARGEFILE */
364 fd = open(path, oflags, mode);
365 #endif /* O_LARGEFILE */
369 usd = (usd_handle_t) malloc(sizeof(*usd));
370 memset(usd, 0, sizeof(*usd));
371 usd->handle = (void *)fd;
372 usd->read = usd_FileRead;
373 usd->write = usd_FileWrite;
374 usd->seek = usd_FileSeek;
375 usd->ioctl = usd_FileIoctl;
376 usd->close = usd_FileClose;
377 usd->fullPathName = (char *)malloc(strlen(path)+1);
378 strcpy(usd->fullPathName, path);
379 usd->openFlags = flags;
382 if (flags & (USD_OPEN_RLOCK|USD_OPEN_WLOCK)) {
385 #else /* O_LARGEFILE */
387 #endif /* O_LARGEFILE */
389 /* make sure both lock bits aren't set */
390 assert(~flags & (USD_OPEN_RLOCK|USD_OPEN_WLOCK));
392 fl.l_type = ((flags & USD_OPEN_RLOCK) ? F_RDLCK : F_WRLCK);
393 fl.l_whence = SEEK_SET;
394 fl.l_start = (osi_lloff_t)0;
395 fl.l_len = (osi_lloff_t)0; /* whole file */
397 code = fcntl(fd, F_SETLK64, &fl);
398 #else /* O_LARGEFILE */
399 code = fcntl(fd, F_SETLK, &fl);
400 #endif /* O_LARGEFILE */
404 /* If we're trying to obtain a write lock on a real disk, then the
405 * aggregate must not be attached by the kernel. If so, unlock it
407 * WARNING: The code to check for the above has been removed when this
408 * file was ported from DFS src. It should be put back if
409 * this library is used to access hard disks
413 if (code == 0 && usdP)
420 static int usd_FileDummyClose(usd_handle_t usd)
426 int usd_Open(const char *path, int oflag, int mode, usd_handle_t *usdP)
428 return usd_FileOpen(path, oflag, mode, usdP);
431 static int usd_FileStandardInput(
439 usd = (usd_handle_t) malloc(sizeof(*usd));
440 memset(usd, 0, sizeof(*usd));
441 usd->handle = (void *)((unsigned long)0);
442 usd->read = usd_FileRead;
443 usd->write = usd_FileWrite;
444 usd->seek = usd_FileSeek;
445 usd->ioctl = usd_FileIoctl;
446 usd->close = usd_FileDummyClose;
447 usd->fullPathName = "STDIN";
454 int usd_StandardInput(usd_handle_t *usdP)
456 return usd_FileStandardInput(usdP);
459 static int usd_FileStandardOutput(
467 usd = (usd_handle_t) malloc(sizeof(*usd));
468 memset(usd, 0, sizeof(*usd));
469 usd->handle = (void *)((unsigned long)1);
470 usd->read = usd_FileRead;
471 usd->write = usd_FileWrite;
472 usd->seek = usd_FileSeek;
473 usd->ioctl = usd_FileIoctl;
474 usd->close = usd_FileDummyClose;
475 usd->fullPathName = "STDOUT";
482 int usd_StandardOutput(usd_handle_t *usdP)
484 return usd_FileStandardOutput(usdP);